Skip to content

Commit

Permalink
mpt3sas: When device is blocked followed by unblock fails, unfreeze t…
Browse files Browse the repository at this point in the history
…he I/Os

Issue: When the disks are getting discovered and assigned device
handles by the kernel, a device block followed by an unblock
(due to broadcast primitives) issued by the driver is
interspersed by the kernel changing the state of the device.
Therefore the unblock by the driver results in a no operation
within the kernel API.

To fix this one, the below patch checks the return of the unblock API
and performs a block followed by an unblock to unfreeze the block
layer's I/O queue. Sufficient checks and prints are also added in the
driver to identify this condition caused by the kernel.

Signed-off-by: Sreekanth Reddy <Sreekanth.Reddy@avagotech.com>
Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
Signed-off-by: James Bottomley <JBottomley@Odin.com>
  • Loading branch information
Sreekanth Reddy authored and James Bottomley committed Aug 27, 2015
1 parent 3681402 commit df838f9
Showing 1 changed file with 75 additions and 14 deletions.
89 changes: 75 additions & 14 deletions drivers/scsi/mpt3sas/mpt3sas_scsih.c
Original file line number Diff line number Diff line change
Expand Up @@ -2604,6 +2604,75 @@ _scsih_fw_event_cleanup_queue(struct MPT3SAS_ADAPTER *ioc)
}
}

/**
* _scsih_internal_device_block - block the sdev device
* @sdev: per device object
* @sas_device_priv_data : per device driver private data
*
* make sure device is blocked without error, if not
* print an error
*/
static void
_scsih_internal_device_block(struct scsi_device *sdev,
struct MPT3SAS_DEVICE *sas_device_priv_data)
{
int r = 0;

sdev_printk(KERN_INFO, sdev, "device_block, handle(0x%04x)\n",
sas_device_priv_data->sas_target->handle);
sas_device_priv_data->block = 1;

r = scsi_internal_device_block(sdev);
if (r == -EINVAL)
sdev_printk(KERN_WARNING, sdev,
"device_block failed with return(%d) for handle(0x%04x)\n",
sas_device_priv_data->sas_target->handle, r);
}

/**
* _scsih_internal_device_unblock - unblock the sdev device
* @sdev: per device object
* @sas_device_priv_data : per device driver private data
* make sure device is unblocked without error, if not retry
* by blocking and then unblocking
*/

static void
_scsih_internal_device_unblock(struct scsi_device *sdev,
struct MPT3SAS_DEVICE *sas_device_priv_data)
{
int r = 0;

sdev_printk(KERN_WARNING, sdev, "device_unblock and setting to running, "
"handle(0x%04x)\n", sas_device_priv_data->sas_target->handle);
sas_device_priv_data->block = 0;
r = scsi_internal_device_unblock(sdev, SDEV_RUNNING);
if (r == -EINVAL) {
/* The device has been set to SDEV_RUNNING by SD layer during
* device addition but the request queue is still stopped by
* our earlier block call. We need to perform a block again
* to get the device to SDEV_BLOCK and then to SDEV_RUNNING */

sdev_printk(KERN_WARNING, sdev,
"device_unblock failed with return(%d) for handle(0x%04x) "
"performing a block followed by an unblock\n",
sas_device_priv_data->sas_target->handle, r);
sas_device_priv_data->block = 1;
r = scsi_internal_device_block(sdev);
if (r)
sdev_printk(KERN_WARNING, sdev, "retried device_block "
"failed with return(%d) for handle(0x%04x)\n",
sas_device_priv_data->sas_target->handle, r);

sas_device_priv_data->block = 0;
r = scsi_internal_device_unblock(sdev, SDEV_RUNNING);
if (r)
sdev_printk(KERN_WARNING, sdev, "retried device_unblock"
" failed with return(%d) for handle(0x%04x)\n",
sas_device_priv_data->sas_target->handle, r);
}
}

/**
* _scsih_ublock_io_all_device - unblock every device
* @ioc: per adapter object
Expand All @@ -2623,11 +2692,10 @@ _scsih_ublock_io_all_device(struct MPT3SAS_ADAPTER *ioc)
if (!sas_device_priv_data->block)
continue;

sas_device_priv_data->block = 0;
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, SDEV_RUNNING);
_scsih_internal_device_unblock(sdev, sas_device_priv_data);
}
}

Expand All @@ -2652,10 +2720,9 @@ _scsih_ublock_io_device(struct MPT3SAS_ADAPTER *ioc, u64 sas_address)
if (sas_device_priv_data->sas_target->sas_address
!= sas_address)
continue;
if (sas_device_priv_data->block) {
sas_device_priv_data->block = 0;
scsi_internal_device_unblock(sdev, SDEV_RUNNING);
}
if (sas_device_priv_data->block)
_scsih_internal_device_unblock(sdev,
sas_device_priv_data);
}
}

Expand All @@ -2678,10 +2745,7 @@ _scsih_block_io_all_device(struct MPT3SAS_ADAPTER *ioc)
continue;
if (sas_device_priv_data->block)
continue;
sas_device_priv_data->block = 1;
scsi_internal_device_block(sdev);
sdev_printk(KERN_INFO, sdev, "device_blocked, handle(0x%04x)\n",
sas_device_priv_data->sas_target->handle);
_scsih_internal_device_block(sdev, sas_device_priv_data);
}
}

Expand Down Expand Up @@ -2713,10 +2777,7 @@ _scsih_block_io_device(struct MPT3SAS_ADAPTER *ioc, u16 handle)
continue;
if (sas_device->pend_sas_rphy_add)
continue;
sas_device_priv_data->block = 1;
scsi_internal_device_block(sdev);
sdev_printk(KERN_INFO, sdev,
"device_blocked, handle(0x%04x)\n", handle);
_scsih_internal_device_block(sdev, sas_device_priv_data);
}
}

Expand Down

0 comments on commit df838f9

Please sign in to comment.