Commit 8bf11557 authored by Michael Cyr's avatar Michael Cyr Committed by Martin K. Petersen

scsi: ibmvscsis: Synchronize cmds at remove time

This patch adds code to disconnect from the client, which will make sure
any outstanding commands have been completed, before continuing on with
the remove operation.
Signed-off-by: default avatarMichael Cyr <mikecyr@us.ibm.com>
Signed-off-by: default avatarBryant G. Ly <bryantly@linux.vnet.ibm.com>
Tested-by: default avatarSteven Royer <seroyer@linux.vnet.ibm.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent c9b3379f
...@@ -469,6 +469,18 @@ static void ibmvscsis_disconnect(struct work_struct *work) ...@@ -469,6 +469,18 @@ static void ibmvscsis_disconnect(struct work_struct *work)
case WAIT_ENABLED: case WAIT_ENABLED:
switch (new_state) { switch (new_state) {
case UNCONFIGURING:
vscsi->state = new_state;
vscsi->flags |= RESPONSE_Q_DOWN;
vscsi->flags &= ~(SCHEDULE_DISCONNECT |
DISCONNECT_SCHEDULED);
dma_rmb();
if (vscsi->flags & CFG_SLEEPING) {
vscsi->flags &= ~CFG_SLEEPING;
complete(&vscsi->unconfig);
}
break;
/* should never happen */ /* should never happen */
case ERR_DISCONNECT: case ERR_DISCONNECT:
case ERR_DISCONNECT_RECONNECT: case ERR_DISCONNECT_RECONNECT:
...@@ -481,6 +493,13 @@ static void ibmvscsis_disconnect(struct work_struct *work) ...@@ -481,6 +493,13 @@ static void ibmvscsis_disconnect(struct work_struct *work)
case WAIT_IDLE: case WAIT_IDLE:
switch (new_state) { switch (new_state) {
case UNCONFIGURING:
vscsi->flags |= RESPONSE_Q_DOWN;
vscsi->state = new_state;
vscsi->flags &= ~(SCHEDULE_DISCONNECT |
DISCONNECT_SCHEDULED);
ibmvscsis_free_command_q(vscsi);
break;
case ERR_DISCONNECT: case ERR_DISCONNECT:
case ERR_DISCONNECT_RECONNECT: case ERR_DISCONNECT_RECONNECT:
vscsi->state = new_state; vscsi->state = new_state;
...@@ -1186,6 +1205,15 @@ static void ibmvscsis_adapter_idle(struct scsi_info *vscsi) ...@@ -1186,6 +1205,15 @@ static void ibmvscsis_adapter_idle(struct scsi_info *vscsi)
free_qs = true; free_qs = true;
switch (vscsi->state) { switch (vscsi->state) {
case UNCONFIGURING:
ibmvscsis_free_command_q(vscsi);
dma_rmb();
isync();
if (vscsi->flags & CFG_SLEEPING) {
vscsi->flags &= ~CFG_SLEEPING;
complete(&vscsi->unconfig);
}
break;
case ERR_DISCONNECT_RECONNECT: case ERR_DISCONNECT_RECONNECT:
ibmvscsis_reset_queue(vscsi); ibmvscsis_reset_queue(vscsi);
pr_debug("adapter_idle, disc_rec: flags 0x%x\n", vscsi->flags); pr_debug("adapter_idle, disc_rec: flags 0x%x\n", vscsi->flags);
...@@ -3338,6 +3366,7 @@ static int ibmvscsis_probe(struct vio_dev *vdev, ...@@ -3338,6 +3366,7 @@ static int ibmvscsis_probe(struct vio_dev *vdev,
(unsigned long)vscsi); (unsigned long)vscsi);
init_completion(&vscsi->wait_idle); init_completion(&vscsi->wait_idle);
init_completion(&vscsi->unconfig);
snprintf(wq_name, 24, "ibmvscsis%s", dev_name(&vdev->dev)); snprintf(wq_name, 24, "ibmvscsis%s", dev_name(&vdev->dev));
vscsi->work_q = create_workqueue(wq_name); vscsi->work_q = create_workqueue(wq_name);
...@@ -3393,10 +3422,11 @@ static int ibmvscsis_remove(struct vio_dev *vdev) ...@@ -3393,10 +3422,11 @@ static int ibmvscsis_remove(struct vio_dev *vdev)
pr_debug("remove (%s)\n", dev_name(&vscsi->dma_dev->dev)); pr_debug("remove (%s)\n", dev_name(&vscsi->dma_dev->dev));
/* spin_lock_bh(&vscsi->intr_lock);
* TBD: Need to handle if there are commands on the waiting_rsp q ibmvscsis_post_disconnect(vscsi, UNCONFIGURING, 0);
* Actually, can there still be cmds outstanding to tcm? vscsi->flags |= CFG_SLEEPING;
*/ spin_unlock_bh(&vscsi->intr_lock);
wait_for_completion(&vscsi->unconfig);
vio_disable_interrupts(vdev); vio_disable_interrupts(vdev);
free_irq(vdev->irq, vscsi); free_irq(vdev->irq, vscsi);
...@@ -3405,7 +3435,6 @@ static int ibmvscsis_remove(struct vio_dev *vdev) ...@@ -3405,7 +3435,6 @@ static int ibmvscsis_remove(struct vio_dev *vdev)
DMA_BIDIRECTIONAL); DMA_BIDIRECTIONAL);
kfree(vscsi->map_buf); kfree(vscsi->map_buf);
tasklet_kill(&vscsi->work_task); tasklet_kill(&vscsi->work_task);
ibmvscsis_unregister_command_q(vscsi);
ibmvscsis_destroy_command_q(vscsi); ibmvscsis_destroy_command_q(vscsi);
ibmvscsis_freetimer(vscsi); ibmvscsis_freetimer(vscsi);
ibmvscsis_free_cmds(vscsi); ibmvscsis_free_cmds(vscsi);
......
...@@ -257,6 +257,8 @@ struct scsi_info { ...@@ -257,6 +257,8 @@ struct scsi_info {
#define SCHEDULE_DISCONNECT 0x00400 #define SCHEDULE_DISCONNECT 0x00400
/* disconnect handler is scheduled */ /* disconnect handler is scheduled */
#define DISCONNECT_SCHEDULED 0x00800 #define DISCONNECT_SCHEDULED 0x00800
/* remove function is sleeping */
#define CFG_SLEEPING 0x01000
u32 flags; u32 flags;
/* adapter lock */ /* adapter lock */
spinlock_t intr_lock; spinlock_t intr_lock;
...@@ -285,6 +287,7 @@ struct scsi_info { ...@@ -285,6 +287,7 @@ struct scsi_info {
struct workqueue_struct *work_q; struct workqueue_struct *work_q;
struct completion wait_idle; struct completion wait_idle;
struct completion unconfig;
struct device dev; struct device dev;
struct vio_dev *dma_dev; struct vio_dev *dma_dev;
struct srp_target target; struct srp_target target;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment