diff options
Diffstat (limited to 'drivers/scsi/scsi_lib.c')
| -rw-r--r-- | drivers/scsi/scsi_lib.c | 40 | 
1 files changed, 23 insertions, 17 deletions
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 340c569d453..36521a0ac54 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -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);  |