📄 aha152x.c
字号:
}#endif printk("detected %d controller(s)\n", setup_count); for (i = 0; i < setup_count; i++) { struct Scsi_Host *shpnt; unsigned long int the_time; shpnt = aha152x_host[setup[i].irq - IRQ_MIN] = scsi_register(tpnt, sizeof(struct aha152x_hostdata)); registered_count++; shpnt->io_port = setup[i].io_port; shpnt->n_io_port = IO_RANGE; shpnt->irq = setup[i].irq; ISSUE_SC = (Scsi_Cmnd *) NULL; CURRENT_SC = (Scsi_Cmnd *) NULL; DISCONNECTED_SC = (Scsi_Cmnd *) NULL; HOSTDATA(shpnt)->reconnect = setup[i].reconnect; HOSTDATA(shpnt)->parity = setup[i].parity; HOSTDATA(shpnt)->synchronous = setup[i].synchronous; HOSTDATA(shpnt)->delay = setup[i].delay; HOSTDATA(shpnt)->ext_trans = setup[i].ext_trans;#ifdef DEBUG_AHA152X HOSTDATA(shpnt)->debug = setup[i].debug;#endif HOSTDATA(shpnt)->aborting = 0; HOSTDATA(shpnt)->abortion_complete = 0; HOSTDATA(shpnt)->abort_result = 0; HOSTDATA(shpnt)->commands = 0; HOSTDATA(shpnt)->message_len = 0; for (j = 0; j < 8; j++) HOSTDATA(shpnt)->syncrate[j] = 0; SETPORT(SCSIID, setup[i].scsiid << 4); shpnt->this_id = setup[i].scsiid; if (setup[i].reconnect) shpnt->can_queue = AHA152X_MAXQUEUE; /* RESET OUT */ SETBITS(SCSISEQ, SCSIRSTO); do_pause(30); CLRBITS(SCSISEQ, SCSIRSTO); do_pause(setup[i].delay); aha152x_reset_ports(shpnt); printk("aha152x%d: vital data: PORTBASE=0x%03lx, IRQ=%d, SCSI ID=%d," " reconnect=%s, parity=%s, synchronous=%s, delay=%d, extended translation=%s\n", i, shpnt->io_port, shpnt->irq, shpnt->this_id, HOSTDATA(shpnt)->reconnect ? "enabled" : "disabled", HOSTDATA(shpnt)->parity ? "enabled" : "disabled", HOSTDATA(shpnt)->synchronous ? "enabled" : "disabled", HOSTDATA(shpnt)->delay, HOSTDATA(shpnt)->ext_trans ? "enabled" : "disabled"); request_region(shpnt->io_port, IO_RANGE, "aha152x"); /* Register */ /* not expecting any interrupts */ SETPORT(SIMODE0, 0); SETPORT(SIMODE1, 0); SETBITS(DMACNTRL0, INTEN); ok = request_irq(shpnt->irq, aha152x_swintr, SA_INTERRUPT, "aha152x", shpnt); if (ok < 0) { if (ok == -EINVAL) printk("aha152x%d: bad IRQ %d.\n", i, shpnt->irq); else if (ok == -EBUSY) printk("aha152x%d: IRQ %d already in use.\n", i, shpnt->irq); else printk("\naha152x%d: Unexpected error code %d on requesting IRQ %d.\n", i, ok, shpnt->irq); printk("aha152x: driver needs an IRQ.\n"); scsi_unregister(shpnt); registered_count--; release_region(shpnt->io_port, IO_RANGE); shpnt = aha152x_host[shpnt->irq - IRQ_MIN] = 0; continue; } HOSTDATA(shpnt)->swint = 0; printk("aha152x: trying software interrupt, "); SETBITS(DMACNTRL0, SWINT); the_time = jiffies + 100; while (!HOSTDATA(shpnt)->swint && time_before(jiffies, the_time)) barrier(); free_irq(shpnt->irq, shpnt); if (!HOSTDATA(shpnt)->swint) { if (TESTHI(DMASTAT, INTSTAT)) { printk("lost.\n"); } else { printk("failed.\n"); } printk("aha152x: IRQ %d possibly wrong. Please verify.\n", shpnt->irq); scsi_unregister(shpnt); registered_count--; release_region(shpnt->io_port, IO_RANGE); shpnt = aha152x_host[shpnt->irq - IRQ_MIN] = 0; continue; } printk("ok.\n"); CLRBITS(DMACNTRL0, SWINT); /* clear interrupts */ SETPORT(SSTAT0, 0x7f); SETPORT(SSTAT1, 0xef); if (request_irq(shpnt->irq, aha152x_intr, SA_INTERRUPT, "aha152x", shpnt) < 0) { printk("aha152x: failed to reassign interrupt.\n"); } } return (registered_count > 0);}int aha152x_release(struct Scsi_Host *shpnt){ if (shpnt->irq) free_irq(shpnt->irq, shpnt); if (shpnt->io_port) release_region(shpnt->io_port, IO_RANGE); return 0;}/* * Queue a command and setup interrupts for a free bus. */int aha152x_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)){ struct Scsi_Host *shpnt = SCpnt->host; unsigned long flags;#if defined(DEBUG_RACE) enter_driver("queue");#else#if defined(DEBUG_QUEUE) if (HOSTDATA(shpnt)->debug & debug_queue) printk("aha152x: queue(), ");#endif#endif#if defined(DEBUG_QUEUE) if (HOSTDATA(shpnt)->debug & debug_queue) { printk("SCpnt (target = %d lun = %d cmnd = ", SCpnt->target, SCpnt->lun); print_command(SCpnt->cmnd); printk(", cmd_len=%d, pieces = %d size = %u), ", SCpnt->cmd_len, SCpnt->use_sg, SCpnt->request_bufflen); disp_ports(shpnt); }#endif SCpnt->scsi_done = done; /* setup scratch area SCp.ptr : buffer pointer SCp.this_residual : buffer length SCp.buffer : next buffer SCp.buffers_residual : left buffers in list SCp.phase : current state of the command */ SCpnt->SCp.phase = not_issued; if (SCpnt->use_sg) { SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->request_buffer; SCpnt->SCp.ptr = SCpnt->SCp.buffer->address; 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; } SCpnt->SCp.Status = CHECK_CONDITION; SCpnt->SCp.Message = 0; SCpnt->SCp.have_data_in = 0; SCpnt->SCp.sent_command = 0; /* Turn led on, when this is the first command. */ save_flags(flags); cli(); HOSTDATA(shpnt)->commands++; if (HOSTDATA(shpnt)->commands == 1) SETPORT(PORTA, 1);#if defined(DEBUG_QUEUES) if (HOSTDATA(shpnt)->debug & debug_queues) printk("i+ (%d), ", HOSTDATA(shpnt)->commands);#endif append_SC(&ISSUE_SC, SCpnt); /* Enable bus free interrupt, when we aren't currently on the bus */ if (!CURRENT_SC) { SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); } restore_flags(flags);#if defined(DEBUG_RACE) leave_driver("queue");#endif return 0;}/* * We only support commands in interrupt-driven fashion */int aha152x_command(Scsi_Cmnd * SCpnt){ printk("aha152x: interrupt driven driver; use aha152x_queue()\n"); return -1;}/* * Abort a queued command * (commands that are on the bus can't be aborted easily) */int aha152x_abort(Scsi_Cmnd * SCpnt){ struct Scsi_Host *shpnt = SCpnt->host; unsigned long flags; Scsi_Cmnd *ptr, *prev; save_flags(flags); cli();#if defined(DEBUG_ABORT) if (HOSTDATA(shpnt)->debug & debug_abort) { printk("aha152x: abort(), SCpnt=0x%08x, ", (unsigned int) SCpnt); show_queues(shpnt); }#endif /* look for command in issue queue */ for (ptr = ISSUE_SC, prev = NULL; ptr && ptr != SCpnt; prev = ptr, ptr = (Scsi_Cmnd *) ptr->host_scribble); if (ptr) { /* dequeue */ if (prev) prev->host_scribble = ptr->host_scribble; else ISSUE_SC = (Scsi_Cmnd *) ptr->host_scribble; HOSTDATA(shpnt)->commands--; restore_flags(flags); ptr->host_scribble = NULL; ptr->result = DID_ABORT << 16; spin_lock_irqsave(&io_request_lock, flags); ptr->scsi_done(ptr); spin_unlock_irqrestore(&io_request_lock, flags); return SCSI_ABORT_SUCCESS; } /* if the bus is busy or a command is currently processed, we can't do anything more */ if (TESTLO(SSTAT1, BUSFREE) || (CURRENT_SC && CURRENT_SC != SCpnt)) { /* fail abortion, if bus is busy */ if (!CURRENT_SC) printk("bus busy w/o current command, "); restore_flags(flags); return SCSI_ABORT_BUSY; } /* bus is free */ if (CURRENT_SC) { HOSTDATA(shpnt)->commands--; /* target entered bus free before COMMAND COMPLETE, nothing to abort */ restore_flags(flags); spin_lock_irqsave(&io_request_lock, flags); CURRENT_SC->result = DID_ERROR << 16; CURRENT_SC->scsi_done(CURRENT_SC); CURRENT_SC = (Scsi_Cmnd *) NULL; spin_unlock_irqrestore(&io_request_lock, flags); return SCSI_ABORT_SUCCESS; } /* look for command in disconnected queue */ for (ptr = DISCONNECTED_SC, prev = NULL; ptr && ptr != SCpnt; prev = ptr, ptr = (Scsi_Cmnd *) ptr->host_scribble); if (!ptr) { /* command wasn't found */ printk("command not found\n"); restore_flags(flags); return SCSI_ABORT_NOT_RUNNING; } if (!HOSTDATA(shpnt)->aborting) { /* dequeue */ if (prev) prev->host_scribble = ptr->host_scribble; else DISCONNECTED_SC = (Scsi_Cmnd *) ptr->host_scribble; HOSTDATA(shpnt)->commands--; /* set command current and initiate selection, let the interrupt routine take care of the abortion */ CURRENT_SC = ptr; ptr->SCp.phase = in_selection | aborted; SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->target); ADDMSG(ABORT); /* 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); SETBITS(DMACNTRL0, INTEN); HOSTDATA(shpnt)->abort_result = SCSI_ABORT_SUCCESS; HOSTDATA(shpnt)->aborting++; HOSTDATA(shpnt)->abortion_complete = 0; restore_flags(flags); /* sleep until the abortion is complete */ while (!HOSTDATA(shpnt)->abortion_complete) barrier(); HOSTDATA(shpnt)->aborting = 0; return HOSTDATA(shpnt)->abort_result; } else { /* we're already aborting a command */ restore_flags(flags); return SCSI_ABORT_BUSY; }}/* * Restore default values to the AIC-6260 registers and reset the fifos */static void aha152x_reset_ports(struct Scsi_Host *shpnt){ /* disable interrupts */ SETPORT(DMACNTRL0, RSTFIFO); SETPORT(SCSISEQ, 0); SETPORT(SXFRCTL1, 0); SETPORT(SCSISIG, 0); SETPORT(SCSIRATE, 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 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -