|
@@ -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);
|
|
|
|