⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 aic94xx_task.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
		ts->resp = SAS_TASK_UNDELIVERED;		ts->stat = SAS_DEV_NO_RESPONSE;		break;	case TC_LINK_ADM_RESP:	case TC_CONTROL_PHY:	case TC_RESUME:	case TC_PARTIAL_SG_LIST:	default:		ASD_DPRINTK("%s: dl opcode: 0x%x?\n", __FUNCTION__, opcode);		break;	}	switch (task->task_proto) {	case SATA_PROTO:	case SAS_PROTO_STP:		asd_unbuild_ata_ascb(ascb);		break;	case SAS_PROTO_SMP:		asd_unbuild_smp_ascb(ascb);		break;	case SAS_PROTO_SSP:		asd_unbuild_ssp_ascb(ascb);	default:		break;	}	spin_lock_irqsave(&task->task_state_lock, flags);	task->task_state_flags &= ~SAS_TASK_STATE_PENDING;	task->task_state_flags &= ~SAS_TASK_AT_INITIATOR;	task->task_state_flags |= SAS_TASK_STATE_DONE;	if (unlikely((task->task_state_flags & SAS_TASK_STATE_ABORTED))) {		spin_unlock_irqrestore(&task->task_state_lock, flags);		ASD_DPRINTK("task 0x%p done with opcode 0x%x resp 0x%x "			    "stat 0x%x but aborted by upper layer!\n",			    task, opcode, ts->resp, ts->stat);		complete(&ascb->completion);	} else {		spin_unlock_irqrestore(&task->task_state_lock, flags);		task->lldd_task = NULL;		asd_ascb_free(ascb);		mb();		task->task_done(task);	}}/* ---------- ATA ---------- */static int asd_build_ata_ascb(struct asd_ascb *ascb, struct sas_task *task,			      gfp_t gfp_flags){	struct domain_device *dev = task->dev;	struct scb *scb;	u8     flags;	int    res = 0;	scb = ascb->scb;	if (unlikely(task->ata_task.device_control_reg_update))		scb->header.opcode = CONTROL_ATA_DEV;	else if (dev->sata_dev.command_set == ATA_COMMAND_SET)		scb->header.opcode = INITIATE_ATA_TASK;	else		scb->header.opcode = INITIATE_ATAPI_TASK;	scb->ata_task.proto_conn_rate = (1 << 5); /* STP */	if (dev->port->oob_mode == SAS_OOB_MODE)		scb->ata_task.proto_conn_rate |= dev->linkrate;	scb->ata_task.total_xfer_len = cpu_to_le32(task->total_xfer_len);	scb->ata_task.fis = task->ata_task.fis;	if (likely(!task->ata_task.device_control_reg_update))		scb->ata_task.fis.flags |= 0x80; /* C=1: update ATA cmd reg */	scb->ata_task.fis.flags &= 0xF0; /* PM_PORT field shall be 0 */	if (dev->sata_dev.command_set == ATAPI_COMMAND_SET)		memcpy(scb->ata_task.atapi_packet, task->ata_task.atapi_packet,		       16);	scb->ata_task.sister_scb = cpu_to_le16(0xFFFF);	scb->ata_task.conn_handle = cpu_to_le16(		(u16)(unsigned long)dev->lldd_dev);	if (likely(!task->ata_task.device_control_reg_update)) {		flags = 0;		if (task->ata_task.dma_xfer)			flags |= DATA_XFER_MODE_DMA;		if (task->ata_task.use_ncq &&		    dev->sata_dev.command_set != ATAPI_COMMAND_SET)			flags |= ATA_Q_TYPE_NCQ;		flags |= data_dir_flags[task->data_dir];		scb->ata_task.ata_flags = flags;		scb->ata_task.retry_count = task->ata_task.retry_count;		flags = 0;		if (task->ata_task.set_affil_pol)			flags |= SET_AFFIL_POLICY;		if (task->ata_task.stp_affil_pol)			flags |= STP_AFFIL_POLICY;		scb->ata_task.flags = flags;	}	ascb->tasklet_complete = asd_task_tasklet_complete;	if (likely(!task->ata_task.device_control_reg_update))		res = asd_map_scatterlist(task, scb->ata_task.sg_element,					  gfp_flags);	return res;}static void asd_unbuild_ata_ascb(struct asd_ascb *a){	asd_unmap_scatterlist(a);}/* ---------- SMP ---------- */static int asd_build_smp_ascb(struct asd_ascb *ascb, struct sas_task *task,			      gfp_t gfp_flags){	struct asd_ha_struct *asd_ha = ascb->ha;	struct domain_device *dev = task->dev;	struct scb *scb;	pci_map_sg(asd_ha->pcidev, &task->smp_task.smp_req, 1,		   PCI_DMA_TODEVICE);	pci_map_sg(asd_ha->pcidev, &task->smp_task.smp_resp, 1,		   PCI_DMA_FROMDEVICE);	scb = ascb->scb;	scb->header.opcode = INITIATE_SMP_TASK;	scb->smp_task.proto_conn_rate = dev->linkrate;	scb->smp_task.smp_req.bus_addr =		cpu_to_le64((u64)sg_dma_address(&task->smp_task.smp_req));	scb->smp_task.smp_req.size =		cpu_to_le32((u32)sg_dma_len(&task->smp_task.smp_req)-4);	scb->smp_task.smp_resp.bus_addr =		cpu_to_le64((u64)sg_dma_address(&task->smp_task.smp_resp));	scb->smp_task.smp_resp.size =		cpu_to_le32((u32)sg_dma_len(&task->smp_task.smp_resp)-4);	scb->smp_task.sister_scb = cpu_to_le16(0xFFFF);	scb->smp_task.conn_handle = cpu_to_le16((u16)						(unsigned long)dev->lldd_dev);	ascb->tasklet_complete = asd_task_tasklet_complete;	return 0;}static void asd_unbuild_smp_ascb(struct asd_ascb *a){	struct sas_task *task = a->uldd_task;	BUG_ON(!task);	pci_unmap_sg(a->ha->pcidev, &task->smp_task.smp_req, 1,		     PCI_DMA_TODEVICE);	pci_unmap_sg(a->ha->pcidev, &task->smp_task.smp_resp, 1,		     PCI_DMA_FROMDEVICE);}/* ---------- SSP ---------- */static int asd_build_ssp_ascb(struct asd_ascb *ascb, struct sas_task *task,			      gfp_t gfp_flags){	struct domain_device *dev = task->dev;	struct scb *scb;	int    res = 0;	scb = ascb->scb;	scb->header.opcode = INITIATE_SSP_TASK;	scb->ssp_task.proto_conn_rate  = (1 << 4); /* SSP */	scb->ssp_task.proto_conn_rate |= dev->linkrate;	scb->ssp_task.total_xfer_len = cpu_to_le32(task->total_xfer_len);	scb->ssp_task.ssp_frame.frame_type = SSP_DATA;	memcpy(scb->ssp_task.ssp_frame.hashed_dest_addr, dev->hashed_sas_addr,	       HASHED_SAS_ADDR_SIZE);	memcpy(scb->ssp_task.ssp_frame.hashed_src_addr,	       dev->port->ha->hashed_sas_addr, HASHED_SAS_ADDR_SIZE);	scb->ssp_task.ssp_frame.tptt = cpu_to_be16(0xFFFF);	memcpy(scb->ssp_task.ssp_cmd.lun, task->ssp_task.LUN, 8);	if (task->ssp_task.enable_first_burst)		scb->ssp_task.ssp_cmd.efb_prio_attr |= EFB_MASK;	scb->ssp_task.ssp_cmd.efb_prio_attr |= (task->ssp_task.task_prio << 3);	scb->ssp_task.ssp_cmd.efb_prio_attr |= (task->ssp_task.task_attr & 7);	memcpy(scb->ssp_task.ssp_cmd.cdb, task->ssp_task.cdb, 16);	scb->ssp_task.sister_scb = cpu_to_le16(0xFFFF);	scb->ssp_task.conn_handle = cpu_to_le16(		(u16)(unsigned long)dev->lldd_dev);	scb->ssp_task.data_dir = data_dir_flags[task->data_dir];	scb->ssp_task.retry_count = scb->ssp_task.retry_count;	ascb->tasklet_complete = asd_task_tasklet_complete;	res = asd_map_scatterlist(task, scb->ssp_task.sg_element, gfp_flags);	return res;}static void asd_unbuild_ssp_ascb(struct asd_ascb *a){	asd_unmap_scatterlist(a);}/* ---------- Execute Task ---------- */static inline int asd_can_queue(struct asd_ha_struct *asd_ha, int num){	int res = 0;	unsigned long flags;	spin_lock_irqsave(&asd_ha->seq.pend_q_lock, flags);	if ((asd_ha->seq.can_queue - num) < 0)		res = -SAS_QUEUE_FULL;	else		asd_ha->seq.can_queue -= num;	spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags);	return res;}int asd_execute_task(struct sas_task *task, const int num,		     gfp_t gfp_flags){	int res = 0;	LIST_HEAD(alist);	struct sas_task *t = task;	struct asd_ascb *ascb = NULL, *a;	struct asd_ha_struct *asd_ha = task->dev->port->ha->lldd_ha;	unsigned long flags;	res = asd_can_queue(asd_ha, num);	if (res)		return res;	res = num;	ascb = asd_ascb_alloc_list(asd_ha, &res, gfp_flags);	if (res) {		res = -ENOMEM;		goto out_err;	}	__list_add(&alist, ascb->list.prev, &ascb->list);	list_for_each_entry(a, &alist, list) {		a->uldd_task = t;		t->lldd_task = a;		t = list_entry(t->list.next, struct sas_task, list);	}	list_for_each_entry(a, &alist, list) {		t = a->uldd_task;		a->uldd_timer = 1;		if (t->task_proto & SAS_PROTO_STP)			t->task_proto = SAS_PROTO_STP;		switch (t->task_proto) {		case SATA_PROTO:		case SAS_PROTO_STP:			res = asd_build_ata_ascb(a, t, gfp_flags);			break;		case SAS_PROTO_SMP:			res = asd_build_smp_ascb(a, t, gfp_flags);			break;		case SAS_PROTO_SSP:			res = asd_build_ssp_ascb(a, t, gfp_flags);			break;		default:			asd_printk("unknown sas_task proto: 0x%x\n",				   t->task_proto);			res = -ENOMEM;			break;		}		if (res)			goto out_err_unmap;		spin_lock_irqsave(&t->task_state_lock, flags);		t->task_state_flags |= SAS_TASK_AT_INITIATOR;		spin_unlock_irqrestore(&t->task_state_lock, flags);	}	list_del_init(&alist);	res = asd_post_ascb_list(asd_ha, ascb, num);	if (unlikely(res)) {		a = NULL;		__list_add(&alist, ascb->list.prev, &ascb->list);		goto out_err_unmap;	}	return 0;out_err_unmap:	{		struct asd_ascb *b = a;		list_for_each_entry(a, &alist, list) {			if (a == b)				break;			t = a->uldd_task;			spin_lock_irqsave(&t->task_state_lock, flags);			t->task_state_flags &= ~SAS_TASK_AT_INITIATOR;			spin_unlock_irqrestore(&t->task_state_lock, flags);			switch (t->task_proto) {			case SATA_PROTO:			case SAS_PROTO_STP:				asd_unbuild_ata_ascb(a);				break;			case SAS_PROTO_SMP:				asd_unbuild_smp_ascb(a);				break;			case SAS_PROTO_SSP:				asd_unbuild_ssp_ascb(a);			default:				break;			}			t->lldd_task = NULL;		}	}	list_del_init(&alist);out_err:	if (ascb)		asd_ascb_free_list(ascb);	asd_can_dequeue(asd_ha, num);	return res;}

⌨️ 快捷键说明

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