Merge tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 15 Dec 2017 20:51:42 +0000 (12:51 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 15 Dec 2017 20:51:42 +0000 (12:51 -0800)
Pull SCSI fixes from James Bottomley:
 "The most important one is the bfa fix because it's easy to oops the
  kernel with this driver (this includes the commit that corrects the
  compiler warning in the original), a regression in the new timespec
  conversion in aacraid and a regression in the Fibre Channel ELS
  handling patch.

  The other three are a theoretical problem with termination in the
  vendor/host matching code and a use after free in lpfc.

  The additional patches are a fix for an I/O hang in the mq code under
  certain circumstances and a rare oops in some debugging code"

* tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi:
  scsi: core: Fix a scsi_show_rq() NULL pointer dereference
  scsi: MAINTAINERS: change FCoE list to linux-scsi
  scsi: libsas: fix length error in sas_smp_handler()
  scsi: bfa: fix type conversion warning
  scsi: core: run queue if SCSI device queue isn't ready and queue is idle
  scsi: scsi_devinfo: cleanly zero-pad devinfo strings
  scsi: scsi_devinfo: handle non-terminated strings
  scsi: bfa: fix access to bfad_im_port_s
  scsi: aacraid: address UBSAN warning regression
  scsi: libfc: fix ELS request handling
  scsi: lpfc: Use after free in lpfc_rq_buf_free()

12 files changed:
MAINTAINERS
drivers/scsi/aacraid/commsup.c
drivers/scsi/bfa/bfad_bsg.c
drivers/scsi/bfa/bfad_im.c
drivers/scsi/bfa/bfad_im.h
drivers/scsi/libfc/fc_lport.c
drivers/scsi/libsas/sas_expander.c
drivers/scsi/lpfc/lpfc_mem.c
drivers/scsi/scsi_debugfs.c
drivers/scsi/scsi_devinfo.c
drivers/scsi/scsi_lib.c
drivers/scsi/sd.c

index 82ad0eabce4f3e3955dfab54c7df2cae03644268..e626cb622dca896a6cc4f9ab8eb26d45be798ff5 100644 (file)
@@ -5431,7 +5431,7 @@ F:        drivers/media/tuners/fc2580*
 
 FCOE SUBSYSTEM (libfc, libfcoe, fcoe)
 M:     Johannes Thumshirn <jth@kernel.org>
-L:     fcoe-devel@open-fcoe.org
+L:     linux-scsi@vger.kernel.org
 W:     www.Open-FCoE.org
 S:     Supported
 F:     drivers/scsi/libfc/
index bec9f3193f607c0aa1ca5f728f5eac85de518d61..80a8cb26cdea43c8252bc5afe68b2b72540ff045 100644 (file)
@@ -2482,8 +2482,8 @@ int aac_command_thread(void *data)
                        /* Synchronize our watches */
                        if (((NSEC_PER_SEC - (NSEC_PER_SEC / HZ)) > now.tv_nsec)
                         && (now.tv_nsec > (NSEC_PER_SEC / HZ)))
-                               difference = (((NSEC_PER_SEC - now.tv_nsec) * HZ)
-                                 + NSEC_PER_SEC / 2) / NSEC_PER_SEC;
+                               difference = HZ + HZ / 2 -
+                                            now.tv_nsec / (NSEC_PER_SEC / HZ);
                        else {
                                if (now.tv_nsec > NSEC_PER_SEC / 2)
                                        ++now.tv_sec;
@@ -2507,6 +2507,10 @@ int aac_command_thread(void *data)
                if (kthread_should_stop())
                        break;
 
+               /*
+                * we probably want usleep_range() here instead of the
+                * jiffies computation
+                */
                schedule_timeout(difference);
 
                if (kthread_should_stop())
index 72ca2a2e08e259b70be45e8880354bf8291ef9c4..b2fa195adc7a3a6e405a6c23132060952916138f 100644 (file)
@@ -3135,7 +3135,8 @@ bfad_im_bsg_vendor_request(struct bsg_job *job)
        struct fc_bsg_request *bsg_request = job->request;
        struct fc_bsg_reply *bsg_reply = job->reply;
        uint32_t vendor_cmd = bsg_request->rqst_data.h_vendor.vendor_cmd[0];
-       struct bfad_im_port_s *im_port = shost_priv(fc_bsg_to_shost(job));
+       struct Scsi_Host *shost = fc_bsg_to_shost(job);
+       struct bfad_im_port_s *im_port = bfad_get_im_port(shost);
        struct bfad_s *bfad = im_port->bfad;
        void *payload_kbuf;
        int rc = -EINVAL;
@@ -3350,7 +3351,8 @@ int
 bfad_im_bsg_els_ct_request(struct bsg_job *job)
 {
        struct bfa_bsg_data *bsg_data;
-       struct bfad_im_port_s *im_port = shost_priv(fc_bsg_to_shost(job));
+       struct Scsi_Host *shost = fc_bsg_to_shost(job);
+       struct bfad_im_port_s *im_port = bfad_get_im_port(shost);
        struct bfad_s *bfad = im_port->bfad;
        bfa_bsg_fcpt_t *bsg_fcpt;
        struct bfad_fcxp    *drv_fcxp;
index 24e657a4ec80df3caf82eff0b284288acc875a28..c05d6e91e4bde9cde7e9146ad48bae69727d476f 100644 (file)
@@ -546,6 +546,7 @@ int
 bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port,
                        struct device *dev)
 {
+       struct bfad_im_port_pointer *im_portp;
        int error = 1;
 
        mutex_lock(&bfad_mutex);
@@ -564,7 +565,8 @@ bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port,
                goto out_free_idr;
        }
 
-       im_port->shost->hostdata[0] = (unsigned long)im_port;
+       im_portp = shost_priv(im_port->shost);
+       im_portp->p = im_port;
        im_port->shost->unique_id = im_port->idr_id;
        im_port->shost->this_id = -1;
        im_port->shost->max_id = MAX_FCP_TARGET;
@@ -748,7 +750,7 @@ bfad_scsi_host_alloc(struct bfad_im_port_s *im_port, struct bfad_s *bfad)
 
        sht->sg_tablesize = bfad->cfg_data.io_max_sge;
 
-       return scsi_host_alloc(sht, sizeof(unsigned long));
+       return scsi_host_alloc(sht, sizeof(struct bfad_im_port_pointer));
 }
 
 void
index c81ec2a77ef5034d3fdd3c70f1466002e012be10..06ce4ba2b7bc9e6e562a20d98de2a6a99fff93d1 100644 (file)
@@ -69,6 +69,16 @@ struct bfad_im_port_s {
        struct fc_vport *fc_vport;
 };
 
+struct bfad_im_port_pointer {
+       struct bfad_im_port_s *p;
+};
+
+static inline struct bfad_im_port_s *bfad_get_im_port(struct Scsi_Host *host)
+{
+       struct bfad_im_port_pointer *im_portp = shost_priv(host);
+       return im_portp->p;
+}
+
 enum bfad_itnim_state {
        ITNIM_STATE_NONE,
        ITNIM_STATE_ONLINE,
index 5da46052e179c200a8e476f38551e470f6dd9173..21be672679fb5026120049b1609569bf8d25259a 100644 (file)
@@ -904,10 +904,14 @@ static void fc_lport_recv_els_req(struct fc_lport *lport,
                case ELS_FLOGI:
                        if (!lport->point_to_multipoint)
                                fc_lport_recv_flogi_req(lport, fp);
+                       else
+                               fc_rport_recv_req(lport, fp);
                        break;
                case ELS_LOGO:
                        if (fc_frame_sid(fp) == FC_FID_FLOGI)
                                fc_lport_recv_logo_req(lport, fp);
+                       else
+                               fc_rport_recv_req(lport, fp);
                        break;
                case ELS_RSCN:
                        lport->tt.disc_recv_req(lport, fp);
index ca1566237ae7744703a9e3ae3533138c4e81af53..3183d63de4dab7f5b000f2b6da856eea70c6b900 100644 (file)
@@ -2145,7 +2145,7 @@ void sas_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,
                struct sas_rphy *rphy)
 {
        struct domain_device *dev;
-       unsigned int reslen = 0;
+       unsigned int rcvlen = 0;
        int ret = -EINVAL;
 
        /* no rphy means no smp target support (ie aic94xx host) */
@@ -2179,12 +2179,12 @@ void sas_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,
 
        ret = smp_execute_task_sg(dev, job->request_payload.sg_list,
                        job->reply_payload.sg_list);
-       if (ret > 0) {
-               /* positive number is the untransferred residual */
-               reslen = ret;
+       if (ret >= 0) {
+               /* bsg_job_done() requires the length received  */
+               rcvlen = job->reply_payload.payload_len - ret;
                ret = 0;
        }
 
 out:
-       bsg_job_done(job, ret, reslen);
+       bsg_job_done(job, ret, rcvlen);
 }
index 56faeb049b4ac50ec04783349fcea9b79c20583f..87c08ff37dddff46fed7841247a41f585ebc8f1d 100644 (file)
@@ -753,12 +753,12 @@ lpfc_rq_buf_free(struct lpfc_hba *phba, struct lpfc_dmabuf *mp)
        drqe.address_hi = putPaddrHigh(rqb_entry->dbuf.phys);
        rc = lpfc_sli4_rq_put(rqb_entry->hrq, rqb_entry->drq, &hrqe, &drqe);
        if (rc < 0) {
-               (rqbp->rqb_free_buffer)(phba, rqb_entry);
                lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
                                "6409 Cannot post to RQ %d: %x %x\n",
                                rqb_entry->hrq->queue_id,
                                rqb_entry->hrq->host_index,
                                rqb_entry->hrq->hba_index);
+               (rqbp->rqb_free_buffer)(phba, rqb_entry);
        } else {
                list_add_tail(&rqb_entry->hbuf.list, &rqbp->rqb_buffer_list);
                rqbp->buffer_count++;
index 01f08c03f2c185dc3f7e1d423c3459da95fb6cbb..c3765d29fd3ff8167a647563b43be57e885dd6a9 100644 (file)
@@ -8,9 +8,11 @@ void scsi_show_rq(struct seq_file *m, struct request *rq)
 {
        struct scsi_cmnd *cmd = container_of(scsi_req(rq), typeof(*cmd), req);
        int msecs = jiffies_to_msecs(jiffies - cmd->jiffies_at_alloc);
-       char buf[80];
+       const u8 *const cdb = READ_ONCE(cmd->cmnd);
+       char buf[80] = "(?)";
 
-       __scsi_format_command(buf, sizeof(buf), cmd->cmnd, cmd->cmd_len);
+       if (cdb)
+               __scsi_format_command(buf, sizeof(buf), cdb, cmd->cmd_len);
        seq_printf(m, ", .cmd=%s, .retries=%d, allocated %d.%03d s ago", buf,
                   cmd->retries, msecs / 1000, msecs % 1000);
 }
index 78d4aa8df675a1671df5daf12dfc7d9000f3cbe5..449ef5adbb2bc3719b3ba72953ebbecef9e4d086 100644 (file)
@@ -34,7 +34,6 @@ struct scsi_dev_info_list_table {
 };
 
 
-static const char spaces[] = "                "; /* 16 of them */
 static blist_flags_t scsi_default_dev_flags;
 static LIST_HEAD(scsi_dev_info_list);
 static char scsi_dev_flags[256];
@@ -298,20 +297,13 @@ static void scsi_strcpy_devinfo(char *name, char *to, size_t to_length,
        size_t from_length;
 
        from_length = strlen(from);
-       strncpy(to, from, min(to_length, from_length));
-       if (from_length < to_length) {
-               if (compatible) {
-                       /*
-                        * NUL terminate the string if it is short.
-                        */
-                       to[from_length] = '\0';
-               } else {
-                       /*
-                        * space pad the string if it is short.
-                        */
-                       strncpy(&to[from_length], spaces,
-                               to_length - from_length);
-               }
+       /* This zero-pads the destination */
+       strncpy(to, from, to_length);
+       if (from_length < to_length && !compatible) {
+               /*
+                * space pad the string if it is short.
+                */
+               memset(&to[from_length], ' ', to_length - from_length);
        }
        if (from_length > to_length)
                 printk(KERN_WARNING "%s: %s string '%s' is too long\n",
@@ -458,7 +450,8 @@ static struct scsi_dev_info_list *scsi_dev_info_list_find(const char *vendor,
                        /*
                         * vendor strings must be an exact match
                         */
-                       if (vmax != strlen(devinfo->vendor) ||
+                       if (vmax != strnlen(devinfo->vendor,
+                                           sizeof(devinfo->vendor)) ||
                            memcmp(devinfo->vendor, vskip, vmax))
                                continue;
 
@@ -466,7 +459,7 @@ static struct scsi_dev_info_list *scsi_dev_info_list_find(const char *vendor,
                         * @model specifies the full string, and
                         * must be larger or equal to devinfo->model
                         */
-                       mlen = strlen(devinfo->model);
+                       mlen = strnlen(devinfo->model, sizeof(devinfo->model));
                        if (mmax < mlen || memcmp(devinfo->model, mskip, mlen))
                                continue;
                        return devinfo;
index 00742c50cd44ed6e452dc50b4eb9bf5bd3f36e80..d9ca1dfab154c83f79ba1dab210f1a3521d1ea5d 100644 (file)
@@ -1967,6 +1967,8 @@ static bool scsi_mq_get_budget(struct blk_mq_hw_ctx *hctx)
 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;
 }
 
index 24fe685227169d1be705e9ddc1d8861cb962d2bf..a028ab3322a9a4ed3b37530c19268dc90d9098f4 100644 (file)
@@ -1312,6 +1312,7 @@ static int sd_init_command(struct scsi_cmnd *cmd)
 static void sd_uninit_command(struct scsi_cmnd *SCpnt)
 {
        struct request *rq = SCpnt->request;
+       u8 *cmnd;
 
        if (SCpnt->flags & SCMD_ZONE_WRITE_LOCK)
                sd_zbc_write_unlock_zone(SCpnt);
@@ -1320,9 +1321,10 @@ static void sd_uninit_command(struct scsi_cmnd *SCpnt)
                __free_page(rq->special_vec.bv_page);
 
        if (SCpnt->cmnd != scsi_req(rq)->cmd) {
-               mempool_free(SCpnt->cmnd, sd_cdb_pool);
+               cmnd = SCpnt->cmnd;
                SCpnt->cmnd = NULL;
                SCpnt->cmd_len = 0;
+               mempool_free(cmnd, sd_cdb_pool);
        }
 }