ib_srp.c

来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 1,809 行 · 第 1/3 页

C
1,809
字号
		buf->len = cpu_to_be32(datalen);		len = sizeof (struct srp_cmd) +			sizeof (struct srp_indirect_buf) +			count * sizeof (struct srp_direct_buf);	}	if (scmnd->sc_data_direction == DMA_TO_DEVICE)		cmd->buf_fmt = fmt << 4;	else		cmd->buf_fmt = fmt;	return len;}static void srp_remove_req(struct srp_target_port *target, struct srp_request *req){	srp_unmap_data(req->scmnd, target, req);	list_move_tail(&req->list, &target->free_reqs);}static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp){	struct srp_request *req;	struct scsi_cmnd *scmnd;	unsigned long flags;	s32 delta;	delta = (s32) be32_to_cpu(rsp->req_lim_delta);	spin_lock_irqsave(target->scsi_host->host_lock, flags);	target->req_lim += delta;	req = &target->req_ring[rsp->tag & ~SRP_TAG_TSK_MGMT];	if (unlikely(rsp->tag & SRP_TAG_TSK_MGMT)) {		if (be32_to_cpu(rsp->resp_data_len) < 4)			req->tsk_status = -1;		else			req->tsk_status = rsp->data[3];		complete(&req->done);	} else {		scmnd = req->scmnd;		if (!scmnd)			printk(KERN_ERR "Null scmnd for RSP w/tag %016llx\n",			       (unsigned long long) rsp->tag);		scmnd->result = rsp->status;		if (rsp->flags & SRP_RSP_FLAG_SNSVALID) {			memcpy(scmnd->sense_buffer, rsp->data +			       be32_to_cpu(rsp->resp_data_len),			       min_t(int, be32_to_cpu(rsp->sense_data_len),				     SCSI_SENSE_BUFFERSIZE));		}		if (rsp->flags & (SRP_RSP_FLAG_DOOVER | SRP_RSP_FLAG_DOUNDER))			scmnd->resid = be32_to_cpu(rsp->data_out_res_cnt);		else if (rsp->flags & (SRP_RSP_FLAG_DIOVER | SRP_RSP_FLAG_DIUNDER))			scmnd->resid = be32_to_cpu(rsp->data_in_res_cnt);		if (!req->tsk_mgmt) {			scmnd->host_scribble = (void *) -1L;			scmnd->scsi_done(scmnd);			srp_remove_req(target, req);		} else			req->cmd_done = 1;	}	spin_unlock_irqrestore(target->scsi_host->host_lock, flags);}static void srp_reconnect_work(void *target_ptr){	struct srp_target_port *target = target_ptr;	srp_reconnect_target(target);}static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc){	struct srp_iu *iu;	u8 opcode;	iu = target->rx_ring[wc->wr_id & ~SRP_OP_RECV];	dma_sync_single_for_cpu(target->srp_host->dev->dma_device, iu->dma,				target->max_ti_iu_len, DMA_FROM_DEVICE);	opcode = *(u8 *) iu->buf;	if (0) {		int i;		printk(KERN_ERR PFX "recv completion, opcode 0x%02x\n", opcode);		for (i = 0; i < wc->byte_len; ++i) {			if (i % 8 == 0)				printk(KERN_ERR "  [%02x] ", i);			printk(" %02x", ((u8 *) iu->buf)[i]);			if ((i + 1) % 8 == 0)				printk("\n");		}		if (wc->byte_len % 8)			printk("\n");	}	switch (opcode) {	case SRP_RSP:		srp_process_rsp(target, iu->buf);		break;	case SRP_T_LOGOUT:		/* XXX Handle target logout */		printk(KERN_WARNING PFX "Got target logout request\n");		break;	default:		printk(KERN_WARNING PFX "Unhandled SRP opcode 0x%02x\n", opcode);		break;	}	dma_sync_single_for_device(target->srp_host->dev->dma_device, iu->dma,				   target->max_ti_iu_len, DMA_FROM_DEVICE);}static void srp_completion(struct ib_cq *cq, void *target_ptr){	struct srp_target_port *target = target_ptr;	struct ib_wc wc;	unsigned long flags;	ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);	while (ib_poll_cq(cq, 1, &wc) > 0) {		if (wc.status) {			printk(KERN_ERR PFX "failed %s status %d\n",			       wc.wr_id & SRP_OP_RECV ? "receive" : "send",			       wc.status);			spin_lock_irqsave(target->scsi_host->host_lock, flags);			if (target->state == SRP_TARGET_LIVE)				schedule_work(&target->work);			spin_unlock_irqrestore(target->scsi_host->host_lock, flags);			break;		}		if (wc.wr_id & SRP_OP_RECV)			srp_handle_recv(target, &wc);		else			++target->tx_tail;	}}static int __srp_post_recv(struct srp_target_port *target){	struct srp_iu *iu;	struct ib_sge list;	struct ib_recv_wr wr, *bad_wr;	unsigned int next;	int ret;	next 	 = target->rx_head & (SRP_RQ_SIZE - 1);	wr.wr_id = next | SRP_OP_RECV;	iu 	 = target->rx_ring[next];	list.addr   = iu->dma;	list.length = iu->size;	list.lkey   = target->srp_host->mr->lkey;	wr.next     = NULL;	wr.sg_list  = &list;	wr.num_sge  = 1;	ret = ib_post_recv(target->qp, &wr, &bad_wr);	if (!ret)		++target->rx_head;	return ret;}static int srp_post_recv(struct srp_target_port *target){	unsigned long flags;	int ret;	spin_lock_irqsave(target->scsi_host->host_lock, flags);	ret = __srp_post_recv(target);	spin_unlock_irqrestore(target->scsi_host->host_lock, flags);	return ret;}/* * Must be called with target->scsi_host->host_lock held to protect * req_lim and tx_head.  Lock cannot be dropped between call here and * call to __srp_post_send(). */static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target){	if (target->tx_head - target->tx_tail >= SRP_SQ_SIZE)		return NULL;	if (unlikely(target->req_lim < 1)) {		if (printk_ratelimit())			printk(KERN_DEBUG PFX "Target has req_lim %d\n",			       target->req_lim);		return NULL;	}	return target->tx_ring[target->tx_head & SRP_SQ_SIZE];}/* * Must be called with target->scsi_host->host_lock held to protect * req_lim and tx_head. */static int __srp_post_send(struct srp_target_port *target,			   struct srp_iu *iu, int len){	struct ib_sge list;	struct ib_send_wr wr, *bad_wr;	int ret = 0;	list.addr   = iu->dma;	list.length = len;	list.lkey   = target->srp_host->mr->lkey;	wr.next       = NULL;	wr.wr_id      = target->tx_head & SRP_SQ_SIZE;	wr.sg_list    = &list;	wr.num_sge    = 1;	wr.opcode     = IB_WR_SEND;	wr.send_flags = IB_SEND_SIGNALED;	ret = ib_post_send(target->qp, &wr, &bad_wr);	if (!ret) {		++target->tx_head;		--target->req_lim;	}	return ret;}static int srp_queuecommand(struct scsi_cmnd *scmnd,			    void (*done)(struct scsi_cmnd *)){	struct srp_target_port *target = host_to_target(scmnd->device->host);	struct srp_request *req;	struct srp_iu *iu;	struct srp_cmd *cmd;	int len;	if (target->state == SRP_TARGET_CONNECTING)		goto err;	if (target->state == SRP_TARGET_DEAD ||	    target->state == SRP_TARGET_REMOVED) {		scmnd->result = DID_BAD_TARGET << 16;		done(scmnd);		return 0;	}	iu = __srp_get_tx_iu(target);	if (!iu)		goto err;	dma_sync_single_for_cpu(target->srp_host->dev->dma_device, iu->dma,				SRP_MAX_IU_LEN, DMA_TO_DEVICE);	req = list_entry(target->free_reqs.next, struct srp_request, list);	scmnd->scsi_done     = done;	scmnd->result        = 0;	scmnd->host_scribble = (void *) (long) req->index;	cmd = iu->buf;	memset(cmd, 0, sizeof *cmd);	cmd->opcode = SRP_CMD;	cmd->lun    = cpu_to_be64((u64) scmnd->device->lun << 48);	cmd->tag    = req->index;	memcpy(cmd->cdb, scmnd->cmnd, scmnd->cmd_len);	req->scmnd    = scmnd;	req->cmd      = iu;	req->cmd_done = 0;	req->tsk_mgmt = NULL;	len = srp_map_data(scmnd, target, req);	if (len < 0) {		printk(KERN_ERR PFX "Failed to map data\n");		goto err;	}	if (__srp_post_recv(target)) {		printk(KERN_ERR PFX "Recv failed\n");		goto err_unmap;	}	dma_sync_single_for_device(target->srp_host->dev->dma_device, iu->dma,				   SRP_MAX_IU_LEN, DMA_TO_DEVICE);	if (__srp_post_send(target, iu, len)) {		printk(KERN_ERR PFX "Send failed\n");		goto err_unmap;	}	list_move_tail(&req->list, &target->req_queue);	return 0;err_unmap:	srp_unmap_data(scmnd, target, req);err:	return SCSI_MLQUEUE_HOST_BUSY;}static int srp_alloc_iu_bufs(struct srp_target_port *target){	int i;	for (i = 0; i < SRP_RQ_SIZE; ++i) {		target->rx_ring[i] = srp_alloc_iu(target->srp_host,						  target->max_ti_iu_len,						  GFP_KERNEL, DMA_FROM_DEVICE);		if (!target->rx_ring[i])			goto err;	}	for (i = 0; i < SRP_SQ_SIZE + 1; ++i) {		target->tx_ring[i] = srp_alloc_iu(target->srp_host,						  SRP_MAX_IU_LEN,						  GFP_KERNEL, DMA_TO_DEVICE);		if (!target->tx_ring[i])			goto err;	}	return 0;err:	for (i = 0; i < SRP_RQ_SIZE; ++i) {		srp_free_iu(target->srp_host, target->rx_ring[i]);		target->rx_ring[i] = NULL;	}	for (i = 0; i < SRP_SQ_SIZE + 1; ++i) {		srp_free_iu(target->srp_host, target->tx_ring[i]);		target->tx_ring[i] = NULL;	}	return -ENOMEM;}static void srp_cm_rej_handler(struct ib_cm_id *cm_id,			       struct ib_cm_event *event,			       struct srp_target_port *target){	struct ib_class_port_info *cpi;	int opcode;	switch (event->param.rej_rcvd.reason) {	case IB_CM_REJ_PORT_CM_REDIRECT:		cpi = event->param.rej_rcvd.ari;		target->path.dlid = cpi->redirect_lid;		target->path.pkey = cpi->redirect_pkey;		cm_id->remote_cm_qpn = be32_to_cpu(cpi->redirect_qp) & 0x00ffffff;		memcpy(target->path.dgid.raw, cpi->redirect_gid, 16);		target->status = target->path.dlid ?			SRP_DLID_REDIRECT : SRP_PORT_REDIRECT;		break;	case IB_CM_REJ_PORT_REDIRECT:		if (topspin_workarounds &&		    !memcmp(&target->ioc_guid, topspin_oui, 3)) {			/*			 * Topspin/Cisco SRP gateways incorrectly send			 * reject reason code 25 when they mean 24			 * (port redirect).			 */			memcpy(target->path.dgid.raw,			       event->param.rej_rcvd.ari, 16);			printk(KERN_DEBUG PFX "Topspin/Cisco redirect to target port GID %016llx%016llx\n",			       (unsigned long long) be64_to_cpu(target->path.dgid.global.subnet_prefix),			       (unsigned long long) be64_to_cpu(target->path.dgid.global.interface_id));			target->status = SRP_PORT_REDIRECT;		} else {			printk(KERN_WARNING "  REJ reason: IB_CM_REJ_PORT_REDIRECT\n");			target->status = -ECONNRESET;		}		break;	case IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID:		printk(KERN_WARNING "  REJ reason: IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID\n");		target->status = -ECONNRESET;		break;	case IB_CM_REJ_CONSUMER_DEFINED:		opcode = *(u8 *) event->private_data;		if (opcode == SRP_LOGIN_REJ) {			struct srp_login_rej *rej = event->private_data;			u32 reason = be32_to_cpu(rej->reason);			if (reason == SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE)				printk(KERN_WARNING PFX				       "SRP_LOGIN_REJ: requested max_it_iu_len too large\n");			else				printk(KERN_WARNING PFX				       "SRP LOGIN REJECTED, reason 0x%08x\n", reason);		} else			printk(KERN_WARNING "  REJ reason: IB_CM_REJ_CONSUMER_DEFINED,"			       " opcode 0x%02x\n", opcode);		target->status = -ECONNRESET;		break;	default:		printk(KERN_WARNING "  REJ reason 0x%x\n",		       event->param.rej_rcvd.reason);		target->status = -ECONNRESET;	}}static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event){	struct srp_target_port *target = cm_id->context;	struct ib_qp_attr *qp_attr = NULL;	int attr_mask = 0;	int comp = 0;	int opcode = 0;	switch (event->event) {	case IB_CM_REQ_ERROR:		printk(KERN_DEBUG PFX "Sending CM REQ failed\n");		comp = 1;		target->status = -ECONNRESET;		break;	case IB_CM_REP_RECEIVED:		comp = 1;		opcode = *(u8 *) event->private_data;		if (opcode == SRP_LOGIN_RSP) {			struct srp_login_rsp *rsp = event->private_data;			target->max_ti_iu_len = be32_to_cpu(rsp->max_ti_iu_len);			target->req_lim       = be32_to_cpu(rsp->req_lim_delta);			target->scsi_host->can_queue = min(target->req_lim,							   target->scsi_host->can_queue);		} else {			printk(KERN_WARNING PFX "Unhandled RSP opcode %#x\n", opcode);			target->status = -ECONNRESET;			break;		}		target->status = srp_alloc_iu_bufs(target);		if (target->status)			break;		qp_attr = kmalloc(sizeof *qp_attr, GFP_KERNEL);		if (!qp_attr) {			target->status = -ENOMEM;			break;		}		qp_attr->qp_state = IB_QPS_RTR;		target->status = ib_cm_init_qp_attr(cm_id, qp_attr, &attr_mask);		if (target->status)			break;		target->status = ib_modify_qp(target->qp, qp_attr, attr_mask);		if (target->status)			break;		target->status = srp_post_recv(target);		if (target->status)			break;		qp_attr->qp_state = IB_QPS_RTS;		target->status = ib_cm_init_qp_attr(cm_id, qp_attr, &attr_mask);		if (target->status)			break;		target->status = ib_modify_qp(target->qp, qp_attr, attr_mask);		if (target->status)			break;		target->status = ib_send_cm_rtu(cm_id, NULL, 0);		if (target->status)			break;		break;	case IB_CM_REJ_RECEIVED:		printk(KERN_DEBUG PFX "REJ received\n");		comp = 1;		srp_cm_rej_handler(cm_id, event, target);		break;	case IB_CM_MRA_RECEIVED:		printk(KERN_ERR PFX "MRA received\n");		break;	case IB_CM_DREP_RECEIVED:		break;	case IB_CM_TIMEWAIT_EXIT:		printk(KERN_ERR PFX "connection closed\n");		comp = 1;		target->status = 0;		break;	default:		printk(KERN_WARNING PFX "Unhandled CM event %d\n", event->event);		break;	}	if (comp)		complete(&target->done);	kfree(qp_attr);	return 0;}static int srp_send_tsk_mgmt(struct srp_target_port *target,			     struct srp_request *req, u8 func){	struct srp_iu *iu;	struct srp_tsk_mgmt *tsk_mgmt;	spin_lock_irq(target->scsi_host->host_lock);	if (target->state == SRP_TARGET_DEAD ||	    target->state == SRP_TARGET_REMOVED) {		req->scmnd->result = DID_BAD_TARGET << 16;		goto out;	}	init_completion(&req->done);	iu = __srp_get_tx_iu(target);	if (!iu)		goto out;	tsk_mgmt = iu->buf;	memset(tsk_mgmt, 0, sizeof *tsk_mgmt);	tsk_mgmt->opcode 	= SRP_TSK_MGMT;	tsk_mgmt->lun 		= cpu_to_be64((u64) req->scmnd->device->lun << 48);	tsk_mgmt->tag 		= req->index | SRP_TAG_TSK_MGMT;	tsk_mgmt->tsk_mgmt_func = func;	tsk_mgmt->task_tag 	= req->index;	if (__srp_post_send(target, iu, sizeof *tsk_mgmt))		goto out;	req->tsk_mgmt = iu;	spin_unlock_irq(target->scsi_host->host_lock);	if (!wait_for_completion_timeout(&req->done,					 msecs_to_jiffies(SRP_ABORT_TIMEOUT_MS)))		return -1;	return 0;out:	spin_unlock_irq(target->scsi_host->host_lock);	return -1;}static int srp_find_req(struct srp_target_port *target,			struct scsi_cmnd *scmnd,			struct srp_request **req){	if (scmnd->host_scribble == (void *) -1L)		return -1;	*req = &target->req_ring[(long) scmnd->host_scribble];	return 0;}static int srp_abort(struct scsi_cmnd *scmnd){	struct srp_target_port *target = host_to_target(scmnd->device->host);	struct srp_request *req;	int ret = SUCCESS;	printk(KERN_ERR "SRP abort called\n");	if (srp_find_req(target, scmnd, &req))		return FAILED;	if (srp_send_tsk_mgmt(target, req, SRP_TSK_ABORT_TASK))

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?