📄 aha152x.c
字号:
info_array[2] = disk->capacity / (64 * 32); /* for disks >1GB do some guessing */ if (info_array[2] >= 1024) { int info[3]; /* try to figure out the geometry from the partition table */ if (scsicam_bios_param(disk, dev, info) < 0 || !((info[0] == 64 && info[1] == 32) || (info[0] == 255 && info[1] == 63))) { if (EXT_TRANS) { printk("aha152x: unable to verify geometry for disk with >1GB.\n" " using extended translation.\n"); info_array[0] = 255; info_array[1] = 63; info_array[2] = disk->capacity / (255 * 63); } else { printk("aha152x: unable to verify geometry for disk with >1GB.\n" " Using default translation. Please verify yourself.\n" " Perhaps you need to enable extended translation in the driver.\n" " See /usr/src/linux/drivers/scsi/aha152x.c for details.\n"); } } else { info_array[0] = info[0]; info_array[1] = info[1]; info_array[2] = info[2]; if (info[0] == 255 && !EXT_TRANS) { printk("aha152x: current partition table is using extended translation.\n" " using it also, although it's not explicty enabled.\n"); } } }#if defined(DEBUG_BIOSPARAM) if (HOSTDATA(shpnt)->debug & debug_biosparam) { printk("bios geometry: head=%d, sec=%d, cyl=%d\n", info_array[0], info_array[1], info_array[2]); printk("WARNING: check, if the bios geometry is correct.\n"); }#endif return 0;}/* * Internal done function */void aha152x_done(struct Scsi_Host *shpnt, int error){ unsigned long flags; Scsi_Cmnd *done_SC;#if defined(DEBUG_DONE) if (HOSTDATA(shpnt)->debug & debug_done) { printk("\naha152x: done(), "); disp_ports(shpnt); }#endif if (CURRENT_SC) {#if defined(DEBUG_DONE) if (HOSTDATA(shpnt)->debug & debug_done) printk("done(%x), ", error);#endif save_flags(flags); cli(); done_SC = CURRENT_SC; CURRENT_SC = NULL; /* turn led off, when no commands are in the driver */ HOSTDATA(shpnt)->commands--; if (!HOSTDATA(shpnt)->commands) SETPORT(PORTA, 0); /* turn led off */#if defined(DEBUG_QUEUES) if (HOSTDATA(shpnt)->debug & debug_queues) printk("ok (%d), ", HOSTDATA(shpnt)->commands);#endif restore_flags(flags); SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);#if 0/* Why poll for the BUS FREE phase, when we have setup the interrupt!? */#if defined(DEBUG_PHASES) if (HOSTDATA(shpnt)->debug & debug_phases) printk("BUS FREE loop, ");#endif while (TESTLO(SSTAT1, BUSFREE)) barrier();#if defined(DEBUG_PHASES) if (HOSTDATA(shpnt)->debug & debug_phases) printk("BUS FREE\n");#endif#endif done_SC->result = error; if (done_SC->scsi_done) {#if defined(DEBUG_DONE) if (HOSTDATA(shpnt)->debug & debug_done) printk("calling scsi_done, ");#endif spin_lock_irqsave(&io_request_lock, flags); done_SC->scsi_done(done_SC); spin_unlock_irqrestore(&io_request_lock, flags);#if defined(DEBUG_DONE) if (HOSTDATA(shpnt)->debug & debug_done) printk("done returned, ");#endif } else panic("aha152x: current_SC->scsi_done() == NULL"); } else aha152x_panic(shpnt, "done() called outside of command");}static void aha152x_complete(struct Scsi_Host *);static struct tq_struct aha152x_tq;/* * Run service completions on the card with interrupts enabled. */static void aha152x_run(void){ int i; for (i = 0; i < IRQS; i++) { struct Scsi_Host *shpnt = aha152x_host[i]; if (shpnt && HOSTDATA(shpnt)->service) { HOSTDATA(shpnt)->service = 0; aha152x_complete(shpnt); } }}/* * Interrupts handler (main routine of the driver) */static void aha152x_intr(int irqno, void *dev_id, struct pt_regs *regs){ struct Scsi_Host *shpnt = aha152x_host[irqno - IRQ_MIN];#if defined(DEBUG_RACE) enter_driver("intr");#else#if defined(DEBUG_INTR) if (HOSTDATA(shpnt)->debug & debug_intr) printk("\naha152x: intr(), ");#endif#endif if (!shpnt) panic("aha152x: catched interrupt for unknown controller.\n"); /* no more interrupts from the controller, while we're busy. INTEN is restored by the BH handler */ CLRBITS(DMACNTRL0, INTEN); /* Poke the BH handler */ HOSTDATA(shpnt)->service = 1; aha152x_tq.routine = (void *) aha152x_run; queue_task(&aha152x_tq, &tq_immediate); mark_bh(IMMEDIATE_BH);}static void aha152x_complete(struct Scsi_Host *shpnt){ unsigned int flags; int done = 0, phase; /* disconnected target is trying to reconnect. Only possible, if we have disconnected nexuses and nothing is occupying the bus. */ if (TESTHI(SSTAT0, SELDI) && DISCONNECTED_SC && (!CURRENT_SC || (CURRENT_SC->SCp.phase & in_selection))) { int identify_msg, target, i; /* Avoid conflicts when a target reconnects while we are trying to connect to another. */ if (CURRENT_SC) {#if defined(DEBUG_QUEUES) if (HOSTDATA(shpnt)->debug & debug_queues) printk("i+, ");#endif save_flags(flags); cli(); append_SC(&ISSUE_SC, CURRENT_SC); CURRENT_SC = NULL; restore_flags(flags); } /* disable sequences */ SETPORT(SCSISEQ, 0); SETPORT(SSTAT0, CLRSELDI); SETPORT(SSTAT1, CLRBUSFREE);#if defined(DEBUG_QUEUES) || defined(DEBUG_PHASES) if (HOSTDATA(shpnt)->debug & (debug_queues | debug_phases)) printk("reselected, ");#endif i = GETPORT(SELID) & ~(1 << shpnt->this_id); target = 0; if (i == 0) aha152x_panic(shpnt, "reconnecting target unknown"); for (; (i & 1) == 0; target++, i >>= 1);#if defined(DEBUG_QUEUES) if (HOSTDATA(shpnt)->debug & debug_queues) printk("SELID=%02x, target=%d, ", GETPORT(SELID), target);#endif SETPORT(SCSIID, (shpnt->this_id << OID_) | target); SETPORT(SCSISEQ, ENRESELI); if (TESTLO(SSTAT0, SELDI)) aha152x_panic(shpnt, "RESELI failed"); SETPORT(SCSIRATE, HOSTDATA(shpnt)->syncrate[target] & 0x7f); SETPORT(SCSISIG, P_MSGI); /* Get identify message */ if ((i = getphase(shpnt)) != P_MSGI) { printk("target doesn't enter MSGI to identify (phase=%02x)\n", i); aha152x_panic(shpnt, "unknown lun"); } SETPORT(SCSISEQ, 0); SETPORT(SXFRCTL0, CH1); identify_msg = GETPORT(SCSIBUS); if (!(identify_msg & IDENTIFY_BASE)) { printk("target=%d, inbound message (%02x) != IDENTIFY\n", target, identify_msg); aha152x_panic(shpnt, "unknown lun"); }#if defined(DEBUG_QUEUES) if (HOSTDATA(shpnt)->debug & debug_queues) printk("identify=%02x, lun=%d, ", identify_msg, identify_msg & 0x3f);#endif save_flags(flags); cli();#if defined(DEBUG_QUEUES) if (HOSTDATA(shpnt)->debug & debug_queues) printk("d-, ");#endif CURRENT_SC = remove_SC(&DISCONNECTED_SC, target, identify_msg & 0x3f); if (!CURRENT_SC) { printk("lun=%d, ", identify_msg & 0x3f); aha152x_panic(shpnt, "no disconnected command for that lun"); } CURRENT_SC->SCp.phase &= ~disconnected; restore_flags(flags); make_acklow(shpnt); if (getphase(shpnt) != P_MSGI) { SETPORT(SIMODE0, 0); SETPORT(SIMODE1, ENPHASEMIS | ENBUSFREE);#if defined(DEBUG_RACE) leave_driver("(reselected) intr");#endif SETBITS(DMACNTRL0, INTEN); return; } } /* Check, if we aren't busy with a command */ if (!CURRENT_SC) { /* bus is free to issue a queued command */ if (TESTHI(SSTAT1, BUSFREE) && ISSUE_SC) { save_flags(flags); cli();#if defined(DEBUG_QUEUES) if (HOSTDATA(shpnt)->debug & debug_queues) printk("i-, ");#endif CURRENT_SC = remove_first_SC(&ISSUE_SC); restore_flags(flags);#if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES) if (HOSTDATA(shpnt)->debug & (debug_intr | debug_selection | debug_phases)) printk("issuing command, ");#endif CURRENT_SC->SCp.phase = in_selection;#if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES) if (HOSTDATA(shpnt)->debug & (debug_intr | debug_selection | debug_phases)) printk("selecting %d, ", CURRENT_SC->target);#endif SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->target); /* Enable interrupts for SELECTION OUT DONE and SELECTION OUT INITIATED */ SETPORT(SXFRCTL1, HOSTDATA(shpnt)->parity ? (ENSPCHK | ENSTIMER) : ENSTIMER); /* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */ SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0)); SETPORT(SIMODE1, ENSELTIMO); /* Enable SELECTION OUT sequence */ SETBITS(SCSISEQ, ENSELO | ENAUTOATNO); } else { /* No command we are busy with and no new to issue */ printk("aha152x: ignoring spurious interrupt, nothing to do\n"); if (TESTHI(DMACNTRL0, SWINT)) { printk("aha152x: SWINT is set! Why?\n"); CLRBITS(DMACNTRL0, SWINT); } show_queues(shpnt); }#if defined(DEBUG_RACE) leave_driver("(selecting) intr");#endif SETBITS(DMACNTRL0, INTEN); return; } /* the bus is busy with something */#if defined(DEBUG_INTR) if (HOSTDATA(shpnt)->debug & debug_intr) disp_ports(shpnt);#endif /* we are waiting for the result of a selection attempt */ if (CURRENT_SC->SCp.phase & in_selection) { if (TESTLO(SSTAT1, SELTO)) { /* no timeout */ if (TESTHI(SSTAT0, SELDO)) { /* clear BUS FREE interrupt */ SETPORT(SSTAT1, CLRBUSFREE); /* Disable SELECTION OUT sequence */ CLRBITS(SCSISEQ, ENSELO | ENAUTOATNO); /* Disable SELECTION OUT DONE interrupt */ CLRBITS(SIMODE0, ENSELDO); CLRBITS(SIMODE1, ENSELTIMO); if (TESTLO(SSTAT0, SELDO)) { printk("aha152x: passing bus free condition\n");#if defined(DEBUG_RACE) leave_driver("(passing bus free) intr");#endif SETBITS(DMACNTRL0, INTEN); if (CURRENT_SC->SCp.phase & aborted) { HOSTDATA(shpnt)->abort_result = SCSI_ABORT_ERROR; HOSTDATA(shpnt)->abortion_complete++; } aha152x_done(shpnt, DID_NO_CONNECT << 16); return; }#if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES) if (HOSTDATA(shpnt)->debug & (debug_selection | debug_phases)) printk("SELDO (SELID=%x), ", GETPORT(SELID));#endif /* selection was done */ SETPORT(SSTAT0, CLRSELDO);#if defined(DEBUG_ABORT) if ((HOSTDATA(shpnt)->debug & debug_abort) && (CURRENT_SC->SCp.phase & aborted)) printk("(ABORT) target selected, ");#endif CURRENT_SC->SCp.phase &= ~in_selection; CURRENT_SC->SCp.phase |= in_other; ADDMSG(IDENTIFY(HOSTDATA(shpnt)->reconnect, CURRENT_SC->lun)); if (!(SYNCRATE & 0x80) && HOSTDATA(shpnt)->synchronous) { ADDMSG(EXTENDED_MESSAGE); ADDMSG(3); ADDMSG(EXTENDED_SDTR); ADDMSG(50); ADDMSG(8); printk("outbound SDTR: "); print_msg(&MSG(MSGLEN - 5)); SYNCRATE = 0x80; CURRENT_SC->SCp.phase |= in_sync; }#if defined(DEBUG_RACE) leave_driver("(SELDO) intr");#endif SETPORT(SCSIRATE, SYNCRATE & 0x7f); SETPORT(SCSISIG, P_MSGO); SETPORT(SIMODE0, 0); SETPORT(SIMODE1, ENREQINIT | ENBUSFREE); SETBITS(DMACNTRL0, INTEN); return; } else aha152x_panic(shpnt, "neither timeout nor selection\007"); } else {#if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES) if (HOSTDATA(shpnt)->debug & (debug_selection | debug_phases)) printk("SELTO, ");#endif /* end selection attempt */ CLRBITS(SCSISEQ, ENSELO | ENAUTOATNO); /* timeout */ SETPORT(SSTAT1, CLRSELTIMO); SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); SETBITS(DMACNTRL0, INTEN);#if defined(DEBUG_RACE) leave_driver("(SELTO) intr");#endif if (CURRENT_SC->SCp.phase & aborted) {#if defined(DEBUG_ABORT) if (HOSTDATA(shpnt)->debug & debug_abort) printk("(ABORT) selection timeout, ");#endif HOSTDATA(shpnt)->abort_result = SCSI_ABORT_ERROR; HOSTDATA(shpnt)->abortion_complete++; } if (TESTLO(SSTAT0, SELINGO)) /* ARBITRATION not won */ aha152x_done(shpnt, DID_BUS_BUSY << 16); else /* ARBITRATION won, but SELECTION failed */ aha152x_done(shpnt, DID_NO_CONNECT << 16); return; } } /* enable interrupt, when target leaves current phase */ phase = getphase(shpnt); if (!(phase & ~P_MASK)) /* "real" phase */ SETPORT(SCSISIG, phase); SETPORT(SSTAT1, CLRPHASECHG); CURRENT_SC->SCp.phase = (CURRENT_SC->SCp.phase & ~((P_MASK | 1) << 16)) | (phase << 16); /* information transfer phase */ switch (phase) { case P_MSGO: /* MESSAGE OUT */ { int i, identify = 0, abort = 0;#if defined(DEBUG_INTR) || defined(DEBUG_MSGO) || defined(DEBUG_PHASES) if (HOSTDATA(shpnt)->debug & (debug_intr | debug_msgo | debug_phases)) printk("MESSAGE OUT, ");#endif if (MSGLEN == 0) { ADDMSG(MESSAGE_REJECT);#if defined(DEBUG_MSGO) if (HOSTDATA(shpnt)->debug & debug_msgo) printk("unexpected MESSAGE OUT phase; rejecting, ");#endif } CLRBITS(SXFRCTL0, ENDMA); SETPORT(SIMODE0, 0); SETPORT(SIMODE1, ENPHASEMIS | ENREQINIT | ENBUSFREE); /* wait for data latch to become ready or a phase change */ while (TESTLO(DMASTAT, INTSTAT)) barrier();#if defined(DEBUG_MSGO) if (HOSTDATA(shpnt)->debug & debug_msgo) { int i;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -