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

📄 wd7000.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
 *  an execution phase code. * *  There are other formats besides these; these are the ones I've tried *  to use.  Formats for some of the defined ICB opcodes are not defined *  (notably, get/set unsolicited interrupt status) in my copy of the OEM *  manual, and others are ambiguous/hard to follow. */#define ICB_OP_MASK           0x80	/* distinguishes scbs from icbs        */#define ICB_OP_OPEN_RBUF      0x80	/* open receive buffer                 */#define ICB_OP_RECV_CMD       0x81	/* receive command from initiator      */#define ICB_OP_RECV_DATA      0x82	/* receive data from initiator         */#define ICB_OP_RECV_SDATA     0x83	/* receive data with status from init. */#define ICB_OP_SEND_DATA      0x84	/* send data with status to initiator  */#define ICB_OP_SEND_STAT      0x86	/* send command status to initiator    */					/* 0x87 is reserved                    */#define ICB_OP_READ_INIT      0x88	/* read initialization bytes           */#define ICB_OP_READ_ID        0x89	/* read adapter's SCSI ID              */#define ICB_OP_SET_UMASK      0x8A	/* set unsolicited interrupt mask      */#define ICB_OP_GET_UMASK      0x8B	/* read unsolicited interrupt mask     */#define ICB_OP_GET_REVISION   0x8C	/* read firmware revision level        */#define ICB_OP_DIAGNOSTICS    0x8D	/* execute diagnostics                 */#define ICB_OP_SET_EPARMS     0x8E	/* set execution parameters            */#define ICB_OP_GET_EPARMS     0x8F	/* read execution parameters           */typedef struct icbRecvCmd {    unchar op;    unchar IDlun;		/* Initiator SCSI ID/lun     */    unchar len[3];		/* command buffer length     */    unchar ptr[3];		/* command buffer address    */    unchar rsvd[7];		/* reserved                  */    volatile unchar vue;	/* vendor-unique error code  */    volatile unchar status;	/* returned (icmb) status    */    volatile unchar phase;	/* used by interrupt handler */} IcbRecvCmd;typedef struct icbSendStat {    unchar op;    unchar IDlun;		/* Target SCSI ID/lun                  */    unchar stat;		/* (outgoing) completion status byte 1 */    unchar rsvd[12];		/* reserved                            */    volatile unchar vue;	/* vendor-unique error code            */    volatile unchar status;	/* returned (icmb) status              */    volatile unchar phase;	/* used by interrupt handler           */} IcbSendStat;typedef struct icbRevLvl {    unchar op;    volatile unchar primary;	/* primary revision level (returned)   */    volatile unchar secondary;	/* secondary revision level (returned) */    unchar rsvd[12];		/* reserved                            */    volatile unchar vue;	/* vendor-unique error code            */    volatile unchar status;	/* returned (icmb) status              */    volatile unchar phase;	/* used by interrupt handler           */} IcbRevLvl;typedef struct icbUnsMask {	/* I'm totally guessing here */    unchar op;    volatile unchar mask[14];	/* mask bits                 */#if 0    unchar rsvd[12];		/* reserved                  */#endif    volatile unchar vue;	/* vendor-unique error code  */    volatile unchar status;	/* returned (icmb) status    */    volatile unchar phase;	/* used by interrupt handler */} IcbUnsMask;typedef struct icbDiag {    unchar op;    unchar type;		/* diagnostics type code (0-3) */    unchar len[3];		/* buffer length               */    unchar ptr[3];		/* buffer address              */    unchar rsvd[7];		/* reserved                    */    volatile unchar vue;	/* vendor-unique error code    */    volatile unchar status;	/* returned (icmb) status      */    volatile unchar phase;	/* used by interrupt handler   */} IcbDiag;#define ICB_DIAG_POWERUP   0	/* Power-up diags only       */#define ICB_DIAG_WALKING   1	/* walking 1's pattern       */#define ICB_DIAG_DMA       2	/* DMA - system memory diags */#define ICB_DIAG_FULL      3	/* do both 1 & 2             */typedef struct icbParms {    unchar op;    unchar rsvd1;		/* reserved                  */    unchar len[3];		/* parms buffer length       */    unchar ptr[3];		/* parms buffer address      */    unchar idx[2];		/* index (MSB-LSB)           */    unchar rsvd2[5];		/* reserved                  */    volatile unchar vue;	/* vendor-unique error code  */    volatile unchar status;	/* returned (icmb) status    */    volatile unchar phase;	/* used by interrupt handler */} IcbParms;typedef struct icbAny {    unchar op;    unchar data[14];		/* format-specific data      */    volatile unchar vue;	/* vendor-unique error code  */    volatile unchar status;	/* returned (icmb) status    */    volatile unchar phase;	/* used by interrupt handler */} IcbAny;typedef union icb {    unchar op;			/* ICB opcode                     */    IcbRecvCmd recv_cmd;	/* format for receive command     */    IcbSendStat send_stat;	/* format for send status         */    IcbRevLvl rev_lvl;		/* format for get revision level  */    IcbDiag diag;		/* format for execute diagnostics */    IcbParms eparms;		/* format for get/set exec parms  */    IcbAny icb;			/* generic format                 */    unchar data[18];} Icb;#ifdef MODULEstatic char * wd7000 = NULL;MODULE_PARM(wd7000, "s");#endif/* *  Driver SCB structure pool. * *  The SCBs declared here are shared by all host adapters; hence, this *  structure is not part of the Adapter structure. */static Scb scbs[MAX_SCBS];static Scb *scbfree = NULL;	/* free list         */static int freescbs = MAX_SCBS;	/* free list counter *//* *  END of data/declarations - code follows. */static void setup_error (char *mesg, int *ints){    if (ints[0] == 3)        printk ("wd7000_setup: \"wd7000=%d,%d,0x%x\" -> %s\n",                ints[1], ints[2], ints[3], mesg);    else if (ints[0] == 4)        printk ("wd7000_setup: \"wd7000=%d,%d,0x%x,%d\" -> %s\n",                ints[1], ints[2], ints[3], ints[4], mesg);    else        printk ("wd7000_setup: \"wd7000=%d,%d,0x%x,%d,%d\" -> %s\n",                ints[1], ints[2], ints[3], ints[4], ints[5], mesg);}/* * Note: You can now set these options from the kernel's "command line". * The syntax is: * *     wd7000=<IRQ>,<DMA>,<IO>[,<BUS_ON>[,<BUS_OFF>]] * * , where BUS_ON and BUS_OFF are in nanoseconds. BIOS default values * are 8000ns for BUS_ON and 1875ns for BUS_OFF. * eg: *     wd7000=7,6,0x350 * * will configure the driver for a WD-7000 controller * using IRQ 15 with a DMA channel 6, at IO base address 0x350. */static int __init wd7000_setup(char *str){	static short wd7000_card_num = 0;	short i, j;	int ints[6];	(void)get_options(str, ARRAY_SIZE(ints), ints);	if (wd7000_card_num >= NUM_CONFIGS) {		printk("wd7000_setup: Too many \"wd7000=\" configurations in "		"command line!\n");		return 0;	}	if ((ints[0] < 3) || (ints[0] > 5)) {		printk("wd7000_setup: Error in command line!  "		"Usage: wd7000=<IRQ>,<DMA>,IO>[,<BUS_ON>[,<BUS_OFF>]]\n");	} else {		for (i = 0; i < NUM_IRQS; i++)			if (ints[1] == wd7000_irq[i])				break;		if (i == NUM_IRQS) {			setup_error("invalid IRQ.", ints);			return 0;		} else			configs[wd7000_card_num].irq = ints[1];		for (i = 0; i < NUM_DMAS; i++)			if (ints[2] == wd7000_dma[i])				break;		if (i == NUM_DMAS) {			setup_error("invalid DMA channel.", ints);			return 0;		} else			configs[wd7000_card_num].dma = ints[2];		for (i = 0; i < NUM_IOPORTS; i++)			if (ints[3] == wd7000_iobase[i])				break;		if (i == NUM_IOPORTS) {			setup_error("invalid I/O base address.", ints);			return 0;		} else			configs[wd7000_card_num].iobase = ints[3];		if (ints[0] > 3) {			if ((ints[4] < 500) || (ints[4] > 31875)) {				setup_error("BUS_ON value is out of range (500 to 31875 nanoseconds)!", ints);				configs[wd7000_card_num].bus_on = BUS_ON;			} else				configs[wd7000_card_num].bus_on = ints[4] / 125;		} else			configs[wd7000_card_num].bus_on = BUS_ON;		if (ints[0] > 4) {			if ((ints[5] < 500) || (ints[5] > 31875)) {				setup_error("BUS_OFF value is out of range (500 to 31875 nanoseconds)!", ints);				configs[wd7000_card_num].bus_off = BUS_OFF;			} else				configs[wd7000_card_num].bus_off = ints[5] / 125;		} else			configs[wd7000_card_num].bus_off = BUS_OFF;		if (wd7000_card_num) {			for (i = 0; i < (wd7000_card_num - 1); i++)				for (j = i + 1; j < wd7000_card_num; j++)					if (configs[i].irq == configs[j].irq) {						setup_error("duplicated IRQ!", ints);						return 0;					} else if (configs[i].dma == configs[j].dma) {						setup_error("duplicated DMA channel!", ints);						return 0;					} else if (configs[i].iobase == configs[j].iobase) {						setup_error ("duplicated I/O base address!", ints);						return 0;					}		}#ifdef WD7000_DEBUG		printk ("wd7000_setup: IRQ=%d, DMA=%d, I/O=0x%x, BUS_ON=%dns, BUS_OFF=%dns\n",			configs[wd7000_card_num].irq,			configs[wd7000_card_num].dma,			configs[wd7000_card_num].iobase,			configs[wd7000_card_num].bus_on * 125,			configs[wd7000_card_num].bus_off * 125);#endif		wd7000_card_num++;	}	return 1;}__setup("wd7000=", wd7000_setup);#ifdef ANY2SCSI_INLINE/* * Since they're used a lot, I've redone the following from the macros * formerly in wd7000.h, hopefully to speed them up by getting rid of * all the shifting (it may not matter; GCC might have done as well anyway). * * xany2scsi and xscsi2int were not being used, and are no longer defined. * (They were simply 4-byte versions of these routines). */typedef union {			/* let's cheat... */    int i;    unchar u[sizeof (int)];	/* the sizeof(int) makes it more portable */} i_u;static inline void any2scsi (unchar * scsi, int any){    *scsi++ = ((i_u) any).u[2];    *scsi++ = ((i_u) any).u[1];    *scsi++ = ((i_u) any).u[0];}static inline int scsi2int (unchar * scsi){    i_u result;    result.i = 0;		/* clears unused bytes */    result.u[2] = *scsi++;    result.u[1] = *scsi++;    result.u[0] = *scsi++;    return (result.i);}#else/* * These are the old ones - I've just moved them here... */#undef any2scsi#define any2scsi(up, p)   (up)[0] = (((unsigned long) (p)) >> 16);	\			  (up)[1] = ((unsigned long) (p)) >> 8;		\			  (up)[2] = ((unsigned long) (p));#undef scsi2int#define scsi2int(up)   ( (((unsigned long) *(up)) << 16) +	\			 (((unsigned long) (up)[1]) << 8) +	\			 ((unsigned long) (up)[2]) )#endifstatic inline void wd7000_enable_intr (Adapter *host){    host->control |= INT_EN;    outb (host->control, host->iobase + ASC_CONTROL);}static inline void wd7000_enable_dma (Adapter *host){    unsigned long flags;    host->control |= DMA_EN;    outb (host->control, host->iobase + ASC_CONTROL);        flags = claim_dma_lock();    set_dma_mode (host->dma, DMA_MODE_CASCADE);    enable_dma (host->dma);    release_dma_lock(flags);    }#define WAITnexttimeout 200	/* 2 seconds */static inline short WAIT (unsigned port, unsigned mask, unsigned allof, unsigned noneof){    register unsigned WAITbits;    register unsigned long WAITtimeout = jiffies + WAITnexttimeout;    while (time_before_eq(jiffies, WAITtimeout)) {	WAITbits = inb (port) & mask;	if (((WAITbits & allof) == allof) && ((WAITbits & noneof) == 0))	    return (0);    }    return (1);}static inline void delay (unsigned how_long){    register unsigned long time = jiffies + how_long;    while (time_before(jiffies, time));}static inline int command_out (Adapter * host, unchar * cmd, int len){    if (!WAIT (host->iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) {	while (len--) {	    do {		outb (*cmd, host->iobase + ASC_COMMAND);		WAIT (host->iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0);	    } while (inb (host->iobase + ASC_STAT) & CMD_REJ);	    cmd++;	}	return (1);    }    printk ("wd7000 command_out: WAIT failed(%d)\n", len + 1);    return (0);}/* *  This version of alloc_scbs is in preparation for supporting multiple *  commands per lun and command chaining, by queueing pending commands. *  We will need to allocate Scbs in blocks since they will wait to be *  executed so there is the possibility of deadlock otherwise. *  Also, to keep larger requests from being starved by smaller requests, *  we limit access to this routine with an internal busy flag, so that *  the satisfiability of a request is not dependent on the size of the *  request. */static inline Scb *alloc_scbs (int needed){    register Scb *scb, *p;    register unsigned long flags;    register unsigned long timeout = jiffies + WAITnexttimeout;    register unsigned long now;    static int busy = 0;    int i;    if (needed <= 0)	return (NULL);		/* sanity check */    save_flags (flags);    cli ();    while (busy) {		/* someone else is allocating */	spin_unlock_irq(&io_request_lock);	for (now = jiffies; now == jiffies; );	/* wait a jiffy */	spin_lock_irq(&io_request_lock);    }    busy = 1;			/* not busy now; it's our turn */    while (freescbs < needed) {	timeout = jiffies + WAITnexttimeout;	do {	    spin_unlock_irq(&io_request_lock);	    for (now = jiffies; now == jiffies; );	/* wait a jiffy */	    spin_lock_irq(&io_request_lock);	} while (freescbs < needed && time_before_eq(jiffies, timeout));	/*	 *  If we get here with enough free Scbs, we can take them.	 *  Otherwise, we timed out and didn't get enough.	 */	if (freescbs < needed) {	    busy = 0;	    panic ("wd7000: can't get enough free SCBs.\n");	    restore_flags (flags);	    return (NULL);	}    }    scb = scbfree;    freescbs -= needed;    for (i = 0; i < needed; i++) {	p = scbfree;	scbfree = p->next;    }    p->next = NULL;    busy = 0;			/* we're done */    restore_flags (flags);    return (scb);}static inline void free_scb (Scb *scb){    register unsigned long flags;    save_flags (flags);    cli ();    memset (scb, 0, sizeof (Scb));    scb->next = scbfree;

⌨️ 快捷键说明

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