📄 qlogicfas.c
字号:
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 + -