📄 aha152x.c
字号:
/* * Abort a command * */int aha152x_abort(Scsi_Cmnd *SCpnt){ struct Scsi_Host *shpnt = SCpnt->host; Scsi_Cmnd *ptr; unsigned long flags; if(!shpnt) { printk(ERR_LEAD "abort(%p): no host structure\n", CMDINFO(SCpnt), SCpnt); return FAILED; }#if defined(AHA152X_DEBUG) if(HOSTDATA(shpnt)->debug & debug_eh) { printk(DEBUG_LEAD "abort(%p)", CMDINFO(SCpnt), SCpnt); show_queues(shpnt); mdelay(1000); }#endif DO_LOCK(flags); ptr=remove_SC(&ISSUE_SC, SCpnt); if(ptr) { DPRINTK(debug_eh, DEBUG_LEAD "not yet issued - SUCCESS\n", CMDINFO(SCpnt)); HOSTDATA(shpnt)->commands--; if (!HOSTDATA(shpnt)->commands) SETPORT(PORTA, 0); DO_UNLOCK(flags); kfree(SCpnt->host_scribble); SCpnt->host_scribble=0; return SUCCESS; } DO_UNLOCK(flags); /* * FIXME: * for current command: queue ABORT for message out and raise ATN * for disconnected command: pseudo SC with ABORT message or ABORT on reselection? * */ printk(ERR_LEAD "cannot abort running or disconnected command\n", CMDINFO(SCpnt)); return FAILED;}static void timer_expired(unsigned long p){ struct semaphore *sem = (void *)p; printk(KERN_INFO "aha152x: timer expired\n"); up(sem);}/* * Reset a device * * FIXME: never seen this live. might lockup... * */int aha152x_device_reset(Scsi_Cmnd * SCpnt){ struct Scsi_Host *shpnt = SCpnt->host; DECLARE_MUTEX_LOCKED(sem); struct timer_list timer; Scsi_Cmnd cmnd;#if defined(AHA152X_DEBUG) if(HOSTDATA(shpnt)->debug & debug_eh) { printk(INFO_LEAD "aha152x_device_reset(%p)", CMDINFO(SCpnt), SCpnt); show_queues(shpnt); mdelay(1000); }#endif if(CURRENT_SC==SCpnt) { printk(ERR_LEAD "cannot reset current device\n", CMDINFO(SCpnt)); return FAILED; } cmnd.cmd_len = 0; cmnd.host = SCpnt->host; cmnd.target = SCpnt->target; cmnd.lun = SCpnt->lun; cmnd.use_sg = 0; cmnd.request_buffer = 0; cmnd.request_bufflen = 0; init_timer(&timer); timer.data = (unsigned long) &sem; timer.expires = jiffies + 10 * HZ; /* 10s */ timer.function = (void (*)(unsigned long)) timer_expired; add_timer(&timer); aha152x_internal_queue(&cmnd, &sem, resetting, 0, internal_done); down(&sem); del_timer(&timer); if(cmnd.SCp.phase & resetted) { return SUCCESS; } else { return FAILED; }}void free_hard_reset_SCs(struct Scsi_Host *shpnt, Scsi_Cmnd **SCs){ Scsi_Cmnd *ptr; unsigned long flags; DO_LOCK(flags); ptr=*SCs; while(ptr) { Scsi_Cmnd *next = SCNEXT(ptr); if (!ptr->device->soft_reset) { DPRINTK(debug_eh, DEBUG_LEAD "disconnected command %p removed\n", CMDINFO(ptr), ptr); remove_SC(SCs, ptr); HOSTDATA(shpnt)->commands--; kfree(ptr->host_scribble); ptr->host_scribble=0; } ptr = next; } DO_UNLOCK(flags);}/* * Reset the bus * */int aha152x_bus_reset(Scsi_Cmnd *SCpnt){ struct Scsi_Host *shpnt = SCpnt->host; unsigned long flags;#if defined(AHA152X_DEBUG) if(HOSTDATA(shpnt)->debug & debug_eh) { printk(DEBUG_LEAD "aha152x_bus_reset(%p)", CMDINFO(SCpnt), SCpnt); show_queues(shpnt); mdelay(1000); }#endif free_hard_reset_SCs(shpnt, &ISSUE_SC); free_hard_reset_SCs(shpnt, &DISCONNECTED_SC); DPRINTK(debug_eh, DEBUG_LEAD "resetting bus\n", CMDINFO(SCpnt)); SETPORT(SCSISEQ, SCSIRSTO); mdelay(256); SETPORT(SCSISEQ, 0); mdelay(DELAY); DPRINTK(debug_eh, DEBUG_LEAD "bus reset returns\n", CMDINFO(SCpnt)); DO_LOCK(flags); setup_expected_interrupts(shpnt); if(HOSTDATA(shpnt)->commands==0) SETPORT(PORTA, 0); DO_UNLOCK(flags); return SUCCESS;}/* * Restore default values to the AIC-6260 registers and reset the fifos * */static void reset_ports(struct Scsi_Host *shpnt){ unsigned long flags; /* disable interrupts */ SETPORT(DMACNTRL0, RSTFIFO); SETPORT(SCSISEQ, 0); SETPORT(SXFRCTL1, 0); SETPORT(SCSISIG, 0); SETRATE(0); /* 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 fifos and transfer count */ SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT); SETPORT(SXFRCTL0, CH1); DO_LOCK(flags); setup_expected_interrupts(shpnt); DO_UNLOCK(flags);}/* * Reset the host (bus and controller) * */int aha152x_host_reset(Scsi_Cmnd * SCpnt){#if defined(AHA152X_DEBUG) struct Scsi_Host *shpnt = SCpnt->host;#endif DPRINTK(debug_eh, DEBUG_LEAD "aha152x_host_reset(%p)\n", CMDINFO(SCpnt), SCpnt); aha152x_bus_reset(SCpnt); DPRINTK(debug_eh, DEBUG_LEAD "resetting ports\n", CMDINFO(SCpnt)); reset_ports(SCpnt->host); return SUCCESS;}/* * Return the "logical geometry" * */int aha152x_biosparam(Scsi_Disk * disk, kdev_t dev, int *info_array){ struct Scsi_Host *shpnt = disk->device->host; /* 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(KERN_NOTICE "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(KERN_NOTICE "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/README.aha152x 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(KERN_NOTICE "aha152x: current partition table is using extended translation.\n" " using it also, although it's not explictly enabled.\n"); } } } return 0;}/* * Internal done function * */static void done(struct Scsi_Host *shpnt, int error){ if (CURRENT_SC) { if(DONE_SC) printk(ERR_LEAD "there's already a completed command %p - will cause abort\n", CMDINFO(CURRENT_SC), DONE_SC); DONE_SC = CURRENT_SC; CURRENT_SC = 0; DONE_SC->result = error; } else printk(KERN_ERR "aha152x: done() called outside of command\n");}static struct tq_struct aha152x_tq;/* * Run service completions on the card with interrupts enabled. * */static void 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; complete(shpnt); } }}/* * Interrupts handler * */static void intr(int irqno, void *dev_id, struct pt_regs *regs){ struct Scsi_Host *shpnt = aha152x_host[irqno - IRQ_MIN]; if (!shpnt) { printk(KERN_ERR "aha152x: catched interrupt for unknown controller.\n"); return; } /* no more interrupts from the controller, while we're busy. INTEN is restored by the BH handler */ CLRBITS(DMACNTRL0, INTEN);#if 0 /* check if there is already something to be serviced; should not happen */ if(HOSTDATA(shpnt)->service) { printk(KERN_ERR "aha152x%d: lost interrupt (%d)\n", HOSTNO, HOSTDATA(shpnt)->service); show_queues(shpnt); }#endif /* Poke the BH handler */ HOSTDATA(shpnt)->service++; aha152x_tq.routine = (void *) run; queue_task(&aha152x_tq, &tq_immediate); mark_bh(IMMEDIATE_BH);}/* * busfree phase * - handle completition/disconnection/error of current command * - start selection for next command (if any) */static void busfree_run(struct Scsi_Host *shpnt){ unsigned long flags;#if defined(AHA152X_STAT) int action=0;#endif SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT); SETPORT(SXFRCTL0, CH1); SETPORT(SSTAT1, CLRBUSFREE); if(CURRENT_SC) {#if defined(AHA152X_STAT) action++;#endif CURRENT_SC->SCp.phase &= ~syncneg; if(CURRENT_SC->SCp.phase & completed) { /* target sent COMMAND COMPLETE */ done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16)); } else if(CURRENT_SC->SCp.phase & aborted) { DPRINTK(debug_eh, DEBUG_LEAD "ABORT sent\n", CMDINFO(CURRENT_SC)); done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_ABORT << 16)); } else if(CURRENT_SC->SCp.phase & resetted) { DPRINTK(debug_eh, DEBUG_LEAD "BUS DEVICE RESET sent\n", CMDINFO(CURRENT_SC)); done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_RESET << 16)); } else if(CURRENT_SC->SCp.phase & disconnected) { /* target sent DISCONNECT */ DPRINTK(debug_selection, DEBUG_LEAD "target disconnected at %d/%d\n", CMDINFO(CURRENT_SC), CURRENT_SC->resid, CURRENT_SC->request_bufflen);#if defined(AHA152X_STAT) HOSTDATA(shpnt)->disconnections++;#endif append_SC(&DISCONNECTED_SC, CURRENT_SC); CURRENT_SC->SCp.phase |= 1 << 16; CURRENT_SC = 0; } else { done(shpnt, DID_ERROR << 16); }#if defined(AHA152X_STAT) } else { HOSTDATA(shpnt)->busfree_without_old_command++;#endif } DO_LOCK(flags); if(DONE_SC) {#if defined(AHA152X_STAT) action++;#endif if(SCDONE(DONE_SC)) { Scsi_Cmnd *ptr=DONE_SC; DONE_SC=SCDONE(DONE_SC);#if 0 if(HOSTDATA(shpnt)->debug & debug_eh) { printk(ERR_LEAD "received sense: ", CMDINFO(ptr)); print_sense("bh", DONE_SC); }#endif HOSTDATA(shpnt)->commands--; if (!HOSTDATA(shpnt)->commands) SETPORT(PORTA, 0); /* turn led off */ kfree(ptr->host_scribble); kfree(ptr); } else if(DONE_SC->SCp.Status==0x02) {#if defined(AHA152X_STAT) HOSTDATA(shpnt)->busfree_with_check_condition++;#endif#if 0 DPRINTK(debug_eh, ERR_LEAD "CHECK CONDITION found\n", CMDINFO(DONE_SC));#endif if(!(DONE_SC->SCp.Status & not_issued)) { Scsi_Cmnd *cmnd = kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC); if(cmnd) { Scsi_Cmnd *ptr=DONE_SC; DONE_SC=0;#if 0 DPRINTK(debug_eh, ERR_LEAD "requesting sense\n", CMDINFO(ptr));#endif cmnd->cmnd[0] = REQUEST_SENSE; cmnd->cmnd[1] = 0; cmnd->cmnd[2] = 0; cmnd->cmnd[3] = 0; cmnd->cmnd[4] = sizeof(ptr->sense_buffer); cmnd->cmnd[5] = 0; cmnd->cmd_len = 6; cmnd->host = ptr->host; cmnd->target = ptr->target; cmnd->lun = ptr->lun; cmnd->use_sg = 0; cmnd->request_buffer = ptr->sense_buffer; cmnd->request_bufflen = sizeof(ptr->sense_buffer); DO_UNLOCK(flags); aha152x_internal_queue(cmnd, 0, 0, ptr, internal_done); DO_LOCK(flags); } else { printk(ERR_LEAD "allocation failed\n", CMDINFO(CURRENT_SC)); if(cmnd) kfree(cmnd); } } else {#if 0 DPRINTK(debug_eh, ERR_LEAD "command not issued - CHECK CONDITION ignored\n", CMDINFO(DONE_SC));#endif } } if(DONE_SC && DONE_SC->scsi_done) { /* turn led off, when no commands are in the driver */ HOSTDATA(shpnt)->commands--; if (!HOSTDATA(shpnt)->commands) SETPORT(PORTA, 0); /* turn led off */ kfree(DONE_SC->host_scribble); DONE_SC->host_scribble=0; DO_UNLOCK(flags); DPRINTK(debug_done, DEBUG_LEAD "calling scsi_done(%p)\n", CMDINFO(DONE_SC), DONE_SC); DONE_SC->scsi_done(DONE_SC); DPRINTK(debug_done, DEBUG_LEAD "scsi_done(%p) returned\n", CMDINFO(DONE_SC), DONE_SC); DO_LOCK(flags); } DONE_SC=0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -