Use a dedicated command to send a device reset instead of relying
on using the command which triggered the device failure.

Signed-off-by: Hannes Reinecke <h...@suse.com>
---
 drivers/scsi/fnic/fnic_main.c |  2 ++
 drivers/scsi/fnic/fnic_scsi.c | 78 +++++++++++++------------------------------
 2 files changed, 26 insertions(+), 54 deletions(-)

diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c
index aacadbf..22fd37c 100644
--- a/drivers/scsi/fnic/fnic_main.c
+++ b/drivers/scsi/fnic/fnic_main.c
@@ -706,6 +706,8 @@ static int fnic_probe(struct pci_dev *pdev, const struct 
pci_device_id *ent)
                                        fnic->config.io_throttle_count));
        }
        fnic->fnic_max_tag_id = host->can_queue;
+       /* Reserve the last tag for device reset */
+       host->can_queue--;
 
        host->max_lun = fnic->config.luns_per_tgt;
        host->max_id = FNIC_MAX_FCP_TARGET;
diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c
index 731ec87..acf7d1d 100644
--- a/drivers/scsi/fnic/fnic_scsi.c
+++ b/drivers/scsi/fnic/fnic_scsi.c
@@ -2106,9 +2106,7 @@ static inline int fnic_queue_dr_io_req(struct fnic *fnic,
  * successfully aborted, 1 otherwise
  */
 static int fnic_clean_pending_aborts(struct fnic *fnic,
-                                    struct scsi_cmnd *lr_sc,
-                                        bool new_sc)
-
+                                    struct scsi_cmnd *lr_sc)
 {
        int tag, abt_tag;
        struct fnic_io_req *io_req;
@@ -2129,7 +2127,7 @@ static int fnic_clean_pending_aborts(struct fnic *fnic,
                 * ignore this lun reset cmd if issued using new SC
                 * or cmds that do not belong to this lun
                 */
-               if (!sc || ((sc == lr_sc) && new_sc) || sc->device != lun_dev) {
+               if (!sc || sc == lr_sc || sc->device != lun_dev) {
                        spin_unlock_irqrestore(io_lock, flags);
                        continue;
                }
@@ -2334,6 +2332,7 @@ static int fnic_clean_pending_aborts(struct fnic *fnic,
  */
 int fnic_device_reset(struct scsi_cmnd *sc)
 {
+       struct scsi_device *sdev = sc->device;
        struct fc_lport *lp;
        struct fnic *fnic;
        struct fnic_io_req *io_req = NULL;
@@ -2348,18 +2347,16 @@ int fnic_device_reset(struct scsi_cmnd *sc)
        struct reset_stats *reset_stats;
        int tag = 0;
        DECLARE_COMPLETION_ONSTACK(tm_done);
-       int tag_gen_flag = 0;   /*to track tags allocated by fnic driver*/
-       bool new_sc = 0;
 
        /* Wait for rport to unblock */
-       rport = starget_to_rport(scsi_target(sc->device));
+       rport = starget_to_rport(scsi_target(sdev));
        ret = fc_block_scsi_eh(rport);
        if (ret)
                return ret;
 
        ret = FAILED;
        /* Get local-port, check ready and link up */
-       lp = shost_priv(sc->device->host);
+       lp = shost_priv(sdev->host);
 
        fnic = lport_priv(lp);
        fnic_stats = &fnic->fnic_stats;
@@ -2368,8 +2365,8 @@ int fnic_device_reset(struct scsi_cmnd *sc)
        atomic64_inc(&reset_stats->device_resets);
 
        FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host,
-                     "Device reset called FCID 0x%x, LUN 0x%llx sc 0x%p\n",
-                     rport->port_id, sc->device->lun, sc);
+                     "Device reset called FCID 0x%x, LUN 0x%llx\n",
+                     rport->port_id, sdev->lun);
 
        if (lp->state != LPORT_ST_READY || !(lp->link_up))
                goto fnic_device_reset_end;
@@ -2379,51 +2376,28 @@ int fnic_device_reset(struct scsi_cmnd *sc)
                atomic64_inc(&fnic_stats->misc_stats.rport_not_ready);
                goto fnic_device_reset_end;
        }
-
-       CMD_FLAGS(sc) = FNIC_DEVICE_RESET;
-       /* Allocate tag if not present */
-
-       tag = sc->request->tag;
-       if (unlikely(tag < 0)) {
+       /* The last tag is reserved for device reset */
+       sc = scsi_host_find_tag(sdev->host, fnic->fnic_max_tag_id - 1);
+       io_lock = fnic_io_lock_hash(fnic, sc);
+       spin_lock_irqsave(io_lock, flags);
+       if (CMD_SP(sc)) {
                /*
-                * XXX(hch): current the midlayer fakes up a struct
-                * request for the explicit reset ioctls, and those
-                * don't have a tag allocated to them.  The below
-                * code pokes into midlayer structures to paper over
-                * this design issue, but that won't work for blk-mq.
-                *
-                * Either someone who can actually test the hardware
-                * will have to come up with a similar hack for the
-                * blk-mq case, or we'll have to bite the bullet and
-                * fix the way the EH ioctls work for real, but until
-                * that happens we fail these explicit requests here.
+                * Reset tag busy
                 */
-
-               tag = fnic_scsi_host_start_tag(fnic, sc);
-               if (unlikely(tag == SCSI_NO_TAG))
-                       goto fnic_device_reset_end;
-               tag_gen_flag = 1;
-               new_sc = 1;
+               spin_unlock_irqrestore(io_lock, flags);
+               goto fnic_device_reset_end;
        }
-       io_lock = fnic_io_lock_hash(fnic, sc);
-       spin_lock_irqsave(io_lock, flags);
-       io_req = (struct fnic_io_req *)CMD_SP(sc);
-
-       /*
-        * If there is a io_req attached to this command, then use it,
-        * else allocate a new one.
-        */
+       io_req = mempool_alloc(fnic->io_req_pool, GFP_ATOMIC);
        if (!io_req) {
-               io_req = mempool_alloc(fnic->io_req_pool, GFP_ATOMIC);
-               if (!io_req) {
-                       spin_unlock_irqrestore(io_lock, flags);
-                       goto fnic_device_reset_end;
-               }
-               memset(io_req, 0, sizeof(*io_req));
-               io_req->port_id = rport->port_id;
-               CMD_SP(sc) = (char *)io_req;
+               spin_unlock_irqrestore(io_lock, flags);
+               goto fnic_device_reset_end;
        }
+       memset(io_req, 0, sizeof(*io_req));
+       io_req->port_id = rport->port_id;
+       CMD_SP(sc) = (char *)io_req;
        io_req->dr_done = &tm_done;
+
+       CMD_FLAGS(sc) = FNIC_DEVICE_RESET;
        CMD_STATE(sc) = FNIC_IOREQ_CMD_PENDING;
        CMD_LR_STATUS(sc) = FCPIO_INVALID_CODE;
        spin_unlock_irqrestore(io_lock, flags);
@@ -2538,7 +2512,7 @@ int fnic_device_reset(struct scsi_cmnd *sc)
         * the lun reset cmd. If all cmds get cleaned, the lun reset
         * succeeds
         */
-       if (fnic_clean_pending_aborts(fnic, sc, new_sc)) {
+       if (fnic_clean_pending_aborts(fnic, sc)) {
                spin_lock_irqsave(io_lock, flags);
                io_req = (struct fnic_io_req *)CMD_SP(sc);
                FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host,
@@ -2575,10 +2549,6 @@ int fnic_device_reset(struct scsi_cmnd *sc)
                  (u64)sc->cmnd[4] << 8 | sc->cmnd[5]),
                  (((u64)CMD_FLAGS(sc) << 32) | CMD_STATE(sc)));
 
-       /* free tag if it is allocated */
-       if (unlikely(tag_gen_flag))
-               fnic_scsi_host_end_tag(fnic, sc);
-
        FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host,
                      "Returning from device reset %s\n",
                      (ret == SUCCESS) ?
-- 
1.8.5.6

Reply via email to