aha1542.c
来自「GNU Mach 微内核源代码, 基于美国卡内基美隆大学的 Mach 研究项目」· C语言 代码 · 共 1,326 行 · 第 1/3 页
C
1,326 行
#ifdef DEBUG printk("...done %d %d\n",mbo, mbi);#endif SCtmp = HOSTDATA(shost)->SCint[mbo]; if (!SCtmp || !SCtmp->scsi_done) { printk("aha1542_intr_handle: Unexpected interrupt\n"); printk("tarstat=%x, hastat=%x idlun=%x ccb#=%d \n", ccb[mbo].tarstat, ccb[mbo].hastat, ccb[mbo].idlun, mbo); return; } my_done = SCtmp->scsi_done; if (SCtmp->host_scribble) scsi_free(SCtmp->host_scribble, 512); /* Fetch the sense data, and tuck it away, in the required slot. The Adaptec automatically fetches it, and there is no guarantee that we will still have it in the cdb when we come back */ if (ccb[mbo].tarstat == 2) memcpy(SCtmp->sense_buffer, &ccb[mbo].cdb[ccb[mbo].cdblen], sizeof(SCtmp->sense_buffer)); /* is there mail :-) */ /* more error checking left out here */ if (mbistatus != 1) /* This is surely wrong, but I don't know what's right */ errstatus = makecode(ccb[mbo].hastat, ccb[mbo].tarstat); else errstatus = 0; #ifdef DEBUG if(errstatus) printk("(aha1542 error:%x %x %x) ",errstatus, ccb[mbo].hastat, ccb[mbo].tarstat);#endif if (ccb[mbo].tarstat == 2) {#ifdef DEBUG int i;#endif DEB(printk("aha1542_intr_handle: sense:"));#ifdef DEBUG for (i = 0; i < 12; i++) printk("%02x ", ccb[mbo].cdb[ccb[mbo].cdblen+i]); printk("\n");#endif /* DEB(printk("aha1542_intr_handle: buf:")); for (i = 0; i < bufflen; i++) printk("%02x ", ((unchar *)buff)[i]); printk("\n"); */ } DEB(if (errstatus) printk("aha1542_intr_handle: returning %6x\n", errstatus)); SCtmp->result = errstatus; HOSTDATA(shost)->SCint[mbo] = NULL; /* This effectively frees up the mailbox slot, as far as queuecommand is concerned */ my_done(SCtmp); number_serviced++; };}int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *)){ unchar ahacmd = CMD_START_SCSI; unchar direction; unchar *cmd = (unchar *) SCpnt->cmnd; unchar target = SCpnt->target; unchar lun = SCpnt->lun; unsigned long flags; void *buff = SCpnt->request_buffer; int bufflen = SCpnt->request_bufflen; int mbo; struct mailbox * mb; struct ccb *ccb; DEB(int i); mb = HOSTDATA(SCpnt->host)->mb; ccb = HOSTDATA(SCpnt->host)->ccb; DEB(if (target > 1) { SCpnt->result = DID_TIME_OUT << 16; done(SCpnt); return 0;}); if(*cmd == REQUEST_SENSE){#ifndef DEBUG if (bufflen != sizeof(SCpnt->sense_buffer)) { printk("Wrong buffer length supplied for request sense (%d)\n",bufflen); };#endif SCpnt->result = 0; done(SCpnt); return 0; };#ifdef DEBUG if (*cmd == READ_10 || *cmd == WRITE_10) i = xscsi2int(cmd+2); else if (*cmd == READ_6 || *cmd == WRITE_6) i = scsi2int(cmd+2); else i = -1; if (done) printk("aha1542_queuecommand: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen); else printk("aha1542_command: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen); aha1542_stat(); printk("aha1542_queuecommand: dumping scsi cmd:"); for (i = 0; i < SCpnt->cmd_len; i++) printk("%02x ", cmd[i]); printk("\n"); if (*cmd == WRITE_10 || *cmd == WRITE_6) return 0; /* we are still testing, so *don't* write */#endif/* Use the outgoing mailboxes in a round-robin fashion, because this is how the host adapter will scan for them */ save_flags(flags); cli(); mbo = HOSTDATA(SCpnt->host)->aha1542_last_mbo_used + 1; if (mbo >= AHA1542_MAILBOXES) mbo = 0; do{ if(mb[mbo].status == 0 && HOSTDATA(SCpnt->host)->SCint[mbo] == NULL) break; mbo++; if (mbo >= AHA1542_MAILBOXES) mbo = 0; } while (mbo != HOSTDATA(SCpnt->host)->aha1542_last_mbo_used); if(mb[mbo].status || HOSTDATA(SCpnt->host)->SCint[mbo]) panic("Unable to find empty mailbox for aha1542.\n"); HOSTDATA(SCpnt->host)->SCint[mbo] = SCpnt; /* This will effectively prevent someone else from screwing with this cdb. */ HOSTDATA(SCpnt->host)->aha1542_last_mbo_used = mbo; restore_flags(flags);#ifdef DEBUG printk("Sending command (%d %x)...",mbo, done);#endif any2scsi(mb[mbo].ccbptr, &ccb[mbo]); /* This gets trashed for some reason*/ memset(&ccb[mbo], 0, sizeof(struct ccb)); ccb[mbo].cdblen = SCpnt->cmd_len; direction = 0; if (*cmd == READ_10 || *cmd == READ_6) direction = 8; else if (*cmd == WRITE_10 || *cmd == WRITE_6) direction = 16; memcpy(ccb[mbo].cdb, cmd, ccb[mbo].cdblen); if (SCpnt->use_sg) { struct scatterlist * sgpnt; struct chain * cptr;#ifdef DEBUG unsigned char * ptr;#endif int i; ccb[mbo].op = 2; /* SCSI Initiator Command w/scatter-gather*/ SCpnt->host_scribble = (unsigned char *) scsi_malloc(512); sgpnt = (struct scatterlist *) SCpnt->request_buffer; cptr = (struct chain *) SCpnt->host_scribble; if (cptr == NULL) panic("aha1542.c: unable to allocate DMA memory\n"); for(i=0; i<SCpnt->use_sg; i++) { if(sgpnt[i].length == 0 || SCpnt->use_sg > 16 || (((int)sgpnt[i].address) & 1) || (sgpnt[i].length & 1)){ unsigned char * ptr; printk("Bad segment list supplied to aha1542.c (%d, %d)\n",SCpnt->use_sg,i); for(i=0;i<SCpnt->use_sg;i++){ printk("%d: %x %x %d\n",i,(unsigned int) sgpnt[i].address, (unsigned int) sgpnt[i].alt_address, sgpnt[i].length); }; printk("cptr %x: ",(unsigned int) cptr); ptr = (unsigned char *) &cptr[i]; for(i=0;i<18;i++) printk("%02x ", ptr[i]); panic("Foooooooood fight!"); }; any2scsi(cptr[i].dataptr, sgpnt[i].address); if(((unsigned int) sgpnt[i].address) & 0xff000000) goto baddma; any2scsi(cptr[i].datalen, sgpnt[i].length); }; any2scsi(ccb[mbo].datalen, SCpnt->use_sg * sizeof(struct chain)); any2scsi(ccb[mbo].dataptr, cptr);#ifdef DEBUG printk("cptr %x: ",cptr); ptr = (unsigned char *) cptr; for(i=0;i<18;i++) printk("%02x ", ptr[i]);#endif } else { ccb[mbo].op = 0; /* SCSI Initiator Command */ SCpnt->host_scribble = NULL; any2scsi(ccb[mbo].datalen, bufflen); if(((unsigned int) buff & 0xff000000)) goto baddma; any2scsi(ccb[mbo].dataptr, buff); }; ccb[mbo].idlun = (target&7)<<5 | direction | (lun & 7); /*SCSI Target Id*/ ccb[mbo].rsalen = 16; ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0; ccb[mbo].commlinkid = 0;#ifdef DEBUG { int i; printk("aha1542_command: sending.. "); for (i = 0; i < sizeof(ccb[mbo])-10; i++) printk("%02x ", ((unchar *)&ccb[mbo])[i]); };#endif if (done) { DEB(printk("aha1542_queuecommand: now waiting for interrupt "); aha1542_stat()); SCpnt->scsi_done = done; mb[mbo].status = 1; aha1542_out(SCpnt->host->io_port, &ahacmd, 1); /* start scsi command */ DEB(aha1542_stat()); } else printk("aha1542_queuecommand: done can't be NULL\n"); return 0; baddma: panic("Buffer at address > 16Mb used for 1542B");}static void internal_done(Scsi_Cmnd * SCpnt){ SCpnt->SCp.Status++;}int aha1542_command(Scsi_Cmnd * SCpnt){ DEB(printk("aha1542_command: ..calling aha1542_queuecommand\n")); aha1542_queuecommand(SCpnt, internal_done); SCpnt->SCp.Status = 0; while (!SCpnt->SCp.Status) barrier(); return SCpnt->result;}/* Initialize mailboxes */static void setup_mailboxes(int bse, struct Scsi_Host * shpnt){ int i; struct mailbox * mb; struct ccb *ccb; unchar cmd[5] = {CMD_MBINIT, AHA1542_MAILBOXES, 0, 0, 0}; mb = HOSTDATA(shpnt)->mb; ccb = HOSTDATA(shpnt)->ccb; for(i=0; i<AHA1542_MAILBOXES; i++){ mb[i].status = mb[AHA1542_MAILBOXES+i].status = 0; any2scsi(mb[i].ccbptr, &ccb[i]); }; aha1542_intr_reset(bse); /* reset interrupts, so they don't block */ any2scsi((cmd+2), mb); aha1542_out(bse, cmd, 5); WAIT(INTRFLAGS(bse), INTRMASK, HACC, 0); while (0) { fail: printk("aha1542_detect: failed setting up mailboxes\n"); } aha1542_intr_reset(bse);}static int aha1542_getconfig(int base_io, unsigned char * irq_level, unsigned char * dma_chan, unsigned char * scsi_id){ unchar inquiry_cmd[] = {CMD_RETCONF }; unchar inquiry_result[3]; int i; i = inb(STATUS(base_io)); if (i & DF) { i = inb(DATA(base_io)); }; aha1542_out(base_io, inquiry_cmd, 1); aha1542_in(base_io, inquiry_result, 3); WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0); while (0) { fail: printk("aha1542_detect: query board settings\n"); } aha1542_intr_reset(base_io); switch(inquiry_result[0]){ case 0x80: *dma_chan = 7; break; case 0x40: *dma_chan = 6; break; case 0x20: *dma_chan = 5; break; case 0x01: *dma_chan = 0; break; case 0: /* This means that the adapter, although Adaptec 1542 compatible, doesn't use a DMA channel. Currently only aware of the BusLogic BT-445S VL-Bus adapter which needs this. */ *dma_chan = 0xFF; break; default: printk("Unable to determine Adaptec DMA priority. Disabling board\n"); return -1; }; switch(inquiry_result[1]){ case 0x40: *irq_level = 15; break; case 0x20: *irq_level = 14; break; case 0x8: *irq_level = 12; break; case 0x4: *irq_level = 11; break; case 0x2: *irq_level = 10; break; case 0x1: *irq_level = 9; break; default: printk("Unable to determine Adaptec IRQ level. Disabling board\n"); return -1; }; *scsi_id=inquiry_result[2] & 7; return 0;}/* This function should only be called for 1542C boards - we can detect the special firmware settings and unlock the board */static int aha1542_mbenable(int base){ static unchar mbenable_cmd[3]; static unchar mbenable_result[2]; int retval; retval = BIOS_TRANSLATION_6432; mbenable_cmd[0]=CMD_EXTBIOS; aha1542_out(base,mbenable_cmd,1); if(aha1542_in1(base,mbenable_result,2)) return retval; WAITd(INTRFLAGS(base),INTRMASK,HACC,0,100); aha1542_intr_reset(base); if ((mbenable_result[0] & 0x08) || mbenable_result[1]) { mbenable_cmd[0]=CMD_MBENABLE; mbenable_cmd[1]=0; mbenable_cmd[2]=mbenable_result[1]; if((mbenable_result[0] & 0x08) && (mbenable_result[1] & 0x03)) retval = BIOS_TRANSLATION_25563; aha1542_out(base,mbenable_cmd,3); WAIT(INTRFLAGS(base),INTRMASK,HACC,0); }; while(0) {fail: printk("aha1542_mbenable: Mailbox init failed\n"); }aha1542_intr_reset(base);return retval;}/* Query the board to find out if it is a 1542 or a 1740, or whatever. */static int aha1542_query(int base_io, int * transl){ unchar inquiry_cmd[] = {CMD_INQUIRY }; unchar inquiry_result[4]; int i; i = inb(STATUS(base_io)); if (i & DF) { i = inb(DATA(base_io)); }; aha1542_out(base_io, inquiry_cmd, 1); aha1542_in(base_io, inquiry_result, 4); WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0); while (0) { fail: printk("aha1542_detect: query card type\n"); } aha1542_intr_reset(base_io); *transl = BIOS_TRANSLATION_6432; /* Default case *//* For an AHA1740 series board, we ignore the board since there is a hardware bug which can lead to wrong blocks being returned if the board is operating in the 1542 emulation mode. Since there is an extended mode driver, we simply ignore the board and let the 1740 driver pick it up.*/ if (inquiry_result[0] == 0x43) { printk("aha1542.c: Emulation mode not supported for AHA 174N hardware.\n"); return 1; }; /* Always call this - boards that do not support extended bios translation will ignore the command, and we will set the proper default */ *transl = aha1542_mbenable(base_io); return 0;}/* called from init/main.c */void aha1542_setup( char *str, int *ints){ const char *ahausage = "aha1542: usage: aha1542=<PORTBASE>[,<BUSON>,<BUSOFF>[,<DMASPEED>]]\n"; static int setup_idx = 0; int setup_portbase; if(setup_idx >= MAXBOARDS) { printk("aha1542: aha1542_setup called too many times! Bad LILO params ?\n"); printk(" Entryline 1: %s\n",setup_str[0]); printk(" Entryline 2: %s\n",setup_str[1]); printk(" This line: %s\n",str); return; } if (ints[0] < 1 || ints[0] > 4) { printk("aha1542: %s\n", str ); printk(ahausage); printk("aha1542: Wrong parameters may cause system malfunction.. We try anyway..\n"); } setup_called[setup_idx]=ints[0]; setup_str[setup_idx]=str;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?