Skip to content

Commit 318ddb3

Browse files
wxiong38martinkpetersen
authored andcommitted
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>
1 parent 8c39e26 commit 318ddb3

File tree

2 files changed

+62
-45
lines changed

2 files changed

+62
-45
lines changed

drivers/scsi/ipr.c

Lines changed: 61 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -3335,6 +3335,65 @@ static void ipr_release_dump(struct kref *kref)
33353335
LEAVE;
33363336
}
33373337

3338+
static void ipr_add_remove_thread(struct work_struct *work)
3339+
{
3340+
unsigned long lock_flags;
3341+
struct ipr_resource_entry *res;
3342+
struct scsi_device *sdev;
3343+
struct ipr_ioa_cfg *ioa_cfg =
3344+
container_of(work, struct ipr_ioa_cfg, scsi_add_work_q);
3345+
u8 bus, target, lun;
3346+
int did_work;
3347+
3348+
ENTER;
3349+
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
3350+
3351+
restart:
3352+
do {
3353+
did_work = 0;
3354+
if (!ioa_cfg->hrrq[IPR_INIT_HRRQ].allow_cmds) {
3355+
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
3356+
return;
3357+
}
3358+
3359+
list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
3360+
if (res->del_from_ml && res->sdev) {
3361+
did_work = 1;
3362+
sdev = res->sdev;
3363+
if (!scsi_device_get(sdev)) {
3364+
if (!res->add_to_ml)
3365+
list_move_tail(&res->queue, &ioa_cfg->free_res_q);
3366+
else
3367+
res->del_from_ml = 0;
3368+
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
3369+
scsi_remove_device(sdev);
3370+
scsi_device_put(sdev);
3371+
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
3372+
}
3373+
break;
3374+
}
3375+
}
3376+
} while (did_work);
3377+
3378+
list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
3379+
if (res->add_to_ml) {
3380+
bus = res->bus;
3381+
target = res->target;
3382+
lun = res->lun;
3383+
res->add_to_ml = 0;
3384+
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
3385+
scsi_add_device(ioa_cfg->host, bus, target, lun);
3386+
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
3387+
goto restart;
3388+
}
3389+
}
3390+
3391+
ioa_cfg->scan_done = 1;
3392+
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
3393+
kobject_uevent(&ioa_cfg->host->shost_dev.kobj, KOBJ_CHANGE);
3394+
LEAVE;
3395+
}
3396+
33383397
/**
33393398
* ipr_worker_thread - Worker thread
33403399
* @work: ioa config struct
@@ -3349,13 +3408,9 @@ static void ipr_release_dump(struct kref *kref)
33493408
static void ipr_worker_thread(struct work_struct *work)
33503409
{
33513410
unsigned long lock_flags;
3352-
struct ipr_resource_entry *res;
3353-
struct scsi_device *sdev;
33543411
struct ipr_dump *dump;
33553412
struct ipr_ioa_cfg *ioa_cfg =
33563413
container_of(work, struct ipr_ioa_cfg, work_q);
3357-
u8 bus, target, lun;
3358-
int did_work;
33593414

33603415
ENTER;
33613416
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
@@ -3393,49 +3448,9 @@ static void ipr_worker_thread(struct work_struct *work)
33933448
return;
33943449
}
33953450

3396-
restart:
3397-
do {
3398-
did_work = 0;
3399-
if (!ioa_cfg->hrrq[IPR_INIT_HRRQ].allow_cmds) {
3400-
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
3401-
return;
3402-
}
3451+
schedule_work(&ioa_cfg->scsi_add_work_q);
34033452

3404-
list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
3405-
if (res->del_from_ml && res->sdev) {
3406-
did_work = 1;
3407-
sdev = res->sdev;
3408-
if (!scsi_device_get(sdev)) {
3409-
if (!res->add_to_ml)
3410-
list_move_tail(&res->queue, &ioa_cfg->free_res_q);
3411-
else
3412-
res->del_from_ml = 0;
3413-
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
3414-
scsi_remove_device(sdev);
3415-
scsi_device_put(sdev);
3416-
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
3417-
}
3418-
break;
3419-
}
3420-
}
3421-
} while (did_work);
3422-
3423-
list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
3424-
if (res->add_to_ml) {
3425-
bus = res->bus;
3426-
target = res->target;
3427-
lun = res->lun;
3428-
res->add_to_ml = 0;
3429-
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
3430-
scsi_add_device(ioa_cfg->host, bus, target, lun);
3431-
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
3432-
goto restart;
3433-
}
3434-
}
3435-
3436-
ioa_cfg->scan_done = 1;
34373453
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
3438-
kobject_uevent(&ioa_cfg->host->shost_dev.kobj, KOBJ_CHANGE);
34393454
LEAVE;
34403455
}
34413456

@@ -9933,6 +9948,7 @@ static void ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg,
99339948
INIT_LIST_HEAD(&ioa_cfg->free_res_q);
99349949
INIT_LIST_HEAD(&ioa_cfg->used_res_q);
99359950
INIT_WORK(&ioa_cfg->work_q, ipr_worker_thread);
9951+
INIT_WORK(&ioa_cfg->scsi_add_work_q, ipr_add_remove_thread);
99369952
init_waitqueue_head(&ioa_cfg->reset_wait_q);
99379953
init_waitqueue_head(&ioa_cfg->msi_wait_q);
99389954
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
@@ -1575,6 +1575,7 @@ struct ipr_ioa_cfg {
15751575
u8 saved_mode_page_len;
15761576

15771577
struct work_struct work_q;
1578+
struct work_struct scsi_add_work_q;
15781579
struct workqueue_struct *reset_work_q;
15791580

15801581
wait_queue_head_t reset_wait_q;

0 commit comments

Comments
 (0)