diff options
Diffstat (limited to 'drivers/scsi/ibmvscsi/ibmvscsi.c')
-rw-r--r-- | drivers/scsi/ibmvscsi/ibmvscsi.c | 175 |
1 files changed, 113 insertions, 62 deletions
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 22d91ee173c..78d46a900bb 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -556,7 +556,7 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, unsigned long timeout) { u64 *crq_as_u64 = (u64 *) &evt_struct->crq; - int request_status; + int request_status = 0; int rc; /* If we have exhausted our request limit, just fail this request, @@ -574,6 +574,13 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, if (request_status < -1) goto send_error; /* Otherwise, we may have run out of requests. */ + /* If request limit was 0 when we started the adapter is in the + * process of performing a login with the server adapter, or + * we may have run out of requests. + */ + else if (request_status == -1 && + evt_struct->iu.srp.login_req.opcode != SRP_LOGIN_REQ) + goto send_busy; /* Abort and reset calls should make it through. * Nothing except abort and reset should use the last two * slots unless we had two or less to begin with. @@ -622,6 +629,16 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, list_del(&evt_struct->list); del_timer(&evt_struct->timer); + /* If send_crq returns H_CLOSED, return SCSI_MLQUEUE_HOST_BUSY. + * Firmware will send a CRQ with a transport event (0xFF) to + * tell this client what has happened to the transport. This + * will be handled in ibmvscsi_handle_crq() + */ + if (rc == H_CLOSED) { + dev_warn(hostdata->dev, "send warning. " + "Receive queue closed, will retry.\n"); + goto send_busy; + } dev_err(hostdata->dev, "send error %d\n", rc); atomic_inc(&hostdata->request_limit); goto send_error; @@ -633,7 +650,8 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev); free_event_struct(&hostdata->pool, evt_struct); - atomic_inc(&hostdata->request_limit); + if (request_status != -1) + atomic_inc(&hostdata->request_limit); return SCSI_MLQUEUE_HOST_BUSY; send_error: @@ -927,10 +945,11 @@ static int send_srp_login(struct ibmvscsi_host_data *hostdata) login->req_buf_fmt = SRP_BUF_FORMAT_DIRECT | SRP_BUF_FORMAT_INDIRECT; spin_lock_irqsave(hostdata->host->host_lock, flags); - /* Start out with a request limit of 1, since this is negotiated in - * the login request we are just sending + /* Start out with a request limit of 0, since this is negotiated in + * the login request we are just sending and login requests always + * get sent by the driver regardless of request_limit. */ - atomic_set(&hostdata->request_limit, 1); + atomic_set(&hostdata->request_limit, 0); rc = ibmvscsi_send_srp_event(evt_struct, hostdata, init_timeout * 2); spin_unlock_irqrestore(hostdata->host->host_lock, flags); @@ -967,58 +986,74 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd) int rsp_rc; unsigned long flags; u16 lun = lun_from_dev(cmd->device); + unsigned long wait_switch = 0; /* First, find this command in our sent list so we can figure * out the correct tag */ spin_lock_irqsave(hostdata->host->host_lock, flags); - found_evt = NULL; - list_for_each_entry(tmp_evt, &hostdata->sent, list) { - if (tmp_evt->cmnd == cmd) { - found_evt = tmp_evt; - break; + wait_switch = jiffies + (init_timeout * HZ); + do { + found_evt = NULL; + list_for_each_entry(tmp_evt, &hostdata->sent, list) { + if (tmp_evt->cmnd == cmd) { + found_evt = tmp_evt; + break; + } } - } - if (!found_evt) { - spin_unlock_irqrestore(hostdata->host->host_lock, flags); - return SUCCESS; - } + if (!found_evt) { + spin_unlock_irqrestore(hostdata->host->host_lock, flags); + return SUCCESS; + } - evt = get_event_struct(&hostdata->pool); - if (evt == NULL) { - spin_unlock_irqrestore(hostdata->host->host_lock, flags); - sdev_printk(KERN_ERR, cmd->device, "failed to allocate abort event\n"); - return FAILED; - } + evt = get_event_struct(&hostdata->pool); + if (evt == NULL) { + spin_unlock_irqrestore(hostdata->host->host_lock, flags); + sdev_printk(KERN_ERR, cmd->device, + "failed to allocate abort event\n"); + return FAILED; + } - init_event_struct(evt, - sync_completion, - VIOSRP_SRP_FORMAT, - init_timeout); + init_event_struct(evt, + sync_completion, + VIOSRP_SRP_FORMAT, + init_timeout); - tsk_mgmt = &evt->iu.srp.tsk_mgmt; + tsk_mgmt = &evt->iu.srp.tsk_mgmt; - /* Set up an abort SRP command */ - memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt)); - tsk_mgmt->opcode = SRP_TSK_MGMT; - tsk_mgmt->lun = ((u64) lun) << 48; - tsk_mgmt->tsk_mgmt_func = SRP_TSK_ABORT_TASK; - tsk_mgmt->task_tag = (u64) found_evt; - - sdev_printk(KERN_INFO, cmd->device, "aborting command. lun 0x%lx, tag 0x%lx\n", - tsk_mgmt->lun, tsk_mgmt->task_tag); - - evt->sync_srp = &srp_rsp; - init_completion(&evt->comp); - rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2); + /* Set up an abort SRP command */ + memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt)); + tsk_mgmt->opcode = SRP_TSK_MGMT; + tsk_mgmt->lun = ((u64) lun) << 48; + tsk_mgmt->tsk_mgmt_func = SRP_TSK_ABORT_TASK; + tsk_mgmt->task_tag = (u64) found_evt; + + evt->sync_srp = &srp_rsp; + + init_completion(&evt->comp); + rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2); + + if (rsp_rc != SCSI_MLQUEUE_HOST_BUSY) + break; + + spin_unlock_irqrestore(hostdata->host->host_lock, flags); + msleep(10); + spin_lock_irqsave(hostdata->host->host_lock, flags); + } while (time_before(jiffies, wait_switch)); + spin_unlock_irqrestore(hostdata->host->host_lock, flags); + if (rsp_rc != 0) { sdev_printk(KERN_ERR, cmd->device, "failed to send abort() event. rc=%d\n", rsp_rc); return FAILED; } + sdev_printk(KERN_INFO, cmd->device, + "aborting command. lun 0x%lx, tag 0x%lx\n", + (((u64) lun) << 48), (u64) found_evt); + wait_for_completion(&evt->comp); /* make sure we got a good response */ @@ -1090,41 +1125,56 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd) int rsp_rc; unsigned long flags; u16 lun = lun_from_dev(cmd->device); + unsigned long wait_switch = 0; spin_lock_irqsave(hostdata->host->host_lock, flags); - evt = get_event_struct(&hostdata->pool); - if (evt == NULL) { - spin_unlock_irqrestore(hostdata->host->host_lock, flags); - sdev_printk(KERN_ERR, cmd->device, "failed to allocate reset event\n"); - return FAILED; - } + wait_switch = jiffies + (init_timeout * HZ); + do { + evt = get_event_struct(&hostdata->pool); + if (evt == NULL) { + spin_unlock_irqrestore(hostdata->host->host_lock, flags); + sdev_printk(KERN_ERR, cmd->device, + "failed to allocate reset event\n"); + return FAILED; + } - init_event_struct(evt, - sync_completion, - VIOSRP_SRP_FORMAT, - init_timeout); + init_event_struct(evt, + sync_completion, + VIOSRP_SRP_FORMAT, + init_timeout); - tsk_mgmt = &evt->iu.srp.tsk_mgmt; + tsk_mgmt = &evt->iu.srp.tsk_mgmt; - /* Set up a lun reset SRP command */ - memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt)); - tsk_mgmt->opcode = SRP_TSK_MGMT; - tsk_mgmt->lun = ((u64) lun) << 48; - tsk_mgmt->tsk_mgmt_func = SRP_TSK_LUN_RESET; + /* Set up a lun reset SRP command */ + memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt)); + tsk_mgmt->opcode = SRP_TSK_MGMT; + tsk_mgmt->lun = ((u64) lun) << 48; + tsk_mgmt->tsk_mgmt_func = SRP_TSK_LUN_RESET; - sdev_printk(KERN_INFO, cmd->device, "resetting device. lun 0x%lx\n", - tsk_mgmt->lun); + evt->sync_srp = &srp_rsp; + + init_completion(&evt->comp); + rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2); + + if (rsp_rc != SCSI_MLQUEUE_HOST_BUSY) + break; + + spin_unlock_irqrestore(hostdata->host->host_lock, flags); + msleep(10); + spin_lock_irqsave(hostdata->host->host_lock, flags); + } while (time_before(jiffies, wait_switch)); - evt->sync_srp = &srp_rsp; - init_completion(&evt->comp); - rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2); spin_unlock_irqrestore(hostdata->host->host_lock, flags); + if (rsp_rc != 0) { sdev_printk(KERN_ERR, cmd->device, "failed to send reset event. rc=%d\n", rsp_rc); return FAILED; } + sdev_printk(KERN_INFO, cmd->device, "resetting device. lun 0x%lx\n", + (((u64) lun) << 48)); + wait_for_completion(&evt->comp); /* make sure we got a good response */ @@ -1377,8 +1427,10 @@ static int ibmvscsi_slave_configure(struct scsi_device *sdev) unsigned long lock_flags = 0; spin_lock_irqsave(shost->host_lock, lock_flags); - if (sdev->type == TYPE_DISK) + if (sdev->type == TYPE_DISK) { sdev->allow_restart = 1; + sdev->timeout = 60 * HZ; + } scsi_adjust_queue_depth(sdev, 0, shost->cmd_per_lun); spin_unlock_irqrestore(shost->host_lock, lock_flags); return 0; @@ -1548,7 +1600,6 @@ static struct scsi_host_template driver_template = { .this_id = -1, .sg_tablesize = SG_ALL, .use_clustering = ENABLE_CLUSTERING, - .use_sg_chaining = ENABLE_SG_CHAINING, .shost_attrs = ibmvscsi_attrs, }; |