ibmvscsi.c
来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 1,586 行 · 第 1/4 页
C
1,586 行
break; case SRP_LOGIN_REJ: /* refused! */ printk(KERN_INFO "ibmvscsi: SRP_LOGIN_REJ reason %u\n", evt_struct->xfer_iu->srp.login_rej.reason); /* 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.login_rsp.opcode); /* 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.req_lim_delta > (max_requests - 2)) evt_struct->xfer_iu->srp.login_rsp.req_lim_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.req_lim_delta); hostdata->host->can_queue = evt_struct->xfer_iu->srp.login_rsp.req_lim_delta - 2; if (hostdata->host->can_queue < 1) { printk(KERN_ERR "ibmvscsi: Invalid request_limit_delta\n"); return; } /* If we had any pending I/Os, kick them */ scsi_unblock_requests(hostdata->host); 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; memset(login, 0x00, sizeof(struct srp_login_req)); login->opcode = SRP_LOGIN_REQ; login->req_it_iu_len = sizeof(union srp_iu); 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 */ atomic_set(&hostdata->request_limit, 1); rc = ibmvscsi_send_srp_event(evt_struct, hostdata); spin_unlock_irqrestore(hostdata->host->host_lock, flags); printk("ibmvscsic: sent SRP login\n"); 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; unsigned long flags; u16 lun = lun_from_dev(cmd->device); /* 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; } } if (!found_evt) { spin_unlock_irqrestore(hostdata->host->host_lock, flags); return FAILED; } evt = get_event_struct(&hostdata->pool); if (evt == NULL) { spin_unlock_irqrestore(hostdata->host->host_lock, flags); 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->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; printk(KERN_INFO "ibmvscsi: 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); spin_unlock_irqrestore(hostdata->host->host_lock, flags); if (rsp_rc != 0) { printk(KERN_ERR "ibmvscsi: failed to send abort() event\n"); return FAILED; } wait_for_completion(&evt->comp); /* make sure we got a good response */ if (unlikely(srp_rsp.srp.rsp.opcode != SRP_RSP)) { if (printk_ratelimit()) printk(KERN_WARNING "ibmvscsi: abort bad SRP RSP type %d\n", srp_rsp.srp.rsp.opcode); return FAILED; } if (srp_rsp.srp.rsp.flags & SRP_RSP_FLAG_RSPVALID) rsp_rc = *((int *)srp_rsp.srp.rsp.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->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 */ 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; } } if (found_evt == NULL) { spin_unlock_irqrestore(hostdata->host->host_lock, flags); printk(KERN_INFO "ibmvscsi: aborted task tag 0x%lx completed\n", tsk_mgmt->task_tag); return SUCCESS; } printk(KERN_INFO "ibmvscsi: successfully aborted task tag 0x%lx\n", tsk_mgmt->task_tag); cmd->result = (DID_ABORT << 16); list_del(&found_evt->list); unmap_cmd_data(&found_evt->iu.srp.cmd, found_evt, found_evt->hostdata->dev); free_event_struct(&found_evt->hostdata->pool, found_evt); spin_unlock_irqrestore(hostdata->host->host_lock, flags); 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; unsigned long flags; u16 lun = lun_from_dev(cmd->device); 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); 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->opcode = SRP_TSK_MGMT; tsk_mgmt->lun = ((u64) lun) << 48; tsk_mgmt->tsk_mgmt_func = SRP_TSK_LUN_RESET; printk(KERN_INFO "ibmvscsi: 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); spin_unlock_irqrestore(hostdata->host->host_lock, flags); if (rsp_rc != 0) { printk(KERN_ERR "ibmvscsi: failed to send reset event\n"); return FAILED; } wait_for_completion(&evt->comp); /* make sure we got a good response */ if (unlikely(srp_rsp.srp.rsp.opcode != SRP_RSP)) { if (printk_ratelimit()) printk(KERN_WARNING "ibmvscsi: reset bad SRP RSP type %d\n", srp_rsp.srp.rsp.opcode); return FAILED; } if (srp_rsp.srp.rsp.flags & SRP_RSP_FLAG_RSPVALID) rsp_rc = *((int *)srp_rsp.srp.rsp.data); else rsp_rc = srp_rsp.srp.rsp.status; if (rsp_rc) { if (printk_ratelimit()) printk(KERN_WARNING "ibmvscsi: reset code %d for task tag 0x%lx\n", rsp_rc, tsk_mgmt->task_tag); return FAILED; } /* We need to find all commands for this LUN that have not yet been * responded to, and fail them with DID_RESET */ spin_lock_irqsave(hostdata->host->host_lock, flags); list_for_each_entry_safe(tmp_evt, pos, &hostdata->sent, list) { if ((tmp_evt->cmnd) && (tmp_evt->cmnd->device == cmd->device)) { if (tmp_evt->cmnd) tmp_evt->cmnd->result = (DID_RESET << 16); list_del(&tmp_evt->list); unmap_cmd_data(&tmp_evt->iu.srp.cmd, tmp_evt, tmp_evt->hostdata->dev); free_event_struct(&tmp_evt->hostdata->pool, tmp_evt); atomic_inc(&hostdata->request_limit); if (tmp_evt->cmnd_done) tmp_evt->cmnd_done(tmp_evt->cmnd); else if (tmp_evt->done) tmp_evt->done(tmp_evt); } } spin_unlock_irqrestore(hostdata->host->host_lock, flags); return SUCCESS;}/** * purge_requests: Our virtual adapter just shut down. purge any sent requests * @hostdata: the adapter */static void purge_requests(struct ibmvscsi_host_data *hostdata, int error_code){ struct srp_event_struct *tmp_evt, *pos; unsigned long flags; spin_lock_irqsave(hostdata->host->host_lock, flags); list_for_each_entry_safe(tmp_evt, pos, &hostdata->sent, list) { list_del(&tmp_evt->list); if (tmp_evt->cmnd) { tmp_evt->cmnd->result = (error_code << 16); unmap_cmd_data(&tmp_evt->iu.srp.cmd, tmp_evt, tmp_evt->hostdata->dev); if (tmp_evt->cmnd_done) tmp_evt->cmnd_done(tmp_evt->cmnd); } else { if (tmp_evt->done) { tmp_evt->done(tmp_evt); } } free_event_struct(&tmp_evt->hostdata->pool, tmp_evt); } spin_unlock_irqrestore(hostdata->host->host_lock, flags);}/** * ibmvscsi_handle_crq: - Handles and frees received events in the CRQ * @crq: Command/Response queue * @hostdata: ibmvscsi_host_data of host **/void ibmvscsi_handle_crq(struct viosrp_crq *crq, struct ibmvscsi_host_data *hostdata){ unsigned long flags; struct srp_event_struct *evt_struct = (struct srp_event_struct *)crq->IU_data_ptr; switch (crq->valid) { case 0xC0: /* initialization */ switch (crq->format) { case 0x01: /* Initialization message */ printk(KERN_INFO "ibmvscsi: partner initialized\n"); /* Send back a response */ if (ibmvscsi_send_crq(hostdata, 0xC002000000000000LL, 0) == 0) { /* Now login */ send_srp_login(hostdata); } else { printk(KERN_ERR "ibmvscsi: Unable to send init rsp\n"); } break; case 0x02: /* Initialization response */ printk(KERN_INFO "ibmvscsi: partner initialization complete\n"); /* Now login */ send_srp_login(hostdata); break; default: printk(KERN_ERR "ibmvscsi: unknown crq message type\n"); } return; case 0xFF: /* Hypervisor telling us the connection is closed */ scsi_block_requests(hostdata->host); if (crq->format == 0x06) { /* We need to re-setup the interpartition connection */ printk(KERN_INFO "ibmvscsi: Re-enabling adapter!\n");
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?