scsi: ipr: System hung while dlpar adding primary ipr adapter back
While dlpar adding primary ipr adapter back, driver goes through adapter initialization then schedule ipr_worker_thread to start te disk scan by dropping the host lock, calling scsi_add_device. Then get the adapter reset request again, so driver does scsi_block_requests, this will cause the scsi_add_device get hung until we unblock. But we can't run ipr_worker_thread to do the unblock because its stuck in scsi_add_device. This patch fixes the issue. [mkp: typo and whitespace fixes] Signed-off-by: Wen Xiong <wenxiong@linux.vnet.ibm.com> Acked-by: Brian King <brking@linux.vnet.ibm.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
parent
8c39e2699f
commit
318ddb34b2
|
@ -3335,64 +3335,19 @@ static void ipr_release_dump(struct kref *kref)
|
||||||
LEAVE;
|
LEAVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static void ipr_add_remove_thread(struct work_struct *work)
|
||||||
* ipr_worker_thread - Worker thread
|
|
||||||
* @work: ioa config struct
|
|
||||||
*
|
|
||||||
* Called at task level from a work thread. This function takes care
|
|
||||||
* of adding and removing device from the mid-layer as configuration
|
|
||||||
* changes are detected by the adapter.
|
|
||||||
*
|
|
||||||
* Return value:
|
|
||||||
* nothing
|
|
||||||
**/
|
|
||||||
static void ipr_worker_thread(struct work_struct *work)
|
|
||||||
{
|
{
|
||||||
unsigned long lock_flags;
|
unsigned long lock_flags;
|
||||||
struct ipr_resource_entry *res;
|
struct ipr_resource_entry *res;
|
||||||
struct scsi_device *sdev;
|
struct scsi_device *sdev;
|
||||||
struct ipr_dump *dump;
|
|
||||||
struct ipr_ioa_cfg *ioa_cfg =
|
struct ipr_ioa_cfg *ioa_cfg =
|
||||||
container_of(work, struct ipr_ioa_cfg, work_q);
|
container_of(work, struct ipr_ioa_cfg, scsi_add_work_q);
|
||||||
u8 bus, target, lun;
|
u8 bus, target, lun;
|
||||||
int did_work;
|
int did_work;
|
||||||
|
|
||||||
ENTER;
|
ENTER;
|
||||||
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
|
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
|
||||||
|
|
||||||
if (ioa_cfg->sdt_state == READ_DUMP) {
|
|
||||||
dump = ioa_cfg->dump;
|
|
||||||
if (!dump) {
|
|
||||||
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
kref_get(&dump->kref);
|
|
||||||
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
|
|
||||||
ipr_get_ioa_dump(ioa_cfg, dump);
|
|
||||||
kref_put(&dump->kref, ipr_release_dump);
|
|
||||||
|
|
||||||
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
|
|
||||||
if (ioa_cfg->sdt_state == DUMP_OBTAINED && !ioa_cfg->dump_timeout)
|
|
||||||
ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
|
|
||||||
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ioa_cfg->scsi_unblock) {
|
|
||||||
ioa_cfg->scsi_unblock = 0;
|
|
||||||
ioa_cfg->scsi_blocked = 0;
|
|
||||||
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
|
|
||||||
scsi_unblock_requests(ioa_cfg->host);
|
|
||||||
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
|
|
||||||
if (ioa_cfg->scsi_blocked)
|
|
||||||
scsi_block_requests(ioa_cfg->host);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ioa_cfg->scan_enabled) {
|
|
||||||
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
restart:
|
restart:
|
||||||
do {
|
do {
|
||||||
did_work = 0;
|
did_work = 0;
|
||||||
|
@ -3439,6 +3394,66 @@ static void ipr_worker_thread(struct work_struct *work)
|
||||||
LEAVE;
|
LEAVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ipr_worker_thread - Worker thread
|
||||||
|
* @work: ioa config struct
|
||||||
|
*
|
||||||
|
* Called at task level from a work thread. This function takes care
|
||||||
|
* of adding and removing device from the mid-layer as configuration
|
||||||
|
* changes are detected by the adapter.
|
||||||
|
*
|
||||||
|
* Return value:
|
||||||
|
* nothing
|
||||||
|
**/
|
||||||
|
static void ipr_worker_thread(struct work_struct *work)
|
||||||
|
{
|
||||||
|
unsigned long lock_flags;
|
||||||
|
struct ipr_dump *dump;
|
||||||
|
struct ipr_ioa_cfg *ioa_cfg =
|
||||||
|
container_of(work, struct ipr_ioa_cfg, work_q);
|
||||||
|
|
||||||
|
ENTER;
|
||||||
|
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
|
||||||
|
|
||||||
|
if (ioa_cfg->sdt_state == READ_DUMP) {
|
||||||
|
dump = ioa_cfg->dump;
|
||||||
|
if (!dump) {
|
||||||
|
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
kref_get(&dump->kref);
|
||||||
|
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
|
||||||
|
ipr_get_ioa_dump(ioa_cfg, dump);
|
||||||
|
kref_put(&dump->kref, ipr_release_dump);
|
||||||
|
|
||||||
|
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
|
||||||
|
if (ioa_cfg->sdt_state == DUMP_OBTAINED && !ioa_cfg->dump_timeout)
|
||||||
|
ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
|
||||||
|
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ioa_cfg->scsi_unblock) {
|
||||||
|
ioa_cfg->scsi_unblock = 0;
|
||||||
|
ioa_cfg->scsi_blocked = 0;
|
||||||
|
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
|
||||||
|
scsi_unblock_requests(ioa_cfg->host);
|
||||||
|
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
|
||||||
|
if (ioa_cfg->scsi_blocked)
|
||||||
|
scsi_block_requests(ioa_cfg->host);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ioa_cfg->scan_enabled) {
|
||||||
|
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
schedule_work(&ioa_cfg->scsi_add_work_q);
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
|
||||||
|
LEAVE;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_SCSI_IPR_TRACE
|
#ifdef CONFIG_SCSI_IPR_TRACE
|
||||||
/**
|
/**
|
||||||
* ipr_read_trace - Dump the adapter trace
|
* ipr_read_trace - Dump the adapter trace
|
||||||
|
@ -9933,6 +9948,7 @@ static void ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg,
|
||||||
INIT_LIST_HEAD(&ioa_cfg->free_res_q);
|
INIT_LIST_HEAD(&ioa_cfg->free_res_q);
|
||||||
INIT_LIST_HEAD(&ioa_cfg->used_res_q);
|
INIT_LIST_HEAD(&ioa_cfg->used_res_q);
|
||||||
INIT_WORK(&ioa_cfg->work_q, ipr_worker_thread);
|
INIT_WORK(&ioa_cfg->work_q, ipr_worker_thread);
|
||||||
|
INIT_WORK(&ioa_cfg->scsi_add_work_q, ipr_add_remove_thread);
|
||||||
init_waitqueue_head(&ioa_cfg->reset_wait_q);
|
init_waitqueue_head(&ioa_cfg->reset_wait_q);
|
||||||
init_waitqueue_head(&ioa_cfg->msi_wait_q);
|
init_waitqueue_head(&ioa_cfg->msi_wait_q);
|
||||||
init_waitqueue_head(&ioa_cfg->eeh_wait_q);
|
init_waitqueue_head(&ioa_cfg->eeh_wait_q);
|
||||||
|
|
|
@ -1575,6 +1575,7 @@ struct ipr_ioa_cfg {
|
||||||
u8 saved_mode_page_len;
|
u8 saved_mode_page_len;
|
||||||
|
|
||||||
struct work_struct work_q;
|
struct work_struct work_q;
|
||||||
|
struct work_struct scsi_add_work_q;
|
||||||
struct workqueue_struct *reset_work_q;
|
struct workqueue_struct *reset_work_q;
|
||||||
|
|
||||||
wait_queue_head_t reset_wait_q;
|
wait_queue_head_t reset_wait_q;
|
||||||
|
|
Loading…
Reference in New Issue