Merge tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 2 Jun 2019 16:26:34 +0000 (09:26 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 2 Jun 2019 16:26:34 +0000 (09:26 -0700)
Pull SCSI fixes from James Bottomley:
 "Six minor fixes to device drivers and one to the multipath alua
  handler.

  The most extensive fix is the zfcp port remove prevention one, but
  it's impact is only s390"

* tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi:
  scsi: libsas: delete sas port if expander discover failed
  scsi: libsas: only clear phy->in_shutdown after shutdown event done
  scsi: scsi_dh_alua: Fix possible null-ptr-deref
  scsi: smartpqi: properly set both the DMA mask and the coherent DMA mask
  scsi: zfcp: fix to prevent port_remove with pure auto scan LUNs (only sdevs)
  scsi: zfcp: fix missing zfcp_port reference put on -EBUSY from port_remove
  scsi: libcxgbi: add a check for NULL pointer in cxgbi_check_route()

drivers/s390/scsi/zfcp_ext.h
drivers/s390/scsi/zfcp_scsi.c
drivers/s390/scsi/zfcp_sysfs.c
drivers/s390/scsi/zfcp_unit.c
drivers/scsi/cxgbi/libcxgbi.c
drivers/scsi/device_handler/scsi_dh_alua.c
drivers/scsi/libsas/sas_expander.c
drivers/scsi/libsas/sas_phy.c
drivers/scsi/smartpqi/smartpqi_init.c

index c6acca521ffec71ee7b3f7e7231a32b18fdceff7..31e8a7240fd7eaaafad530fd8fa1700225c7cbad 100644 (file)
@@ -167,6 +167,7 @@ extern const struct attribute_group *zfcp_port_attr_groups[];
 extern struct mutex zfcp_sysfs_port_units_mutex;
 extern struct device_attribute *zfcp_sysfs_sdev_attrs[];
 extern struct device_attribute *zfcp_sysfs_shost_attrs[];
+bool zfcp_sysfs_port_is_removing(const struct zfcp_port *const port);
 
 /* zfcp_unit.c */
 extern int zfcp_unit_add(struct zfcp_port *, u64);
index 221d0dfb849329eb5ebf1758004628301b500ba8..e9ded2befa0dce4bac59d31ef2bfd4fc8daccd61 100644 (file)
@@ -129,6 +129,15 @@ static int zfcp_scsi_slave_alloc(struct scsi_device *sdev)
 
        zfcp_sdev->erp_action.port = port;
 
+       mutex_lock(&zfcp_sysfs_port_units_mutex);
+       if (zfcp_sysfs_port_is_removing(port)) {
+               /* port is already gone */
+               mutex_unlock(&zfcp_sysfs_port_units_mutex);
+               put_device(&port->dev); /* undo zfcp_get_port_by_wwpn() */
+               return -ENXIO;
+       }
+       mutex_unlock(&zfcp_sysfs_port_units_mutex);
+
        unit = zfcp_unit_find(port, zfcp_scsi_dev_lun(sdev));
        if (unit)
                put_device(&unit->dev);
index b277be6f7611ccc9925bc8148416637f5fdb6b58..af197e2b3e69d180ff60c9101efbe8f44b34cebe 100644 (file)
@@ -235,6 +235,53 @@ static ZFCP_DEV_ATTR(adapter, port_rescan, S_IWUSR, NULL,
 
 DEFINE_MUTEX(zfcp_sysfs_port_units_mutex);
 
+static void zfcp_sysfs_port_set_removing(struct zfcp_port *const port)
+{
+       lockdep_assert_held(&zfcp_sysfs_port_units_mutex);
+       atomic_set(&port->units, -1);
+}
+
+bool zfcp_sysfs_port_is_removing(const struct zfcp_port *const port)
+{
+       lockdep_assert_held(&zfcp_sysfs_port_units_mutex);
+       return atomic_read(&port->units) == -1;
+}
+
+static bool zfcp_sysfs_port_in_use(struct zfcp_port *const port)
+{
+       struct zfcp_adapter *const adapter = port->adapter;
+       unsigned long flags;
+       struct scsi_device *sdev;
+       bool in_use = true;
+
+       mutex_lock(&zfcp_sysfs_port_units_mutex);
+       if (atomic_read(&port->units) > 0)
+               goto unlock_port_units_mutex; /* zfcp_unit(s) under port */
+
+       spin_lock_irqsave(adapter->scsi_host->host_lock, flags);
+       __shost_for_each_device(sdev, adapter->scsi_host) {
+               const struct zfcp_scsi_dev *zsdev = sdev_to_zfcp(sdev);
+
+               if (sdev->sdev_state == SDEV_DEL ||
+                   sdev->sdev_state == SDEV_CANCEL)
+                       continue;
+               if (zsdev->port != port)
+                       continue;
+               /* alive scsi_device under port of interest */
+               goto unlock_host_lock;
+       }
+
+       /* port is about to be removed, so no more unit_add or slave_alloc */
+       zfcp_sysfs_port_set_removing(port);
+       in_use = false;
+
+unlock_host_lock:
+       spin_unlock_irqrestore(adapter->scsi_host->host_lock, flags);
+unlock_port_units_mutex:
+       mutex_unlock(&zfcp_sysfs_port_units_mutex);
+       return in_use;
+}
+
 static ssize_t zfcp_sysfs_port_remove_store(struct device *dev,
                                            struct device_attribute *attr,
                                            const char *buf, size_t count)
@@ -257,15 +304,11 @@ static ssize_t zfcp_sysfs_port_remove_store(struct device *dev,
        else
                retval = 0;
 
-       mutex_lock(&zfcp_sysfs_port_units_mutex);
-       if (atomic_read(&port->units) > 0) {
+       if (zfcp_sysfs_port_in_use(port)) {
                retval = -EBUSY;
-               mutex_unlock(&zfcp_sysfs_port_units_mutex);
+               put_device(&port->dev); /* undo zfcp_get_port_by_wwpn() */
                goto out;
        }
-       /* port is about to be removed, so no more unit_add */
-       atomic_set(&port->units, -1);
-       mutex_unlock(&zfcp_sysfs_port_units_mutex);
 
        write_lock_irq(&adapter->port_list_lock);
        list_del(&port->list);
index 1bf0a0984a098f083b8ff5e53fffe3710cbe6884..e67bf7388cae82d5b533e9e6ff12f271754fdf32 100644 (file)
@@ -124,7 +124,7 @@ int zfcp_unit_add(struct zfcp_port *port, u64 fcp_lun)
        int retval = 0;
 
        mutex_lock(&zfcp_sysfs_port_units_mutex);
-       if (atomic_read(&port->units) == -1) {
+       if (zfcp_sysfs_port_is_removing(port)) {
                /* port is already gone */
                retval = -ENODEV;
                goto out;
@@ -168,8 +168,14 @@ int zfcp_unit_add(struct zfcp_port *port, u64 fcp_lun)
        write_lock_irq(&port->unit_list_lock);
        list_add_tail(&unit->list, &port->unit_list);
        write_unlock_irq(&port->unit_list_lock);
+       /*
+        * lock order: shost->scan_mutex before zfcp_sysfs_port_units_mutex
+        * due to      zfcp_unit_scsi_scan() => zfcp_scsi_slave_alloc()
+        */
+       mutex_unlock(&zfcp_sysfs_port_units_mutex);
 
        zfcp_unit_scsi_scan(unit);
+       return retval;
 
 out:
        mutex_unlock(&zfcp_sysfs_port_units_mutex);
index 8b915d4ed98dcffdb41bfa8d4ded91cd526bac6a..7d43e014bd21528f970f34480bc2a369db3c284e 100644 (file)
@@ -639,6 +639,10 @@ cxgbi_check_route(struct sockaddr *dst_addr, int ifindex)
 
        if (ndev->flags & IFF_LOOPBACK) {
                ndev = ip_dev_find(&init_net, daddr->sin_addr.s_addr);
+               if (!ndev) {
+                       err = -ENETUNREACH;
+                       goto rel_neigh;
+               }
                mtu = ndev->mtu;
                pr_info("rt dev %s, loopback -> %s, mtu %u.\n",
                        n->dev->name, ndev->name, mtu);
index a7a4a772f501bd7c442e054f11f6742156dd2af9..f0066f8a17864ab94a5fe86ff15093f77be784f6 100644 (file)
@@ -1160,10 +1160,8 @@ static int __init alua_init(void)
        int r;
 
        kaluad_wq = alloc_workqueue("kaluad", WQ_MEM_RECLAIM, 0);
-       if (!kaluad_wq) {
-               /* Temporary failure, bypass */
-               return SCSI_DH_DEV_TEMP_BUSY;
-       }
+       if (!kaluad_wq)
+               return -ENOMEM;
 
        r = scsi_register_device_handler(&alua_dh);
        if (r != 0) {
index 83f2fd70ce76b4e23d996a6386dc8aeb7b2724ea..9f7e2457360e2dbd750542035e8e8fccee98f15d 100644 (file)
@@ -1019,6 +1019,8 @@ static struct domain_device *sas_ex_discover_expander(
                list_del(&child->dev_list_node);
                spin_unlock_irq(&parent->port->dev_list_lock);
                sas_put_device(child);
+               sas_port_delete(phy->port);
+               phy->port = NULL;
                return NULL;
        }
        list_add_tail(&child->siblings, &parent->ex_dev.children);
index e030e145213631877428cd1f95a5d91fd9d44fbd..b71f5ac6c7dcf5b1b684061298c397faf8c61553 100644 (file)
@@ -35,7 +35,6 @@ static void sas_phye_loss_of_signal(struct work_struct *work)
        struct asd_sas_event *ev = to_asd_sas_event(work);
        struct asd_sas_phy *phy = ev->phy;
 
-       phy->in_shutdown = 0;
        phy->error = 0;
        sas_deform_port(phy, 1);
 }
@@ -45,7 +44,6 @@ static void sas_phye_oob_done(struct work_struct *work)
        struct asd_sas_event *ev = to_asd_sas_event(work);
        struct asd_sas_phy *phy = ev->phy;
 
-       phy->in_shutdown = 0;
        phy->error = 0;
 }
 
@@ -126,6 +124,7 @@ static void sas_phye_shutdown(struct work_struct *work)
                                  ret);
        } else
                pr_notice("phy%d is not enabled, cannot shutdown\n", phy->id);
+       phy->in_shutdown = 0;
 }
 
 /* ---------- Phy class registration ---------- */
index b17761eafca91eeb8ff68126567f46f4942184f6..d6be4e8f4a8f0852aac445d2193da9b4ed7b8c96 100644 (file)
@@ -7291,7 +7291,7 @@ static int pqi_pci_init(struct pqi_ctrl_info *ctrl_info)
        else
                mask = DMA_BIT_MASK(32);
 
-       rc = dma_set_mask(&ctrl_info->pci_dev->dev, mask);
+       rc = dma_set_mask_and_coherent(&ctrl_info->pci_dev->dev, mask);
        if (rc) {
                dev_err(&ctrl_info->pci_dev->dev, "failed to set DMA mask\n");
                goto disable_device;