diff options
Diffstat (limited to 'drivers/scsi/ipr.c')
| -rw-r--r-- | drivers/scsi/ipr.c | 106 | 
1 files changed, 61 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)  	LEAVE;  } +static void ipr_add_remove_thread(struct work_struct *work) +{ +	unsigned long lock_flags; +	struct ipr_resource_entry *res; +	struct scsi_device *sdev; +	struct ipr_ioa_cfg *ioa_cfg = +		container_of(work, struct ipr_ioa_cfg, scsi_add_work_q); +	u8 bus, target, lun; +	int did_work; + +	ENTER; +	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + +restart: +	do { +		did_work = 0; +		if (!ioa_cfg->hrrq[IPR_INIT_HRRQ].allow_cmds) { +			spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); +			return; +		} + +		list_for_each_entry(res, &ioa_cfg->used_res_q, queue) { +			if (res->del_from_ml && res->sdev) { +				did_work = 1; +				sdev = res->sdev; +				if (!scsi_device_get(sdev)) { +					if (!res->add_to_ml) +						list_move_tail(&res->queue, &ioa_cfg->free_res_q); +					else +						res->del_from_ml = 0; +					spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); +					scsi_remove_device(sdev); +					scsi_device_put(sdev); +					spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); +				} +				break; +			} +		} +	} while (did_work); + +	list_for_each_entry(res, &ioa_cfg->used_res_q, queue) { +		if (res->add_to_ml) { +			bus = res->bus; +			target = res->target; +			lun = res->lun; +			res->add_to_ml = 0; +			spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); +			scsi_add_device(ioa_cfg->host, bus, target, lun); +			spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); +			goto restart; +		} +	} + +	ioa_cfg->scan_done = 1; +	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); +	kobject_uevent(&ioa_cfg->host->shost_dev.kobj, KOBJ_CHANGE); +	LEAVE; +} +  /**   * ipr_worker_thread - Worker thread   * @work:		ioa config struct @@ -3349,13 +3408,9 @@ static void ipr_release_dump(struct kref *kref)  static void ipr_worker_thread(struct work_struct *work)  {  	unsigned long lock_flags; -	struct ipr_resource_entry *res; -	struct scsi_device *sdev;  	struct ipr_dump *dump;  	struct ipr_ioa_cfg *ioa_cfg =  		container_of(work, struct ipr_ioa_cfg, work_q); -	u8 bus, target, lun; -	int did_work;  	ENTER;  	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); @@ -3393,49 +3448,9 @@ static void ipr_worker_thread(struct work_struct *work)  		return;  	} -restart: -	do { -		did_work = 0; -		if (!ioa_cfg->hrrq[IPR_INIT_HRRQ].allow_cmds) { -			spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); -			return; -		} +	schedule_work(&ioa_cfg->scsi_add_work_q); -		list_for_each_entry(res, &ioa_cfg->used_res_q, queue) { -			if (res->del_from_ml && res->sdev) { -				did_work = 1; -				sdev = res->sdev; -				if (!scsi_device_get(sdev)) { -					if (!res->add_to_ml) -						list_move_tail(&res->queue, &ioa_cfg->free_res_q); -					else -						res->del_from_ml = 0; -					spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); -					scsi_remove_device(sdev); -					scsi_device_put(sdev); -					spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); -				} -				break; -			} -		} -	} while (did_work); - -	list_for_each_entry(res, &ioa_cfg->used_res_q, queue) { -		if (res->add_to_ml) { -			bus = res->bus; -			target = res->target; -			lun = res->lun; -			res->add_to_ml = 0; -			spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); -			scsi_add_device(ioa_cfg->host, bus, target, lun); -			spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); -			goto restart; -		} -	} - -	ioa_cfg->scan_done = 1;  	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); -	kobject_uevent(&ioa_cfg->host->shost_dev.kobj, KOBJ_CHANGE);  	LEAVE;  } @@ -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->used_res_q);  	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->msi_wait_q);  	init_waitqueue_head(&ioa_cfg->eeh_wait_q);  |