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 + -
显示快捷键?