ini9100u.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 728 行 · 第 1/2 页

C
728
字号
		tul_num_scb = MAX_TARGETS * i91u_MAXQUEUE;	} else {		tul_num_scb = MAX_TARGETS + 3;	/* 1-tape, 1-CD_ROM, 1- extra */	}			/* Update actually SCBs per adapter */	/* Get total memory needed for HCS */	i = tul_num_ch * sizeof(HCS);	memset((unsigned char *) &tul_hcs[0], 0, i);	/* Initialize tul_hcs 0 */	/* Get total memory needed for SCB */	for (; tul_num_scb >= MAX_TARGETS + 3; tul_num_scb--) {		i = tul_num_ch * tul_num_scb * sizeof(SCB);		if ((tul_scb = (SCB *) kmalloc(i, GFP_ATOMIC | GFP_DMA)) != NULL)			break;	}	if (tul_scb == NULL) {		printk("i91u: SCB memory allocation error\n");		return (0);	}	memset((unsigned char *) tul_scb, 0, i);	for (i = 0, pHCB = &tul_hcs[0];		/* Get pointer for control block */	     i < tul_num_ch;	     i++, pHCB++) {		pHCB->pSRB_head = NULL;		/* Initial SRB save queue       */		pHCB->pSRB_tail = NULL;		/* Initial SRB save queue       */		pHCB->pSRB_lock = SPIN_LOCK_UNLOCKED;	/* SRB save queue lock */		get_tulipPCIConfig(pHCB, i);		dBiosAdr = pHCB->HCS_BIOS;		dBiosAdr = (dBiosAdr << 4);		pbBiosAdr = phys_to_virt(dBiosAdr);		init_tulip(pHCB, tul_scb + (i * tul_num_scb), tul_num_scb, pbBiosAdr, 10);		request_region(pHCB->HCS_Base, 256, "i91u"); /* Register */ 		pHCB->HCS_Index = i;	/* 7/29/98 */		hreg = scsi_register(tpnt, sizeof(HCS));		if(hreg == NULL) {			release_region(pHCB->HCS_Base, 256);			return 0;		}		hreg->io_port = pHCB->HCS_Base;		hreg->n_io_port = 0xff;		hreg->can_queue = tul_num_scb;	/* 03/05/98                      */		hreg->unique_id = pHCB->HCS_Base;		hreg->max_id = pHCB->HCS_MaxTar;		hreg->max_lun = 32;	/* 10/21/97                     */		hreg->irq = pHCB->HCS_Intr;		hreg->this_id = pHCB->HCS_SCSI_ID;	/* Assign HCS index           */		hreg->base = (unsigned long)pHCB;		hreg->sg_tablesize = TOTAL_SG_ENTRY;	/* Maximun support is 32 */		/* Initial tulip chip           */		ok = request_irq(pHCB->HCS_Intr, i91u_intr, SA_INTERRUPT | SA_SHIRQ, "i91u", hreg);		if (ok < 0) {			printk(KERN_WARNING "i91u: unable to request IRQ %d\n\n", pHCB->HCS_Intr);			return 0;		}	}	tpnt->this_id = -1;	tpnt->can_queue = 1;	return 1;}static void i91uBuildSCB(HCS * pHCB, SCB * pSCB, Scsi_Cmnd * SCpnt){				/* Create corresponding SCB     */	struct scatterlist *pSrbSG;	SG *pSG;		/* Pointer to SG list           */	int i;	long TotalLen;	dma_addr_t dma_addr;	pSCB->SCB_Post = i91uSCBPost;	/* i91u's callback routine      */	pSCB->SCB_Srb = SCpnt;	pSCB->SCB_Opcode = ExecSCSI;	pSCB->SCB_Flags = SCF_POST;	/* After SCSI done, call post routine */	pSCB->SCB_Target = SCpnt->device->id;	pSCB->SCB_Lun = SCpnt->device->lun;	pSCB->SCB_Ident = SCpnt->device->lun | DISC_ALLOW;	pSCB->SCB_Flags |= SCF_SENSE;	/* Turn on auto request sense   */	dma_addr = dma_map_single(&pHCB->pci_dev->dev, SCpnt->sense_buffer,				  SENSE_SIZE, DMA_FROM_DEVICE);	pSCB->SCB_SensePtr = cpu_to_le32((u32)dma_addr);	pSCB->SCB_SenseLen = cpu_to_le32(SENSE_SIZE);	SCpnt->SCp.ptr = (char *)(unsigned long)dma_addr;	pSCB->SCB_CDBLen = SCpnt->cmd_len;	pSCB->SCB_HaStat = 0;	pSCB->SCB_TaStat = 0;	memcpy(&pSCB->SCB_CDB[0], &SCpnt->cmnd, SCpnt->cmd_len);	if (SCpnt->device->tagged_supported) {	/* Tag Support                  */		pSCB->SCB_TagMsg = SIMPLE_QUEUE_TAG;	/* Do simple tag only   */	} else {		pSCB->SCB_TagMsg = 0;	/* No tag support               */	}	/* todo handle map_sg error */	if (SCpnt->use_sg) {		dma_addr = dma_map_single(&pHCB->pci_dev->dev, &pSCB->SCB_SGList[0],					  sizeof(struct SG_Struc) * TOTAL_SG_ENTRY,					  DMA_BIDIRECTIONAL);		pSCB->SCB_BufPtr = cpu_to_le32((u32)dma_addr);		SCpnt->SCp.dma_handle = dma_addr;		pSrbSG = (struct scatterlist *) SCpnt->request_buffer;		pSCB->SCB_SGLen = dma_map_sg(&pHCB->pci_dev->dev, pSrbSG,					     SCpnt->use_sg, SCpnt->sc_data_direction);		pSCB->SCB_Flags |= SCF_SG;	/* Turn on SG list flag       */		for (i = 0, TotalLen = 0, pSG = &pSCB->SCB_SGList[0];	/* 1.01g */		     i < pSCB->SCB_SGLen; i++, pSG++, pSrbSG++) {			pSG->SG_Ptr = cpu_to_le32((u32)sg_dma_address(pSrbSG));			TotalLen += pSG->SG_Len = cpu_to_le32((u32)sg_dma_len(pSrbSG));		}		pSCB->SCB_BufLen = (SCpnt->request_bufflen > TotalLen) ?		    TotalLen : SCpnt->request_bufflen;	} else if (SCpnt->request_bufflen) {		/* Non SG */		dma_addr = dma_map_single(&pHCB->pci_dev->dev, SCpnt->request_buffer,					  SCpnt->request_bufflen,					  SCpnt->sc_data_direction);		SCpnt->SCp.dma_handle = dma_addr;		pSCB->SCB_BufPtr = cpu_to_le32((u32)dma_addr);		pSCB->SCB_BufLen = cpu_to_le32((u32)SCpnt->request_bufflen);		pSCB->SCB_SGLen = 0;	} else {		pSCB->SCB_BufLen = 0;		pSCB->SCB_SGLen = 0;	}}/*  *  Queue a command and setup interrupts for a free bus. */int i91u_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)){	register SCB *pSCB;	HCS *pHCB;		/* Point to Host adapter control block */	if (SCpnt->device->lun > 16) {	/* 07/22/98 */		SCpnt->result = (DID_TIME_OUT << 16);		done(SCpnt);	/* Notify system DONE           */		return (0);	}	pHCB = (HCS *) SCpnt->device->host->base;	SCpnt->scsi_done = done;	/* Get free SCSI control block  */	if ((pSCB = tul_alloc_scb(pHCB)) == NULL) {		i91uAppendSRBToQueue(pHCB, SCpnt);	/* Buffer this request  */		return (0);	}	i91uBuildSCB(pHCB, pSCB, SCpnt);	tul_exec_scb(pHCB, pSCB);	/* Start execute SCB            */	return (0);}/* *  Abort a queued command *  (commands that are on the bus can't be aborted easily) */int i91u_abort(Scsi_Cmnd * SCpnt){	HCS *pHCB;	pHCB = (HCS *) SCpnt->device->host->base;	return tul_abort_srb(pHCB, SCpnt);}/* *  Reset registers, reset a hanging bus and *  kill active and disconnected commands for target w/o soft reset */int i91u_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags){				/* I need Host Control Block Information */	HCS *pHCB;	pHCB = (HCS *) SCpnt->device->host->base;	if (reset_flags & (SCSI_RESET_SUGGEST_BUS_RESET | SCSI_RESET_SUGGEST_HOST_RESET))		return tul_reset_scsi_bus(pHCB);	else		return tul_device_reset(pHCB, (ULONG) SCpnt, SCpnt->device->id, reset_flags);}int i91u_bus_reset(Scsi_Cmnd * SCpnt){	HCS *pHCB;	pHCB = (HCS *) SCpnt->device->host->base;	tul_reset_scsi(pHCB, 0);	return SUCCESS;}/* * Return the "logical geometry" */int i91u_biosparam(struct scsi_device *sdev, struct block_device *dev,		sector_t capacity, int *info_array){	HCS *pHcb;		/* Point to Host adapter control block */	TCS *pTcb;	pHcb = (HCS *) sdev->host->base;	pTcb = &pHcb->HCS_Tcs[sdev->id];	if (pTcb->TCS_DrvHead) {		info_array[0] = pTcb->TCS_DrvHead;		info_array[1] = pTcb->TCS_DrvSector;		info_array[2] = (unsigned long)capacity / pTcb->TCS_DrvHead / pTcb->TCS_DrvSector;	} else {		if (pTcb->TCS_DrvFlags & TCF_DRV_255_63) {			info_array[0] = 255;			info_array[1] = 63;			info_array[2] = (unsigned long)capacity / 255 / 63;		} else {			info_array[0] = 64;			info_array[1] = 32;			info_array[2] = (unsigned long)capacity >> 11;		}	}#if defined(DEBUG_BIOSPARAM)	if (i91u_debug & debug_biosparam) {		printk("bios geometry: head=%d, sec=%d, cyl=%d\n",		       info_array[0], info_array[1], info_array[2]);		printk("WARNING: check, if the bios geometry is correct.\n");	}#endif	return 0;}static void i91u_unmap_cmnd(struct pci_dev *pci_dev, struct scsi_cmnd *cmnd){	/* auto sense buffer */	if (cmnd->SCp.ptr) {		dma_unmap_single(&pci_dev->dev,				 (dma_addr_t)((unsigned long)cmnd->SCp.ptr),				 SENSE_SIZE, SCSI_DATA_READ);		cmnd->SCp.ptr = NULL;	}	/* request buffer */	if (cmnd->use_sg) {		dma_unmap_single(&pci_dev->dev, cmnd->SCp.dma_handle,				 sizeof(struct SG_Struc) * TOTAL_SG_ENTRY,				 DMA_BIDIRECTIONAL);		dma_unmap_sg(&pci_dev->dev, cmnd->request_buffer,			     cmnd->use_sg,			     cmnd->sc_data_direction);	} else if (cmnd->request_bufflen) {		dma_unmap_single(&pci_dev->dev, cmnd->SCp.dma_handle,				 cmnd->request_bufflen,				 cmnd->sc_data_direction);	}}/***************************************************************************** Function name  : i91uSCBPost Description    : This is callback routine be called when tulip finish one			SCSI command. Input          : pHCB  -       Pointer to host adapter control block.		  pSCB  -       Pointer to SCSI control block. Output         : None. Return         : None.*****************************************************************************/static void i91uSCBPost(BYTE * pHcb, BYTE * pScb){	Scsi_Cmnd *pSRB;	/* Pointer to SCSI request block */	HCS *pHCB;	SCB *pSCB;	pHCB = (HCS *) pHcb;	pSCB = (SCB *) pScb;	if ((pSRB = pSCB->SCB_Srb) == 0) {		printk("i91uSCBPost: SRB pointer is empty\n");		tul_release_scb(pHCB, pSCB);	/* Release SCB for current channel */		return;	}	switch (pSCB->SCB_HaStat) {	case 0x0:	case 0xa:		/* Linked command complete without error and linked normally */	case 0xb:		/* Linked command complete without error interrupt generated */		pSCB->SCB_HaStat = 0;		break;	case 0x11:		/* Selection time out-The initiator selection or target				   reselection was not complete within the SCSI Time out period */		pSCB->SCB_HaStat = DID_TIME_OUT;		break;	case 0x14:		/* Target bus phase sequence failure-An invalid bus phase or bus				   phase sequence was requested by the target. The host adapter				   will generate a SCSI Reset Condition, notifying the host with				   a SCRD interrupt */		pSCB->SCB_HaStat = DID_RESET;		break;	case 0x1a:		/* SCB Aborted. 07/21/98 */		pSCB->SCB_HaStat = DID_ABORT;		break;	case 0x12:		/* Data overrun/underrun-The target attempted to transfer more data				   than was allocated by the Data Length field or the sum of the				   Scatter / Gather Data Length fields. */	case 0x13:		/* Unexpected bus free-The target dropped the SCSI BSY at an unexpected time. */	case 0x16:		/* Invalid SCB Operation Code. */	default:		printk("ini9100u: %x %x\n", pSCB->SCB_HaStat, pSCB->SCB_TaStat);		pSCB->SCB_HaStat = DID_ERROR;	/* Couldn't find any better */		break;	}	pSRB->result = pSCB->SCB_TaStat | (pSCB->SCB_HaStat << 16);	if (pSRB == NULL) {		printk("pSRB is NULL\n");	}	i91u_unmap_cmnd(pHCB->pci_dev, pSRB);	pSRB->scsi_done(pSRB);	/* Notify system DONE           */	if ((pSRB = i91uPopSRBFromQueue(pHCB)) != NULL)		/* Find the next pending SRB    */	{			/* Assume resend will success   */		/* Reuse old SCB                */		i91uBuildSCB(pHCB, pSCB, pSRB);		/* Create corresponding SCB     */		tul_exec_scb(pHCB, pSCB);	/* Start execute SCB            */	} else {		/* No Pending SRB               */		tul_release_scb(pHCB, pSCB);	/* Release SCB for current channel */	}	return;}/*  * Dump the current driver status and panic... */static void i91u_panic(char *msg){	printk("\ni91u_panic: %s\n", msg);	panic("i91u panic");}/* * Release ressources */int i91u_release(struct Scsi_Host *hreg){	free_irq(hreg->irq, hreg);	release_region(hreg->io_port, 256);	return 0;}MODULE_LICENSE("Dual BSD/GPL");

⌨️ 快捷键说明

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