unsigned char model[16]; /* bytes 16-31 of inquiry data */
unsigned char raid_level; /* from inquiry page 0xC1 */
unsigned char volume_offline; /* discovered via TUR or VPD */
+ u16 queue_depth; /* max queue_depth for this device */
+ atomic_t ioaccel_cmds_out; /* Only used for physical devices
+ * counts commands sent to physical
+ * device via "ioaccel" path.
+ */
u32 ioaccel_handle;
int offload_config; /* I/O accel RAID offload configured */
int offload_enabled; /* I/O accel RAID offload enabled */
*/
struct raid_map_data raid_map; /* I/O accelerator RAID map */
+ /*
+ * Pointers from logical drive map indices to the phys drives that
+ * make those logical drives. Note, multiple logical drives may
+ * share physical drives. You can have for instance 5 physical
+ * drives with 3 logical drives each using those same 5 physical
+ * disks. We need these pointers for counting i/o's out to physical
+ * devices in order to honor physical device queue depth limits.
+ */
+ struct hpsa_scsi_dev_t *phys_disk[RAID_MAP_MAX_ENTRIES];
};
struct reply_queue_buffer {
struct CfgTable __iomem *cfgtable;
int interrupts_enabled;
int max_commands;
+ int last_allocation;
atomic_t commands_outstanding;
# define PERF_MODE_INT 0
# define DOORBELL_INT 1
/* cap concurrent passthrus at some reasonable maximum */
#define HPSA_MAX_CONCURRENT_PASSTHRUS (10)
- spinlock_t passthru_count_lock; /* protects passthru_count */
- int passthru_count;
+ atomic_t passthru_cmds_avail;
/*
* Performant mode completion buffers
atomic_t firmware_flash_in_progress;
u32 __percpu *lockup_detected;
struct delayed_work monitor_ctlr_work;
+ struct delayed_work rescan_ctlr_work;
int remove_in_progress;
/* Address of h->q[x] is passed to intr handler to know which queue */
u8 q[MAX_REPLY_QUEUES];
spinlock_t offline_device_lock;
struct list_head offline_device_list;
int acciopath_status;
- int drv_req_rescan; /* flag for driver to request rescan event */
int raid_offload_debug;
+ struct workqueue_struct *resubmit_wq;
+ struct workqueue_struct *rescan_ctlr_wq;
};
struct offline_device_entry {
*/
#define SA5_DOORBELL 0x20
#define SA5_REQUEST_PORT_OFFSET 0x40
+#define SA5_REQUEST_PORT64_LO_OFFSET 0xC0
+#define SA5_REQUEST_PORT64_HI_OFFSET 0xC4
#define SA5_REPLY_INTR_MASK_OFFSET 0x34
#define SA5_REPLY_PORT_OFFSET 0x44
#define SA5_INTR_STATUS 0x30
static void SA5_submit_command_ioaccel2(struct ctlr_info *h,
struct CommandList *c)
{
- if (c->cmd_type == CMD_IOACCEL2)
- writel(c->busaddr, h->vaddr + IOACCEL2_INBOUND_POSTQ_32);
- else
- writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET);
+ writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET);
}
/*
unsigned long register_value = FIFO_EMPTY;
/* msi auto clears the interrupt pending bit. */
- if (!(h->msi_vector || h->msix_vector)) {
+ if (unlikely(!(h->msi_vector || h->msix_vector))) {
/* flush the controller write of the reply queue by reading
* outbound doorbell status register.
*/
- register_value = readl(h->vaddr + SA5_OUTDB_STATUS);
+ (void) readl(h->vaddr + SA5_OUTDB_STATUS);
writel(SA5_OUTDB_CLEAR_PERF_BIT, h->vaddr + SA5_OUTDB_CLEAR);
/* Do a read in order to flush the write to the controller
* (as per spec.)
*/
- register_value = readl(h->vaddr + SA5_OUTDB_STATUS);
+ (void) readl(h->vaddr + SA5_OUTDB_STATUS);
}
- if ((rq->head[rq->current_entry] & 1) == rq->wraparound) {
+ if ((((u32) rq->head[rq->current_entry]) & 1) == rq->wraparound) {
register_value = rq->head[rq->current_entry];
rq->current_entry++;
atomic_dec(&h->commands_outstanding);
if (!register_value)
return false;
- if (h->msi_vector || h->msix_vector)
- return true;
-
/* Read outbound doorbell to flush */
register_value = readl(h->vaddr + SA5_OUTDB_STATUS);
return register_value & SA5_OUTDB_STATUS_PERF_BIT;