diff options
Diffstat (limited to 'drivers/scsi/ibmvscsi')
-rw-r--r-- | drivers/scsi/ibmvscsi/ibmvscsi.c | 77 | ||||
-rw-r--r-- | drivers/scsi/ibmvscsi/ibmvscsi.h | 10 |
2 files changed, 66 insertions, 21 deletions
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 4aea97ee4b24..7f66a7783209 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -814,7 +814,7 @@ static void ibmvscsi_reset_host(struct ibmvscsi_host_data *hostdata) atomic_set(&hostdata->request_limit, 0); purge_requests(hostdata, DID_ERROR); - hostdata->reset_crq = 1; + hostdata->action = IBMVSCSI_HOST_ACTION_RESET; wake_up(&hostdata->work_wait_q); } @@ -1165,7 +1165,8 @@ static void login_rsp(struct srp_event_struct *evt_struct) be32_to_cpu(evt_struct->xfer_iu->srp.login_rsp.req_lim_delta)); /* If we had any pending I/Os, kick them */ - scsi_unblock_requests(hostdata->host); + hostdata->action = IBMVSCSI_HOST_ACTION_UNBLOCK; + wake_up(&hostdata->work_wait_q); } /** @@ -1783,7 +1784,7 @@ static void ibmvscsi_handle_crq(struct viosrp_crq *crq, /* We need to re-setup the interpartition connection */ dev_info(hostdata->dev, "Re-enabling adapter!\n"); hostdata->client_migrated = 1; - hostdata->reenable_crq = 1; + hostdata->action = IBMVSCSI_HOST_ACTION_REENABLE; purge_requests(hostdata, DID_REQUEUE); wake_up(&hostdata->work_wait_q); } else { @@ -2036,6 +2037,16 @@ static struct device_attribute ibmvscsi_host_config = { .show = show_host_config, }; +static int ibmvscsi_host_reset(struct Scsi_Host *shost, int reset_type) +{ + struct ibmvscsi_host_data *hostdata = shost_priv(shost); + + dev_info(hostdata->dev, "Initiating adapter reset!\n"); + ibmvscsi_reset_host(hostdata); + + return 0; +} + static struct device_attribute *ibmvscsi_attrs[] = { &ibmvscsi_host_vhost_loc, &ibmvscsi_host_vhost_name, @@ -2062,6 +2073,7 @@ static struct scsi_host_template driver_template = { .eh_host_reset_handler = ibmvscsi_eh_host_reset_handler, .slave_configure = ibmvscsi_slave_configure, .change_queue_depth = ibmvscsi_change_queue_depth, + .host_reset = ibmvscsi_host_reset, .cmd_per_lun = IBMVSCSI_CMDS_PER_LUN_DEFAULT, .can_queue = IBMVSCSI_MAX_REQUESTS_DEFAULT, .this_id = -1, @@ -2091,48 +2103,75 @@ static unsigned long ibmvscsi_get_desired_dma(struct vio_dev *vdev) static void ibmvscsi_do_work(struct ibmvscsi_host_data *hostdata) { + unsigned long flags; int rc; char *action = "reset"; - if (hostdata->reset_crq) { - smp_rmb(); - hostdata->reset_crq = 0; - + spin_lock_irqsave(hostdata->host->host_lock, flags); + switch (hostdata->action) { + case IBMVSCSI_HOST_ACTION_UNBLOCK: + rc = 0; + break; + case IBMVSCSI_HOST_ACTION_RESET: + spin_unlock_irqrestore(hostdata->host->host_lock, flags); rc = ibmvscsi_reset_crq_queue(&hostdata->queue, hostdata); + spin_lock_irqsave(hostdata->host->host_lock, flags); if (!rc) rc = ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0); vio_enable_interrupts(to_vio_dev(hostdata->dev)); - } else if (hostdata->reenable_crq) { - smp_rmb(); + break; + case IBMVSCSI_HOST_ACTION_REENABLE: action = "enable"; + spin_unlock_irqrestore(hostdata->host->host_lock, flags); rc = ibmvscsi_reenable_crq_queue(&hostdata->queue, hostdata); - hostdata->reenable_crq = 0; + spin_lock_irqsave(hostdata->host->host_lock, flags); if (!rc) rc = ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0); - } else + break; + case IBMVSCSI_HOST_ACTION_NONE: + default: + spin_unlock_irqrestore(hostdata->host->host_lock, flags); return; + } + + hostdata->action = IBMVSCSI_HOST_ACTION_NONE; if (rc) { atomic_set(&hostdata->request_limit, -1); dev_err(hostdata->dev, "error after %s\n", action); } + spin_unlock_irqrestore(hostdata->host->host_lock, flags); scsi_unblock_requests(hostdata->host); } -static int ibmvscsi_work_to_do(struct ibmvscsi_host_data *hostdata) +static int __ibmvscsi_work_to_do(struct ibmvscsi_host_data *hostdata) { if (kthread_should_stop()) return 1; - else if (hostdata->reset_crq) { - smp_rmb(); - return 1; - } else if (hostdata->reenable_crq) { - smp_rmb(); - return 1; + switch (hostdata->action) { + case IBMVSCSI_HOST_ACTION_NONE: + return 0; + case IBMVSCSI_HOST_ACTION_RESET: + case IBMVSCSI_HOST_ACTION_REENABLE: + case IBMVSCSI_HOST_ACTION_UNBLOCK: + default: + break; } - return 0; + return 1; +} + +static int ibmvscsi_work_to_do(struct ibmvscsi_host_data *hostdata) +{ + unsigned long flags; + int rc; + + spin_lock_irqsave(hostdata->host->host_lock, flags); + rc = __ibmvscsi_work_to_do(hostdata); + spin_unlock_irqrestore(hostdata->host->host_lock, flags); + + return rc; } static int ibmvscsi_work(void *data) diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.h b/drivers/scsi/ibmvscsi/ibmvscsi.h index 6ebd1410488d..e60916ef7a49 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.h +++ b/drivers/scsi/ibmvscsi/ibmvscsi.h @@ -74,13 +74,19 @@ struct event_pool { dma_addr_t iu_token; }; +enum ibmvscsi_host_action { + IBMVSCSI_HOST_ACTION_NONE = 0, + IBMVSCSI_HOST_ACTION_RESET, + IBMVSCSI_HOST_ACTION_REENABLE, + IBMVSCSI_HOST_ACTION_UNBLOCK, +}; + /* all driver data associated with a host adapter */ struct ibmvscsi_host_data { struct list_head host_list; atomic_t request_limit; int client_migrated; - int reset_crq; - int reenable_crq; + enum ibmvscsi_host_action action; struct device *dev; struct event_pool pool; struct crq_queue queue; |