Skip to content

Commit b6b5bc2

Browse files
wxiong38gregkh
authored andcommitted
scsi: ipr: System hung while dlpar adding primary ipr adapter back
[ Upstream commit 318ddb3 ] 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> Signed-off-by: Sasha Levin <alexander.levin@microsoft.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 26377fe commit b6b5bc2

2 files changed

Lines changed: 62 additions & 45 deletions

File tree

drivers/scsi/ipr.c

Lines changed: 61 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -3308,6 +3308,65 @@ static void ipr_release_dump(struct kref *kref)
33083308
LEAVE;
33093309
}
33103310

3311+
static void ipr_add_remove_thread(struct work_struct *work)
3312+
{
3313+
unsigned long lock_flags;
3314+
struct ipr_resource_entry *res;
3315+
struct scsi_device *sdev;
3316+
struct ipr_ioa_cfg *ioa_cfg =
3317+
container_of(work, struct ipr_ioa_cfg, scsi_add_work_q);
3318+
u8 bus, target, lun;
3319+
int did_work;
3320+
3321+
ENTER;
3322+
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
3323+
3324+
restart:
3325+
do {
3326+
did_work = 0;
3327+
if (!ioa_cfg->hrrq[IPR_INIT_HRRQ].allow_cmds) {
3328+
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
3329+
return;
3330+
}
3331+
3332+
list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
3333+
if (res->del_from_ml && res->sdev) {
3334+
did_work = 1;
3335+
sdev = res->sdev;
3336+
if (!scsi_device_get(sdev)) {
3337+
if (!res->add_to_ml)
3338+
list_move_tail(&res->queue, &ioa_cfg->free_res_q);
3339+
else
3340+
res->del_from_ml = 0;
3341+
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
3342+
scsi_remove_device(sdev);
3343+
scsi_device_put(sdev);
3344+
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
3345+
}
3346+
break;
3347+
}
3348+
}
3349+
} while (did_work);
3350+
3351+
list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
3352+
if (res->add_to_ml) {
3353+
bus = res->bus;
3354+
target = res->target;
3355+
lun = res->lun;
3356+
res->add_to_ml = 0;
3357+
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
3358+
scsi_add_device(ioa_cfg->host, bus, target, lun);
3359+
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
3360+
goto restart;
3361+
}
3362+
}
3363+
3364+
ioa_cfg->scan_done = 1;
3365+
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
3366+
kobject_uevent(&ioa_cfg->host->shost_dev.kobj, KOBJ_CHANGE);
3367+
LEAVE;
3368+
}
3369+
33113370
/**
33123371
* ipr_worker_thread - Worker thread
33133372
* @work: ioa config struct
@@ -3322,13 +3381,9 @@ static void ipr_release_dump(struct kref *kref)
33223381
static void ipr_worker_thread(struct work_struct *work)
33233382
{
33243383
unsigned long lock_flags;
3325-
struct ipr_resource_entry *res;
3326-
struct scsi_device *sdev;
33273384
struct ipr_dump *dump;
33283385
struct ipr_ioa_cfg *ioa_cfg =
33293386
container_of(work, struct ipr_ioa_cfg, work_q);
3330-
u8 bus, target, lun;
3331-
int did_work;
33323387

33333388
ENTER;
33343389
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
@@ -3366,49 +3421,9 @@ static void ipr_worker_thread(struct work_struct *work)
33663421
return;
33673422
}
33683423

3369-
restart:
3370-
do {
3371-
did_work = 0;
3372-
if (!ioa_cfg->hrrq[IPR_INIT_HRRQ].allow_cmds) {
3373-
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
3374-
return;
3375-
}
3424+
schedule_work(&ioa_cfg->scsi_add_work_q);
33763425

3377-
list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
3378-
if (res->del_from_ml && res->sdev) {
3379-
did_work = 1;
3380-
sdev = res->sdev;
3381-
if (!scsi_device_get(sdev)) {
3382-
if (!res->add_to_ml)
3383-
list_move_tail(&res->queue, &ioa_cfg->free_res_q);
3384-
else
3385-
res->del_from_ml = 0;
3386-
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
3387-
scsi_remove_device(sdev);
3388-
scsi_device_put(sdev);
3389-
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
3390-
}
3391-
break;
3392-
}
3393-
}
3394-
} while (did_work);
3395-
3396-
list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
3397-
if (res->add_to_ml) {
3398-
bus = res->bus;
3399-
target = res->target;
3400-
lun = res->lun;
3401-
res->add_to_ml = 0;
3402-
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
3403-
scsi_add_device(ioa_cfg->host, bus, target, lun);
3404-
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
3405-
goto restart;
3406-
}
3407-
}
3408-
3409-
ioa_cfg->scan_done = 1;
34103426
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
3411-
kobject_uevent(&ioa_cfg->host->shost_dev.kobj, KOBJ_CHANGE);
34123427
LEAVE;
34133428
}
34143429

@@ -9937,6 +9952,7 @@ static void ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg,
99379952
INIT_LIST_HEAD(&ioa_cfg->free_res_q);
99389953
INIT_LIST_HEAD(&ioa_cfg->used_res_q);
99399954
INIT_WORK(&ioa_cfg->work_q, ipr_worker_thread);
9955+
INIT_WORK(&ioa_cfg->scsi_add_work_q, ipr_add_remove_thread);
99409956
init_waitqueue_head(&ioa_cfg->reset_wait_q);
99419957
init_waitqueue_head(&ioa_cfg->msi_wait_q);
99429958
init_waitqueue_head(&ioa_cfg->eeh_wait_q);

drivers/scsi/ipr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1568,6 +1568,7 @@ struct ipr_ioa_cfg {
15681568
u8 saved_mode_page_len;
15691569

15701570
struct work_struct work_q;
1571+
struct work_struct scsi_add_work_q;
15711572
struct workqueue_struct *reset_work_q;
15721573

15731574
wait_queue_head_t reset_wait_q;

0 commit comments

Comments
 (0)