Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

scsi: fnic: Replace sgreset tag with max_tag_id

sgreset is issued with a SCSI command pointer. The device reset code
assumes that it was issued on a hardware queue, and calls block multiqueue
layer. However, the assumption is broken, and there is no hardware queue
associated with the sgreset, and this leads to a crash due to a null
pointer exception.

Fix the code to use the max_tag_id as a tag which does not overlap with the
other tags issued by mid layer.

Tested by running FC traffic for a few minutes, and by issuing sgreset on
the device in parallel. Without the fix, the crash is observed right away.
With this fix, no crash is observed.

Reviewed-by: Sesidhar Baddela <sebaddel@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/20230817182146.229059-1-kartilak@cisco.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>

authored by

Karan Tilak Kumar and committed by
Martin K. Petersen
15924b05 530e86c7

+11 -12
+2 -1
drivers/scsi/fnic/fnic.h
··· 27 27 28 28 #define DRV_NAME "fnic" 29 29 #define DRV_DESCRIPTION "Cisco FCoE HBA Driver" 30 - #define DRV_VERSION "1.6.0.54" 30 + #define DRV_VERSION "1.6.0.56" 31 31 #define PFX DRV_NAME ": " 32 32 #define DFX DRV_NAME "%d: " 33 33 ··· 236 236 unsigned int wq_count; 237 237 unsigned int cq_count; 238 238 239 + struct mutex sgreset_mutex; 239 240 struct dentry *fnic_stats_debugfs_host; 240 241 struct dentry *fnic_stats_debugfs_file; 241 242 struct dentry *fnic_reset_debugfs_file;
+9 -11
drivers/scsi/fnic/fnic_scsi.c
··· 2220 2220 struct reset_stats *reset_stats; 2221 2221 int tag = rq->tag; 2222 2222 DECLARE_COMPLETION_ONSTACK(tm_done); 2223 - int tag_gen_flag = 0; /*to track tags allocated by fnic driver*/ 2224 2223 bool new_sc = 0; 2225 2224 2226 2225 /* Wait for rport to unblock */ ··· 2249 2250 } 2250 2251 2251 2252 fnic_priv(sc)->flags = FNIC_DEVICE_RESET; 2252 - /* Allocate tag if not present */ 2253 2253 2254 2254 if (unlikely(tag < 0)) { 2255 2255 /* 2256 - * Really should fix the midlayer to pass in a proper 2257 - * request for ioctls... 2256 + * For device reset issued through sg3utils, we let 2257 + * only one LUN_RESET to go through and use a special 2258 + * tag equal to max_tag_id so that we don't have to allocate 2259 + * or free it. It won't interact with tags 2260 + * allocated by mid layer. 2258 2261 */ 2259 - tag = fnic_scsi_host_start_tag(fnic, sc); 2260 - if (unlikely(tag == SCSI_NO_TAG)) 2261 - goto fnic_device_reset_end; 2262 - tag_gen_flag = 1; 2262 + mutex_lock(&fnic->sgreset_mutex); 2263 + tag = fnic->fnic_max_tag_id; 2263 2264 new_sc = 1; 2264 2265 } 2265 2266 io_lock = fnic_io_lock_hash(fnic, sc); ··· 2431 2432 (u64)sc->cmnd[4] << 8 | sc->cmnd[5]), 2432 2433 fnic_flags_and_state(sc)); 2433 2434 2434 - /* free tag if it is allocated */ 2435 - if (unlikely(tag_gen_flag)) 2436 - fnic_scsi_host_end_tag(fnic, sc); 2435 + if (new_sc) 2436 + mutex_unlock(&fnic->sgreset_mutex); 2437 2437 2438 2438 FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, 2439 2439 "Returning from device reset %s\n",