]> Git Repo - linux.git/blobdiff - drivers/scsi/ipr.c
Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
[linux.git] / drivers / scsi / ipr.c
index 5d5e272fd815a3ed076eb52e2df47d3ff765fd3a..b0c68d24db011ba9465dd31a41c05acd4f13c283 100644 (file)
@@ -820,7 +820,7 @@ static int ipr_set_pcix_cmd_reg(struct ipr_ioa_cfg *ioa_cfg)
 }
 
 /**
- * ipr_sata_eh_done - done function for aborted SATA commands
+ * __ipr_sata_eh_done - done function for aborted SATA commands
  * @ipr_cmd:   ipr command struct
  *
  * This function is invoked for ops generated to SATA
@@ -829,19 +829,41 @@ static int ipr_set_pcix_cmd_reg(struct ipr_ioa_cfg *ioa_cfg)
  * Return value:
  *     none
  **/
-static void ipr_sata_eh_done(struct ipr_cmnd *ipr_cmd)
+static void __ipr_sata_eh_done(struct ipr_cmnd *ipr_cmd)
 {
        struct ata_queued_cmd *qc = ipr_cmd->qc;
        struct ipr_sata_port *sata_port = qc->ap->private_data;
 
        qc->err_mask |= AC_ERR_OTHER;
        sata_port->ioasa.status |= ATA_BUSY;
-       list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q);
        ata_qc_complete(qc);
+       if (ipr_cmd->eh_comp)
+               complete(ipr_cmd->eh_comp);
+       list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q);
 }
 
 /**
- * ipr_scsi_eh_done - mid-layer done function for aborted ops
+ * ipr_sata_eh_done - done function for aborted SATA commands
+ * @ipr_cmd:   ipr command struct
+ *
+ * This function is invoked for ops generated to SATA
+ * devices which are being aborted.
+ *
+ * Return value:
+ *     none
+ **/
+static void ipr_sata_eh_done(struct ipr_cmnd *ipr_cmd)
+{
+       struct ipr_hrr_queue *hrrq = ipr_cmd->hrrq;
+       unsigned long hrrq_flags;
+
+       spin_lock_irqsave(&hrrq->_lock, hrrq_flags);
+       __ipr_sata_eh_done(ipr_cmd);
+       spin_unlock_irqrestore(&hrrq->_lock, hrrq_flags);
+}
+
+/**
+ * __ipr_scsi_eh_done - mid-layer done function for aborted ops
  * @ipr_cmd:   ipr command struct
  *
  * This function is invoked by the interrupt handler for
@@ -850,7 +872,7 @@ static void ipr_sata_eh_done(struct ipr_cmnd *ipr_cmd)
  * Return value:
  *     none
  **/
-static void ipr_scsi_eh_done(struct ipr_cmnd *ipr_cmd)
+static void __ipr_scsi_eh_done(struct ipr_cmnd *ipr_cmd)
 {
        struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd;
 
@@ -863,6 +885,26 @@ static void ipr_scsi_eh_done(struct ipr_cmnd *ipr_cmd)
        list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q);
 }
 
+/**
+ * ipr_scsi_eh_done - mid-layer done function for aborted ops
+ * @ipr_cmd:   ipr command struct
+ *
+ * This function is invoked by the interrupt handler for
+ * ops generated by the SCSI mid-layer which are being aborted.
+ *
+ * Return value:
+ *     none
+ **/
+static void ipr_scsi_eh_done(struct ipr_cmnd *ipr_cmd)
+{
+       unsigned long hrrq_flags;
+       struct ipr_hrr_queue *hrrq = ipr_cmd->hrrq;
+
+       spin_lock_irqsave(&hrrq->_lock, hrrq_flags);
+       __ipr_scsi_eh_done(ipr_cmd);
+       spin_unlock_irqrestore(&hrrq->_lock, hrrq_flags);
+}
+
 /**
  * ipr_fail_all_ops - Fails all outstanding ops.
  * @ioa_cfg:   ioa config struct
@@ -890,9 +932,9 @@ static void ipr_fail_all_ops(struct ipr_ioa_cfg *ioa_cfg)
                                cpu_to_be32(IPR_DRIVER_ILID);
 
                        if (ipr_cmd->scsi_cmd)
-                               ipr_cmd->done = ipr_scsi_eh_done;
+                               ipr_cmd->done = __ipr_scsi_eh_done;
                        else if (ipr_cmd->qc)
-                               ipr_cmd->done = ipr_sata_eh_done;
+                               ipr_cmd->done = __ipr_sata_eh_done;
 
                        ipr_trc_hook(ipr_cmd, IPR_TRACE_FINISH,
                                     IPR_IOASC_IOA_WAS_RESET);
@@ -5005,6 +5047,42 @@ static int ipr_match_lun(struct ipr_cmnd *ipr_cmd, void *device)
        return 0;
 }
 
+/**
+ * ipr_cmnd_is_free - Check if a command is free or not
+ * @ipr_cmd    ipr command struct
+ *
+ * Returns:
+ *     true / false
+ **/
+static bool ipr_cmnd_is_free(struct ipr_cmnd *ipr_cmd)
+{
+       struct ipr_cmnd *loop_cmd;
+
+       list_for_each_entry(loop_cmd, &ipr_cmd->hrrq->hrrq_free_q, queue) {
+               if (loop_cmd == ipr_cmd)
+                       return true;
+       }
+
+       return false;
+}
+
+/**
+ * ipr_match_res - Match function for specified resource entry
+ * @ipr_cmd:   ipr command struct
+ * @resource:  resource entry to match
+ *
+ * Returns:
+ *     1 if command matches sdev / 0 if command does not match sdev
+ **/
+static int ipr_match_res(struct ipr_cmnd *ipr_cmd, void *resource)
+{
+       struct ipr_resource_entry *res = resource;
+
+       if (res && ipr_cmd->ioarcb.res_handle == res->res_handle)
+               return 1;
+       return 0;
+}
+
 /**
  * ipr_wait_for_ops - Wait for matching commands to complete
  * @ipr_cmd:   ipr command struct
@@ -5018,7 +5096,7 @@ static int ipr_wait_for_ops(struct ipr_ioa_cfg *ioa_cfg, void *device,
                            int (*match)(struct ipr_cmnd *, void *))
 {
        struct ipr_cmnd *ipr_cmd;
-       int wait;
+       int wait, i;
        unsigned long flags;
        struct ipr_hrr_queue *hrrq;
        signed long timeout = IPR_ABORT_TASK_TIMEOUT;
@@ -5030,10 +5108,13 @@ static int ipr_wait_for_ops(struct ipr_ioa_cfg *ioa_cfg, void *device,
 
                for_each_hrrq(hrrq, ioa_cfg) {
                        spin_lock_irqsave(hrrq->lock, flags);
-                       list_for_each_entry(ipr_cmd, &hrrq->hrrq_pending_q, queue) {
-                               if (match(ipr_cmd, device)) {
-                                       ipr_cmd->eh_comp = ∁
-                                       wait++;
+                       for (i = hrrq->min_cmd_id; i <= hrrq->max_cmd_id; i++) {
+                               ipr_cmd = ioa_cfg->ipr_cmnd_list[i];
+                               if (!ipr_cmnd_is_free(ipr_cmd)) {
+                                       if (match(ipr_cmd, device)) {
+                                               ipr_cmd->eh_comp = &comp;
+                                               wait++;
+                                       }
                                }
                        }
                        spin_unlock_irqrestore(hrrq->lock, flags);
@@ -5047,10 +5128,13 @@ static int ipr_wait_for_ops(struct ipr_ioa_cfg *ioa_cfg, void *device,
 
                                for_each_hrrq(hrrq, ioa_cfg) {
                                        spin_lock_irqsave(hrrq->lock, flags);
-                                       list_for_each_entry(ipr_cmd, &hrrq->hrrq_pending_q, queue) {
-                                               if (match(ipr_cmd, device)) {
-                                                       ipr_cmd->eh_comp = NULL;
-                                                       wait++;
+                                       for (i = hrrq->min_cmd_id; i <= hrrq->max_cmd_id; i++) {
+                                               ipr_cmd = ioa_cfg->ipr_cmnd_list[i];
+                                               if (!ipr_cmnd_is_free(ipr_cmd)) {
+                                                       if (match(ipr_cmd, device)) {
+                                                               ipr_cmd->eh_comp = NULL;
+                                                               wait++;
+                                                       }
                                                }
                                        }
                                        spin_unlock_irqrestore(hrrq->lock, flags);
@@ -5179,7 +5263,7 @@ static int ipr_sata_reset(struct ata_link *link, unsigned int *classes,
        struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg;
        struct ipr_resource_entry *res;
        unsigned long lock_flags = 0;
-       int rc = -ENXIO;
+       int rc = -ENXIO, ret;
 
        ENTER;
        spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
@@ -5193,9 +5277,19 @@ static int ipr_sata_reset(struct ata_link *link, unsigned int *classes,
        if (res) {
                rc = ipr_device_reset(ioa_cfg, res);
                *classes = res->ata_class;
-       }
+               spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+
+               ret = ipr_wait_for_ops(ioa_cfg, res, ipr_match_res);
+               if (ret != SUCCESS) {
+                       spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+                       ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_ABBREV);
+                       spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+
+                       wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
+               }
+       } else
+               spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
 
-       spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
        LEAVE;
        return rc;
 }
@@ -5217,16 +5311,13 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd *scsi_cmd)
        struct ipr_ioa_cfg *ioa_cfg;
        struct ipr_resource_entry *res;
        struct ata_port *ap;
-       int rc = 0;
+       int rc = 0, i;
        struct ipr_hrr_queue *hrrq;
 
        ENTER;
        ioa_cfg = (struct ipr_ioa_cfg *) scsi_cmd->device->host->hostdata;
        res = scsi_cmd->device->hostdata;
 
-       if (!res)
-               return FAILED;
-
        /*
         * If we are currently going through reset/reload, return failed. This will force the
         * mid-layer to call ipr_eh_host_reset, which will then go to sleep and wait for the
@@ -5239,14 +5330,17 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd *scsi_cmd)
 
        for_each_hrrq(hrrq, ioa_cfg) {
                spin_lock(&hrrq->_lock);
-               list_for_each_entry(ipr_cmd, &hrrq->hrrq_pending_q, queue) {
+               for (i = hrrq->min_cmd_id; i <= hrrq->max_cmd_id; i++) {
+                       ipr_cmd = ioa_cfg->ipr_cmnd_list[i];
+
                        if (ipr_cmd->ioarcb.res_handle == res->res_handle) {
-                               if (ipr_cmd->scsi_cmd)
-                                       ipr_cmd->done = ipr_scsi_eh_done;
-                               if (ipr_cmd->qc)
-                                       ipr_cmd->done = ipr_sata_eh_done;
-                               if (ipr_cmd->qc &&
-                                   !(ipr_cmd->qc->flags & ATA_QCFLAG_FAILED)) {
+                               if (!ipr_cmd->qc)
+                                       continue;
+                               if (ipr_cmnd_is_free(ipr_cmd))
+                                       continue;
+
+                               ipr_cmd->done = ipr_sata_eh_done;
+                               if (!(ipr_cmd->qc->flags & ATA_QCFLAG_FAILED)) {
                                        ipr_cmd->qc->err_mask |= AC_ERR_TIMEOUT;
                                        ipr_cmd->qc->flags |= ATA_QCFLAG_FAILED;
                                }
@@ -5262,19 +5356,6 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd *scsi_cmd)
                spin_unlock_irq(scsi_cmd->device->host->host_lock);
                ata_std_error_handler(ap);
                spin_lock_irq(scsi_cmd->device->host->host_lock);
-
-               for_each_hrrq(hrrq, ioa_cfg) {
-                       spin_lock(&hrrq->_lock);
-                       list_for_each_entry(ipr_cmd,
-                                           &hrrq->hrrq_pending_q, queue) {
-                               if (ipr_cmd->ioarcb.res_handle ==
-                                   res->res_handle) {
-                                       rc = -EIO;
-                                       break;
-                               }
-                       }
-                       spin_unlock(&hrrq->_lock);
-               }
        } else
                rc = ipr_device_reset(ioa_cfg, res);
        res->resetting_device = 0;
@@ -5288,15 +5369,24 @@ static int ipr_eh_dev_reset(struct scsi_cmnd *cmd)
 {
        int rc;
        struct ipr_ioa_cfg *ioa_cfg;
+       struct ipr_resource_entry *res;
 
        ioa_cfg = (struct ipr_ioa_cfg *) cmd->device->host->hostdata;
+       res = cmd->device->hostdata;
+
+       if (!res)
+               return FAILED;
 
        spin_lock_irq(cmd->device->host->host_lock);
        rc = __ipr_eh_dev_reset(cmd);
        spin_unlock_irq(cmd->device->host->host_lock);
 
-       if (rc == SUCCESS)
-               rc = ipr_wait_for_ops(ioa_cfg, cmd->device, ipr_match_lun);
+       if (rc == SUCCESS) {
+               if (ipr_is_gata(res) && res->sata_port)
+                       rc = ipr_wait_for_ops(ioa_cfg, res, ipr_match_res);
+               else
+                       rc = ipr_wait_for_ops(ioa_cfg, cmd->device, ipr_match_lun);
+       }
 
        return rc;
 }
@@ -5393,7 +5483,7 @@ static int ipr_cancel_op(struct scsi_cmnd *scsi_cmd)
        struct ipr_resource_entry *res;
        struct ipr_cmd_pkt *cmd_pkt;
        u32 ioasc, int_reg;
-       int op_found = 0;
+       int i, op_found = 0;
        struct ipr_hrr_queue *hrrq;
 
        ENTER;
@@ -5422,11 +5512,12 @@ static int ipr_cancel_op(struct scsi_cmnd *scsi_cmd)
 
        for_each_hrrq(hrrq, ioa_cfg) {
                spin_lock(&hrrq->_lock);
-               list_for_each_entry(ipr_cmd, &hrrq->hrrq_pending_q, queue) {
-                       if (ipr_cmd->scsi_cmd == scsi_cmd) {
-                               ipr_cmd->done = ipr_scsi_eh_done;
-                               op_found = 1;
-                               break;
+               for (i = hrrq->min_cmd_id; i <= hrrq->max_cmd_id; i++) {
+                       if (ioa_cfg->ipr_cmnd_list[i]->scsi_cmd == scsi_cmd) {
+                               if (!ipr_cmnd_is_free(ioa_cfg->ipr_cmnd_list[i])) {
+                                       op_found = 1;
+                                       break;
+                               }
                        }
                }
                spin_unlock(&hrrq->_lock);
@@ -5917,7 +6008,7 @@ static int ipr_build_ioadl(struct ipr_ioa_cfg *ioa_cfg,
 }
 
 /**
- * ipr_erp_done - Process completion of ERP for a device
+ * __ipr_erp_done - Process completion of ERP for a device
  * @ipr_cmd:           ipr command struct
  *
  * This function copies the sense buffer into the scsi_cmd
@@ -5926,7 +6017,7 @@ static int ipr_build_ioadl(struct ipr_ioa_cfg *ioa_cfg,
  * Return value:
  *     nothing
  **/
-static void ipr_erp_done(struct ipr_cmnd *ipr_cmd)
+static void __ipr_erp_done(struct ipr_cmnd *ipr_cmd)
 {
        struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd;
        struct ipr_resource_entry *res = scsi_cmd->device->hostdata;
@@ -5947,8 +6038,30 @@ static void ipr_erp_done(struct ipr_cmnd *ipr_cmd)
                res->in_erp = 0;
        }
        scsi_dma_unmap(ipr_cmd->scsi_cmd);
-       list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q);
        scsi_cmd->scsi_done(scsi_cmd);
+       if (ipr_cmd->eh_comp)
+               complete(ipr_cmd->eh_comp);
+       list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q);
+}
+
+/**
+ * ipr_erp_done - Process completion of ERP for a device
+ * @ipr_cmd:           ipr command struct
+ *
+ * This function copies the sense buffer into the scsi_cmd
+ * struct and pushes the scsi_done function.
+ *
+ * Return value:
+ *     nothing
+ **/
+static void ipr_erp_done(struct ipr_cmnd *ipr_cmd)
+{
+       struct ipr_hrr_queue *hrrq = ipr_cmd->hrrq;
+       unsigned long hrrq_flags;
+
+       spin_lock_irqsave(&hrrq->_lock, hrrq_flags);
+       __ipr_erp_done(ipr_cmd);
+       spin_unlock_irqrestore(&hrrq->_lock, hrrq_flags);
 }
 
 /**
@@ -5983,7 +6096,7 @@ static void ipr_reinit_ipr_cmnd_for_erp(struct ipr_cmnd *ipr_cmd)
 }
 
 /**
- * ipr_erp_request_sense - Send request sense to a device
+ * __ipr_erp_request_sense - Send request sense to a device
  * @ipr_cmd:   ipr command struct
  *
  * This function sends a request sense to a device as a result
@@ -5992,13 +6105,13 @@ static void ipr_reinit_ipr_cmnd_for_erp(struct ipr_cmnd *ipr_cmd)
  * Return value:
  *     nothing
  **/
-static void ipr_erp_request_sense(struct ipr_cmnd *ipr_cmd)
+static void __ipr_erp_request_sense(struct ipr_cmnd *ipr_cmd)
 {
        struct ipr_cmd_pkt *cmd_pkt = &ipr_cmd->ioarcb.cmd_pkt;
        u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc);
 
        if (IPR_IOASC_SENSE_KEY(ioasc) > 0) {
-               ipr_erp_done(ipr_cmd);
+               __ipr_erp_done(ipr_cmd);
                return;
        }
 
@@ -6018,6 +6131,26 @@ static void ipr_erp_request_sense(struct ipr_cmnd *ipr_cmd)
                   IPR_REQUEST_SENSE_TIMEOUT * 2);
 }
 
+/**
+ * ipr_erp_request_sense - Send request sense to a device
+ * @ipr_cmd:   ipr command struct
+ *
+ * This function sends a request sense to a device as a result
+ * of a check condition.
+ *
+ * Return value:
+ *     nothing
+ **/
+static void ipr_erp_request_sense(struct ipr_cmnd *ipr_cmd)
+{
+       struct ipr_hrr_queue *hrrq = ipr_cmd->hrrq;
+       unsigned long hrrq_flags;
+
+       spin_lock_irqsave(&hrrq->_lock, hrrq_flags);
+       __ipr_erp_request_sense(ipr_cmd);
+       spin_unlock_irqrestore(&hrrq->_lock, hrrq_flags);
+}
+
 /**
  * ipr_erp_cancel_all - Send cancel all to a device
  * @ipr_cmd:   ipr command struct
@@ -6041,7 +6174,7 @@ static void ipr_erp_cancel_all(struct ipr_cmnd *ipr_cmd)
        ipr_reinit_ipr_cmnd_for_erp(ipr_cmd);
 
        if (!scsi_cmd->device->simple_tags) {
-               ipr_erp_request_sense(ipr_cmd);
+               __ipr_erp_request_sense(ipr_cmd);
                return;
        }
 
@@ -6261,7 +6394,7 @@ static void ipr_erp_start(struct ipr_ioa_cfg *ioa_cfg,
        u32 masked_ioasc = ioasc & IPR_IOASC_IOASC_MASK;
 
        if (!res) {
-               ipr_scsi_eh_done(ipr_cmd);
+               __ipr_scsi_eh_done(ipr_cmd);
                return;
        }
 
@@ -6343,8 +6476,10 @@ static void ipr_erp_start(struct ipr_ioa_cfg *ioa_cfg,
        }
 
        scsi_dma_unmap(ipr_cmd->scsi_cmd);
-       list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q);
        scsi_cmd->scsi_done(scsi_cmd);
+       if (ipr_cmd->eh_comp)
+               complete(ipr_cmd->eh_comp);
+       list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q);
 }
 
 /**
@@ -6370,8 +6505,10 @@ static void ipr_scsi_done(struct ipr_cmnd *ipr_cmd)
                scsi_dma_unmap(scsi_cmd);
 
                spin_lock_irqsave(ipr_cmd->hrrq->lock, lock_flags);
-               list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q);
                scsi_cmd->scsi_done(scsi_cmd);
+               if (ipr_cmd->eh_comp)
+                       complete(ipr_cmd->eh_comp);
+               list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q);
                spin_unlock_irqrestore(ipr_cmd->hrrq->lock, lock_flags);
        } else {
                spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
This page took 0.050138 seconds and 4 git commands to generate.