📄 ibmvscsi.c
字号:
/* Copy the IU into the transfer area */ *evt_struct->xfer_iu = evt_struct->iu; evt_struct->xfer_iu->srp.generic.tag = (u64)evt_struct; /* Add this to the sent list. We need to do this * before we actually send * in case it comes back REALLY fast */ list_add_tail(&evt_struct->list, &hostdata->sent); if ((rc = ibmvscsi_send_crq(hostdata, crq_as_u64[0], crq_as_u64[1])) != 0) { list_del(&evt_struct->list); printk(KERN_ERR "ibmvscsi: failed to send event struct rc %d\n", rc); goto send_error; } return 0; send_error: unmap_cmd_data(&evt_struct->iu.srp.cmd, hostdata->dev); if ((cmnd = evt_struct->cmnd) != NULL) { cmnd->result = DID_ERROR << 16; evt_struct->cmnd_done(cmnd); } else if (evt_struct->done) evt_struct->done(evt_struct); free_event_struct(&hostdata->pool, evt_struct); return 0;}/** * handle_cmd_rsp: - Handle responses from commands * @evt_struct: srp_event_struct to be handled * * Used as a callback by when sending scsi cmds. * Gets called by ibmvscsi_handle_crq()*/static void handle_cmd_rsp(struct srp_event_struct *evt_struct){ struct srp_rsp *rsp = &evt_struct->xfer_iu->srp.rsp; struct scsi_cmnd *cmnd = evt_struct->cmnd; if (unlikely(rsp->type != SRP_RSP_TYPE)) { if (printk_ratelimit()) printk(KERN_WARNING "ibmvscsi: bad SRP RSP type %d\n", rsp->type); } if (cmnd) { cmnd->result = rsp->status; if (((cmnd->result >> 1) & 0x1f) == CHECK_CONDITION) memcpy(cmnd->sense_buffer, rsp->sense_and_response_data, rsp->sense_data_list_length); unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct->hostdata->dev); if (rsp->doover) cmnd->resid = rsp->data_out_residual_count; else if (rsp->diover) cmnd->resid = rsp->data_in_residual_count; } if (evt_struct->cmnd_done) evt_struct->cmnd_done(cmnd);}/** * lun_from_dev: - Returns the lun of the scsi device * @dev: struct scsi_device **/static inline u16 lun_from_dev(struct scsi_device *dev){ return (0x2 << 14) | (dev->id << 8) | (dev->channel << 5) | dev->lun;}/** * ibmvscsi_queue: - The queuecommand function of the scsi template * @cmd: struct scsi_cmnd to be executed * @done: Callback function to be called when cmd is completed*/static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)){ struct srp_cmd *srp_cmd; struct srp_event_struct *evt_struct; struct ibmvscsi_host_data *hostdata = (struct ibmvscsi_host_data *)&cmnd->device->host->hostdata; u16 lun = lun_from_dev(cmnd->device); evt_struct = get_event_struct(&hostdata->pool); if (!evt_struct) return SCSI_MLQUEUE_HOST_BUSY; init_event_struct(evt_struct, handle_cmd_rsp, VIOSRP_SRP_FORMAT, cmnd->timeout); evt_struct->cmnd = cmnd; evt_struct->cmnd_done = done; /* Set up the actual SRP IU */ srp_cmd = &evt_struct->iu.srp.cmd; memset(srp_cmd, 0x00, sizeof(*srp_cmd)); srp_cmd->type = SRP_CMD_TYPE; memcpy(srp_cmd->cdb, cmnd->cmnd, sizeof(cmnd->cmnd)); srp_cmd->lun = ((u64) lun) << 48; if (!map_data_for_srp_cmd(cmnd, srp_cmd, hostdata->dev)) { printk(KERN_ERR "ibmvscsi: couldn't convert cmd to srp_cmd\n"); free_event_struct(&hostdata->pool, evt_struct); return SCSI_MLQUEUE_HOST_BUSY; } /* Fix up dma address of the buffer itself */ if ((srp_cmd->data_out_format == SRP_INDIRECT_BUFFER) || (srp_cmd->data_in_format == SRP_INDIRECT_BUFFER)) { struct indirect_descriptor *indirect = (struct indirect_descriptor *)srp_cmd->additional_data; indirect->head.virtual_address = evt_struct->crq.IU_data_ptr + offsetof(struct srp_cmd, additional_data) + offsetof(struct indirect_descriptor, list); } return ibmvscsi_send_srp_event(evt_struct, hostdata);}/* ------------------------------------------------------------ * Routines for driver initialization *//** * adapter_info_rsp: - Handle response to MAD adapter info request * @evt_struct: srp_event_struct with the response * * Used as a "done" callback by when sending adapter_info. Gets called * by ibmvscsi_handle_crq()*/static void adapter_info_rsp(struct srp_event_struct *evt_struct){ struct ibmvscsi_host_data *hostdata = evt_struct->hostdata; dma_unmap_single(hostdata->dev, evt_struct->iu.mad.adapter_info.buffer, evt_struct->iu.mad.adapter_info.common.length, DMA_BIDIRECTIONAL); if (evt_struct->xfer_iu->mad.adapter_info.common.status) { printk("ibmvscsi: error %d getting adapter info\n", evt_struct->xfer_iu->mad.adapter_info.common.status); } else { printk("ibmvscsi: host srp version: %s, " "host partition %s (%d), OS %d, max io %u\n", hostdata->madapter_info.srp_version, hostdata->madapter_info.partition_name, hostdata->madapter_info.partition_number, hostdata->madapter_info.os_type, hostdata->madapter_info.port_max_txu[0]); if (hostdata->madapter_info.port_max_txu[0]) hostdata->host->max_sectors = hostdata->madapter_info.port_max_txu[0] >> 9; }}/** * send_mad_adapter_info: - Sends the mad adapter info request * and stores the result so it can be retrieved with * sysfs. We COULD consider causing a failure if the * returned SRP version doesn't match ours. * @hostdata: ibmvscsi_host_data of host * * Returns zero if successful.*/static void send_mad_adapter_info(struct ibmvscsi_host_data *hostdata){ struct viosrp_adapter_info *req; struct srp_event_struct *evt_struct; memset(&hostdata->madapter_info, 0x00, sizeof(hostdata->madapter_info)); evt_struct = get_event_struct(&hostdata->pool); if (!evt_struct) { printk(KERN_ERR "ibmvscsi: couldn't allocate an event " "for ADAPTER_INFO_REQ!\n"); return; } init_event_struct(evt_struct, adapter_info_rsp, VIOSRP_MAD_FORMAT, init_timeout * HZ); req = &evt_struct->iu.mad.adapter_info; memset(req, 0x00, sizeof(*req)); req->common.type = VIOSRP_ADAPTER_INFO_TYPE; req->common.length = sizeof(hostdata->madapter_info); req->buffer = dma_map_single(hostdata->dev, &hostdata->madapter_info, sizeof(hostdata->madapter_info), DMA_BIDIRECTIONAL); if (dma_mapping_error(req->buffer)) { printk(KERN_ERR "ibmvscsi: Unable to map request_buffer " "for adapter_info!\n"); free_event_struct(&hostdata->pool, evt_struct); return; } if (ibmvscsi_send_srp_event(evt_struct, hostdata)) printk(KERN_ERR "ibmvscsi: couldn't send ADAPTER_INFO_REQ!\n");};/** * login_rsp: - Handle response to SRP login request * @evt_struct: srp_event_struct with the response * * Used as a "done" callback by when sending srp_login. Gets called * by ibmvscsi_handle_crq()*/static void login_rsp(struct srp_event_struct *evt_struct){ struct ibmvscsi_host_data *hostdata = evt_struct->hostdata; switch (evt_struct->xfer_iu->srp.generic.type) { case SRP_LOGIN_RSP_TYPE: /* it worked! */ break; case SRP_LOGIN_REJ_TYPE: /* refused! */ printk(KERN_INFO "ibmvscsi: SRP_LOGIN_REQ rejected\n"); /* Login failed. */ atomic_set(&hostdata->request_limit, -1); return; default: printk(KERN_ERR "ibmvscsi: Invalid login response typecode 0x%02x!\n", evt_struct->xfer_iu->srp.generic.type); /* Login failed. */ atomic_set(&hostdata->request_limit, -1); return; } printk(KERN_INFO "ibmvscsi: SRP_LOGIN succeeded\n"); if (evt_struct->xfer_iu->srp.login_rsp.request_limit_delta > (max_requests - 2)) evt_struct->xfer_iu->srp.login_rsp.request_limit_delta = max_requests - 2; /* Now we know what the real request-limit is */ atomic_set(&hostdata->request_limit, evt_struct->xfer_iu->srp.login_rsp.request_limit_delta); hostdata->host->can_queue = evt_struct->xfer_iu->srp.login_rsp.request_limit_delta - 2; if (hostdata->host->can_queue < 1) { printk(KERN_ERR "ibmvscsi: Invalid request_limit_delta\n"); return; } send_mad_adapter_info(hostdata); return;}/** * send_srp_login: - Sends the srp login * @hostdata: ibmvscsi_host_data of host * * Returns zero if successful.*/static int send_srp_login(struct ibmvscsi_host_data *hostdata){ int rc; unsigned long flags; struct srp_login_req *login; struct srp_event_struct *evt_struct = get_event_struct(&hostdata->pool); if (!evt_struct) { printk(KERN_ERR "ibmvscsi: couldn't allocate an event for login req!\n"); return FAILED; } init_event_struct(evt_struct, login_rsp, VIOSRP_SRP_FORMAT, init_timeout * HZ); login = &evt_struct->iu.srp.login_req; login->type = SRP_LOGIN_REQ_TYPE; login->max_requested_initiator_to_target_iulen = sizeof(union srp_iu); login->required_buffer_formats = 0x0006; /* Start out with a request limit of 1, since this is negotiated in * the login request we are just sending */ atomic_set(&hostdata->request_limit, 1); spin_lock_irqsave(hostdata->host->host_lock, flags); rc = ibmvscsi_send_srp_event(evt_struct, hostdata); spin_unlock_irqrestore(hostdata->host->host_lock, flags); return rc;};/** * sync_completion: Signal that a synchronous command has completed * Note that after returning from this call, the evt_struct is freed. * the caller waiting on this completion shouldn't touch the evt_struct * again. */static void sync_completion(struct srp_event_struct *evt_struct){ /* copy the response back */ if (evt_struct->sync_srp) *evt_struct->sync_srp = *evt_struct->xfer_iu; complete(&evt_struct->comp);}/** * ibmvscsi_abort: Abort a command...from scsi host template * send this over to the server and wait synchronously for the response */static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd){ struct ibmvscsi_host_data *hostdata = (struct ibmvscsi_host_data *)cmd->device->host->hostdata; struct srp_tsk_mgmt *tsk_mgmt; struct srp_event_struct *evt; struct srp_event_struct *tmp_evt, *found_evt; union viosrp_iu srp_rsp; int rsp_rc; u16 lun = lun_from_dev(cmd->device); /* First, find this command in our sent list so we can figure * out the correct tag */ 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) return FAILED; evt = get_event_struct(&hostdata->pool); if (evt == NULL) { printk(KERN_ERR "ibmvscsi: failed to allocate abort event\n"); return FAILED; } init_event_struct(evt, sync_completion, VIOSRP_SRP_FORMAT, init_timeout * HZ); tsk_mgmt = &evt->iu.srp.tsk_mgmt; /* Set up an abort SRP command */ memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt)); tsk_mgmt->type = SRP_TSK_MGMT_TYPE; tsk_mgmt->lun = ((u64) lun) << 48; tsk_mgmt->task_mgmt_flags = 0x01; /* ABORT TASK */ tsk_mgmt->managed_task_tag = (u64) found_evt; printk(KERN_INFO "ibmvscsi: aborting command. lun 0x%lx, tag 0x%lx\n", tsk_mgmt->lun, tsk_mgmt->managed_task_tag); evt->sync_srp = &srp_rsp; init_completion(&evt->comp); if (ibmvscsi_send_srp_event(evt, hostdata) != 0) { printk(KERN_ERR "ibmvscsi: failed to send abort() event\n"); return FAILED; } spin_unlock_irq(hostdata->host->host_lock); wait_for_completion(&evt->comp); spin_lock_irq(hostdata->host->host_lock); /* make sure we got a good response */ if (unlikely(srp_rsp.srp.generic.type != SRP_RSP_TYPE)) { if (printk_ratelimit()) printk(KERN_WARNING "ibmvscsi: abort bad SRP RSP type %d\n", srp_rsp.srp.generic.type); return FAILED; } if (srp_rsp.srp.rsp.rspvalid) rsp_rc = *((int *)srp_rsp.srp.rsp.sense_and_response_data); else rsp_rc = srp_rsp.srp.rsp.status; if (rsp_rc) { if (printk_ratelimit()) printk(KERN_WARNING "ibmvscsi: abort code %d for task tag 0x%lx\n", rsp_rc, tsk_mgmt->managed_task_tag); return FAILED; } /* Because we dropped the spinlock above, it's possible * The event is no longer in our list. Make sure it didn't * complete while we were aborting */ 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 == NULL) { printk(KERN_INFO "ibmvscsi: aborted task tag 0x%lx completed\n", tsk_mgmt->managed_task_tag); return SUCCESS; } printk(KERN_INFO "ibmvscsi: successfully aborted task tag 0x%lx\n", tsk_mgmt->managed_task_tag); cmd->result = (DID_ABORT << 16); list_del(&found_evt->list); unmap_cmd_data(&found_evt->iu.srp.cmd, found_evt->hostdata->dev); free_event_struct(&found_evt->hostdata->pool, found_evt); atomic_inc(&hostdata->request_limit); return SUCCESS;}/** * ibmvscsi_eh_device_reset_handler: Reset a single LUN...from scsi host * template send this over to the server and wait synchronously for the * response */static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd){ struct ibmvscsi_host_data *hostdata = (struct ibmvscsi_host_data *)cmd->device->host->hostdata; struct srp_tsk_mgmt *tsk_mgmt; struct srp_event_struct *evt; struct srp_event_struct *tmp_evt, *pos; union viosrp_iu srp_rsp; int rsp_rc; u16 lun = lun_from_dev(cmd->device); evt = get_event_struct(&hostdata->pool); if (evt == NULL) { printk(KERN_ERR "ibmvscsi: failed to allocate reset event\n"); return FAILED; } init_event_struct(evt, sync_completion, VIOSRP_SRP_FORMAT, init_timeout * HZ); tsk_mgmt = &evt->iu.srp.tsk_mgmt; /* Set up a lun reset SRP command */ memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt)); tsk_mgmt->type = SRP_TSK_MGMT_TYPE; tsk_mgmt->lun = ((u64) lun) << 48; tsk_mgmt->task_mgmt_flags = 0x08; /* LUN RESET */ printk(KERN_INFO "ibmvscsi: resetting device. lun 0x%lx\n", tsk_mgmt->lun); evt->sync_srp = &srp_rsp; init_completion(&evt->comp); if (ibmvscsi_send_srp_event(evt, hostdata) != 0) { printk(KERN_ERR "ibmvscsi: failed to send reset event\n"); return FAILED; } spin_unlock_irq(hostdata->host->host_lock); wait_for_completion(&evt->comp); spin_lock_irq(hostdata->host->host_lock);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -