inia100.c

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

C
581
字号
/************************************************************************** * Initio A100 device driver for Linux. * * Copyright (c) 1994-1998 Initio Corporation * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING.  If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * * -------------------------------------------------------------------------- * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions, and the following disclaimer, *    without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products *    derived from this software without specific prior written permission. * * Where this Software is combined with software released under the terms of  * the GNU General Public License ("GPL") and the terms of the GPL would require the  * combined work to also be released under the terms of the GPL, the terms * and conditions of this License will apply in addition to those of the * GPL with the exception of any terms or conditions of this License that * conflict with, or are expressly prohibited by, the GPL. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ************************************************************************** *  * module: inia100.c * DESCRIPTION: * 	This is the Linux low-level SCSI driver for Initio INIA100 SCSI host * 	adapters * 09/24/98 hl - v1.02 initial production release. * 12/19/98 bv - v1.02a Use spinlocks for 2.1.95 and up. * 06/25/02 Doug Ledford <dledford@redhat.com> - v1.02d *          - Remove limit on number of controllers *          - Port to DMA mapping API *          - Clean up interrupt handler registration *          - Fix memory leaks *          - Fix allocation of scsi host structs and private data * 18/11/03 Christoph Hellwig <hch@lst.de> *	    - Port to new probing API *	    - Fix some more leaks in init failure cases * TODO: *	    - use list.h macros for SCB queue *	  ( - merge with i60uscsi.c ) **************************************************************************/#include <linux/module.h>#include <linux/errno.h>#include <linux/delay.h>#include <linux/interrupt.h>#include <linux/pci.h>#include <linux/init.h>#include <linux/blkdev.h>#include <linux/spinlock.h>#include <linux/kernel.h>#include <linux/string.h>#include <linux/ioport.h>#include <linux/slab.h>#include <asm/io.h>#include <asm/irq.h>#include <scsi/scsi.h>#include <scsi/scsi_cmnd.h>#include <scsi/scsi_device.h>#include <scsi/scsi_host.h>#include "inia100.h"#define ORC_RDWORD(x,y)         (short)(inl((int)((ULONG)((ULONG)x+(UCHAR)y)) ))char *inia100_Copyright = "Copyright (C) 1998-99";char *inia100_InitioName = "by Initio Corporation";char *inia100_ProductName = "INI-A100U2W";char *inia100_Version = "v1.02d";/* ---- EXTERNAL FUNCTIONS ---- */extern void inia100SCBPost(BYTE * pHcb, BYTE * pScb);extern int init_inia100Adapter_table(int);extern ORC_SCB *orc_alloc_scb(ORC_HCS * hcsp);extern void orc_exec_scb(ORC_HCS * hcsp, ORC_SCB * scbp);extern void orc_release_scb(ORC_HCS * hcsp, ORC_SCB * scbp);extern void orc_release_dma(ORC_HCS * hcsp, struct scsi_cmnd * cmnd);extern void orc_interrupt(ORC_HCS * hcsp);extern int orc_device_reset(ORC_HCS * pHCB, struct scsi_cmnd *SCpnt, unsigned int target);extern int orc_reset_scsi_bus(ORC_HCS * pHCB);extern int abort_SCB(ORC_HCS * hcsp, ORC_SCB * pScb);extern int orc_abort_srb(ORC_HCS * hcsp, struct scsi_cmnd *SCpnt);extern int init_orchid(ORC_HCS * hcsp);/***************************************************************************** Function name  : inia100AppendSRBToQueue Description    : This function will push current request into save list Input          : pSRB  -       Pointer to SCSI request block.		  pHCB  -       Pointer to host adapter structure Output         : None. Return         : None.*****************************************************************************/static void inia100AppendSRBToQueue(ORC_HCS * pHCB, struct scsi_cmnd * pSRB){	ULONG flags;	spin_lock_irqsave(&(pHCB->pSRB_lock), flags);	pSRB->SCp.ptr = NULL;	/* Pointer to next */	if (pHCB->pSRB_head == NULL)		pHCB->pSRB_head = pSRB;	else		pHCB->pSRB_tail->SCp.ptr = (char *)pSRB;	/* Pointer to next */	pHCB->pSRB_tail = pSRB;	spin_unlock_irqrestore(&(pHCB->pSRB_lock), flags);	return;}/***************************************************************************** Function name  : inia100PopSRBFromQueue Description    : This function will pop current request from save list Input          : pHCB  -       Pointer to host adapter structure Output         : None. Return         : pSRB  -       Pointer to SCSI request block.*****************************************************************************/static struct scsi_cmnd *inia100PopSRBFromQueue(ORC_HCS * pHCB){	struct scsi_cmnd *pSRB;	ULONG flags;	spin_lock_irqsave(&(pHCB->pSRB_lock), flags);	if ((pSRB = (struct scsi_cmnd *) pHCB->pSRB_head) != NULL) {		pHCB->pSRB_head = (struct scsi_cmnd *) pHCB->pSRB_head->SCp.ptr;		pSRB->SCp.ptr = NULL;	}	spin_unlock_irqrestore(&(pHCB->pSRB_lock), flags);	return (pSRB);}/***************************************************************************** Function name  : inia100BuildSCB Description    :  Input          : pHCB  -       Pointer to host adapter structure Output         : None. Return         : pSRB  -       Pointer to SCSI request block.*****************************************************************************/static void inia100BuildSCB(ORC_HCS * pHCB, ORC_SCB * pSCB, struct scsi_cmnd * SCpnt){				/* Create corresponding SCB     */	struct scatterlist *pSrbSG;	ORC_SG *pSG;		/* Pointer to SG list           */	int i, count_sg;	U32 TotalLen;	ESCB *pEScb;	pEScb = pSCB->SCB_EScb;	pEScb->SCB_Srb = SCpnt;	pSG = NULL;	pSCB->SCB_Opcode = ORC_EXECSCSI;	pSCB->SCB_Flags = SCF_NO_DCHK;	/* Clear done bit               */	pSCB->SCB_Target = SCpnt->device->id;	pSCB->SCB_Lun = SCpnt->device->lun;	pSCB->SCB_Reserved0 = 0;	pSCB->SCB_Reserved1 = 0;	pSCB->SCB_SGLen = 0;	if ((pSCB->SCB_XferLen = (U32) SCpnt->request_bufflen)) {		pSG = (ORC_SG *) & pEScb->ESCB_SGList[0];		if (SCpnt->use_sg) {			TotalLen = 0;			pSrbSG = (struct scatterlist *) SCpnt->request_buffer;			count_sg = pci_map_sg(pHCB->pdev, pSrbSG, SCpnt->use_sg,					SCpnt->sc_data_direction);			pSCB->SCB_SGLen = (U32) (count_sg * 8);			for (i = 0; i < count_sg; i++, pSG++, pSrbSG++) {				pSG->SG_Ptr = (U32) sg_dma_address(pSrbSG);				pSG->SG_Len = (U32) sg_dma_len(pSrbSG);				TotalLen += (U32) sg_dma_len(pSrbSG);			}		} else if (SCpnt->request_bufflen != 0) {/* Non SG */			pSCB->SCB_SGLen = 0x8;			pSG->SG_Ptr = (U32) pci_map_single(pHCB->pdev,				SCpnt->request_buffer, SCpnt->request_bufflen,				SCpnt->sc_data_direction);			SCpnt->host_scribble = (void *)pSG->SG_Ptr;			pSG->SG_Len = (U32) SCpnt->request_bufflen;		} else {			pSCB->SCB_SGLen = 0;			pSG->SG_Ptr = 0;			pSG->SG_Len = 0;		}	}	pSCB->SCB_SGPAddr = (U32) pSCB->SCB_SensePAddr;	pSCB->SCB_HaStat = 0;	pSCB->SCB_TaStat = 0;	pSCB->SCB_Link = 0xFF;	pSCB->SCB_SenseLen = SENSE_SIZE;	pSCB->SCB_CDBLen = SCpnt->cmd_len;	if (pSCB->SCB_CDBLen >= IMAX_CDB) {		printk("max cdb length= %x\b", SCpnt->cmd_len);		pSCB->SCB_CDBLen = IMAX_CDB;	}	pSCB->SCB_Ident = SCpnt->device->lun | DISC_ALLOW;	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               */	}	memcpy(&pSCB->SCB_CDB[0], &SCpnt->cmnd, pSCB->SCB_CDBLen);	return;}/***************************************************************************** Function name  : inia100_queue Description    : Queue a command and setup interrupts for a free bus. Input          : pHCB  -       Pointer to host adapter structure Output         : None. Return         : pSRB  -       Pointer to SCSI request block.*****************************************************************************/static int inia100_queue(struct scsi_cmnd * SCpnt, void (*done) (struct scsi_cmnd *)){	register ORC_SCB *pSCB;	ORC_HCS *pHCB;		/* Point to Host adapter control block */	pHCB = (ORC_HCS *) SCpnt->device->host->hostdata;	SCpnt->scsi_done = done;	/* Get free SCSI control block  */	if ((pSCB = orc_alloc_scb(pHCB)) == NULL) {		inia100AppendSRBToQueue(pHCB, SCpnt);	/* Buffer this request  */		/* printk("inia100_entry: can't allocate SCB\n"); */		return (0);	}	inia100BuildSCB(pHCB, pSCB, SCpnt);	orc_exec_scb(pHCB, pSCB);	/* Start execute SCB            */	return (0);}/***************************************************************************** Function name  : inia100_abort Description    : Abort a queued command.	                 (commands that are on the bus can't be aborted easily) Input          : pHCB  -       Pointer to host adapter structure Output         : None. Return         : pSRB  -       Pointer to SCSI request block.*****************************************************************************/static int inia100_abort(struct scsi_cmnd * SCpnt){	ORC_HCS *hcsp;	hcsp = (ORC_HCS *) SCpnt->device->host->hostdata;	return orc_abort_srb(hcsp, SCpnt);}/***************************************************************************** Function name  : inia100_reset Description    : Reset registers, reset a hanging bus and                  kill active and disconnected commands for target w/o soft reset Input          : pHCB  -       Pointer to host adapter structure Output         : None. Return         : pSRB  -       Pointer to SCSI request block.*****************************************************************************/static int inia100_bus_reset(struct scsi_cmnd * SCpnt){				/* I need Host Control Block Information */	ORC_HCS *pHCB;	pHCB = (ORC_HCS *) SCpnt->device->host->hostdata;	return orc_reset_scsi_bus(pHCB);}

⌨️ 快捷键说明

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