Merge tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 7 Mar 2018 18:50:15 +0000 (10:50 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 7 Mar 2018 18:50:15 +0000 (10:50 -0800)
Pull SCSI fixes from James Bottomley:
 "This is mostly fixes for driver specific issues (nine of them) and the
  storvsc performance improvement with interrupt handling which was
  dropped from the previous fixes pull request.

  We also have two regressions: one is a double call_rcu() in ATA error
  handling and the other is a missed conversion to BLK_STS_OK in
  __scsi_error_from_host_byte()"

* tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi:
  scsi: qedi: Fix kernel crash during port toggle
  scsi: qla2xxx: Fix FC-NVMe LUN discovery
  scsi: core: return BLK_STS_OK for DID_OK in __scsi_error_from_host_byte()
  scsi: core: Avoid that ATA error handling can trigger a kernel hang or oops
  scsi: qla2xxx: ensure async flags are reset correctly
  scsi: qla2xxx: do not check login_state if no loop id is assigned
  scsi: qla2xxx: Fixup locking for session deletion
  scsi: qla2xxx: Fix NULL pointer crash due to active timer for ABTS
  scsi: mpt3sas: wait for and flush running commands on shutdown/unload
  scsi: mpt3sas: fix oops in error handlers after shutdown/unload
  scsi: storvsc: Spread interrupts when picking a channel for I/O requests
  scsi: megaraid_sas: Do not use 32-bit atomic request descriptor for Ventura controllers

1  2 
drivers/scsi/qedi/qedi_fw.c
drivers/scsi/scsi_lib.c
drivers/scsi/storvsc_drv.c
include/scsi/scsi_cmnd.h

index 667d7697ba01d6a63da5b28ce6953d7cb9465e09,03c772c223fa9efdfdd471216ddbc515b299e0de..d09afe1b567d9dd2cbfd383fb771071e61d61609
@@@ -87,7 -87,7 +87,7 @@@ static void qedi_process_text_resp(stru
  {
        struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data;
        struct iscsi_session *session = conn->session;
 -      struct iscsi_task_context *task_ctx;
 +      struct e4_iscsi_task_context *task_ctx;
        struct iscsi_text_rsp *resp_hdr_ptr;
        struct iscsi_text_response_hdr *cqe_text_response;
        struct qedi_cmd *cmd;
@@@ -260,7 -260,7 +260,7 @@@ static void qedi_process_login_resp(str
  {
        struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data;
        struct iscsi_session *session = conn->session;
 -      struct iscsi_task_context *task_ctx;
 +      struct e4_iscsi_task_context *task_ctx;
        struct iscsi_login_rsp *resp_hdr_ptr;
        struct iscsi_login_response_hdr *cqe_login_response;
        struct qedi_cmd *cmd;
@@@ -326,7 -326,7 +326,7 @@@ static void qedi_get_rq_bdq_buf(struct 
                  (qedi->bdq_prod_idx % qedi->rq_num_entries));
  
        /* Obtain buffer address from rqe_opaque */
 -      idx = cqe->rqe_opaque.lo;
 +      idx = cqe->rqe_opaque;
        if (idx > (QEDI_BDQ_NUM - 1)) {
                QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN,
                          "wrong idx %d returned by FW, dropping the unsolicited pkt\n",
        }
  
        QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN,
 -                "rqe_opaque.lo [0x%p], rqe_opaque.hi [0x%p], idx [%d]\n",
 -                cqe->rqe_opaque.lo, cqe->rqe_opaque.hi, idx);
 +                "rqe_opaque [0x%p], idx [%d]\n", cqe->rqe_opaque, idx);
  
        QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN,
                  "unsol_cqe_type = %d\n", cqe->unsol_cqe_type);
@@@ -362,7 -363,7 +362,7 @@@ static void qedi_put_rq_bdq_buf(struct 
        struct scsi_bd *pbl;
  
        /* Obtain buffer address from rqe_opaque */
 -      idx = cqe->rqe_opaque.lo;
 +      idx = cqe->rqe_opaque;
        if (idx > (QEDI_BDQ_NUM - 1)) {
                QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN,
                          "wrong idx %d returned by FW, dropping the unsolicited pkt\n",
        QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN,
                  "pbl [0x%p] pbl->address hi [0x%llx] lo [0x%llx] idx [%d]\n",
                  pbl, pbl->address.hi, pbl->address.lo, idx);
 -      pbl->opaque.hi = 0;
 -      pbl->opaque.lo = cpu_to_le32(QEDI_U64_LO(idx));
 +      pbl->opaque.iscsi_opaque.reserved_zero[0] = 0;
 +      pbl->opaque.iscsi_opaque.reserved_zero[1] = 0;
 +      pbl->opaque.iscsi_opaque.reserved_zero[2] = 0;
 +      pbl->opaque.iscsi_opaque.opaque = cpu_to_le32(idx);
  
        /* Increment producer to let f/w know we've handled the frame */
        qedi->bdq_prod_idx += count;
@@@ -762,6 -761,11 +762,11 @@@ static void qedi_process_cmd_cleanup_re
  
        iscsi_cid = cqe->conn_id;
        qedi_conn = qedi->cid_que.conn_cid_tbl[iscsi_cid];
+       if (!qedi_conn) {
+               QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,
+                         "icid not found 0x%x\n", cqe->conn_id);
+               return;
+       }
  
        /* Based on this itt get the corresponding qedi_cmd */
        spin_lock_bh(&qedi_conn->tmf_work_lock);
@@@ -1018,7 -1022,7 +1023,7 @@@ int qedi_send_iscsi_login(struct qedi_c
        struct scsi_sgl_task_params tx_sgl_task_params;
        struct scsi_sgl_task_params rx_sgl_task_params;
        struct iscsi_task_params task_params;
 -      struct iscsi_task_context *fw_task_ctx;
 +      struct e4_iscsi_task_context *fw_task_ctx;
        struct qedi_ctx *qedi = qedi_conn->qedi;
        struct iscsi_login_req *login_hdr;
        struct scsi_sge *resp_sge = NULL;
                return -ENOMEM;
  
        fw_task_ctx =
 -           (struct iscsi_task_context *)qedi_get_task_mem(&qedi->tasks, tid);
 -      memset(fw_task_ctx, 0, sizeof(struct iscsi_task_context));
 +           (struct e4_iscsi_task_context *)qedi_get_task_mem(&qedi->tasks,
 +                                                             tid);
 +      memset(fw_task_ctx, 0, sizeof(struct e4_iscsi_task_context));
  
        qedi_cmd->task_id = tid;
  
@@@ -1121,7 -1124,7 +1126,7 @@@ int qedi_send_iscsi_logout(struct qedi_
        struct scsi_sgl_task_params tx_sgl_task_params;
        struct scsi_sgl_task_params rx_sgl_task_params;
        struct iscsi_task_params task_params;
 -      struct iscsi_task_context *fw_task_ctx;
 +      struct e4_iscsi_task_context *fw_task_ctx;
        struct iscsi_logout *logout_hdr = NULL;
        struct qedi_ctx *qedi = qedi_conn->qedi;
        struct qedi_cmd *qedi_cmd;
                return -ENOMEM;
  
        fw_task_ctx =
 -           (struct iscsi_task_context *)qedi_get_task_mem(&qedi->tasks, tid);
 -      memset(fw_task_ctx, 0, sizeof(struct iscsi_task_context));
 +           (struct e4_iscsi_task_context *)qedi_get_task_mem(&qedi->tasks,
 +                                                             tid);
 +      memset(fw_task_ctx, 0, sizeof(struct e4_iscsi_task_context));
  
        qedi_cmd->task_id = tid;
  
@@@ -1470,7 -1472,7 +1475,7 @@@ static int qedi_send_iscsi_tmf(struct q
        struct iscsi_tmf_request_hdr tmf_pdu_header;
        struct iscsi_task_params task_params;
        struct qedi_ctx *qedi = qedi_conn->qedi;
 -      struct iscsi_task_context *fw_task_ctx;
 +      struct e4_iscsi_task_context *fw_task_ctx;
        struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data;
        struct iscsi_task *ctask;
        struct iscsi_tm *tmf_hdr;
                return -ENOMEM;
  
        fw_task_ctx =
 -           (struct iscsi_task_context *)qedi_get_task_mem(&qedi->tasks, tid);
 -      memset(fw_task_ctx, 0, sizeof(struct iscsi_task_context));
 +           (struct e4_iscsi_task_context *)qedi_get_task_mem(&qedi->tasks,
 +                                                             tid);
 +      memset(fw_task_ctx, 0, sizeof(struct e4_iscsi_task_context));
  
        qedi_cmd->task_id = tid;
  
@@@ -1609,7 -1610,7 +1614,7 @@@ int qedi_send_iscsi_text(struct qedi_co
        struct scsi_sgl_task_params tx_sgl_task_params;
        struct scsi_sgl_task_params rx_sgl_task_params;
        struct iscsi_task_params task_params;
 -      struct iscsi_task_context *fw_task_ctx;
 +      struct e4_iscsi_task_context *fw_task_ctx;
        struct qedi_ctx *qedi = qedi_conn->qedi;
        struct iscsi_text *text_hdr;
        struct scsi_sge *req_sge = NULL;
                return -ENOMEM;
  
        fw_task_ctx =
 -           (struct iscsi_task_context *)qedi_get_task_mem(&qedi->tasks, tid);
 -      memset(fw_task_ctx, 0, sizeof(struct iscsi_task_context));
 +           (struct e4_iscsi_task_context *)qedi_get_task_mem(&qedi->tasks,
 +                                                             tid);
 +      memset(fw_task_ctx, 0, sizeof(struct e4_iscsi_task_context));
  
        qedi_cmd->task_id = tid;
  
@@@ -1710,7 -1710,7 +1715,7 @@@ int qedi_send_iscsi_nopout(struct qedi_
        struct scsi_sgl_task_params rx_sgl_task_params;
        struct iscsi_task_params task_params;
        struct qedi_ctx *qedi = qedi_conn->qedi;
 -      struct iscsi_task_context *fw_task_ctx;
 +      struct e4_iscsi_task_context *fw_task_ctx;
        struct iscsi_nopout *nopout_hdr;
        struct scsi_sge *resp_sge = NULL;
        struct qedi_cmd *qedi_cmd;
                return -ENOMEM;
  
        fw_task_ctx =
 -           (struct iscsi_task_context *)qedi_get_task_mem(&qedi->tasks, tid);
 -      memset(fw_task_ctx, 0, sizeof(struct iscsi_task_context));
 +           (struct e4_iscsi_task_context *)qedi_get_task_mem(&qedi->tasks,
 +                                                             tid);
 +      memset(fw_task_ctx, 0, sizeof(struct e4_iscsi_task_context));
  
        qedi_cmd->task_id = tid;
  
@@@ -2052,7 -2051,7 +2057,7 @@@ int qedi_iscsi_send_ioreq(struct iscsi_
        struct iscsi_task_params task_params;
        struct iscsi_conn_params conn_params;
        struct scsi_initiator_cmd_params cmd_params;
 -      struct iscsi_task_context *fw_task_ctx;
 +      struct e4_iscsi_task_context *fw_task_ctx;
        struct iscsi_cls_conn *cls_conn;
        struct iscsi_scsi_req *hdr = (struct iscsi_scsi_req *)task->hdr;
        enum iscsi_task_type task_type = MAX_ISCSI_TASK_TYPE;
                return -ENOMEM;
  
        fw_task_ctx =
 -           (struct iscsi_task_context *)qedi_get_task_mem(&qedi->tasks, tid);
 -      memset(fw_task_ctx, 0, sizeof(struct iscsi_task_context));
 +           (struct e4_iscsi_task_context *)qedi_get_task_mem(&qedi->tasks,
 +                                                             tid);
 +      memset(fw_task_ctx, 0, sizeof(struct e4_iscsi_task_context));
  
        cmd->task_id = tid;
  
diff --combined drivers/scsi/scsi_lib.c
index a86df9ca7d1c88aceb1d1e2298f48fbdb8bb3c49,c9844043504e18de606b07e87e0fc7ccabf65920..c84f931388f226cdab2071245f7308d2c0b035b3
@@@ -79,15 -79,14 +79,15 @@@ int scsi_init_sense_cache(struct Scsi_H
        if (shost->unchecked_isa_dma) {
                scsi_sense_isadma_cache =
                        kmem_cache_create("scsi_sense_cache(DMA)",
 -                      SCSI_SENSE_BUFFERSIZE, 0,
 -                      SLAB_HWCACHE_ALIGN | SLAB_CACHE_DMA, NULL);
 +                              SCSI_SENSE_BUFFERSIZE, 0,
 +                              SLAB_HWCACHE_ALIGN | SLAB_CACHE_DMA, NULL);
                if (!scsi_sense_isadma_cache)
                        ret = -ENOMEM;
        } else {
                scsi_sense_cache =
 -                      kmem_cache_create("scsi_sense_cache",
 -                      SCSI_SENSE_BUFFERSIZE, 0, SLAB_HWCACHE_ALIGN, NULL);
 +                      kmem_cache_create_usercopy("scsi_sense_cache",
 +                              SCSI_SENSE_BUFFERSIZE, 0, SLAB_HWCACHE_ALIGN,
 +                              0, SCSI_SENSE_BUFFERSIZE, NULL);
                if (!scsi_sense_cache)
                        ret = -ENOMEM;
        }
@@@ -671,6 -670,7 +671,7 @@@ static bool scsi_end_request(struct req
        if (!blk_rq_is_scsi(req)) {
                WARN_ON_ONCE(!(cmd->flags & SCMD_INITIALIZED));
                cmd->flags &= ~SCMD_INITIALIZED;
+               destroy_rcu_head(&cmd->rcu);
        }
  
        if (req->mq_ctx) {
@@@ -720,6 -720,8 +721,8 @@@ static blk_status_t __scsi_error_from_h
                int result)
  {
        switch (host_byte(result)) {
+       case DID_OK:
+               return BLK_STS_OK;
        case DID_TRANSPORT_FAILFAST:
                return BLK_STS_TRANSPORT;
        case DID_TARGET_FAILURE:
@@@ -1151,6 -1153,7 +1154,7 @@@ static void scsi_initialize_rq(struct r
        struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(rq);
  
        scsi_req_init(&cmd->req);
+       init_rcu_head(&cmd->rcu);
        cmd->jiffies_at_alloc = jiffies;
        cmd->retries = 0;
  }
@@@ -1984,8 -1987,6 +1988,8 @@@ static bool scsi_mq_get_budget(struct b
  out_put_device:
        put_device(&sdev->sdev_gendev);
  out:
 +      if (atomic_read(&sdev->device_busy) == 0 && !scsi_device_blocked(sdev))
 +              blk_mq_delay_run_hw_queue(hctx, SCSI_QUEUE_DELAY);
        return false;
  }
  
@@@ -2047,9 -2048,9 +2051,9 @@@ out_put_budget
        case BLK_STS_OK:
                break;
        case BLK_STS_RESOURCE:
 -              if (atomic_read(&sdev->device_busy) == 0 &&
 -                  !scsi_device_blocked(sdev))
 -                      blk_mq_delay_run_hw_queue(hctx, SCSI_QUEUE_DELAY);
 +              if (atomic_read(&sdev->device_busy) ||
 +                  scsi_device_blocked(sdev))
 +                      ret = BLK_STS_DEV_RESOURCE;
                break;
        default:
                /*
@@@ -2167,13 -2168,11 +2171,13 @@@ void __scsi_init_queue(struct Scsi_Hos
                q->limits.cluster = 0;
  
        /*
 -       * set a reasonable default alignment on word boundaries: the
 -       * host and device may alter it using
 -       * blk_queue_update_dma_alignment() later.
 +       * Set a reasonable default alignment:  The larger of 32-byte (dword),
 +       * which is a common minimum for HBAs, and the minimum DMA alignment,
 +       * which is set by the platform.
 +       *
 +       * Devices that require a bigger alignment can increase it later.
         */
 -      blk_queue_dma_alignment(q, 0x03);
 +      blk_queue_dma_alignment(q, max(4, dma_get_cache_alignment()) - 1);
  }
  EXPORT_SYMBOL_GPL(__scsi_init_queue);
  
index 6be5ab32c94fef437f552a38f79bdc36825efb98,620510787763919a5b115aa1eef46f8e84aa4839..8c51d628b52edfd7e891182919fab16b469b0f3c
@@@ -953,11 -953,10 +953,11 @@@ static void storvsc_handle_error(struc
                case TEST_UNIT_READY:
                        break;
                default:
 -                      set_host_byte(scmnd, DID_TARGET_FAILURE);
 +                      set_host_byte(scmnd, DID_ERROR);
                }
                break;
        case SRB_STATUS_INVALID_LUN:
 +              set_host_byte(scmnd, DID_NO_CONNECT);
                do_work = true;
                process_err_fn = storvsc_remove_lun;
                break;
@@@ -1311,7 -1310,8 +1311,8 @@@ static int storvsc_do_io(struct hv_devi
                         */
                        cpumask_and(&alloced_mask, &stor_device->alloced_cpus,
                                    cpumask_of_node(cpu_to_node(q_num)));
-                       for_each_cpu(tgt_cpu, &alloced_mask) {
+                       for_each_cpu_wrap(tgt_cpu, &alloced_mask,
+                                       outgoing_channel->target_cpu + 1) {
                                if (tgt_cpu != outgoing_channel->target_cpu) {
                                        outgoing_channel =
                                        stor_device->stor_chns[tgt_cpu];
diff --combined include/scsi/scsi_cmnd.h
index d8d4a902a88dedbc93ac8da1ca99bb5f3d394d65,0382ceab2ebab8873647e6bff2d2c68c72ec9576..2280b2351739572c5db73579f8ffc0e16d511ebe
@@@ -58,7 -58,8 +58,7 @@@ struct scsi_pointer 
  /* for scmd->flags */
  #define SCMD_TAGGED           (1 << 0)
  #define SCMD_UNCHECKED_ISA_DMA        (1 << 1)
 -#define SCMD_ZONE_WRITE_LOCK  (1 << 2)
 -#define SCMD_INITIALIZED      (1 << 3)
 +#define SCMD_INITIALIZED      (1 << 2)
  /* flags preserved across unprep / reprep */
  #define SCMD_PRESERVED_FLAGS  (SCMD_UNCHECKED_ISA_DMA | SCMD_INITIALIZED)
  
@@@ -68,6 -69,9 +68,9 @@@ struct scsi_cmnd 
        struct list_head list;  /* scsi_cmnd participates in queue lists */
        struct list_head eh_entry; /* entry for the host eh_cmd_q */
        struct delayed_work abort_work;
+       struct rcu_head rcu;
        int eh_eflags;          /* Used by error handlr */
  
        /*