📄 aha152x.c
字号:
SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1; } else { SCpnt->SCp.ptr = (char *) SCpnt->request_buffer; SCpnt->SCp.this_residual = SCpnt->request_bufflen; SCpnt->SCp.buffer = NULL; SCpnt->SCp.buffers_residual = 0; } DO_LOCK(flags);#if defined(AHA152X_STAT) HOSTDATA(shpnt)->total_commands++;#endif /* Turn led on, when this is the first command. */ HOSTDATA(shpnt)->commands++; if (HOSTDATA(shpnt)->commands==1) SETPORT(PORTA, 1); append_SC(&ISSUE_SC, SCpnt); if(!HOSTDATA(shpnt)->in_intr) setup_expected_interrupts(shpnt); DO_UNLOCK(flags); return 0;}int aha152x_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)){#if 0 if(*SCpnt->cmnd == REQUEST_SENSE) { SCpnt->result = 0; done(SCpnt); return 0; }#endif return aha152x_internal_queue(SCpnt, 0, 0, 0, done);}/* * run a command * */void internal_done(Scsi_Cmnd *SCpnt){#if 0 struct Scsi_Host *shpnt = SCpnt->host; DPRINTK(debug_eh, INFO_LEAD "internal_done called\n", CMDINFO(SCpnt));#endif if(SCSEM(SCpnt)) up(SCSEM(SCpnt));}int aha152x_command(Scsi_Cmnd * SCpnt){ DECLARE_MUTEX_LOCKED(sem); aha152x_internal_queue(SCpnt, &sem, 0, 0, internal_done); down(&sem); return SUCCESS;}/* * 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 + 100*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 explicitly 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; is_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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -