Allocate a command to send a device reset instead of relying on using the command which triggered the device failure. Signed-off-by: Hannes Reinecke <hare@xxxxxxx> Reviewed-by: Christoph Hellwig <hch@xxxxxx> --- drivers/scsi/snic/snic_scsi.c | 72 +++++++++++++++++++---------------- 1 file changed, 40 insertions(+), 32 deletions(-) diff --git a/drivers/scsi/snic/snic_scsi.c b/drivers/scsi/snic/snic_scsi.c index f1ef781df837..1807f713504f 100644 --- a/drivers/scsi/snic/snic_scsi.c +++ b/drivers/scsi/snic/snic_scsi.c @@ -2091,70 +2091,78 @@ snic_unlink_and_release_req(struct snic *snic, struct scsi_cmnd *sc, int flag) int snic_device_reset(struct scsi_cmnd *sc) { - struct Scsi_Host *shost = sc->device->host; + struct scsi_device *sdev = sc->device; + struct Scsi_Host *shost = sdev->host; struct snic *snic = shost_priv(shost); + struct request *req; struct snic_req_info *rqi = NULL; - int tag = snic_cmd_tag(sc); int start_time = jiffies; int ret = FAILED; int dr_supp = 0; - SNIC_SCSI_DBG(shost, "dev_reset:sc %p :0x%x :req = %p :tag = %d\n", - sc, sc->cmnd[0], scsi_cmd_to_rq(sc), - snic_cmd_tag(sc)); - dr_supp = snic_dev_reset_supported(sc->device); + SNIC_SCSI_DBG(shost, "dev_reset\n"); + dr_supp = snic_dev_reset_supported(sdev); if (!dr_supp) { /* device reset op is not supported */ SNIC_HOST_INFO(shost, "LUN Reset Op not supported.\n"); - snic_unlink_and_release_req(snic, sc, SNIC_DEV_RST_NOTSUP); - - goto dev_rst_end; + return ret; } if (unlikely(snic_get_state(snic) != SNIC_ONLINE)) { - snic_unlink_and_release_req(snic, sc, 0); SNIC_HOST_ERR(shost, "Devrst: Parent Devs are not online.\n"); - goto dev_rst_end; + return ret; } - /* There is no tag when lun reset is issue through ioctl. */ - if (unlikely(tag <= SNIC_NO_TAG)) { - SNIC_HOST_INFO(snic->shost, - "Devrst: LUN Reset Recvd thru IOCTL.\n"); - - rqi = snic_req_init(snic, 0); - if (!rqi) - goto dev_rst_end; - - memset(scsi_cmd_priv(sc), 0, - sizeof(struct snic_internal_io_state)); - CMD_SP(sc) = (char *)rqi; - CMD_FLAGS(sc) = SNIC_NO_FLAGS; + rqi = snic_req_init(snic, 0); + if (!rqi) + return ret; - /* Add special tag for dr coming from user spc */ - rqi->tm_tag = SNIC_TAG_IOCTL_DEV_RST; - rqi->sc = sc; + req = scsi_alloc_request(sdev->request_queue, REQ_OP_DRV_IN, + BLK_MQ_REQ_NOWAIT); + if (!req) { + /* + * Request allocation might fail, indicating that + * all tags are busy. + * But device reset will be called only from within + * SCSI EH, at which time all I/O is stopped. So the + * only active tags would be for failed I/O, but + * when all I/O is failed it'll be better to escalate + * to host reset anyway. + */ + SNIC_HOST_ERR(snic->shost, + "Devrst: TMF busy, escalate to host reset\n"); + goto dev_rst_end; } + sc = blk_mq_rq_to_pdu(req); + memset(scsi_cmd_priv(sc), 0, + sizeof(struct snic_internal_io_state)); + CMD_SP(sc) = (char *)rqi; + CMD_FLAGS(sc) = SNIC_NO_FLAGS; + /* Add special tag for dr coming from user spc */ + rqi->tm_tag = SNIC_TAG_IOCTL_DEV_RST; + rqi->sc = sc; + WRITE_ONCE(req->state, MQ_RQ_IN_FLIGHT); ret = snic_send_dr_and_wait(snic, sc); if (ret) { SNIC_HOST_ERR(snic->shost, "Devrst: IO w/ Tag %x Failed w/ err = %d\n", - tag, ret); - + snic_cmd_tag(sc), ret); + blk_mq_set_request_complete(req); snic_unlink_and_release_req(snic, sc, 0); goto dev_rst_end; } - + blk_mq_set_request_complete(req); ret = snic_dr_finish(snic, sc); dev_rst_end: - SNIC_TRC(snic->shost->host_no, tag, (ulong) sc, + SNIC_TRC(snic->shost->host_no, snic_cmd_tag(sc), (ulong) sc, jiffies_to_msecs(jiffies - start_time), 0, SNIC_TRC_CMD(sc), SNIC_TRC_CMD_STATE_FLAGS(sc)); - + if (req) + blk_mq_free_request(req); SNIC_SCSI_DBG(snic->shost, "Devrst: Returning from Device Reset : %s\n", (ret == SUCCESS) ? "SUCCESS" : "FAILED"); -- 2.35.3