scsi: fnic: Fix sg_reset success path
authorKaran Tilak Kumar <kartilak@cisco.com>
Tue, 19 Sep 2023 18:24:36 +0000 (11:24 -0700)
committerMartin K. Petersen <martin.petersen@oracle.com>
Wed, 27 Sep 2023 15:03:59 +0000 (11:03 -0400)
sg_reset performs a target or LUN reset. Since the command is issued by the
user, it does not come into the driver with a tag or a queue id. Fix the
fnic driver to create an io_req and use a SCSI command tag.  Fix the ITMF
path to special case the sg_reset response.

Reviewed-by: Sesidhar Baddela <sebaddel@cisco.com>
Reviewed-by: Arulprabhu Ponnusamy <arulponn@cisco.com>
Tested-by: Karan Tilak Kumar <kartilak@cisco.com>
Signed-off-by: Karan Tilak Kumar <kartilak@cisco.com>
Link: https://lore.kernel.org/r/20230919182436.6895-1-kartilak@cisco.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/fnic/fnic.h
drivers/scsi/fnic/fnic_io.h
drivers/scsi/fnic/fnic_main.c
drivers/scsi/fnic/fnic_scsi.c

index 93c6893..22cef28 100644 (file)
@@ -27,7 +27,7 @@
 
 #define DRV_NAME               "fnic"
 #define DRV_DESCRIPTION                "Cisco FCoE HBA Driver"
-#define DRV_VERSION            "1.6.0.56"
+#define DRV_VERSION            "1.6.0.57"
 #define PFX                    DRV_NAME ": "
 #define DFX                     DRV_NAME "%d: "
 
@@ -237,6 +237,8 @@ struct fnic {
        unsigned int cq_count;
 
        struct mutex sgreset_mutex;
+       spinlock_t sgreset_lock; /* lock for sgreset */
+       struct scsi_cmnd *sgreset_sc;
        struct dentry *fnic_stats_debugfs_host;
        struct dentry *fnic_stats_debugfs_file;
        struct dentry *fnic_reset_debugfs_file;
index f4c8769..5895ead 100644 (file)
@@ -52,6 +52,8 @@ struct fnic_io_req {
        unsigned long start_time; /* in jiffies */
        struct completion *abts_done; /* completion for abts */
        struct completion *dr_done; /* completion for device reset */
+       unsigned int tag;
+       struct scsi_cmnd *sc; /* midlayer's cmd pointer */
 };
 
 enum fnic_port_speeds {
index 984bc5f..f27f931 100644 (file)
@@ -754,6 +754,8 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        for (i = 0; i < FNIC_IO_LOCKS; i++)
                spin_lock_init(&fnic->io_req_lock[i]);
 
+       spin_lock_init(&fnic->sgreset_lock);
+
        err = -ENOMEM;
        fnic->io_req_pool = mempool_create_slab_pool(2, fnic_io_req_cache);
        if (!fnic->io_req_pool)
index 9761b2c..416d819 100644 (file)
@@ -1047,9 +1047,9 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic,
 {
        u8 type;
        u8 hdr_status;
-       struct fcpio_tag tag;
+       struct fcpio_tag ftag;
        u32 id;
-       struct scsi_cmnd *sc;
+       struct scsi_cmnd *sc = NULL;
        struct fnic_io_req *io_req;
        struct fnic_stats *fnic_stats = &fnic->fnic_stats;
        struct abort_stats *abts_stats = &fnic->fnic_stats.abts_stats;
@@ -1058,27 +1058,43 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic,
        unsigned long flags;
        spinlock_t *io_lock;
        unsigned long start_time;
+       unsigned int tag;
 
-       fcpio_header_dec(&desc->hdr, &type, &hdr_status, &tag);
-       fcpio_tag_id_dec(&tag, &id);
+       fcpio_header_dec(&desc->hdr, &type, &hdr_status, &ftag);
+       fcpio_tag_id_dec(&ftag, &id);
 
-       if ((id & FNIC_TAG_MASK) >= fnic->fnic_max_tag_id) {
+       tag = id & FNIC_TAG_MASK;
+       if (tag == fnic->fnic_max_tag_id) {
+               if (!(id & FNIC_TAG_DEV_RST)) {
+                       shost_printk(KERN_ERR, fnic->lport->host,
+                                               "Tag out of range id 0x%x hdr status = %s\n",
+                                               id, fnic_fcpio_status_to_str(hdr_status));
+                       return;
+               }
+       } else if (tag > fnic->fnic_max_tag_id) {
                shost_printk(KERN_ERR, fnic->lport->host,
-               "Tag out of range tag %x hdr status = %s\n",
-               id, fnic_fcpio_status_to_str(hdr_status));
+                                       "Tag out of range tag 0x%x hdr status = %s\n",
+                                       tag, fnic_fcpio_status_to_str(hdr_status));
                return;
        }
 
-       sc = scsi_host_find_tag(fnic->lport->host, id & FNIC_TAG_MASK);
+       if ((tag == fnic->fnic_max_tag_id) && (id & FNIC_TAG_DEV_RST)) {
+               sc = fnic->sgreset_sc;
+               io_lock = &fnic->sgreset_lock;
+       } else {
+               sc = scsi_host_find_tag(fnic->lport->host, id & FNIC_TAG_MASK);
+               io_lock = fnic_io_lock_hash(fnic, sc);
+       }
+
        WARN_ON_ONCE(!sc);
        if (!sc) {
                atomic64_inc(&fnic_stats->io_stats.sc_null);
                shost_printk(KERN_ERR, fnic->lport->host,
                          "itmf_cmpl sc is null - hdr status = %s tag = 0x%x\n",
-                         fnic_fcpio_status_to_str(hdr_status), id);
+                         fnic_fcpio_status_to_str(hdr_status), tag);
                return;
        }
-       io_lock = fnic_io_lock_hash(fnic, sc);
+
        spin_lock_irqsave(io_lock, flags);
        io_req = fnic_priv(sc)->io_req;
        WARN_ON_ONCE(!io_req);
@@ -1089,7 +1105,7 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic,
                shost_printk(KERN_ERR, fnic->lport->host,
                          "itmf_cmpl io_req is null - "
                          "hdr status = %s tag = 0x%x sc 0x%p\n",
-                         fnic_fcpio_status_to_str(hdr_status), id, sc);
+                         fnic_fcpio_status_to_str(hdr_status), tag, sc);
                return;
        }
        start_time = io_req->start_time;
@@ -1938,6 +1954,10 @@ static inline int fnic_queue_dr_io_req(struct fnic *fnic,
        struct scsi_lun fc_lun;
        int ret = 0;
        unsigned long intr_flags;
+       unsigned int tag = scsi_cmd_to_rq(sc)->tag;
+
+       if (tag == SCSI_NO_TAG)
+               tag = io_req->tag;
 
        spin_lock_irqsave(host->host_lock, intr_flags);
        if (unlikely(fnic_chk_state_flags_locked(fnic,
@@ -1964,7 +1984,8 @@ static inline int fnic_queue_dr_io_req(struct fnic *fnic,
        /* fill in the lun info */
        int_to_scsilun(sc->device->lun, &fc_lun);
 
-       fnic_queue_wq_copy_desc_itmf(wq, scsi_cmd_to_rq(sc)->tag | FNIC_TAG_DEV_RST,
+       tag |= FNIC_TAG_DEV_RST;
+       fnic_queue_wq_copy_desc_itmf(wq, tag,
                                     0, FCPIO_ITMF_LUN_RESET, SCSI_NO_TAG,
                                     fc_lun.scsi_lun, io_req->port_id,
                                     fnic->config.ra_tov, fnic->config.ed_tov);
@@ -2146,8 +2167,7 @@ static int fnic_clean_pending_aborts(struct fnic *fnic,
                .ret = SUCCESS,
        };
 
-       if (new_sc)
-               iter_data.lr_sc = lr_sc;
+       iter_data.lr_sc = lr_sc;
 
        scsi_host_busy_iter(fnic->lport->host,
                            fnic_pending_aborts_iter, &iter_data);
@@ -2230,8 +2250,14 @@ int fnic_device_reset(struct scsi_cmnd *sc)
                mutex_lock(&fnic->sgreset_mutex);
                tag = fnic->fnic_max_tag_id;
                new_sc = 1;
-       }
-       io_lock = fnic_io_lock_hash(fnic, sc);
+               fnic->sgreset_sc = sc;
+               io_lock = &fnic->sgreset_lock;
+               FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host,
+                       "fcid: 0x%x lun: 0x%llx flags: 0x%x tag: 0x%x Issuing sgreset\n",
+                       rport->port_id, sc->device->lun, fnic_priv(sc)->flags, tag);
+       } else
+               io_lock = fnic_io_lock_hash(fnic, sc);
+
        spin_lock_irqsave(io_lock, flags);
        io_req = fnic_priv(sc)->io_req;
 
@@ -2247,6 +2273,8 @@ int fnic_device_reset(struct scsi_cmnd *sc)
                }
                memset(io_req, 0, sizeof(*io_req));
                io_req->port_id = rport->port_id;
+               io_req->tag = tag;
+               io_req->sc = sc;
                fnic_priv(sc)->io_req = io_req;
        }
        io_req->dr_done = &tm_done;
@@ -2400,8 +2428,10 @@ fnic_device_reset_end:
                  (u64)sc->cmnd[4] << 8 | sc->cmnd[5]),
                  fnic_flags_and_state(sc));
 
-       if (new_sc)
+       if (new_sc) {
+               fnic->sgreset_sc = NULL;
                mutex_unlock(&fnic->sgreset_mutex);
+       }
 
        FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host,
                      "Returning from device reset %s\n",