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,
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[])
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;
}
}
c = cmd_alloc(h);
- if (c == NULL) { /* trouble... */
+ if (c == NULL) {
dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n");
return -ENOMEM;
}
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;
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);
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,
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;
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;
}
/* 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) {
/* 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);
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);
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);
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);
}