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

📄 qlogicfas.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
unsigned int	sgcount;		/* sg counter */rtrc(1)	j = inb(qbase + 6);	i = inb(qbase + 5);	if (i == 0x20) {		return (DID_NO_CONNECT << 16);	}	i |= inb(qbase + 5);	/* the 0x10 bit can be set after the 0x08 */	if (i != 0x18) {		printk("Ql:Bad Interrupt status:%02x\n", i);		ql_zap();		return (DID_BAD_INTR << 16);	}	j &= 7; /* j = inb( qbase + 7 ) >> 5; *//* correct status is supposed to be step 4 *//* it sometimes returns step 3 but with 0 bytes left to send *//* We can try stuffing the FIFO with the max each time, but we will get a   sequence of 3 if any bytes are left (but we do flush the FIFO anyway */	if(j != 3 && j != 4) {		printk("Ql:Bad sequence for command %d, int %02X, cmdleft = %d\n", j, i, inb( qbase+7 ) & 0x1f );		ql_zap();		return (DID_ERROR << 16);	}	result = DID_OK;	if (inb(qbase + 7) & 0x1f)	/* if some bytes in fifo */		outb(1, qbase + 3);		/* clear fifo *//* note that request_bufflen is the total xfer size when sg is used */	reqlen = cmd->request_bufflen;/* note that it won't work if transfers > 16M are requested */	if (reqlen && !((phase = inb(qbase + 4)) & 6)) {	/* data phase */rtrc(2)		outb(reqlen, qbase);			/* low-mid xfer cnt */		outb(reqlen >> 8, qbase+1);			/* low-mid xfer cnt */		outb(reqlen >> 16, qbase + 0xe);	/* high xfer cnt */		outb(0x90, qbase + 3);			/* command do xfer *//* PIO pseudo DMA to buffer or sglist */		REG1;		if (!cmd->use_sg)			ql_pdma(phase, cmd->request_buffer, cmd->request_bufflen);		else {			sgcount = cmd->use_sg;			sglist = cmd->request_buffer;			while (sgcount--) {				if (qabort) {					REG0;					return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16);				}				if (ql_pdma(phase, sglist->address, sglist->length))					break;				sglist++;			}		}		REG0;rtrc(2)/* wait for irq (split into second state of irq handler if this can take time) */		if ((k = ql_wai()))			return (k << 16);		k = inb(qbase + 5);	/* should be 0x10, bus service */	}/*** Enter Status (and Message In) Phase ***/	k = jiffies + WATCHDOG;	while ( k > jiffies && !qabort && !(inb(qbase + 4) & 6));	/* wait for status phase */	if ( k <= jiffies ) {		ql_zap();		return (DID_TIME_OUT << 16);	}	while (inb(qbase + 5)); 				/* clear pending ints */	if (qabort)		return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16);	outb(0x11, qbase + 3);					/* get status and message */	if ((k = ql_wai()))		return (k << 16);	i = inb(qbase + 5);					/* get chip irq stat */	j = inb(qbase + 7) & 0x1f;				/* and bytes rec'd */	status = inb(qbase + 2);	message = inb(qbase + 2);/* should get function complete int if Status and message, else bus serv if only status */	if (!((i == 8 && j == 2) || (i == 0x10 && j == 1))) {		printk("Ql:Error during status phase, int=%02X, %d bytes recd\n", i, j);		result = DID_ERROR;	}	outb(0x12, qbase + 3);	/* done, disconnect */rtrc(1)	if ((k = ql_wai()))		return (k << 16);/* should get bus service interrupt and disconnect interrupt */	i = inb(qbase + 5);	/* should be bus service */	while (!qabort && ((i & 0x20) != 0x20)) {		barrier();		i |= inb(qbase + 5);	}rtrc(0)	if (qabort)		return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16);	return (result << 16) | (message << 8) | (status & STATUS_MASK);}#if QL_USE_IRQ/*----------------------------------------------------------------*//* interrupt handler */static void	    ql_ihandl(int irq, void *dev_id, struct pt_regs * regs){Scsi_Cmnd	   *icmd;	REG0;	if (!(inb(qbase + 4) & 0x80))	/* false alarm? */		return;	if (qlcmd == NULL) {		/* no command to process? */		int	i;		i = 16;		while (i-- && inb(qbase + 5)); /* maybe also ql_zap() */		return;	}	icmd = qlcmd;	icmd->result = ql_pcmd(icmd);	qlcmd = NULL;/* if result is CHECK CONDITION done calls qcommand to request sense */	(icmd->scsi_done) (icmd);}static void	    do_ql_ihandl(int irq, void *dev_id, struct pt_regs * regs){	unsigned long flags;	spin_lock_irqsave(&io_request_lock, flags);	ql_ihandl(irq, dev_id, regs);	spin_unlock_irqrestore(&io_request_lock, flags);}#endif/*----------------------------------------------------------------*//* global functions *//*----------------------------------------------------------------*//* non queued command */#if QL_USE_IRQstatic void	qlidone(Scsi_Cmnd * cmd) {};		/* null function */#endif/* command process */int	qlogicfas_command(Scsi_Cmnd * cmd){int	k;#if QL_USE_IRQ	if (qlirq >= 0) {		qlogicfas_queuecommand(cmd, qlidone);		while (qlcmd != NULL);		return cmd->result;	}#endif/* non-irq version */	if (cmd->target == qinitid)		return (DID_BAD_TARGET << 16);	ql_icmd(cmd);	if ((k = ql_wai()))		return (k << 16);	return ql_pcmd(cmd);}#if QL_USE_IRQ/*----------------------------------------------------------------*//* queued command */int	qlogicfas_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)){	if(cmd->target == qinitid) {		cmd->result = DID_BAD_TARGET << 16;		done(cmd);		return 0;	}	cmd->scsi_done = done;/* wait for the last command's interrupt to finish */	while (qlcmd != NULL)		barrier();	ql_icmd(cmd);	return 0;}#elseint	qlogicfas_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)){	return 1;}#endif#ifdef PCMCIA/*----------------------------------------------------------------*//* allow PCMCIA code to preset the port *//* port should be 0 and irq to -1 respectively for autoprobing */void	qlogicfas_preset(int port, int irq){	qbase=port;	qlirq=irq;}#endif/*----------------------------------------------------------------*//* look for qlogic card and init if found */int	qlogicfas_detect(Scsi_Host_Template * host){int	i, j;			/* these are only used by IRQ detect */int	qltyp;			/* type of chip */struct	Scsi_Host	*hreg;	/* registered host structure */unsigned long	flags;host->proc_name =  "qlogicfas";/* Qlogic Cards only exist at 0x230 or 0x330 (the chip itself decodes the   address - I check 230 first since MIDI cards are typically at 330   Theoretically, two Qlogic cards can coexist in the same system.  This   should work by simply using this as a loadable module for the second   card, but I haven't tested this.*/	if( !qbase ) {		for (qbase = 0x230; qbase < 0x430; qbase += 0x100) {			if( check_region( qbase , 0x10 ) )				continue;			REG1;			if ( ( (inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7 )			  && ( (inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7 ) )				break;		}		if (qbase == 0x430)			return 0;	}	else		printk( "Ql: Using preset base address of %03x\n", qbase );	qltyp = inb(qbase + 0xe) & 0xf8;	qinitid = host->this_id;	if (qinitid < 0)		qinitid = 7;			/* if no ID, use 7 */	outb(1, qbase + 8);			/* set for PIO pseudo DMA */	REG0;	outb(0x40 | qlcfg8 | qinitid, qbase + 8);	/* (ini) bus id, disable scsi rst */	outb(qlcfg5, qbase + 5);		/* select timer */	outb(qlcfg9, qbase + 9);			/* prescaler */#if QL_RESET_AT_START	outb( 3 , qbase + 3 );	REG1;	while( inb( qbase + 0xf ) & 4 );	REG0;#endif#if QL_USE_IRQ/* IRQ probe - toggle pin and check request pending */	if( qlirq == -1 ) {		save_flags( flags );		cli();		i = 0xffff;		j = 3;		outb(0x90, qbase + 3);	/* illegal command - cause interrupt */		REG1;		outb(10, 0x20); /* access pending interrupt map */		outb(10, 0xa0);		while (j--) {			outb(0xb0 | QL_INT_ACTIVE_HIGH , qbase + 0xd);	/* int pin off */			i &= ~(inb(0x20) | (inb(0xa0) << 8));	/* find IRQ off */			outb(0xb4 | QL_INT_ACTIVE_HIGH , qbase + 0xd);	/* int pin on */			i &= inb(0x20) | (inb(0xa0) << 8);	/* find IRQ on */		}		REG0;		while (inb(qbase + 5)); 			/* purge int */		j = -1;		while (i)					/* find on bit */			i >>= 1, j++;	/* should check for exactly 1 on */		qlirq = j;		restore_flags( flags );	}	else		printk( "Ql: Using preset IRQ %d\n", qlirq );	if (qlirq >= 0 && !request_irq(qlirq, do_ql_ihandl, 0, "qlogicfas", NULL))		host->can_queue = 1;#endif	request_region( qbase , 0x10 ,"qlogicfas");	hreg = scsi_register( host , 0 );	/* no host data */	hreg->io_port = qbase;	hreg->n_io_port = 16;	hreg->dma_channel = -1;	if( qlirq != -1 )		hreg->irq = qlirq;	sprintf(qinfo, "Qlogicfas Driver version 0.46, chip %02X at %03X, IRQ %d, TPdma:%d",	    qltyp, qbase, qlirq, QL_TURBO_PDMA );	host->name = qinfo;	return 1;}/*----------------------------------------------------------------*//* return bios parameters */int	qlogicfas_biosparam(Disk * disk, kdev_t dev, int ip[]){/* This should mimic the DOS Qlogic driver's behavior exactly */	ip[0] = 0x40;	ip[1] = 0x20;	ip[2] = disk->capacity / (ip[0] * ip[1]);	if (ip[2] > 1024) {		ip[0] = 0xff;		ip[1] = 0x3f;		ip[2] = disk->capacity / (ip[0] * ip[1]);#if 0		if (ip[2] > 1023)			ip[2] = 1023;#endif	}	return 0;}/*----------------------------------------------------------------*//* abort command in progress */int	qlogicfas_abort(Scsi_Cmnd * cmd){	qabort = 1;	ql_zap();	return 0;}/*----------------------------------------------------------------*//* reset SCSI bus */int	qlogicfas_reset(Scsi_Cmnd * cmd, unsigned int ignored){	qabort = 2;	ql_zap();	return 1;}/*----------------------------------------------------------------*//* return info string */const char	*qlogicfas_info(struct Scsi_Host * host){	return qinfo;}/* Eventually this will go into an include file, but this will be later */static Scsi_Host_Template driver_template = QLOGICFAS;#include "scsi_module.c"

⌨️ 快捷键说明

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