aha152x.c

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

C
2,512
字号
	   previous state,	   last state different from current state */	enum aha152x_state state, prevstate, laststate;	int target;		/* reconnecting target */	unsigned char syncrate[8];		/* current synchronous transfer agreements */	unsigned char syncneg[8];		/* 0: no negotiation;		 * 1: negotiation in progress;		 * 2: negotiation completed		 */	int cmd_i;		/* number of sent bytes of current command */	int msgi_len;		/* number of received message bytes */	unsigned char msgi[256];		/* received message bytes */	int msgo_i, msgo_len;			/* number of sent bytes and length of current messages */	unsigned char msgo[256];		/* pending messages */	int data_len;		/* number of sent/received bytes in dataphase */	unsigned long io_port0;	unsigned long io_port1;#ifdef __ISAPNP__	struct pnp_dev *pnpdev;#endif};/* * host specific command extension * */struct aha152x_scdata {	Scsi_Cmnd *next;	/* next sc in queue */	struct semaphore *sem;	/* semaphore to block on */};/* access macros for hostdata */#define HOSTDATA(shpnt)		((struct aha152x_hostdata *) &shpnt->hostdata)#define HOSTNO			((shpnt)->host_no)#define CURRENT_SC		(HOSTDATA(shpnt)->current_SC)#define DONE_SC			(HOSTDATA(shpnt)->done_SC)#define ISSUE_SC		(HOSTDATA(shpnt)->issue_SC)#define DISCONNECTED_SC		(HOSTDATA(shpnt)->disconnected_SC)#define QLOCK			(HOSTDATA(shpnt)->lock)#define QLOCKER			(HOSTDATA(shpnt)->locker)#define QLOCKERL		(HOSTDATA(shpnt)->lockerl)#define STATE			(HOSTDATA(shpnt)->state)#define PREVSTATE		(HOSTDATA(shpnt)->prevstate)#define LASTSTATE		(HOSTDATA(shpnt)->laststate)#define RECONN_TARGET		(HOSTDATA(shpnt)->target)#define CMD_I			(HOSTDATA(shpnt)->cmd_i)#define MSGO(i)			(HOSTDATA(shpnt)->msgo[i])#define MSGO_I			(HOSTDATA(shpnt)->msgo_i)#define MSGOLEN			(HOSTDATA(shpnt)->msgo_len)#define ADDMSGO(x)		(MSGOLEN<256 ? (void)(MSGO(MSGOLEN++)=x) : aha152x_error(shpnt,"MSGO overflow"))#define MSGI(i)			(HOSTDATA(shpnt)->msgi[i])#define MSGILEN			(HOSTDATA(shpnt)->msgi_len)#define ADDMSGI(x)		(MSGILEN<256 ? (void)(MSGI(MSGILEN++)=x) : aha152x_error(shpnt,"MSGI overflow"))#define DATA_LEN		(HOSTDATA(shpnt)->data_len)#define SYNCRATE		(HOSTDATA(shpnt)->syncrate[CURRENT_SC->device->id])#define SYNCNEG			(HOSTDATA(shpnt)->syncneg[CURRENT_SC->device->id])#define DELAY			(HOSTDATA(shpnt)->delay)#define EXT_TRANS		(HOSTDATA(shpnt)->ext_trans)#define TC1550			(HOSTDATA(shpnt)->tc1550)#define RECONNECT		(HOSTDATA(shpnt)->reconnect)#define PARITY			(HOSTDATA(shpnt)->parity)#define SYNCHRONOUS		(HOSTDATA(shpnt)->synchronous)#define HOSTIOPORT0		(HOSTDATA(shpnt)->io_port0)#define HOSTIOPORT1		(HOSTDATA(shpnt)->io_port1)#define SCDATA(SCpnt)		((struct aha152x_scdata *) (SCpnt)->host_scribble)#define SCNEXT(SCpnt)		SCDATA(SCpnt)->next#define SCSEM(SCpnt)		SCDATA(SCpnt)->sem#define SG_ADDRESS(buffer)	((char *) (page_address((buffer)->page)+(buffer)->offset))/* state handling */static void seldi_run(struct Scsi_Host *shpnt);static void seldo_run(struct Scsi_Host *shpnt);static void selto_run(struct Scsi_Host *shpnt);static void busfree_run(struct Scsi_Host *shpnt);static void msgo_init(struct Scsi_Host *shpnt);static void msgo_run(struct Scsi_Host *shpnt);static void msgo_end(struct Scsi_Host *shpnt);static void cmd_init(struct Scsi_Host *shpnt);static void cmd_run(struct Scsi_Host *shpnt);static void cmd_end(struct Scsi_Host *shpnt);static void datai_init(struct Scsi_Host *shpnt);static void datai_run(struct Scsi_Host *shpnt);static void datai_end(struct Scsi_Host *shpnt);static void datao_init(struct Scsi_Host *shpnt);static void datao_run(struct Scsi_Host *shpnt);static void datao_end(struct Scsi_Host *shpnt);static void status_run(struct Scsi_Host *shpnt);static void msgi_run(struct Scsi_Host *shpnt);static void msgi_end(struct Scsi_Host *shpnt);static void parerr_run(struct Scsi_Host *shpnt);static void rsti_run(struct Scsi_Host *shpnt);static void is_complete(struct Scsi_Host *shpnt);/* * driver states * */static struct {	char		*name;	void		(*init)(struct Scsi_Host *);	void		(*run)(struct Scsi_Host *);	void		(*end)(struct Scsi_Host *);	int		spio;} states[] = {	{ "idle",	NULL,		NULL,		NULL,		0},	{ "unknown",	NULL,		NULL,		NULL,		0},	{ "seldo",	NULL,		seldo_run,	NULL,		0},	{ "seldi",	NULL,		seldi_run,	NULL,		0},	{ "selto",	NULL,		selto_run,	NULL,		0},	{ "busfree",	NULL,		busfree_run,	NULL,		0},	{ "msgo",	msgo_init,	msgo_run,	msgo_end,	1},	{ "cmd",	cmd_init,	cmd_run,	cmd_end,	1},	{ "msgi",	NULL,		msgi_run,	msgi_end,	1},	{ "status",	NULL,		status_run,	NULL,		1},	{ "datai",	datai_init,	datai_run,	datai_end,	0},	{ "datao",	datao_init,	datao_run,	datao_end,	0},	{ "parerr",	NULL,		parerr_run,	NULL,		0},	{ "rsti",	NULL,		rsti_run,	NULL,		0},};/* setup & interrupt */static irqreturn_t intr(int irq, void *dev_id, struct pt_regs *);static void reset_ports(struct Scsi_Host *shpnt);static void aha152x_error(struct Scsi_Host *shpnt, char *msg);static void done(struct Scsi_Host *shpnt, int error);/* diagnostics */static void disp_ports(struct Scsi_Host *shpnt);static void show_command(Scsi_Cmnd * ptr);static void show_queues(struct Scsi_Host *shpnt);static void disp_enintr(struct Scsi_Host *shpnt);/* *  queue services: * */static inline void append_SC(Scsi_Cmnd **SC, Scsi_Cmnd *new_SC){	Scsi_Cmnd *end;	SCNEXT(new_SC) = NULL;	if (!*SC)		*SC = new_SC;	else {		for (end = *SC; SCNEXT(end); end = SCNEXT(end))			;		SCNEXT(end) = new_SC;	}}static inline Scsi_Cmnd *remove_first_SC(Scsi_Cmnd ** SC){	Scsi_Cmnd *ptr;	ptr = *SC;	if (ptr) {		*SC = SCNEXT(*SC);		SCNEXT(ptr)=NULL;	}	return ptr;}static inline Scsi_Cmnd *remove_lun_SC(Scsi_Cmnd ** SC, int target, int lun){	Scsi_Cmnd *ptr, *prev;	for (ptr = *SC, prev = NULL;	     ptr && ((ptr->device->id != target) || (ptr->device->lun != lun));	     prev = ptr, ptr = SCNEXT(ptr))	     ;	if (ptr) {		if (prev)			SCNEXT(prev) = SCNEXT(ptr);		else			*SC = SCNEXT(ptr);		SCNEXT(ptr)=NULL;	}	return ptr;}static inline Scsi_Cmnd *remove_SC(Scsi_Cmnd **SC, Scsi_Cmnd *SCp){	Scsi_Cmnd *ptr, *prev;	for (ptr = *SC, prev = NULL;	     ptr && SCp!=ptr;	     prev = ptr, ptr = SCNEXT(ptr))	     ;	if (ptr) {		if (prev)			SCNEXT(prev) = SCNEXT(ptr);		else			*SC = SCNEXT(ptr);		SCNEXT(ptr)=NULL;	}	return ptr;}static inline struct Scsi_Host *lookup_irq(int irqno){	int i;	for(i=0; i<ARRAY_SIZE(aha152x_host); i++)		if(aha152x_host[i] && aha152x_host[i]->irq==irqno)			return aha152x_host[i];	return NULL;}static irqreturn_t swintr(int irqno, void *dev_id, struct pt_regs *regs){	struct Scsi_Host *shpnt = lookup_irq(irqno);	if (!shpnt) {        	printk(KERN_ERR "aha152x: catched software interrupt %d for unknown controller.\n", irqno);		return IRQ_NONE;	}	HOSTDATA(shpnt)->swint++;	SETPORT(DMACNTRL0, INTEN);	return IRQ_HANDLED;}struct Scsi_Host *aha152x_probe_one(struct aha152x_setup *setup){	struct Scsi_Host *shpnt;	shpnt = scsi_host_alloc(&aha152x_driver_template, sizeof(struct aha152x_hostdata));	if (!shpnt) {		printk(KERN_ERR "aha152x: scsi_host_alloc failed\n");		return NULL;	}	/* need to have host registered before triggering any interrupt */	aha152x_host[registered_count] = shpnt;	memset(HOSTDATA(shpnt), 0, sizeof *HOSTDATA(shpnt));	shpnt->io_port   = setup->io_port;	shpnt->n_io_port = IO_RANGE;	shpnt->irq       = setup->irq;	if (!setup->tc1550) {		HOSTIOPORT0 = setup->io_port;		HOSTIOPORT1 = setup->io_port;	} else {		HOSTIOPORT0 = setup->io_port+0x10;		HOSTIOPORT1 = setup->io_port-0x10;	}	spin_lock_init(&QLOCK);	RECONNECT   = setup->reconnect;	SYNCHRONOUS = setup->synchronous;	PARITY      = setup->parity;	DELAY       = setup->delay;	EXT_TRANS   = setup->ext_trans;#if defined(AHA152X_DEBUG)	HOSTDATA(shpnt)->debug = setup->debug;#endif	SETPORT(SCSIID, setup->scsiid << 4);	shpnt->this_id = setup->scsiid;	if (setup->reconnect)		shpnt->can_queue = AHA152X_MAXQUEUE;	/* RESET OUT */	printk("aha152x: resetting bus...\n");	SETPORT(SCSISEQ, SCSIRSTO);	mdelay(256);	SETPORT(SCSISEQ, 0);	mdelay(DELAY);	reset_ports(shpnt);	printk(KERN_INFO	       "aha152x%d%s: "	       "vital data: rev=%x, "	       "io=0x%03lx (0x%03lx/0x%03lx), "	       "irq=%d, "	       "scsiid=%d, "	       "reconnect=%s, "	       "parity=%s, "	       "synchronous=%s, "	       "delay=%d, "	       "extended translation=%s\n",	       shpnt->host_no, setup->tc1550 ? " (tc1550 mode)" : "",	       GETPORT(REV) & 0x7,	       shpnt->io_port, HOSTIOPORT0, HOSTIOPORT1,	       shpnt->irq,	       shpnt->this_id,	       RECONNECT ? "enabled" : "disabled",	       PARITY ? "enabled" : "disabled",	       SYNCHRONOUS ? "enabled" : "disabled",	       DELAY,	       EXT_TRANS ? "enabled" : "disabled");	/* not expecting any interrupts */	SETPORT(SIMODE0, 0);	SETPORT(SIMODE1, 0);	if( request_irq(shpnt->irq, swintr, SA_INTERRUPT|SA_SHIRQ, "aha152x", shpnt) ) {		printk(KERN_ERR "aha152x%d: irq %d busy.\n", shpnt->host_no, shpnt->irq);		goto out_host_put;	}	HOSTDATA(shpnt)->swint = 0;	printk(KERN_INFO "aha152x%d: trying software interrupt, ", shpnt->host_no);	mb();	SETPORT(DMACNTRL0, SWINT|INTEN);	mdelay(1000);	free_irq(shpnt->irq, shpnt);	if (!HOSTDATA(shpnt)->swint) {		if (TESTHI(DMASTAT, INTSTAT)) {			printk("lost.\n");		} else {			printk("failed.\n");		}		SETPORT(DMACNTRL0, INTEN);		printk(KERN_ERR "aha152x%d: irq %d possibly wrong.  "				"Please verify.\n", shpnt->host_no, shpnt->irq);		goto out_host_put;	}	printk("ok.\n");	/* clear interrupts */	SETPORT(SSTAT0, 0x7f);	SETPORT(SSTAT1, 0xef);	if ( request_irq(shpnt->irq, intr, SA_INTERRUPT|SA_SHIRQ, "aha152x", shpnt) ) {		printk(KERN_ERR "aha152x%d: failed to reassign irq %d.\n", shpnt->host_no, shpnt->irq);		goto out_host_put;	}	if( scsi_add_host(shpnt, NULL) ) {		free_irq(shpnt->irq, shpnt);		printk(KERN_ERR "aha152x%d: failed to add host.\n", shpnt->host_no);		goto out_host_put;	}	scsi_scan_host(shpnt);	registered_count++;	return shpnt;out_host_put:	aha152x_host[registered_count]=NULL;	scsi_host_put(shpnt);	return NULL;}void aha152x_release(struct Scsi_Host *shpnt){	if(!shpnt)		return;	if (shpnt->irq)		free_irq(shpnt->irq, shpnt);#if !defined(PCMCIA)	if (shpnt->io_port)		release_region(shpnt->io_port, IO_RANGE);#endif#ifdef __ISAPNP__	if (HOSTDATA(shpnt)->pnpdev)		pnp_device_detach(HOSTDATA(shpnt)->pnpdev);#endif	scsi_remove_host(shpnt);	scsi_host_put(shpnt);}/* * setup controller to generate interrupts depending * on current state (lock has to be acquired) * */ static int setup_expected_interrupts(struct Scsi_Host *shpnt){	if(CURRENT_SC) {		CURRENT_SC->SCp.phase |= 1 << 16;			if(CURRENT_SC->SCp.phase & selecting) {			DPRINTK(debug_intr, DEBUG_LEAD "expecting: (seldo) (seltimo) (seldi)\n", CMDINFO(CURRENT_SC));			SETPORT(SSTAT1, SELTO);			SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0));			SETPORT(SIMODE1, ENSELTIMO);		} else {			DPRINTK(debug_intr, DEBUG_LEAD "expecting: (phase change) (busfree) %s\n", CMDINFO(CURRENT_SC), CURRENT_SC->SCp.phase & spiordy ? "(spiordy)" : "");			SETPORT(SIMODE0, (CURRENT_SC->SCp.phase & spiordy) ? ENSPIORDY : 0);			SETPORT(SIMODE1, ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE); 		}	} else if(STATE==seldi) {		DPRINTK(debug_intr, DEBUG_LEAD "expecting: (phase change) (identify)\n", CMDINFO(CURRENT_SC));		SETPORT(SIMODE0, 0);		SETPORT(SIMODE1, ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE); 	} else {		DPRINTK(debug_intr, DEBUG_LEAD "expecting: %s %s\n",			CMDINFO(CURRENT_SC),			DISCONNECTED_SC ? "(reselection)" : "",			ISSUE_SC ? "(busfree)" : "");		SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);		SETPORT(SIMODE1, ENSCSIRST | ( (ISSUE_SC||DONE_SC) ? ENBUSFREE : 0));	}	if(!HOSTDATA(shpnt)->in_intr)		SETBITS(DMACNTRL0, INTEN);	return TESTHI(DMASTAT, INTSTAT);}/*  *  Queue a command and setup interrupts for a free bus. */static int aha152x_internal_queue(Scsi_Cmnd *SCpnt, struct semaphore *sem, int phase, void (*done)(Scsi_Cmnd *)){	struct Scsi_Host *shpnt = SCpnt->device->host;	unsigned long flags;#if defined(AHA152X_DEBUG)	if (HOSTDATA(shpnt)->debug & debug_queue) {		printk(INFO_LEAD "queue: %p; cmd_len=%d pieces=%d size=%u cmnd=",		       CMDINFO(SCpnt), SCpnt, SCpnt->cmd_len, SCpnt->use_sg, SCpnt->request_bufflen);		print_command(SCpnt->cmnd);	}#endif	SCpnt->scsi_done	= done;	SCpnt->resid 		= SCpnt->request_bufflen;	SCpnt->SCp.phase	= not_issued | phase;	SCpnt->SCp.Status	= CHECK_CONDITION;	SCpnt->SCp.Message	= 0;	SCpnt->SCp.have_data_in	= 0;	SCpnt->SCp.sent_command	= 0;	if(SCpnt->SCp.phase & (resetting|check_condition)) {		if(SCpnt->host_scribble==0 || SCSEM(SCpnt) || SCNEXT(SCpnt)) {			printk(ERR_LEAD "cannot reuse command\n", CMDINFO(SCpnt));			return FAILED;		}	} else {

⌨️ 快捷键说明

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