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 <hare@xxxxxxxx> --- drivers/scsi/fnic/fnic_scsi.c | 127 +++++++++------------------------- 1 file changed, 34 insertions(+), 93 deletions(-) diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c index 60af6c7a1bc4..b133eb629fa2 100644 --- a/drivers/scsi/fnic/fnic_scsi.c +++ b/drivers/scsi/fnic/fnic_scsi.c @@ -2014,7 +2014,6 @@ static inline int fnic_queue_dr_io_req(struct fnic *fnic, struct fnic_pending_aborts_iter_data { struct fnic *fnic; - struct scsi_cmnd *lr_sc; struct scsi_device *lun_dev; int ret; }; @@ -2033,7 +2032,7 @@ static bool fnic_pending_aborts_iter(struct scsi_cmnd *sc, DECLARE_COMPLETION_ONSTACK(tm_done); enum fnic_ioreq_state old_ioreq_state; - if (sc == iter_data->lr_sc || sc->device != lun_dev) + if (abt_tag == (fnic->fnic_max_tag_id - 1) || sc->device != lun_dev) return true; if (reserved) return true; @@ -2138,17 +2137,11 @@ static bool fnic_pending_aborts_iter(struct scsi_cmnd *sc, return false; } CMD_STATE(sc) = FNIC_IOREQ_ABTS_COMPLETE; - - /* original sc used for lr is handled by dev reset code */ - if (sc != iter_data->lr_sc) - CMD_SP(sc) = NULL; + CMD_SP(sc) = NULL; spin_unlock_irqrestore(io_lock, flags); - /* original sc used for lr is handled by dev reset code */ - if (sc != iter_data->lr_sc) { - fnic_release_ioreq_buf(fnic, io_req, sc); - mempool_free(io_req, fnic->io_req_pool); - } + fnic_release_ioreq_buf(fnic, io_req, sc); + mempool_free(io_req, fnic->io_req_pool); /* * Any IO is returned during reset, it needs to call scsi_done @@ -2169,8 +2162,7 @@ static bool fnic_pending_aborts_iter(struct scsi_cmnd *sc, * 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 ret = SUCCESS; @@ -2180,9 +2172,6 @@ static int fnic_clean_pending_aborts(struct fnic *fnic, .ret = SUCCESS, }; - if (new_sc) - iter_data.lr_sc = lr_sc; - scsi_host_busy_iter(fnic->lport->host, fnic_pending_aborts_iter, &iter_data); if (iter_data.ret == FAILED) { @@ -2199,38 +2188,6 @@ static int fnic_clean_pending_aborts(struct fnic *fnic, return ret; } -/* - * fnic_scsi_host_start_tag - * Allocates tagid from host's tag list - **/ -static inline int -fnic_scsi_host_start_tag(struct fnic *fnic, struct scsi_cmnd *sc) -{ - struct request_queue *q = sc->request->q; - struct request *dummy; - - dummy = blk_mq_alloc_request(q, REQ_OP_WRITE, BLK_MQ_REQ_NOWAIT); - if (IS_ERR(dummy)) - return SCSI_NO_TAG; - - sc->tag = sc->request->tag = dummy->tag; - sc->host_scribble = (unsigned char *)dummy; - - return dummy->tag; -} - -/* - * fnic_scsi_host_end_tag - * frees tag allocated by fnic_scsi_host_start_tag. - **/ -static inline void -fnic_scsi_host_end_tag(struct fnic *fnic, struct scsi_cmnd *sc) -{ - struct request *dummy = (struct request *)sc->host_scribble; - - blk_mq_free_request(dummy); -} - /* * SCSI Eh thread issues a Lun Reset when one or more commands on a LUN * fail to get aborted. It calls driver's eh_device_reset with a SCSI command @@ -2238,6 +2195,7 @@ fnic_scsi_host_end_tag(struct fnic *fnic, struct scsi_cmnd *sc) */ 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; @@ -2252,14 +2210,15 @@ 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 */ - fc_block_scsi_eh(sc); + rport = starget_to_rport(scsi_target(sdev)); + ret = fc_block_rport(rport); + if (ret) + return ret; /* 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; @@ -2267,54 +2226,41 @@ int fnic_device_reset(struct scsi_cmnd *sc) atomic64_inc(&reset_stats->device_resets); - rport = starget_to_rport(scsi_target(sc->device)); 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; /* Check if remote port up */ - if (fc_remote_port_chkready(rport)) { - atomic64_inc(&fnic_stats->misc_stats.rport_not_ready); + if (rport->port_state != FC_PORTSTATE_ONLINE && + rport->port_state != FC_PORTSTATE_MARGINAL) { 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)) { /* - * Really should fix the midlayer to pass in a proper - * request for ioctls... + * 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); @@ -2429,7 +2375,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, @@ -2466,10 +2412,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) ? @@ -2691,6 +2633,7 @@ static bool fnic_abts_pending_iter(struct scsi_cmnd *sc, void *data, { struct fnic_pending_aborts_iter_data *iter_data = data; struct fnic *fnic = iter_data->fnic; + int tag = sc->request->tag; int cmd_state; struct fnic_io_req *io_req; spinlock_t *io_lock; @@ -2700,7 +2643,7 @@ static bool fnic_abts_pending_iter(struct scsi_cmnd *sc, void *data, * ignore this lun reset cmd or cmds that do not belong to * this lun */ - if (iter_data->lr_sc && sc == iter_data->lr_sc) + if (tag == (fnic->fnic_max_tag_id - 1)) return true; if (iter_data->lun_dev && sc->device != iter_data->lun_dev) return true; @@ -2744,10 +2687,8 @@ int fnic_is_abts_pending(struct fnic *fnic, struct scsi_cmnd *lr_sc) .ret = 0, }; - if (lr_sc) { + if (lr_sc) iter_data.lun_dev = lr_sc->device; - iter_data.lr_sc = lr_sc; - } /* walk again to check, if IOs are still pending in fw */ scsi_host_busy_iter(fnic->lport->host, -- 2.29.2