📄 aha152x.c
字号:
/* clear all interrupt conditions */ SETPORT(SSTAT0, 0x7f); SETPORT(SSTAT1, 0xef); SETPORT(SSTAT4, SYNCERR|FWERR|FRERR); SETPORT(DMACNTRL0, 0); SETPORT(DMACNTRL1, 0); SETPORT(BRSTCNTRL, 0xf1); /* clear SCSI fifo and transfer count */ SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT); SETPORT(SXFRCTL0, CH1); /* enable interrupts */ SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);}/* * Reset registers, reset a hanging bus and * kill active and disconnected commands for target w/o soft reset */int aha152x_reset(Scsi_Cmnd *SCpnt, unsigned int unused){ struct Scsi_Host *shpnt = SCpnt->host; unsigned long flags; Scsi_Cmnd *ptr, *prev, *next; aha152x_reset_ports(shpnt); /* Reset, if bus hangs */ if(TESTLO(SSTAT1, BUSFREE)) { CLRBITS(DMACNTRL0, INTEN);#if defined(DEBUG_RESET) if(HOSTDATA(shpnt)->debug & debug_reset) { printk("aha152x: reset(), bus not free: SCSI RESET OUT\n"); show_queues(shpnt); }#endif ptr=CURRENT_SC; if(ptr && !ptr->device->soft_reset) { ptr->host_scribble = NULL; ptr->result = DID_RESET << 16; ptr->scsi_done(CURRENT_SC); CURRENT_SC=NULL; } save_flags(flags); cli(); prev=NULL; ptr=DISCONNECTED_SC; while(ptr) { if(!ptr->device->soft_reset) { if(prev) prev->host_scribble = ptr->host_scribble; else DISCONNECTED_SC = (Scsi_Cmnd *) ptr->host_scribble; next = (Scsi_Cmnd *) ptr->host_scribble; ptr->host_scribble = NULL; ptr->result = DID_RESET << 16; ptr->scsi_done(ptr); ptr = next; } else { prev=ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble; } } restore_flags(flags);#if defined(DEBUG_RESET) if(HOSTDATA(shpnt)->debug & debug_reset) { printk("commands on targets w/ soft-resets:\n"); show_queues(shpnt); }#endif /* RESET OUT */ SETPORT(SCSISEQ, SCSIRSTO); do_pause(30); SETPORT(SCSISEQ, 0); do_pause(DELAY); SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); SETPORT(DMACNTRL0, INTEN); } return SCSI_RESET_SUCCESS;}/* * Return the "logical geometry" */int aha152x_biosparam(Scsi_Disk * disk, kdev_t dev, int *info_array){ struct Scsi_Host *shpnt=disk->device->host;#if defined(DEBUG_BIOSPARAM) if(HOSTDATA(shpnt)->debug & debug_biosparam) printk("aha152x_biosparam: dev=%s, size=%d, ", kdevname(dev), disk->capacity);#endif /* try default translation */ info_array[0]=64; info_array[1]=32; 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 done_SC->scsi_done(done_SC);#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");}/* * Interrupts handler (main routine of the driver) */void aha152x_intr(int irqno, void *dev_id, struct pt_regs * regs){ struct Scsi_Host *shpnt = aha152x_host[irqno-IRQ_MIN]; unsigned int flags; int done=0, phase;#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 has to be restored, when we're ready to leave intr(). To avoid race conditions, we have to return immediately afterwards. */ CLRBITS(DMACNTRL0, INTEN); sti(); /* Yes, sti() really needs to be here */ /* 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -