scsi: mpt3sas: Allow ioctls to blocked access status NVMe
authorSuganath Prabu <suganath-prabu.subramani@broadcom.com>
Sat, 3 Aug 2019 13:59:51 +0000 (09:59 -0400)
committerMartin K. Petersen <martin.petersen@oracle.com>
Thu, 8 Aug 2019 02:46:19 +0000 (22:46 -0400)
If driver sees the NVMe drive with "DEVICE_BLOCKED" AccessStatus in its
PCIe Device Page0, then driver removes the drive from its internal list and
does not allow any IOCTL commands to be sent to the drive and will return
the IOCTLs with "-ENODEV" status.

The driver will now allow NVMe Encapsulated IOCTL issued to the NVMe device
with an access status of DEVICE_BLOCKED. This change allows the user to
flash new drive firmware online and revive the drive.

Add NVMe device only the driver's internal list even though the device is
in the blocked state so that the device will be visible to Apps. This way
Apps can send NVMe Encapsulated IOCTLs to this drive and bring the drive
online. This NVMe drive with DEVICE_BLOCKED access status won't added to
the SML, it will be added only in the driver's internal list.

[mkp: clarified desc]

Signed-off-by: Suganath Prabu <suganath-prabu.subramani@broadcom.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/mpt3sas/mpt3sas_base.h
drivers/scsi/mpt3sas/mpt3sas_scsih.c

index f6a1ae1cf4c0a6dce85d9c3d789ef52f1a7e684d..c13554e82f3d174ece1040542837f09aff9e9d8f 100644 (file)
@@ -583,6 +583,7 @@ static inline void sas_device_put(struct _sas_device *s)
  * @enclosure_level: The level of device's enclosure from the controller
  * @connector_name: ASCII value of the Connector's name
  * @serial_number: pointer of serial number string allocated runtime
+ * @access_status: Device's Access Status
  * @refcount: reference count for deletion
  */
 struct _pcie_device {
@@ -604,6 +605,7 @@ struct _pcie_device {
        u8      connector_name[4];
        u8      *serial_number;
        u8      reset_timeout;
+       u8      access_status;
        struct kref refcount;
 };
 /**
index c8b83894833f49153fe021fa9e3ac8fb02c28a20..91e9a91f8df2bb51b013dcf4a77526e17883950d 100644 (file)
@@ -1152,6 +1152,11 @@ _scsih_pcie_device_add(struct MPT3SAS_ADAPTER *ioc,
        list_add_tail(&pcie_device->list, &ioc->pcie_device_list);
        spin_unlock_irqrestore(&ioc->pcie_device_lock, flags);
 
+       if (pcie_device->access_status ==
+           MPI26_PCIEDEV0_ASTATUS_DEVICE_BLOCKED) {
+               clear_bit(pcie_device->handle, ioc->pend_os_device_add);
+               return;
+       }
        if (scsi_add_device(ioc->shost, PCIE_CHANNEL, pcie_device->id, 0)) {
                _scsih_pcie_device_remove(ioc, pcie_device);
        } else if (!pcie_device->starget) {
@@ -1196,7 +1201,9 @@ _scsih_pcie_device_init_add(struct MPT3SAS_ADAPTER *ioc,
        spin_lock_irqsave(&ioc->pcie_device_lock, flags);
        pcie_device_get(pcie_device);
        list_add_tail(&pcie_device->list, &ioc->pcie_device_init_list);
-       _scsih_determine_boot_device(ioc, pcie_device, PCIE_CHANNEL);
+       if (pcie_device->access_status !=
+           MPI26_PCIEDEV0_ASTATUS_DEVICE_BLOCKED)
+               _scsih_determine_boot_device(ioc, pcie_device, PCIE_CHANNEL);
        spin_unlock_irqrestore(&ioc->pcie_device_lock, flags);
 }
 /**
@@ -6548,6 +6555,11 @@ _scsih_check_pcie_access_status(struct MPT3SAS_ADAPTER *ioc, u64 wwid,
                break;
        case MPI26_PCIEDEV0_ASTATUS_DEVICE_BLOCKED:
                desc = "PCIe device blocked";
+               ioc_info(ioc,
+                   "Device with Access Status (%s): wwid(0x%016llx), "
+                   "handle(0x%04x)\n ll only be added to the internal list",
+                   desc, (u64)wwid, handle);
+               rc = 0;
                break;
        case MPI26_PCIEDEV0_ASTATUS_MEMORY_SPACE_ACCESS_FAILED:
                desc = "PCIe device mem space access failed";
@@ -6652,7 +6664,8 @@ _scsih_pcie_device_remove_from_sml(struct MPT3SAS_ADAPTER *ioc,
                         pcie_device->enclosure_level,
                         pcie_device->connector_name);
 
-       if (pcie_device->starget)
+       if (pcie_device->starget && (pcie_device->access_status !=
+                               MPI26_PCIEDEV0_ASTATUS_DEVICE_BLOCKED))
                scsi_remove_target(&pcie_device->starget->dev);
        dewtprintk(ioc,
                   ioc_info(ioc, "%s: exit: handle(0x%04x), wwid(0x%016llx)\n",
@@ -6718,6 +6731,7 @@ _scsih_pcie_check_device(struct MPT3SAS_ADAPTER *ioc, u16 handle)
        if (unlikely(pcie_device->handle != handle)) {
                starget = pcie_device->starget;
                sas_target_priv_data = starget->hostdata;
+               pcie_device->access_status = pcie_device_pg0.AccessStatus;
                starget_printk(KERN_INFO, starget,
                    "handle changed from(0x%04x) to (0x%04x)!!!\n",
                    pcie_device->handle, handle);
@@ -6859,6 +6873,7 @@ _scsih_pcie_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle)
        pcie_device->id = ioc->pcie_target_id++;
        pcie_device->channel = PCIE_CHANNEL;
        pcie_device->handle = handle;
+       pcie_device->access_status = pcie_device_pg0.AccessStatus;
        pcie_device->device_info = le32_to_cpu(pcie_device_pg0.DeviceInfo);
        pcie_device->wwid = wwid;
        pcie_device->port_num = pcie_device_pg0.PortNum;
@@ -8531,6 +8546,8 @@ _scsih_mark_responding_pcie_device(struct MPT3SAS_ADAPTER *ioc,
                if ((pcie_device->wwid == le64_to_cpu(pcie_device_pg0->WWID))
                    && (pcie_device->slot == le16_to_cpu(
                    pcie_device_pg0->Slot))) {
+                       pcie_device->access_status =
+                                       pcie_device_pg0->AccessStatus;
                        pcie_device->responding = 1;
                        starget = pcie_device->starget;
                        if (starget && starget->hostdata) {
@@ -10063,6 +10080,12 @@ _scsih_probe_pcie(struct MPT3SAS_ADAPTER *ioc)
                        pcie_device_put(pcie_device);
                        continue;
                }
+               if (pcie_device->access_status ==
+                   MPI26_PCIEDEV0_ASTATUS_DEVICE_BLOCKED) {
+                       pcie_device_make_active(ioc, pcie_device);
+                       pcie_device_put(pcie_device);
+                       continue;
+               }
                rc = scsi_add_device(ioc->shost, PCIE_CHANNEL,
                        pcie_device->id, 0);
                if (rc) {