summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWen Xiong <wenxiong@linux.vnet.ibm.com>2018-09-20 20:32:12 -0400
committerMartin K. Petersen <martin.petersen@oracle.com>2018-09-21 12:35:39 -0400
commit318ddb34b2052f838aa243d07173e2badf3e630e (patch)
tree8ea8c5955e10590caa7951a9d39c3e04d04b3b2f
parent8c39e2699f8acb2e29782a834e56306da24937fe (diff)
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>
-rw-r--r--drivers/scsi/ipr.c106
-rw-r--r--drivers/scsi/ipr.h1
2 files changed, 62 insertions, 45 deletions
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index f2ec80b0ffc0..271990bc065b 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -3335,6 +3335,65 @@ static void ipr_release_dump(struct kref *kref)
3335 LEAVE; 3335 LEAVE;
3336} 3336}
3337 3337
3338static 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
3351restart:
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
3338/** 3397/**
3339 * ipr_worker_thread - Worker thread 3398 * ipr_worker_thread - Worker thread
3340 * @work: ioa config struct 3399 * @work: ioa config struct
@@ -3349,13 +3408,9 @@ static void ipr_release_dump(struct kref *kref)
3349static void ipr_worker_thread(struct work_struct *work) 3408static void ipr_worker_thread(struct work_struct *work)
3350{ 3409{
3351 unsigned long lock_flags; 3410 unsigned long lock_flags;
3352 struct ipr_resource_entry *res;
3353 struct scsi_device *sdev;
3354 struct ipr_dump *dump; 3411 struct ipr_dump *dump;
3355 struct ipr_ioa_cfg *ioa_cfg = 3412 struct ipr_ioa_cfg *ioa_cfg =
3356 container_of(work, struct ipr_ioa_cfg, work_q); 3413 container_of(work, struct ipr_ioa_cfg, work_q);
3357 u8 bus, target, lun;
3358 int did_work;
3359 3414
3360 ENTER; 3415 ENTER;
3361 spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 3416 spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
@@ -3393,49 +3448,9 @@ static void ipr_worker_thread(struct work_struct *work)
3393 return; 3448 return;
3394 } 3449 }
3395 3450
3396restart: 3451 schedule_work(&ioa_cfg->scsi_add_work_q);
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 }
3403 3452
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;
3437 spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 3453 spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
3438 kobject_uevent(&ioa_cfg->host->shost_dev.kobj, KOBJ_CHANGE);
3439 LEAVE; 3454 LEAVE;
3440} 3455}
3441 3456
@@ -9933,6 +9948,7 @@ static void ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg,
9933 INIT_LIST_HEAD(&ioa_cfg->free_res_q); 9948 INIT_LIST_HEAD(&ioa_cfg->free_res_q);
9934 INIT_LIST_HEAD(&ioa_cfg->used_res_q); 9949 INIT_LIST_HEAD(&ioa_cfg->used_res_q);
9935 INIT_WORK(&ioa_cfg->work_q, ipr_worker_thread); 9950 INIT_WORK(&ioa_cfg->work_q, ipr_worker_thread);
9951 INIT_WORK(&ioa_cfg->scsi_add_work_q, ipr_add_remove_thread);
9936 init_waitqueue_head(&ioa_cfg->reset_wait_q); 9952 init_waitqueue_head(&ioa_cfg->reset_wait_q);
9937 init_waitqueue_head(&ioa_cfg->msi_wait_q); 9953 init_waitqueue_head(&ioa_cfg->msi_wait_q);
9938 init_waitqueue_head(&ioa_cfg->eeh_wait_q); 9954 init_waitqueue_head(&ioa_cfg->eeh_wait_q);
diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h
index 68afbbde54d3..f6baa2351313 100644
--- a/drivers/scsi/ipr.h
+++ b/drivers/scsi/ipr.h
@@ -1575,6 +1575,7 @@ struct ipr_ioa_cfg {
1575 u8 saved_mode_page_len; 1575 u8 saved_mode_page_len;
1576 1576
1577 struct work_struct work_q; 1577 struct work_struct work_q;
1578 struct work_struct scsi_add_work_q;
1578 struct workqueue_struct *reset_work_q; 1579 struct workqueue_struct *reset_work_q;
1579 1580
1580 wait_queue_head_t reset_wait_q; 1581 wait_queue_head_t reset_wait_q;