[SCSI] core, classes, mpt2sas: have scsi_internal_device_unblock take new state
authorMike Christie <michaelc@cs.wisc.edu>
Fri, 18 May 2012 04:56:57 +0000 (23:56 -0500)
committerJames Bottomley <JBottomley@Parallels.com>
Fri, 20 Jul 2012 07:58:22 +0000 (08:58 +0100)
This has scsi_internal_device_unblock/scsi_target_unblock take
the new state to set the devices as an argument instead of
always setting to running. The patch also converts users of these
functions.

This allows the FC and iSCSI class to transition devices from blocked
to transport-offline, so that when fast_io_fail/replacement_timeout
has fired we do not set the devices back to running. Instead, we
set them to SDEV_TRANSPORT_OFFLINE.

Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
drivers/scsi/mpt2sas/mpt2sas_base.h
drivers/scsi/mpt2sas/mpt2sas_scsih.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_priv.h
drivers/scsi/scsi_transport_fc.c
drivers/scsi/scsi_transport_iscsi.c
include/scsi/scsi_device.h

index b6dd3a5de7f9d50600db25d86c66e79590042ea1..b3a1a30055d610419da7ef3389b0898db7154868 100644 (file)
@@ -1158,6 +1158,7 @@ extern struct scsi_transport_template *mpt2sas_transport_template;
 extern int scsi_internal_device_block(struct scsi_device *sdev);
 extern u8 mpt2sas_stm_zero_smid_handler(struct MPT2SAS_ADAPTER *ioc,
     u8 msix_index, u32 reply);
-extern int scsi_internal_device_unblock(struct scsi_device *sdev);
+extern int scsi_internal_device_unblock(struct scsi_device *sdev,
+                                       enum scsi_device_state new_state);
 
 #endif /* MPT2SAS_BASE_H_INCLUDED */
index 76973e8ca4ba38029309e102021df286493291e9..b1ebd6f8dab3b24d0894d149c26614b4a1e93932 100644 (file)
@@ -2904,7 +2904,7 @@ _scsih_ublock_io_all_device(struct MPT2SAS_ADAPTER *ioc)
                dewtprintk(ioc, sdev_printk(KERN_INFO, sdev, "device_running, "
                    "handle(0x%04x)\n",
                    sas_device_priv_data->sas_target->handle));
-               scsi_internal_device_unblock(sdev);
+               scsi_internal_device_unblock(sdev, SDEV_RUNNING);
        }
 }
 /**
@@ -2933,7 +2933,7 @@ _scsih_ublock_io_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)
                            "sas address(0x%016llx)\n", ioc->name,
                                (unsigned long long)sas_address));
                        sas_device_priv_data->block = 0;
-                       scsi_internal_device_unblock(sdev);
+                       scsi_internal_device_unblock(sdev, SDEV_RUNNING);
                }
        }
 }
index 340c569d45355095aabfc232e042401c9dcbce4e..36521a0ac54ba50a7bfe3745f3bf1452293141d0 100644 (file)
@@ -2444,6 +2444,7 @@ EXPORT_SYMBOL_GPL(scsi_internal_device_block);
 /**
  * scsi_internal_device_unblock - resume a device after a block request
  * @sdev:      device to resume
+ * @new_state: state to set devices to after unblocking
  *
  * Called by scsi lld's or the midlayer to restart the device queue
  * for the previously suspended scsi device.  Called from interrupt or
@@ -2453,25 +2454,30 @@ EXPORT_SYMBOL_GPL(scsi_internal_device_block);
  *
  * Notes:       
  *     This routine transitions the device to the SDEV_RUNNING state
- *     (which must be a legal transition) allowing the midlayer to
- *     goose the queue for this device.  This routine assumes the 
- *     host_lock is held upon entry.
+ *     or to one of the offline states (which must be a legal transition)
+ *     allowing the midlayer to goose the queue for this device. This
+ *     routine assumes the host_lock is held upon entry.
  */
 int
-scsi_internal_device_unblock(struct scsi_device *sdev)
+scsi_internal_device_unblock(struct scsi_device *sdev,
+                            enum scsi_device_state new_state)
 {
        struct request_queue *q = sdev->request_queue; 
        unsigned long flags;
-       
-       /* 
-        * Try to transition the scsi device to SDEV_RUNNING
-        * and goose the device queue if successful.  
+
+       /*
+        * Try to transition the scsi device to SDEV_RUNNING or one of the
+        * offlined states and goose the device queue if successful.
         */
        if (sdev->sdev_state == SDEV_BLOCK)
-               sdev->sdev_state = SDEV_RUNNING;
-       else if (sdev->sdev_state == SDEV_CREATED_BLOCK)
-               sdev->sdev_state = SDEV_CREATED;
-       else if (sdev->sdev_state != SDEV_CANCEL &&
+               sdev->sdev_state = new_state;
+       else if (sdev->sdev_state == SDEV_CREATED_BLOCK) {
+               if (new_state == SDEV_TRANSPORT_OFFLINE ||
+                   new_state == SDEV_OFFLINE)
+                       sdev->sdev_state = new_state;
+               else
+                       sdev->sdev_state = SDEV_CREATED;
+       } else if (sdev->sdev_state != SDEV_CANCEL &&
                 sdev->sdev_state != SDEV_OFFLINE)
                return -EINVAL;
 
@@ -2512,26 +2518,26 @@ EXPORT_SYMBOL_GPL(scsi_target_block);
 static void
 device_unblock(struct scsi_device *sdev, void *data)
 {
-       scsi_internal_device_unblock(sdev);
+       scsi_internal_device_unblock(sdev, *(enum scsi_device_state *)data);
 }
 
 static int
 target_unblock(struct device *dev, void *data)
 {
        if (scsi_is_target_device(dev))
-               starget_for_each_device(to_scsi_target(dev), NULL,
+               starget_for_each_device(to_scsi_target(dev), data,
                                        device_unblock);
        return 0;
 }
 
 void
-scsi_target_unblock(struct device *dev)
+scsi_target_unblock(struct device *dev, enum scsi_device_state new_state)
 {
        if (scsi_is_target_device(dev))
-               starget_for_each_device(to_scsi_target(dev), NULL,
+               starget_for_each_device(to_scsi_target(dev), &new_state,
                                        device_unblock);
        else
-               device_for_each_child(dev, NULL, target_unblock);
+               device_for_each_child(dev, &new_state, target_unblock);
 }
 EXPORT_SYMBOL_GPL(scsi_target_unblock);
 
index 07ce3f51701dba2163074feb89e623054b451e5d..cbfe5df24a3b426687e54f455b5c8a5901039a61 100644 (file)
@@ -2,6 +2,7 @@
 #define _SCSI_PRIV_H
 
 #include <linux/device.h>
+#include <scsi/scsi_device.h>
 
 struct request_queue;
 struct request;
@@ -172,6 +173,7 @@ extern struct list_head scsi_sd_probe_domain;
 
 #define SCSI_DEVICE_BLOCK_MAX_TIMEOUT  600     /* units in seconds */
 extern int scsi_internal_device_block(struct scsi_device *sdev);
-extern int scsi_internal_device_unblock(struct scsi_device *sdev);
+extern int scsi_internal_device_unblock(struct scsi_device *sdev,
+                                       enum scsi_device_state new_state);
 
 #endif /* _SCSI_PRIV_H */
index 2fded793997cdd4a7c417a9bedfdadc31dc3f4a3..2d1e68db9b3ffb5828482cdda3d797e3fa1d6677 100644 (file)
@@ -2495,11 +2495,9 @@ static void fc_terminate_rport_io(struct fc_rport *rport)
                i->f->terminate_rport_io(rport);
 
        /*
-        * must unblock to flush queued IO. The caller will have set
-        * the port_state or flags, so that fc_remote_port_chkready will
-        * fail IO.
+        * Must unblock to flush queued IO. scsi-ml will fail incoming reqs.
         */
-       scsi_target_unblock(&rport->dev);
+       scsi_target_unblock(&rport->dev, SDEV_TRANSPORT_OFFLINE);
 }
 
 /**
@@ -2830,8 +2828,8 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel,
 
                                /* if target, initiate a scan */
                                if (rport->scsi_target_id != -1) {
-                                       scsi_target_unblock(&rport->dev);
-
+                                       scsi_target_unblock(&rport->dev,
+                                                           SDEV_RUNNING);
                                        spin_lock_irqsave(shost->host_lock,
                                                          flags);
                                        rport->flags |= FC_RPORT_SCAN_PENDING;
@@ -2900,7 +2898,7 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel,
                        spin_unlock_irqrestore(shost->host_lock, flags);
 
                        if (ids->roles & FC_PORT_ROLE_FCP_TARGET) {
-                               scsi_target_unblock(&rport->dev);
+                               scsi_target_unblock(&rport->dev, SDEV_RUNNING);
 
                                /* initiate a scan of the target */
                                spin_lock_irqsave(shost->host_lock, flags);
@@ -3105,7 +3103,7 @@ fc_remote_port_rolechg(struct fc_rport  *rport, u32 roles)
                /* ensure any stgt delete functions are done */
                fc_flush_work(shost);
 
-               scsi_target_unblock(&rport->dev);
+               scsi_target_unblock(&rport->dev, SDEV_RUNNING);
                /* initiate a scan of the target */
                spin_lock_irqsave(shost->host_lock, flags);
                rport->flags |= FC_RPORT_SCAN_PENDING;
@@ -3149,7 +3147,7 @@ fc_timeout_deleted_rport(struct work_struct *work)
                        "blocked FC remote port time out: no longer"
                        " a FCP target, removing starget\n");
                spin_unlock_irqrestore(shost->host_lock, flags);
-               scsi_target_unblock(&rport->dev);
+               scsi_target_unblock(&rport->dev, SDEV_TRANSPORT_OFFLINE);
                fc_queue_work(shost, &rport->stgt_delete_work);
                return;
        }
index 1cf640e575da4567fb22516bc5eff3cf3ff0efe9..96ec21a959e99fc8e83b0678720ec222d19b61dc 100644 (file)
@@ -907,7 +907,7 @@ static void session_recovery_timedout(struct work_struct *work)
                session->transport->session_recovery_timedout(session);
 
        ISCSI_DBG_TRANS_SESSION(session, "Unblocking SCSI target\n");
-       scsi_target_unblock(&session->dev);
+       scsi_target_unblock(&session->dev, SDEV_TRANSPORT_OFFLINE);
        ISCSI_DBG_TRANS_SESSION(session, "Completed unblocking SCSI target\n");
 }
 
@@ -930,7 +930,7 @@ static void __iscsi_unblock_session(struct work_struct *work)
        session->state = ISCSI_SESSION_LOGGED_IN;
        spin_unlock_irqrestore(&session->lock, flags);
        /* start IO */
-       scsi_target_unblock(&session->dev);
+       scsi_target_unblock(&session->dev, SDEV_RUNNING);
        /*
         * Only do kernel scanning if the driver is properly hooked into
         * the async scanning code (drivers like iscsi_tcp do login and
@@ -1180,7 +1180,7 @@ void iscsi_remove_session(struct iscsi_cls_session *session)
        session->state = ISCSI_SESSION_FREE;
        spin_unlock_irqrestore(&session->lock, flags);
 
-       scsi_target_unblock(&session->dev);
+       scsi_target_unblock(&session->dev, SDEV_TRANSPORT_OFFLINE);
        /* flush running scans then delete devices */
        scsi_flush_work(shost);
        __iscsi_unbind_session(&session->unbind_work);
index 4045758579628a00c6321084a2907bfb4240c398..bd1a14d89009883cece50c0c6674c4bb7ebe0920 100644 (file)
@@ -374,7 +374,7 @@ extern void scsi_scan_target(struct device *parent, unsigned int channel,
                             unsigned int id, unsigned int lun, int rescan);
 extern void scsi_target_reap(struct scsi_target *);
 extern void scsi_target_block(struct device *);
-extern void scsi_target_unblock(struct device *);
+extern void scsi_target_unblock(struct device *, enum scsi_device_state);
 extern void scsi_remove_target(struct device *);
 extern void int_to_scsilun(unsigned int, struct scsi_lun *);
 extern int scsilun_to_int(struct scsi_lun *);