static irqreturn_t do_hpsa_intr_intx(int irq, void *dev_id);
static irqreturn_t do_hpsa_intr_msi(int irq, void *dev_id);
static int hpsa_ioctl(struct scsi_device *dev, int cmd, void __user *arg);
-static void lock_and_start_io(struct ctlr_info *h);
-static void start_io(struct ctlr_info *h, unsigned long *flags);
#ifdef CONFIG_COMPAT
static int hpsa_compat_ioctl(struct scsi_device *dev, int cmd,
#endif
static void cmd_free(struct ctlr_info *h, struct CommandList *c);
-static void cmd_special_free(struct ctlr_info *h, struct CommandList *c);
static struct CommandList *cmd_alloc(struct ctlr_info *h);
-static struct CommandList *cmd_special_alloc(struct ctlr_info *h);
static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
void *buff, size_t size, u16 page_code, unsigned char *scsi3addr,
int cmd_type);
+static void hpsa_free_cmd_pool(struct ctlr_info *h);
#define VPD_PAGE (1 << 8)
static int hpsa_scsi_queue_command(struct Scsi_Host *h, struct scsi_cmnd *cmd);
static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h,
struct CommandList *c, u32 ioaccel_handle, u8 *cdb, int cdb_len,
u8 *scsi3addr);
+static void hpsa_command_resubmit_worker(struct work_struct *work);
static inline struct ctlr_info *sdev_to_hba(struct scsi_device *sdev)
{
.no_write_same = 1,
};
-
-/* Enqueuing and dequeuing functions for cmdlists. */
-static inline void addQ(struct list_head *list, struct CommandList *c)
-{
- list_add_tail(&c->list, list);
-}
-
static inline u32 next_command(struct ctlr_info *h, u8 q)
{
u32 a;
static void enqueue_cmd_and_start_io(struct ctlr_info *h,
struct CommandList *c)
{
- unsigned long flags;
-
switch (c->cmd_type) {
case CMD_IOACCEL1:
set_ioaccel1_performant_mode(h, c);
set_performant_mode(h, c);
}
dial_down_lockup_detection_during_fw_flash(h, c);
- spin_lock_irqsave(&h->lock, flags);
- addQ(&h->reqQ, c);
- h->Qdepth++;
- start_io(h, &flags);
- spin_unlock_irqrestore(&h->lock, flags);
-}
-
-static inline void removeQ(struct CommandList *c)
-{
- if (WARN_ON(list_empty(&c->list)))
- return;
- list_del_init(&c->list);
+ atomic_inc(&h->commands_outstanding);
+ h->access.submit_command(h, c);
}
static inline int is_hba_lunid(unsigned char scsi3addr[])
h->cmd_sg_list = kzalloc(sizeof(*h->cmd_sg_list) * h->nr_cmds,
GFP_KERNEL);
- if (!h->cmd_sg_list)
+ if (!h->cmd_sg_list) {
+ dev_err(&h->pdev->dev, "Failed to allocate SG list\n");
return -ENOMEM;
+ }
for (i = 0; i < h->nr_cmds; i++) {
h->cmd_sg_list[i] = kmalloc(sizeof(*h->cmd_sg_list[i]) *
h->chainsize, GFP_KERNEL);
- if (!h->cmd_sg_list[i])
+ if (!h->cmd_sg_list[i]) {
+ dev_err(&h->pdev->dev, "Failed to allocate cmd SG\n");
goto clean;
+ }
}
return 0;
struct hpsa_scsi_dev_t *dev)
{
struct io_accel2_cmd *c2 = &h->ioaccel2_cmd_pool[c->cmdindex];
- int raid_retry = 0;
/* check for good status */
if (likely(c2->error_data.serv_response == 0 &&
if (is_logical_dev_addr_mode(dev->scsi3addr) &&
c2->error_data.serv_response ==
IOACCEL2_SERV_RESPONSE_FAILURE) {
- dev->offload_enabled = 0;
- h->drv_req_rescan = 1; /* schedule controller for a rescan */
- cmd->result = DID_SOFT_ERROR << 16;
- cmd_free(h, c);
- cmd->scsi_done(cmd);
- return;
- }
- raid_retry = handle_ioaccel_mode2_error(h, c, cmd, c2);
- /* If error found, disable Smart Path, schedule a rescan,
- * and force a retry on the standard path.
- */
- if (raid_retry) {
- dev_warn(&h->pdev->dev, "%s: Retrying on standard path.\n",
- "HP SSD Smart Path");
- dev->offload_enabled = 0; /* Disable Smart Path */
- h->drv_req_rescan = 1; /* schedule controller rescan */
- cmd->result = DID_SOFT_ERROR << 16;
+ if (c2->error_data.status ==
+ IOACCEL2_STATUS_SR_IOACCEL_DISABLED)
+ dev->offload_enabled = 0;
+ goto retry_cmd;
}
+
+ if (handle_ioaccel_mode2_error(h, c, cmd, c2))
+ goto retry_cmd;
+
cmd_free(h, c);
cmd->scsi_done(cmd);
+ return;
+
+retry_cmd:
+ INIT_WORK(&c->work, hpsa_command_resubmit_worker);
+ queue_work_on(raw_smp_processor_id(), h->resubmit_wq, &c->work);
}
static void complete_scsi_command(struct CommandList *cp)
if (is_logical_dev_addr_mode(dev->scsi3addr)) {
if (ei->CommandStatus == CMD_IOACCEL_DISABLED)
dev->offload_enabled = 0;
- cmd->result = DID_SOFT_ERROR << 16;
- cmd_free(h, cp);
- cmd->scsi_done(cmd);
+ INIT_WORK(&cp->work, hpsa_command_resubmit_worker);
+ queue_work_on(raw_smp_processor_id(),
+ h->resubmit_wq, &cp->work);
return;
}
}
struct CommandList *c;
struct ErrorInfo *ei;
- c = cmd_special_alloc(h);
+ c = cmd_alloc(h);
- if (c == NULL) { /* trouble... */
- dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n");
+ if (c == NULL) {
+ dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n");
return -ENOMEM;
}
rc = -1;
}
out:
- cmd_special_free(h, c);
+ cmd_free(h, c);
return rc;
}
struct CommandList *c;
struct ErrorInfo *ei;
- c = cmd_special_alloc(h);
-
+ c = cmd_alloc(h);
if (c == NULL) { /* trouble... */
- dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n");
+ dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n");
return -ENOMEM;
}
rc = -1;
}
out:
- cmd_special_free(h, c);
+ cmd_free(h, c);
return rc;
}
struct CommandList *c;
struct ErrorInfo *ei;
- c = cmd_special_alloc(h);
+ c = cmd_alloc(h);
if (c == NULL) { /* trouble... */
- dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n");
+ dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n");
return -ENOMEM;
}
hpsa_scsi_interpret_error(h, c);
rc = -1;
}
- cmd_special_free(h, c);
+ cmd_free(h, c);
return rc;
}
struct CommandList *c;
struct ErrorInfo *ei;
- c = cmd_special_alloc(h);
+ c = cmd_alloc(h);
if (c == NULL) {
- dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n");
+ dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n");
return -ENOMEM;
}
if (fill_cmd(c, HPSA_GET_RAID_MAP, h, &this_device->raid_map,
sizeof(this_device->raid_map), 0,
scsi3addr, TYPE_CMD)) {
dev_warn(&h->pdev->dev, "Out of memory in hpsa_get_raid_map()\n");
- cmd_special_free(h, c);
+ cmd_free(h, c);
return -ENOMEM;
}
hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_FROMDEVICE);
ei = c->err_info;
if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) {
hpsa_scsi_interpret_error(h, c);
- cmd_special_free(h, c);
+ cmd_free(h, c);
return -1;
}
- cmd_special_free(h, c);
+ cmd_free(h, c);
/* @todo in the future, dynamically allocate RAID map memory */
if (le32_to_cpu(this_device->raid_map.structure_size) >
unsigned char scsi3addr[8];
struct ErrorInfo *ei;
- c = cmd_special_alloc(h);
+ c = cmd_alloc(h);
if (c == NULL) { /* trouble... */
- dev_err(&h->pdev->dev, "cmd_special_alloc returned NULL!\n");
+ dev_err(&h->pdev->dev, "cmd_alloc returned NULL!\n");
return -1;
}
/* address the controller */
}
}
out:
- cmd_special_free(h, c);
+ cmd_free(h, c);
return rc;
}
kfree(logdev_list);
}
-/* hpsa_scatter_gather takes a struct scsi_cmnd, (cmd), and does the pci
+/*
+ * hpsa_scatter_gather takes a struct scsi_cmnd, (cmd), and does the pci
* dma mapping and fills in the scatter gather entries of the
* hpsa command, cp.
*/
sglist_finished:
cp->Header.SGList = (u8) use_sg; /* no. SGs contig in this cmd */
- cp->Header.SGTotal = cpu_to_le16(use_sg); /* total sgs in this cmd list */
+ cp->Header.SGTotal = cpu_to_le16(use_sg); /* total sgs in cmd list */
return 0;
}
set_encrypt_ioaccel2(h, c, cp);
cp->scsi_nexus = cpu_to_le32(ioaccel_handle);
- cp->Tag = cpu_to_le32(c->cmdindex << DIRECT_LOOKUP_SHIFT |
- DIRECT_LOOKUP_BIT);
+ cp->Tag = cpu_to_le32(c->cmdindex << DIRECT_LOOKUP_SHIFT);
memcpy(cp->cdb, cdb, sizeof(cp->cdb));
/* fill in sg elements */
dev->scsi3addr);
}
-/*
- * Running in struct Scsi_Host->host_lock less mode using LLD internal
- * struct ctlr_info *h->lock w/ spin_lock_irqsave() protection.
- */
-static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
+/* Submit commands down the "normal" RAID stack path */
+static int hpsa_ciss_submit(struct ctlr_info *h,
+ struct CommandList *c, struct scsi_cmnd *cmd,
+ unsigned char scsi3addr[])
{
- struct ctlr_info *h;
- struct hpsa_scsi_dev_t *dev;
- unsigned char scsi3addr[8];
- struct CommandList *c;
- int rc = 0;
-
- /* Get the ptr to our adapter structure out of cmd->host. */
- h = sdev_to_hba(cmd->device);
- dev = cmd->device->hostdata;
- if (!dev) {
- cmd->result = DID_NO_CONNECT << 16;
- cmd->scsi_done(cmd);
- return 0;
- }
- memcpy(scsi3addr, dev->scsi3addr, sizeof(scsi3addr));
-
- if (unlikely(lockup_detected(h))) {
- cmd->result = DID_ERROR << 16;
- cmd->scsi_done(cmd);
- return 0;
- }
- c = cmd_alloc(h);
- if (c == NULL) { /* trouble... */
- dev_err(&h->pdev->dev, "cmd_alloc returned NULL!\n");
- return SCSI_MLQUEUE_HOST_BUSY;
- }
-
- /* Fill in the command list header */
- /* save c in case we have to abort it */
cmd->host_scribble = (unsigned char *) c;
-
c->cmd_type = CMD_SCSI;
c->scsi_cmd = cmd;
-
- /* Call alternate submit routine for I/O accelerated commands.
- * Retries always go down the normal I/O path.
- */
- if (likely(cmd->retries == 0 &&
- cmd->request->cmd_type == REQ_TYPE_FS &&
- h->acciopath_status)) {
- if (dev->offload_enabled) {
- rc = hpsa_scsi_ioaccel_raid_map(h, c);
- if (rc == 0)
- return 0; /* Sent on ioaccel path */
- if (rc < 0) { /* scsi_dma_map failed. */
- cmd_free(h, c);
- return SCSI_MLQUEUE_HOST_BUSY;
- }
- } else if (dev->ioaccel_handle) {
- rc = hpsa_scsi_ioaccel_direct_map(h, c);
- if (rc == 0)
- return 0; /* Sent on direct map path */
- if (rc < 0) { /* scsi_dma_map failed. */
- cmd_free(h, c);
- return SCSI_MLQUEUE_HOST_BUSY;
- }
- }
- }
-
c->Header.ReplyQueue = 0; /* unused in simple mode */
memcpy(&c->Header.LUN.LunAddrBytes[0], &scsi3addr[0], 8);
- c->Header.tag = cpu_to_le64((c->cmdindex << DIRECT_LOOKUP_SHIFT) |
- DIRECT_LOOKUP_BIT);
+ c->Header.tag = cpu_to_le64((c->cmdindex << DIRECT_LOOKUP_SHIFT));
/* Fill in the request block... */
return 0;
}
+static void hpsa_command_resubmit_worker(struct work_struct *work)
+{
+ struct scsi_cmnd *cmd;
+ struct hpsa_scsi_dev_t *dev;
+ struct CommandList *c =
+ container_of(work, struct CommandList, work);
+
+ cmd = c->scsi_cmd;
+ dev = cmd->device->hostdata;
+ if (!dev) {
+ cmd->result = DID_NO_CONNECT << 16;
+ cmd->scsi_done(cmd);
+ return;
+ }
+ if (hpsa_ciss_submit(c->h, c, cmd, dev->scsi3addr)) {
+ /*
+ * If we get here, it means dma mapping failed. Try
+ * again via scsi mid layer, which will then get
+ * SCSI_MLQUEUE_HOST_BUSY.
+ */
+ cmd->result = DID_IMM_RETRY << 16;
+ cmd->scsi_done(cmd);
+ }
+}
+
+/* Running in struct Scsi_Host->host_lock less mode */
+static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
+{
+ struct ctlr_info *h;
+ struct hpsa_scsi_dev_t *dev;
+ unsigned char scsi3addr[8];
+ struct CommandList *c;
+ int rc = 0;
+
+ /* Get the ptr to our adapter structure out of cmd->host. */
+ h = sdev_to_hba(cmd->device);
+ dev = cmd->device->hostdata;
+ if (!dev) {
+ cmd->result = DID_NO_CONNECT << 16;
+ cmd->scsi_done(cmd);
+ return 0;
+ }
+ memcpy(scsi3addr, dev->scsi3addr, sizeof(scsi3addr));
+
+ if (unlikely(lockup_detected(h))) {
+ cmd->result = DID_ERROR << 16;
+ cmd->scsi_done(cmd);
+ return 0;
+ }
+ c = cmd_alloc(h);
+ if (c == NULL) { /* trouble... */
+ dev_err(&h->pdev->dev, "cmd_alloc returned NULL!\n");
+ return SCSI_MLQUEUE_HOST_BUSY;
+ }
+
+ /* Call alternate submit routine for I/O accelerated commands.
+ * Retries always go down the normal I/O path.
+ */
+ if (likely(cmd->retries == 0 &&
+ cmd->request->cmd_type == REQ_TYPE_FS &&
+ h->acciopath_status)) {
+
+ cmd->host_scribble = (unsigned char *) c;
+ c->cmd_type = CMD_SCSI;
+ c->scsi_cmd = cmd;
+
+ if (dev->offload_enabled) {
+ rc = hpsa_scsi_ioaccel_raid_map(h, c);
+ if (rc == 0)
+ return 0; /* Sent on ioaccel path */
+ if (rc < 0) { /* scsi_dma_map failed. */
+ cmd_free(h, c);
+ return SCSI_MLQUEUE_HOST_BUSY;
+ }
+ } else if (dev->ioaccel_handle) {
+ rc = hpsa_scsi_ioaccel_direct_map(h, c);
+ if (rc == 0)
+ return 0; /* Sent on direct map path */
+ if (rc < 0) { /* scsi_dma_map failed. */
+ cmd_free(h, c);
+ return SCSI_MLQUEUE_HOST_BUSY;
+ }
+ }
+ }
+ return hpsa_ciss_submit(h, c, cmd, scsi3addr);
+}
+
static int do_not_scan_if_controller_locked_up(struct ctlr_info *h)
{
unsigned long flags;
sh->max_cmd_len = MAX_COMMAND_SIZE;
sh->max_lun = HPSA_MAX_LUN;
sh->max_id = HPSA_MAX_LUN;
- sh->can_queue = h->nr_cmds;
+ sh->can_queue = h->nr_cmds -
+ HPSA_CMDS_RESERVED_FOR_ABORTS -
+ HPSA_CMDS_RESERVED_FOR_DRIVER -
+ HPSA_MAX_CONCURRENT_PASSTHRUS;
if (h->hba_mode_enabled)
sh->cmd_per_lun = 7;
else
- sh->cmd_per_lun = h->nr_cmds;
+ sh->cmd_per_lun = sh->can_queue;
sh->sg_tablesize = h->maxsgentries;
h->scsi_host = sh;
sh->hostdata[0] = (unsigned long) h;
int waittime = 1; /* seconds */
struct CommandList *c;
- c = cmd_special_alloc(h);
+ c = cmd_alloc(h);
if (!c) {
dev_warn(&h->pdev->dev, "out of memory in "
"wait_for_device_to_become_ready.\n");
else
dev_warn(&h->pdev->dev, "device is ready.\n");
- cmd_special_free(h, c);
+ cmd_free(h, c);
return rc;
}
struct ErrorInfo *ei;
__le32 tagupper, taglower;
- c = cmd_special_alloc(h);
+ c = cmd_alloc(h);
if (c == NULL) { /* trouble... */
- dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n");
+ dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n");
return -ENOMEM;
}
rc = -1;
break;
}
- cmd_special_free(h, c);
+ cmd_free(h, c);
dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: Finished.\n",
__func__, tagupper, taglower);
return rc;
}
-/*
- * hpsa_find_cmd_in_queue
- *
- * Used to determine whether a command (find) is still present
- * in queue_head. Optionally excludes the last element of queue_head.
- *
- * This is used to avoid unnecessary aborts. Commands in h->reqQ have
- * not yet been submitted, and so can be aborted by the driver without
- * sending an abort to the hardware.
- *
- * Returns pointer to command if found in queue, NULL otherwise.
- */
-static struct CommandList *hpsa_find_cmd_in_queue(struct ctlr_info *h,
- struct scsi_cmnd *find, struct list_head *queue_head)
-{
- unsigned long flags;
- struct CommandList *c = NULL; /* ptr into cmpQ */
-
- if (!find)
- return NULL;
- spin_lock_irqsave(&h->lock, flags);
- list_for_each_entry(c, queue_head, list) {
- if (c->scsi_cmd == NULL) /* e.g.: passthru ioctl */
- continue;
- if (c->scsi_cmd == find) {
- spin_unlock_irqrestore(&h->lock, flags);
- return c;
- }
- }
- spin_unlock_irqrestore(&h->lock, flags);
- return NULL;
-}
-
-static struct CommandList *hpsa_find_cmd_in_queue_by_tag(struct ctlr_info *h,
- u8 *tag, struct list_head *queue_head)
-{
- unsigned long flags;
- struct CommandList *c;
-
- spin_lock_irqsave(&h->lock, flags);
- list_for_each_entry(c, queue_head, list) {
- if (memcmp(&c->Header.tag, tag, 8) != 0)
- continue;
- spin_unlock_irqrestore(&h->lock, flags);
- return c;
- }
- spin_unlock_irqrestore(&h->lock, flags);
- return NULL;
-}
-
/* ioaccel2 path firmware cannot handle abort task requests.
* Change abort requests to physical target reset, and send to the
* address of the physical disk used for the ioaccel 2 command.
static int hpsa_send_abort_both_ways(struct ctlr_info *h,
unsigned char *scsi3addr, struct CommandList *abort)
{
- u8 swizzled_tag[8];
- struct CommandList *c;
- int rc = 0, rc2 = 0;
-
/* ioccelerator mode 2 commands should be aborted via the
* accelerated path, since RAID path is unaware of these commands,
* but underlying firmware can't handle abort TMF.
if (abort->cmd_type == CMD_IOACCEL2)
return hpsa_send_reset_as_abort_ioaccel2(h, scsi3addr, abort);
- /* we do not expect to find the swizzled tag in our queue, but
- * check anyway just to be sure the assumptions which make this
- * the case haven't become wrong.
- */
- memcpy(swizzled_tag, &abort->Request.CDB[4], 8);
- swizzle_abort_tag(swizzled_tag);
- c = hpsa_find_cmd_in_queue_by_tag(h, swizzled_tag, &h->cmpQ);
- if (c != NULL) {
- dev_warn(&h->pdev->dev, "Unexpectedly found byte-swapped tag in completion queue.\n");
- return hpsa_send_abort(h, scsi3addr, abort, 0);
- }
- rc = hpsa_send_abort(h, scsi3addr, abort, 0);
-
- /* if the command is still in our queue, we can't conclude that it was
- * aborted (it might have just completed normally) but in any case
- * we don't need to try to abort it another way.
- */
- c = hpsa_find_cmd_in_queue(h, abort->scsi_cmd, &h->cmpQ);
- if (c)
- rc2 = hpsa_send_abort(h, scsi3addr, abort, 1);
- return rc && rc2;
+ return hpsa_send_abort(h, scsi3addr, abort, 0) &&
+ hpsa_send_abort(h, scsi3addr, abort, 1);
}
/* Send an abort for the specified command.
struct ctlr_info *h;
struct hpsa_scsi_dev_t *dev;
struct CommandList *abort; /* pointer to command to be aborted */
- struct CommandList *found;
struct scsi_cmnd *as; /* ptr to scsi cmd inside aborted command. */
char msg[256]; /* For debug messaging. */
int ml = 0;
dev_dbg(&h->pdev->dev, "%s\n", msg);
dev_warn(&h->pdev->dev, "Abort request on C%d:B%d:T%d:L%d\n",
h->scsi_host->host_no, dev->bus, dev->target, dev->lun);
-
- /* Search reqQ to See if command is queued but not submitted,
- * if so, complete the command with aborted status and remove
- * it from the reqQ.
- */
- found = hpsa_find_cmd_in_queue(h, sc, &h->reqQ);
- if (found) {
- found->err_info->CommandStatus = CMD_ABORTED;
- finish_cmd(found);
- dev_info(&h->pdev->dev, "%s Request SUCCEEDED (driver queue).\n",
- msg);
- return SUCCESS;
- }
-
- /* not in reqQ, if also not in cmpQ, must have already completed */
- found = hpsa_find_cmd_in_queue(h, sc, &h->cmpQ);
- if (!found) {
- dev_dbg(&h->pdev->dev, "%s Request SUCCEEDED (not known to driver).\n",
- msg);
- return SUCCESS;
- }
-
/*
* Command is in flight, or possibly already completed
* by the firmware (but not to the scsi mid layer) but we can't
*/
#define ABORT_COMPLETE_WAIT_SECS 30
for (i = 0; i < ABORT_COMPLETE_WAIT_SECS * 10; i++) {
- found = hpsa_find_cmd_in_queue(h, sc, &h->cmpQ);
- if (!found)
+ if (test_bit(abort->cmdindex & (BITS_PER_LONG - 1),
+ h->cmd_pool_bits +
+ (abort->cmdindex / BITS_PER_LONG)))
+ msleep(100);
+ else
return SUCCESS;
- msleep(100);
}
dev_warn(&h->pdev->dev, "%s FAILED. Aborted command has not completed after %d seconds.\n",
msg, ABORT_COMPLETE_WAIT_SECS);
c = h->cmd_pool + i;
memset(c, 0, sizeof(*c));
- cmd_dma_handle = h->cmd_pool_dhandle
- + i * sizeof(*c);
+ c->Header.tag = cpu_to_le64((u64) i << DIRECT_LOOKUP_SHIFT);
+ cmd_dma_handle = h->cmd_pool_dhandle + i * sizeof(*c);
c->err_info = h->errinfo_pool + i;
memset(c->err_info, 0, sizeof(*c->err_info));
err_dma_handle = h->errinfo_pool_dhandle
c->cmdindex = i;
- INIT_LIST_HEAD(&c->list);
c->busaddr = (u32) cmd_dma_handle;
temp64.val = (u64) err_dma_handle;
c->ErrDesc.Addr = cpu_to_le64(err_dma_handle);
return c;
}
-/* For operations that can wait for kmalloc to possibly sleep,
- * this routine can be called. Lock need not be held to call
- * cmd_special_alloc. cmd_special_free() is the complement.
- */
-static struct CommandList *cmd_special_alloc(struct ctlr_info *h)
-{
- struct CommandList *c;
- dma_addr_t cmd_dma_handle, err_dma_handle;
-
- c = pci_zalloc_consistent(h->pdev, sizeof(*c), &cmd_dma_handle);
- if (c == NULL)
- return NULL;
-
- c->cmd_type = CMD_SCSI;
- c->cmdindex = -1;
-
- c->err_info = pci_zalloc_consistent(h->pdev, sizeof(*c->err_info),
- &err_dma_handle);
-
- if (c->err_info == NULL) {
- pci_free_consistent(h->pdev,
- sizeof(*c), c, cmd_dma_handle);
- return NULL;
- }
-
- INIT_LIST_HEAD(&c->list);
- c->busaddr = (u32) cmd_dma_handle;
- c->ErrDesc.Addr = cpu_to_le64(err_dma_handle);
- c->ErrDesc.Len = cpu_to_le32(sizeof(*c->err_info));
-
- c->h = h;
- return c;
-}
-
static void cmd_free(struct ctlr_info *h, struct CommandList *c)
{
int i;
h->cmd_pool_bits + (i / BITS_PER_LONG));
}
-static void cmd_special_free(struct ctlr_info *h, struct CommandList *c)
-{
- pci_free_consistent(h->pdev, sizeof(*c->err_info),
- c->err_info,
- (dma_addr_t) le64_to_cpu(c->ErrDesc.Addr));
- pci_free_consistent(h->pdev, sizeof(*c),
- c, (dma_addr_t) (c->busaddr & DIRECT_LOOKUP_MASK));
-}
-
#ifdef CONFIG_COMPAT
static int hpsa_ioctl32_passthru(struct scsi_device *dev, int cmd,
memset(buff, 0, iocommand.buf_size);
}
}
- c = cmd_special_alloc(h);
+ c = cmd_alloc(h);
if (c == NULL) {
rc = -ENOMEM;
goto out_kfree;
c->Header.SGTotal = cpu_to_le16(0);
}
memcpy(&c->Header.LUN, &iocommand.LUN_info, sizeof(c->Header.LUN));
- /* use the kernel address the cmd block for tag */
- c->Header.tag = cpu_to_le64(c->busaddr);
/* Fill in Request block */
memcpy(&c->Request, &iocommand.Request,
}
}
out:
- cmd_special_free(h, c);
+ cmd_free(h, c);
out_kfree:
kfree(buff);
return rc;
data_ptr += sz;
sg_used++;
}
- c = cmd_special_alloc(h);
+ c = cmd_alloc(h);
if (c == NULL) {
status = -ENOMEM;
goto cleanup1;
c->Header.SGList = (u8) sg_used;
c->Header.SGTotal = cpu_to_le16(sg_used);
memcpy(&c->Header.LUN, &ioc->LUN_info, sizeof(c->Header.LUN));
- c->Header.tag = cpu_to_le64(c->busaddr);
memcpy(&c->Request, &ioc->Request, sizeof(c->Request));
if (ioc->buf_size > 0) {
int i;
}
status = 0;
cleanup0:
- cmd_special_free(h, c);
+ cmd_free(h, c);
cleanup1:
if (buff) {
int i;
c->Header.SGList = 0;
c->Header.SGTotal = cpu_to_le16(0);
}
- c->Header.tag = cpu_to_le64(c->busaddr);
memcpy(c->Header.LUN.LunAddrBytes, scsi3addr, 8);
if (cmd_type == TYPE_CMD) {
return page_remapped ? (page_remapped + page_offs) : NULL;
}
-/* Takes cmds off the submission queue and sends them to the hardware,
- * then puts them on the queue of cmds waiting for completion.
- * Assumes h->lock is held
- */
-static void start_io(struct ctlr_info *h, unsigned long *flags)
-{
- struct CommandList *c;
-
- while (!list_empty(&h->reqQ)) {
- c = list_entry(h->reqQ.next, struct CommandList, list);
- /* can't do anything if fifo is full */
- if ((h->access.fifo_full(h))) {
- h->fifo_recently_full = 1;
- dev_warn(&h->pdev->dev, "fifo full\n");
- break;
- }
- h->fifo_recently_full = 0;
-
- /* Get the first entry from the Request Q */
- removeQ(c);
- h->Qdepth--;
-
- /* Put job onto the completed Q */
- addQ(&h->cmpQ, c);
- atomic_inc(&h->commands_outstanding);
- spin_unlock_irqrestore(&h->lock, *flags);
- /* Tell the controller execute command */
- h->access.submit_command(h, c);
- spin_lock_irqsave(&h->lock, *flags);
- }
-}
-
-static void lock_and_start_io(struct ctlr_info *h)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&h->lock, flags);
- start_io(h, &flags);
- spin_unlock_irqrestore(&h->lock, flags);
-}
-
static inline unsigned long get_next_completion(struct ctlr_info *h, u8 q)
{
return h->access.command_completed(h, q);
static inline void finish_cmd(struct CommandList *c)
{
- unsigned long flags;
- int io_may_be_stalled = 0;
- struct ctlr_info *h = c->h;
- int count;
-
- spin_lock_irqsave(&h->lock, flags);
- removeQ(c);
-
- /*
- * Check for possibly stalled i/o.
- *
- * If a fifo_full condition is encountered, requests will back up
- * in h->reqQ. This queue is only emptied out by start_io which is
- * only called when a new i/o request comes in. If no i/o's are
- * forthcoming, the i/o's in h->reqQ can get stuck. So we call
- * start_io from here if we detect such a danger.
- *
- * Normally, we shouldn't hit this case, but pounding on the
- * CCISS_PASSTHRU ioctl can provoke it. Only call start_io if
- * commands_outstanding is low. We want to avoid calling
- * start_io from in here as much as possible, and esp. don't
- * want to get in a cycle where we call start_io every time
- * through here.
- */
- count = atomic_read(&h->commands_outstanding);
- spin_unlock_irqrestore(&h->lock, flags);
- if (unlikely(h->fifo_recently_full) && count < 5)
- io_may_be_stalled = 1;
-
dial_up_lockup_detection_on_fw_flash_complete(c->h, c);
if (likely(c->cmd_type == CMD_IOACCEL1 || c->cmd_type == CMD_SCSI
|| c->cmd_type == CMD_IOACCEL2))
complete_scsi_command(c);
else if (c->cmd_type == CMD_IOCTL_PEND)
complete(c->waiting);
- if (unlikely(io_may_be_stalled))
- lock_and_start_io(h);
-}
-
-static inline u32 hpsa_tag_contains_index(u32 tag)
-{
- return tag & DIRECT_LOOKUP_BIT;
-}
-
-static inline u32 hpsa_tag_to_index(u32 tag)
-{
- return tag >> DIRECT_LOOKUP_SHIFT;
}
u32 tag_index;
struct CommandList *c;
- tag_index = hpsa_tag_to_index(raw_tag);
+ tag_index = raw_tag >> DIRECT_LOOKUP_SHIFT;
if (!bad_tag(h, tag_index, raw_tag)) {
c = h->cmd_pool + tag_index;
finish_cmd(c);
}
}
-/* process completion of a non-indexed command */
-static inline void process_nonindexed_cmd(struct ctlr_info *h,
- u32 raw_tag)
-{
- u32 tag;
- struct CommandList *c = NULL;
- unsigned long flags;
-
- tag = hpsa_tag_discard_error_bits(h, raw_tag);
- spin_lock_irqsave(&h->lock, flags);
- list_for_each_entry(c, &h->cmpQ, list) {
- if ((c->busaddr & 0xFFFFFFE0) == (tag & 0xFFFFFFE0)) {
- spin_unlock_irqrestore(&h->lock, flags);
- finish_cmd(c);
- return;
- }
- }
- spin_unlock_irqrestore(&h->lock, flags);
- bad_tag(h, h->nr_cmds + 1, raw_tag);
-}
-
/* Some controllers, like p400, will give us one interrupt
* after a soft reset, even if we turned interrupts off.
* Only need to check for this in the hpsa_xxx_discard_completions
while (interrupt_pending(h)) {
raw_tag = get_next_completion(h, q);
while (raw_tag != FIFO_EMPTY) {
- if (likely(hpsa_tag_contains_index(raw_tag)))
- process_indexed_cmd(h, raw_tag);
- else
- process_nonindexed_cmd(h, raw_tag);
+ process_indexed_cmd(h, raw_tag);
raw_tag = next_command(h, q);
}
}
h->last_intr_timestamp = get_jiffies_64();
raw_tag = get_next_completion(h, q);
while (raw_tag != FIFO_EMPTY) {
- if (likely(hpsa_tag_contains_index(raw_tag)))
- process_indexed_cmd(h, raw_tag);
- else
- process_nonindexed_cmd(h, raw_tag);
+ process_indexed_cmd(h, raw_tag);
raw_tag = next_command(h, q);
}
return IRQ_HANDLED;
err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
if (err) {
iounmap(vaddr);
- return -ENOMEM;
+ return err;
}
cmd = pci_alloc_consistent(pdev, cmd_sz, &paddr64);
*/
rc = hpsa_lookup_board_id(pdev, &board_id);
- if (rc < 0 || !ctlr_is_resettable(board_id)) {
- dev_warn(&pdev->dev, "Not resetting device.\n");
+ if (rc < 0) {
+ dev_warn(&pdev->dev, "Board ID not found\n");
+ return rc;
+ }
+ if (!ctlr_is_resettable(board_id)) {
+ dev_warn(&pdev->dev, "Controller not resettable\n");
return -ENODEV;
}
} else {
use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET;
if (use_doorbell) {
- dev_warn(&pdev->dev, "Soft reset not supported. "
- "Firmware update is required.\n");
+ dev_warn(&pdev->dev,
+ "Soft reset not supported. Firmware update is required.\n");
rc = -ENOTSUPP; /* try soft reset */
goto unmap_cfgtable;
}
rc = hpsa_wait_for_board_state(pdev, vaddr, BOARD_READY);
if (rc) {
dev_warn(&pdev->dev,
- "failed waiting for board to become ready "
- "after hard reset\n");
+ "Failed waiting for board to become ready after hard reset\n");
goto unmap_cfgtable;
}
readl(&(tb->HostWrite.CoalIntDelay)));
dev_info(dev, " Coalesce Interrupt Count = 0x%x\n",
readl(&(tb->HostWrite.CoalIntCount)));
- dev_info(dev, " Max outstanding commands = 0x%d\n",
+ dev_info(dev, " Max outstanding commands = %d\n",
readl(&(tb->CmdsOutMax)));
dev_info(dev, " Bus Types = 0x%x\n", readl(&(tb->BusTypes)));
for (i = 0; i < 16; i++)
}
/* If MSI/MSI-X is supported by the kernel we will try to enable it on
- * controllers that are capable. If not, we use IO-APIC mode.
+ * controllers that are capable. If not, we use legacy INTx mode.
*/
static void hpsa_interrupt_mode(struct ctlr_info *h)
(h->board_id == 0x40820E11) || (h->board_id == 0x40830E11))
goto default_int_mode;
if (pci_find_capability(h->pdev, PCI_CAP_ID_MSIX)) {
- dev_info(&h->pdev->dev, "MSIX\n");
+ dev_info(&h->pdev->dev, "MSI-X capable controller\n");
h->msix_vector = MAX_REPLY_QUEUES;
if (h->msix_vector > num_online_cpus())
h->msix_vector = num_online_cpus();
}
single_msi_mode:
if (pci_find_capability(h->pdev, PCI_CAP_ID_MSI)) {
- dev_info(&h->pdev->dev, "MSI\n");
+ dev_info(&h->pdev->dev, "MSI capable controller\n");
if (!pci_enable_msi(h->pdev))
h->msi_vector = 1;
else
return rc;
h->cfgtable = remap_pci_mem(pci_resource_start(h->pdev,
cfg_base_addr_index) + cfg_offset, sizeof(*h->cfgtable));
- if (!h->cfgtable)
+ if (!h->cfgtable) {
+ dev_err(&h->pdev->dev, "Failed mapping cfgtable\n");
return -ENOMEM;
+ }
rc = write_driver_ver_to_cfgtable(h->cfgtable);
if (rc)
return rc;
}
}
+/* If the controller reports that the total max sg entries is greater than 512,
+ * then we know that chained SG blocks work. (Original smart arrays did not
+ * support chained SG blocks and would return zero for max sg entries.)
+ */
+static int hpsa_supports_chained_sg_blocks(struct ctlr_info *h)
+{
+ return h->maxsgentries > 512;
+}
+
/* Interrogate the hardware for some limits:
* max commands, max SG elements without chaining, and with chaining,
* SG chain block size, etc.
static void hpsa_find_board_params(struct ctlr_info *h)
{
hpsa_get_max_perf_mode_cmds(h);
- h->nr_cmds = h->max_commands - 4; /* Allow room for some ioctls */
+ h->nr_cmds = h->max_commands;
h->maxsgentries = readl(&(h->cfgtable->MaxScatterGatherElements));
h->fw_support = readl(&(h->cfgtable->misc_fw_support));
- /*
- * Limit in-command s/g elements to 32 save dma'able memory.
- * Howvever spec says if 0, use 31
- */
- h->max_cmd_sg_entries = 31;
- if (h->maxsgentries > 512) {
+ if (hpsa_supports_chained_sg_blocks(h)) {
+ /* Limit in-command s/g elements to 32 save dma'able memory. */
h->max_cmd_sg_entries = 32;
h->chainsize = h->maxsgentries - h->max_cmd_sg_entries;
h->maxsgentries--; /* save one for chain pointer */
} else {
- h->chainsize = 0;
+ /*
+ * Original smart arrays supported at most 31 s/g entries
+ * embedded inline in the command (trying to use more
+ * would lock up the controller)
+ */
+ h->max_cmd_sg_entries = 31;
h->maxsgentries = 31; /* default to traditional values */
+ h->chainsize = 0;
}
/* Find out what task management functions are supported and cache */
static inline bool hpsa_CISS_signature_present(struct ctlr_info *h)
{
if (!check_signature(h->cfgtable->Signature, "CISS", 4)) {
- dev_warn(&h->pdev->dev, "not a valid CISS config table\n");
+ dev_err(&h->pdev->dev, "not a valid CISS config table\n");
return false;
}
return true;
h->transMethod = CFGTBL_Trans_Simple;
return 0;
error:
- dev_warn(&h->pdev->dev, "unable to get board into simple mode\n");
+ dev_err(&h->pdev->dev, "failed to enter simple mode\n");
return -ENODEV;
}
prod_index = hpsa_lookup_board_id(h->pdev, &h->board_id);
if (prod_index < 0)
- return -ENODEV;
+ return prod_index;
h->product_name = products[prod_index].product_name;
h->access = *(products[prod_index].access);
* "performant mode". Or, it might be 640x, which can't reset
* due to concerns about shared bbwc between 6402/6404 pair.
*/
- if (rc) {
- if (rc != -ENOTSUPP) /* just try to do the kdump anyhow. */
- rc = -ENODEV;
+ if (rc)
goto out_disable;
- }
/* Now try to get the controller to respond to a no-op */
- dev_warn(&pdev->dev, "Waiting for controller to respond to no-op\n");
+ dev_info(&pdev->dev, "Waiting for controller to respond to no-op\n");
for (i = 0; i < HPSA_POST_RESET_NOOP_RETRIES; i++) {
if (hpsa_noop(pdev) == 0)
break;
|| (h->cmd_pool == NULL)
|| (h->errinfo_pool == NULL)) {
dev_err(&h->pdev->dev, "out of memory in %s", __func__);
- return -ENOMEM;
+ goto clean_up;
}
return 0;
+clean_up:
+ hpsa_free_cmd_pool(h);
+ return -ENOMEM;
}
static void hpsa_free_cmd_pool(struct ctlr_info *h)
static void hpsa_irq_affinity_hints(struct ctlr_info *h)
{
- int i, cpu, rc;
+ int i, cpu;
cpu = cpumask_first(cpu_online_mask);
for (i = 0; i < h->msix_vector; i++) {
- rc = irq_set_affinity_hint(h->intr[i], get_cpu_mask(cpu));
+ irq_set_affinity_hint(h->intr[i], get_cpu_mask(cpu));
cpu = cpumask_next(cpu, cpu_online_mask);
}
}
irq_set_affinity_hint(h->intr[i], NULL);
free_irq(h->intr[i], &h->q[i]);
}
+ for (; i < MAX_REPLY_QUEUES; i++)
+ h->q[i] = 0;
}
-static int hpsa_request_irq(struct ctlr_info *h,
+/* returns 0 on success; cleans up and returns -Enn on error */
+static int hpsa_request_irqs(struct ctlr_info *h,
irqreturn_t (*msixhandler)(int, void *),
irqreturn_t (*intxhandler)(int, void *))
{
if (h->intr_mode == PERF_MODE_INT && h->msix_vector > 0) {
/* If performant mode and MSI-X, use multiple reply queues */
- for (i = 0; i < h->msix_vector; i++)
+ for (i = 0; i < h->msix_vector; i++) {
rc = request_irq(h->intr[i], msixhandler,
0, h->devname,
&h->q[i]);
+ if (rc) {
+ int j;
+
+ dev_err(&h->pdev->dev,
+ "failed to get irq %d for %s\n",
+ h->intr[i], h->devname);
+ for (j = 0; j < i; j++) {
+ free_irq(h->intr[j], &h->q[j]);
+ h->q[j] = 0;
+ }
+ for (; j < MAX_REPLY_QUEUES; j++)
+ h->q[j] = 0;
+ return rc;
+ }
+ }
hpsa_irq_affinity_hints(h);
} else {
/* Use single reply pool */
}
/* Called when controller lockup detected. */
-static void fail_all_cmds_on_list(struct ctlr_info *h, struct list_head *list)
+static void fail_all_outstanding_cmds(struct ctlr_info *h)
{
+ int i;
struct CommandList *c = NULL;
- assert_spin_locked(&h->lock);
- /* Mark all outstanding commands as failed and complete them. */
- while (!list_empty(list)) {
- c = list_entry(list->next, struct CommandList, list);
+ flush_workqueue(h->resubmit_wq); /* ensure all cmds are fully built */
+ for (i = 0; i < h->nr_cmds; i++) {
+ if (!test_bit(i & (BITS_PER_LONG - 1),
+ h->cmd_pool_bits + (i / BITS_PER_LONG)))
+ continue;
+ c = h->cmd_pool + i;
c->err_info->CommandStatus = CMD_HARDWARE_ERR;
finish_cmd(c);
}
lockup_detected);
pci_disable_device(h->pdev);
spin_lock_irqsave(&h->lock, flags);
- fail_all_cmds_on_list(h, &h->cmpQ);
- fail_all_cmds_on_list(h, &h->reqQ);
+ fail_all_outstanding_cmds(h);
spin_unlock_irqrestore(&h->lock, flags);
}
int i;
char *event_type;
- /* Clear the driver-requested rescan flag */
- h->drv_req_rescan = 0;
-
/* Ask the controller to clear the events we're handling. */
if ((h->transMethod & (CFGTBL_Trans_io_accel1
| CFGTBL_Trans_io_accel2)) &&
*/
static int hpsa_ctlr_needs_rescan(struct ctlr_info *h)
{
- if (h->drv_req_rescan)
- return 1;
-
if (!(h->fw_support & MISC_FW_EVENT_NOTIFY))
return 0;
if (hpsa_ctlr_needs_rescan(h) || hpsa_offline_devices_ready(h)) {
scsi_host_get(h->scsi_host);
- h->drv_req_rescan = 0;
hpsa_ack_ctlr_events(h);
hpsa_scan_start(h->scsi_host);
scsi_host_put(h->scsi_host);
h->pdev = pdev;
h->intr_mode = hpsa_simple_mode ? SIMPLE_MODE_INT : PERF_MODE_INT;
- INIT_LIST_HEAD(&h->cmpQ);
- INIT_LIST_HEAD(&h->reqQ);
INIT_LIST_HEAD(&h->offline_device_list);
spin_lock_init(&h->lock);
spin_lock_init(&h->offline_device_lock);
spin_lock_init(&h->scan_lock);
spin_lock_init(&h->passthru_count_lock);
+ h->resubmit_wq = alloc_workqueue("hpsa", WQ_MEM_RECLAIM, 0);
+ if (!h->resubmit_wq) {
+ dev_err(&h->pdev->dev, "Failed to allocate work queue\n");
+ rc = -ENOMEM;
+ goto clean1;
+ }
/* Allocate and clear per-cpu variable lockup_detected */
h->lockup_detected = alloc_percpu(u32);
if (!h->lockup_detected) {
/* make sure the board interrupts are off */
h->access.set_intr_mask(h, HPSA_INTR_OFF);
- if (hpsa_request_irq(h, do_hpsa_intr_msi, do_hpsa_intr_intx))
+ if (hpsa_request_irqs(h, do_hpsa_intr_msi, do_hpsa_intr_intx))
goto clean2;
dev_info(&pdev->dev, "%s: <0x%x> at IRQ %d%s using DAC\n",
h->devname, pdev->device,
h->intr[h->intr_mode], dac ? "" : " not");
- if (hpsa_allocate_cmd_pool(h))
- goto clean4;
+ rc = hpsa_allocate_cmd_pool(h);
+ if (rc)
+ goto clean2_and_free_irqs;
if (hpsa_allocate_sg_chain_blocks(h))
goto clean4;
init_waitqueue_head(&h->scan_wait_queue);
h->access.set_intr_mask(h, HPSA_INTR_OFF);
spin_unlock_irqrestore(&h->lock, flags);
hpsa_free_irqs(h);
- rc = hpsa_request_irq(h, hpsa_msix_discard_completions,
+ rc = hpsa_request_irqs(h, hpsa_msix_discard_completions,
hpsa_intx_discard_completions);
if (rc) {
- dev_warn(&h->pdev->dev, "Failed to request_irq after "
- "soft reset.\n");
+ dev_warn(&h->pdev->dev,
+ "Failed to request_irq after soft reset.\n");
goto clean4;
}
/* Enable Accelerated IO path at driver layer */
h->acciopath_status = 1;
- h->drv_req_rescan = 0;
/* Turn the interrupts on so we can service requests */
h->access.set_intr_mask(h, HPSA_INTR_ON);
clean4:
hpsa_free_sg_chain_blocks(h);
hpsa_free_cmd_pool(h);
+clean2_and_free_irqs:
hpsa_free_irqs(h);
clean2:
clean1:
+ if (h->resubmit_wq)
+ destroy_workqueue(h->resubmit_wq);
if (h->lockup_detected)
free_percpu(h->lockup_detected);
kfree(h);
if (!flush_buf)
return;
- c = cmd_special_alloc(h);
+ c = cmd_alloc(h);
if (!c) {
- dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n");
+ dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n");
goto out_of_memory;
}
if (fill_cmd(c, HPSA_CACHE_FLUSH, h, flush_buf, 4, 0,
out:
dev_warn(&h->pdev->dev,
"error flushing cache on controller\n");
- cmd_special_free(h, c);
+ cmd_free(h, c);
out_of_memory:
kfree(flush_buf);
}
h->remove_in_progress = 1;
cancel_delayed_work(&h->monitor_ctlr_work);
spin_unlock_irqrestore(&h->lock, flags);
-
hpsa_unregister_scsi(h); /* unhook from SCSI subsystem */
hpsa_shutdown(pdev);
+ destroy_workqueue(h->resubmit_wq);
iounmap(h->vaddr);
iounmap(h->transtable);
iounmap(h->cfgtable);
hpsa_wait_for_mode_change_ack(h);
register_value = readl(&(h->cfgtable->TransportActive));
if (!(register_value & CFGTBL_Trans_Performant)) {
- dev_warn(&h->pdev->dev, "unable to get board into"
- " performant mode\n");
+ dev_err(&h->pdev->dev,
+ "performant mode problem - transport not active\n");
return;
}
/* Change the access methods to the performant access methods */
cp->timeout_sec = 0;
cp->ReplyQueue = 0;
cp->tag =
- cpu_to_le64((i << DIRECT_LOOKUP_SHIFT) |
- DIRECT_LOOKUP_BIT);
+ cpu_to_le64((i << DIRECT_LOOKUP_SHIFT));
cp->host_addr =
cpu_to_le64(h->ioaccel_cmd_pool_dhandle +
(i * sizeof(struct io_accel1_cmd)));
static void hpsa_drain_accel_commands(struct ctlr_info *h)
{
struct CommandList *c = NULL;
- unsigned long flags;
- int accel_cmds_out;
+ int i, accel_cmds_out;
- do { /* wait for all outstanding commands to drain out */
+ do { /* wait for all outstanding ioaccel commands to drain out */
accel_cmds_out = 0;
- spin_lock_irqsave(&h->lock, flags);
- list_for_each_entry(c, &h->cmpQ, list)
- accel_cmds_out += is_accelerated_cmd(c);
- list_for_each_entry(c, &h->reqQ, list)
+ for (i = 0; i < h->nr_cmds; i++) {
+ if (!test_bit(i & (BITS_PER_LONG - 1),
+ h->cmd_pool_bits + (i / BITS_PER_LONG)))
+ continue;
+ c = h->cmd_pool + i;
accel_cmds_out += is_accelerated_cmd(c);
- spin_unlock_irqrestore(&h->lock, flags);
+ }
if (accel_cmds_out <= 0)
- break;
+ break;
msleep(100);
} while (1);
}