📄 ncr53c9x.c
字号:
esp->dma_mmu_get_scsi_sgl(esp, sp); else sp->SCp.ptr = (char *) virt_to_phys(sp->SCp.buffer->address); }}static void esp_release_dmabufs(struct NCR_ESP *esp, Scsi_Cmnd *sp){ if(sp->use_sg == 0) { if (esp->dma_mmu_release_scsi_one) esp->dma_mmu_release_scsi_one(esp, sp); } else { if (esp->dma_mmu_release_scsi_sgl) esp->dma_mmu_release_scsi_sgl(esp, sp); }}static void esp_restore_pointers(struct NCR_ESP *esp, Scsi_Cmnd *sp){ struct esp_pointers *ep = &esp->data_pointers[sp->target]; sp->SCp.ptr = ep->saved_ptr; sp->SCp.buffer = ep->saved_buffer; sp->SCp.this_residual = ep->saved_this_residual; sp->SCp.buffers_residual = ep->saved_buffers_residual;}static void esp_save_pointers(struct NCR_ESP *esp, Scsi_Cmnd *sp){ struct esp_pointers *ep = &esp->data_pointers[sp->target]; ep->saved_ptr = sp->SCp.ptr; ep->saved_buffer = sp->SCp.buffer; ep->saved_this_residual = sp->SCp.this_residual; ep->saved_buffers_residual = sp->SCp.buffers_residual;}/* Some rules: * * 1) Never ever panic while something is live on the bus. * If there is to be any chance of syncing the disks this * rule is to be obeyed. * * 2) Any target that causes a foul condition will no longer * have synchronous transfers done to it, no questions * asked. * * 3) Keep register accesses to a minimum. Think about some * day when we have Xbus machines this is running on and * the ESP chip is on the other end of the machine on a * different board from the cpu where this is running. *//* Fire off a command. We assume the bus is free and that the only * case where we could see an interrupt is where we have disconnected * commands active and they are trying to reselect us. */static inline void esp_check_cmd(struct NCR_ESP *esp, Scsi_Cmnd *sp){ switch(sp->cmd_len) { case 6: case 10: case 12: esp->esp_slowcmd = 0; break; default: esp->esp_slowcmd = 1; esp->esp_scmdleft = sp->cmd_len; esp->esp_scmdp = &sp->cmnd[0]; break; };}static inline void build_sync_nego_msg(struct NCR_ESP *esp, int period, int offset){ esp->cur_msgout[0] = EXTENDED_MESSAGE; esp->cur_msgout[1] = 3; esp->cur_msgout[2] = EXTENDED_SDTR; esp->cur_msgout[3] = period; esp->cur_msgout[4] = offset; esp->msgout_len = 5;}static void esp_exec_cmd(struct NCR_ESP *esp){ struct ESP_regs *eregs = esp->eregs; Scsi_Cmnd *SCptr; Scsi_Device *SDptr; volatile unchar *cmdp = esp->esp_command; unsigned char the_esp_command; int lun, target; int i; /* Hold off if we have disconnected commands and * an IRQ is showing... */ if(esp->disconnected_SC && esp->dma_irq_p(esp)) return; /* Grab first member of the issue queue. */ SCptr = esp->current_SC = remove_first_SC(&esp->issue_SC); /* Safe to panic here because current_SC is null. */ if(!SCptr) panic("esp: esp_exec_cmd and issue queue is NULL"); SDptr = SCptr->device; lun = SCptr->lun; target = SCptr->target; esp->snip = 0; esp->msgout_len = 0; /* Send it out whole, or piece by piece? The ESP * only knows how to automatically send out 6, 10, * and 12 byte commands. I used to think that the * Linux SCSI code would never throw anything other * than that to us, but then again there is the * SCSI generic driver which can send us anything. */ esp_check_cmd(esp, SCptr); /* If arbitration/selection is successful, the ESP will leave * ATN asserted, causing the target to go into message out * phase. The ESP will feed the target the identify and then * the target can only legally go to one of command, * datain/out, status, or message in phase, or stay in message * out phase (should we be trying to send a sync negotiation * message after the identify). It is not allowed to drop * BSY, but some buggy targets do and we check for this * condition in the selection complete code. Most of the time * we'll make the command bytes available to the ESP and it * will not interrupt us until it finishes command phase, we * cannot do this for command sizes the ESP does not * understand and in this case we'll get interrupted right * when the target goes into command phase. * * It is absolutely _illegal_ in the presence of SCSI-2 devices * to use the ESP select w/o ATN command. When SCSI-2 devices are * present on the bus we _must_ always go straight to message out * phase with an identify message for the target. Being that * selection attempts in SCSI-1 w/o ATN was an option, doing SCSI-2 * selections should not confuse SCSI-1 we hope. */ if(SDptr->sync) { /* this targets sync is known */#ifdef CONFIG_SCSI_MAC_ESPdo_sync_known:#endif if(SDptr->disconnect) *cmdp++ = IDENTIFY(1, lun); else *cmdp++ = IDENTIFY(0, lun); if(esp->esp_slowcmd) { the_esp_command = (ESP_CMD_SELAS | ESP_CMD_DMA); esp_advance_phase(SCptr, in_slct_stop); } else { the_esp_command = (ESP_CMD_SELA | ESP_CMD_DMA); esp_advance_phase(SCptr, in_slct_norm); } } else if(!(esp->targets_present & (1<<target)) || !(SDptr->disconnect)) { /* After the bootup SCSI code sends both the * TEST_UNIT_READY and INQUIRY commands we want * to at least attempt allowing the device to * disconnect. */ ESPMISC(("esp: Selecting device for first time. target=%d " "lun=%d\n", target, SCptr->lun)); if(!SDptr->borken && !SDptr->disconnect) SDptr->disconnect = 1; *cmdp++ = IDENTIFY(0, lun); esp->prevmsgout = NOP; esp_advance_phase(SCptr, in_slct_norm); the_esp_command = (ESP_CMD_SELA | ESP_CMD_DMA); /* Take no chances... */ SDptr->sync_max_offset = 0; SDptr->sync_min_period = 0; } else { int toshiba_cdrom_hwbug_wkaround = 0;#ifdef CONFIG_SCSI_MAC_ESP /* Never allow synchronous transfers (disconnect OK) on * Macintosh. Well, maybe later when we figured out how to * do DMA on the machines that support it ... */ SDptr->disconnect = 1; SDptr->sync_max_offset = 0; SDptr->sync_min_period = 0; SDptr->sync = 1; esp->snip = 0; goto do_sync_known;#endif /* We've talked to this guy before, * but never negotiated. Let's try * sync negotiation. */ if(!SDptr->borken) { if((SDptr->type == TYPE_ROM) && (!strncmp(SDptr->vendor, "TOSHIBA", 7))) { /* Nice try sucker... */ ESPMISC(("esp%d: Disabling sync for buggy " "Toshiba CDROM.\n", esp->esp_id)); toshiba_cdrom_hwbug_wkaround = 1; build_sync_nego_msg(esp, 0, 0); } else { build_sync_nego_msg(esp, esp->sync_defp, 15); } } else { build_sync_nego_msg(esp, 0, 0); } SDptr->sync = 1; esp->snip = 1; /* A fix for broken SCSI1 targets, when they disconnect * they lock up the bus and confuse ESP. So disallow * disconnects for SCSI1 targets for now until we * find a better fix. * * Addendum: This is funny, I figured out what was going * on. The blotzed SCSI1 target would disconnect, * one of the other SCSI2 targets or both would be * disconnected as well. The SCSI1 target would * stay disconnected long enough that we start * up a command on one of the SCSI2 targets. As * the ESP is arbitrating for the bus the SCSI1 * target begins to arbitrate as well to reselect * the ESP. The SCSI1 target refuses to drop it's * ID bit on the data bus even though the ESP is * at ID 7 and is the obvious winner for any * arbitration. The ESP is a poor sport and refuses * to lose arbitration, it will continue indefinately * trying to arbitrate for the bus and can only be * stopped via a chip reset or SCSI bus reset. * Therefore _no_ disconnects for SCSI1 targets * thank you very much. ;-) */ if(((SDptr->scsi_level < 3) && (SDptr->type != TYPE_TAPE)) || toshiba_cdrom_hwbug_wkaround || SDptr->borken) { ESPMISC((KERN_INFO "esp%d: Disabling DISCONNECT for target %d " "lun %d\n", esp->esp_id, SCptr->target, SCptr->lun)); SDptr->disconnect = 0; *cmdp++ = IDENTIFY(0, lun); } else { *cmdp++ = IDENTIFY(1, lun); } /* ESP fifo is only so big... * Make this look like a slow command. */ esp->esp_slowcmd = 1; esp->esp_scmdleft = SCptr->cmd_len; esp->esp_scmdp = &SCptr->cmnd[0]; the_esp_command = (ESP_CMD_SELAS | ESP_CMD_DMA); esp_advance_phase(SCptr, in_slct_msg); } if(!esp->esp_slowcmd) for(i = 0; i < SCptr->cmd_len; i++) *cmdp++ = SCptr->cmnd[i]; esp_write(eregs->esp_busid, (target & 7)); if (esp->prev_soff != SDptr->sync_max_offset || esp->prev_stp != SDptr->sync_min_period || (esp->erev > esp100a && esp->prev_cfg3 != esp->config3[target])) { esp->prev_soff = SDptr->sync_max_offset; esp_write(eregs->esp_soff, esp->prev_soff); esp->prev_stp = SDptr->sync_min_period; esp_write(eregs->esp_stp, esp->prev_stp); if(esp->erev > esp100a) { esp->prev_cfg3 = esp->config3[target]; esp_write(eregs->esp_cfg3, esp->prev_cfg3); } } i = (cmdp - esp->esp_command); /* Set up the DMA and ESP counters */ if(esp->do_pio_cmds){ int j = 0; /* * XXX MSch: * * It seems this is required, at least to clean up * after failed commands when using PIO mode ... */ esp_cmd(esp, eregs, ESP_CMD_FLUSH); for(;j<i;j++) esp_write(eregs->esp_fdata, esp->esp_command[j]); the_esp_command &= ~ESP_CMD_DMA; /* Tell ESP to "go". */ esp_cmd(esp, eregs, the_esp_command); } else { /* Set up the ESP counters */ esp_write(eregs->esp_tclow, i); esp_write(eregs->esp_tcmed, 0); esp->dma_init_write(esp, esp->esp_command_dvma, i); /* Tell ESP to "go". */ esp_cmd(esp, eregs, the_esp_command); }}/* Queue a SCSI command delivered from the mid-level Linux SCSI code. */int esp_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)){ struct NCR_ESP *esp; /* Set up func ptr and initial driver cmd-phase. */ SCpnt->scsi_done = done; SCpnt->SCp.phase = not_issued; esp = (struct NCR_ESP *) SCpnt->host->hostdata; if(esp->dma_led_on) esp->dma_led_on(esp); /* We use the scratch area. */ ESPQUEUE(("esp_queue: target=%d lun=%d ", SCpnt->target, SCpnt->lun)); ESPDISC(("N<%02x,%02x>", SCpnt->target, SCpnt->lun)); esp_get_dmabufs(esp, SCpnt); esp_save_pointers(esp, SCpnt); /* FIXME for tag queueing */ SCpnt->SCp.Status = CHECK_CONDITION; SCpnt->SCp.Message = 0xff; SCpnt->SCp.sent_command = 0; /* Place into our queue. */ if(SCpnt->cmnd[0] == REQUEST_SENSE) { ESPQUEUE(("RQSENSE\n")); prepend_SC(&esp->issue_SC, SCpnt); } else { ESPQUEUE(("\n")); append_SC(&esp->issue_SC, SCpnt); } /* Run it now if we can. */ if(!esp->current_SC && !esp->resetting_bus) esp_exec_cmd(esp); return 0;}/* Only queuing supported in this ESP driver. */int esp_command(Scsi_Cmnd *SCpnt){#ifdef DEBUG_ESP struct NCR_ESP *esp = (struct NCR_ESP *) SCpnt->host->hostdata;#endif ESPLOG(("esp%d: esp_command() called...\n", esp->esp_id)); return -1;}/* Dump driver state. */static void esp_dump_cmd(Scsi_Cmnd *SCptr){ ESPLOG(("[tgt<%02x> lun<%02x> " "pphase<%s> cphase<%s>]", SCptr->target, SCptr->lun, phase_string(SCptr->SCp.sent_command), phase_string(SCptr->SCp.phase)));}static void esp_dump_state(struct NCR_ESP *esp, struct ESP_regs *eregs){ Scsi_Cmnd *SCptr = esp->current_SC;#ifdef DEBUG_ESP_CMDS int i;#endif ESPLOG(("esp%d: dumping state\n", esp->esp_id)); /* Print DMA status */ esp->dma_dump_state(esp); ESPLOG(("esp%d: SW [sreg<%02x> sstep<%02x> ireg<%02x>]\n", esp->esp_id, esp->sreg, esp->seqreg, esp->ireg)); ESPLOG(("esp%d: HW reread [sreg<%02x> sstep<%02x> ireg<%02x>]\n", esp->esp_id, esp_read(eregs->esp_status), esp_read(eregs->esp_sstep), esp_read(eregs->esp_intrpt)));#ifdef DEBUG_ESP_CMDS printk("esp%d: last ESP cmds [", esp->esp_id); i = (esp->espcmdent - 1) & 31; printk("<"); esp_print_cmd(esp->espcmdlog[i]); printk(">"); i = (i - 1) & 31; printk("<"); esp_print_cmd(esp->espcmdlog[i]); printk(">"); i = (i - 1) & 31; printk("<"); esp_print_cmd(esp->espcmdlog[i]); printk(">"); i = (i - 1) & 31; printk("<"); esp_print_cmd(esp->espcmdlog[i]); printk(">"); printk("]\n");#endif /* (DEBUG_ESP_CMDS) */ if(SCptr) { ESPLOG(("esp%d: current command ", esp->esp_id)); esp_dump_cmd(SCptr); } ESPLOG(("\n")); SCptr = esp->disconnected_SC; ESPLOG(("esp%d: disconnected ", esp->esp_id)); while(SCptr) { esp_dump_cmd(SCptr); SCptr = (Scsi_Cmnd *) SCptr->host_scribble; } ESPLOG(("\n"));}/* Abort a command. */int esp_abort(Scsi_Cmnd *SCptr){ struct NCR_ESP *esp = (struct NCR_ESP *) SCptr->host->hostdata; struct ESP_regs *eregs = esp->eregs; int don; ESPLOG(("esp%d: Aborting command\n", esp->esp_id)); esp_dump_state(esp, eregs); /* Wheee, if this is the current command on the bus, the * best we can do is assert ATN and wait for msgout phase. * This should even fix a hung SCSI bus when we lose state * in the driver and timeout because the eventual phase change * will cause the ESP to (eventually) give an interrupt. */ if(esp->current_SC == SCptr) { esp->cur_msgout[0] = ABORT; esp->msgout_len = 1; esp->msgout_ctr = 0; esp_cmd(esp, eregs, ESP_CMD_SATN); return SCSI_ABORT_PENDING; } /* If it is still in the issue queue then we can safely * call the completion routine and report abort success. */ don = esp->dma_ports_p(esp); if(don) { esp->dma_ints_off(esp); synchronize_irq(); } if(esp->issue_SC) { Scsi_Cmnd **prev, *this; for(prev = (&esp->issue_SC), this = esp->issue_SC; this; prev = (Scsi_Cmnd **) &(this->host_scribble),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -