📄 esp.c
字号:
#endif ESP_TEST_FAST_SYNC } else { ep->esp_conf2 = esp->e_espconf2; esp->e_type = ESP236; IPRINTF("found ESP236\n"); } ep->esp_conf3 = espconf3; } else { ep->esp_conf2 = esp->e_espconf2; esp->e_type = ESP100A; } } else { esp->e_type = ESP100; } /* * check for differential scsi bus property */ if (getprop(dev->devi_nodeid, prop_diff, -1) != -1) { IPRINTF("differential scsi bus\n"); esp->e_differential++; } esp_internal_reset(esp, ESP_RESET_ALL); /* * Whew! Now make ourselves known to the rest of the SCSI world... */ scsi_config(&esp->e_tran, dev);#ifdef GASP if (dev->devi_unit == 0 && nesp > 1) { for (i = 1; i < nesp; i++) { dev = dev->devi_next; (void) esp_attach(dev); } }#endif /* GASP */ return (0);}#else /* OPENPROMS */static int esp_probe(), esp_slave(), esp_attach();struct mb_driver espdriver = { esp_probe, esp_slave, esp_attach, 0, 0, esp_poll, ESP_SIZE, "scsibus", 0, "esp", 0, MDR_BIODMA};static intesp_probe(reg, ctlr)caddr_t reg;int ctlr;{ static char first_time = 1; register struct dmaga *dmar; register struct espreg *ep; register struct esp *esp, *nsp; u_long dma_base, ticks; u_char clock_conv; long lptr; /* * These shorthand defines just for this routine */#define DNAME espdriver.mdr_cname#define DUNIT ctlr switch (cpu) {#ifdef sun4 case CPU_SUN4_330: dma_base = (u_long) DVMA; clock_conv = CLOCK_25MHZ; dmar = (struct dmaga *) (((long) reg) + STINGRAY_DMA_OFFSET); break;#endif /* sun4 */#ifdef sun3x case CPU_SUN3X_80: dma_base = (u_long) DVMA; clock_conv = CLOCK_20MHZ; dmar = (struct dmaga *) (((long) reg) + HYDRA_DMA_OFFSET); break;#endif /* sun3x */ default: return (0); } if ((peekl((long *)&(dmar->dmaga_csr), (long *)&(lptr))) == -1) { return (0); } ep = (struct espreg *) reg; if ((peekc((char *)&(ep->esp_xcnt_lo))) == -1) { return (0); } esp = (struct esp *) kmem_zalloc((unsigned) (sizeof (struct esp))); if (esp != (struct esp *) 0) { esp->e_cmdarea = (u_char *) IOPBALLOC(FIFOSIZE); } if (esp == (struct esp *) 0 || esp->e_cmdarea == (u_char *) 0) { printf("esp%d: no space for %s\n", DUNIT, (esp->e_cmdarea) ? "cmd areas" : "data structures"); if (esp) { (void) kmem_free((caddr_t)esp, (sizeof (struct esp))); } return (0); } esp->e_next = (struct esp *)0; esp->e_unit = DUNIT; /* * Establish initial softc values */ if (esp_softc == (struct esp *) 0) { esp_softc = esp; } else { for (nsp = esp_softc; nsp->e_next != (struct esp *) 0; nsp = nsp->e_next); nsp->e_next = esp; } esp->e_dev = &espdriver; esp->e_espconf = DEFAULT_HOSTID; if (scsi_options & SCSI_OPTIONS_PARITY) esp->e_espconf |= ESP_CONF_PAREN; esp->e_espconf |= (espconf & ~ESP_CONF_BUSID); esp->e_burstsizes = 0; esp->e_clock_conv = clock_conv; esp->e_clock_cycle = FIVE_MEG * clock_conv; ticks = ESP_CLOCK_TICK(esp); esp->e_stval = ESP_CLOCK_TIMEOUT(ticks); esp->e_backoff = 0;#ifdef ESP_TEST_FAST_SYNC IPRINTF5("%d mhz, clock_conv %d, clock_cycle %d, ticks %d, stval %d\n", FIVE_MEG * clock_conv, esp->e_clock_conv, esp->e_clock_cycle, ticks, esp->e_stval);#endif ESP_TEST_FAST_SYNC esp->e_reg = ep; esp->e_dma = dmar; /* * Initialize state of DMA gate array. */ dmar->dmaga_csr = dmar->dmaga_csr & ~DMAGA_WRITE; esp->e_dma_base = dma_base; esp->e_tran.tran_start = esp_start; esp->e_tran.tran_abort = esp_abort; esp->e_tran.tran_reset = esp_reset; esp->e_tran.tran_getcap = esp_getcap; esp->e_tran.tran_setcap = esp_setcap; esp->e_tran.tran_pktalloc = scsi_std_pktalloc; esp->e_tran.tran_dmaget = scsi_std_dmaget; esp->e_tran.tran_pktfree = scsi_std_pktfree; esp->e_tran.tran_dmafree = scsi_std_dmafree; esp->e_last_slot = esp->e_cur_slot = UNDEFINED; if (first_time) { first_time = 0; timeout(esp_watch, (caddr_t) 0, hz); } esp_internal_reset(esp, ESP_RESET_ALL);#undef DNAME#undef DUNIT return (ESP_SIZE);}/*ARGSUSED*/static intesp_slave(md, reg)struct mb_device *md;caddr_t reg;{ struct esp *esp; register struct espreg *ep; register int i; for (esp = esp_softc, i = 0; esp->e_next != (struct esp *) 0, i < md->md_ctlr; esp = esp->e_next, i++); ep = esp->e_reg; ep->esp_conf2 = 0; ep->esp_conf2 = 0xa; esp->e_type = ESP100; if ((ep->esp_conf2&0xf) == 0xa) { ep->esp_conf2 = esp->e_espconf2 = espconf2; ep->esp_conf3 = 0; ep->esp_conf3 = 5; if (ep->esp_conf3 == 0x5) { ep->esp_conf3 = espconf3; for (i = 0; i < NTARGETS; i++) { esp->e_espconf3[i] = espconf3; } esp->e_type = ESP236; } else esp->e_type = ESP100A; } md->md_slave = MY_ID(esp) << 3; return (1);}static intesp_attach(md)struct mb_device *md;{ int i; static int esp_spl = 0; struct esp *esp, *nsp; for (esp = esp_softc, i = 0; esp->e_next != (struct esp *) 0, i < md->md_ctlr; esp = esp->e_next, i++); /* * Calculate max locking spl so far seen.. */ esp->e_spl = pritospl(md->md_intpri); esp_spl = MAX(esp_spl, esp->e_spl); /* * Make sure that everyone, including us, is locking at * the same priority. */ for (nsp = esp_softc; nsp != (struct esp *) 0; nsp = nsp->e_next) { nsp->e_tran.tran_spl = esp_spl; }#ifdef ESPDEBUG /* * Initialize last state log. */ for (i = 0; i < NPHASE; i++) { esp->e_phase[i].e_save_state = STATE_FREE; esp->e_phase[i].e_save_stat = -1; esp->e_phase[i].e_val1 = -1; esp->e_phase[i].e_val2 = -1; } esp->e_phase_index = 0; esp->e_xfer = 0;#endif /* ESPDEBUG */ /* * Whew! Now make ourselves known to the rest of the SCSI world... */ scsi_config(&esp->e_tran, md);}#endif /* OPENPROMS *//* * Interface functions * * Visible to the external world via the transport structure. *//* * esp_start - Accept commands for transport */static intesp_start(sp)register struct scsi_cmd *sp;{ register s; register short slot; register struct esp *esp; esp = (struct esp *) sp->cmd_pkt.pkt_address.a_cookie; slot = (sp->cmd_pkt.pkt_address.a_target * NLUNS_PER_TARGET) | (sp->cmd_pkt.pkt_address.a_lun); if (sp->cmd_flags & CFLAG_DMAVALID) { u_long maxdma; switch (DMAGA_REV(esp->e_dma)) { default: case DMA_REV1: case DMA_REV2: case ESC1_REV1: maxdma = 1<<24; break; case DMA_REV3: maxdma = 1<<30; /* be reasonable - 2gb is enuff */ break; } if (sp->cmd_mapseg.d_count >= maxdma) { return (TRAN_BADPKT); } } s = splr(esp->e_tran.tran_spl); if (esp->e_slots[slot] != (struct scsi_cmd *) 0) { /* * This is where we would see if this is a SCSI-2 * multiple command target. */ /* * Else queueing error... */ (void) splx(s); return (TRAN_BUSY); } /* * Else, accept the command */ esp->e_slots[slot] = sp; esp->e_ncmds++; /* * Reinitialize some fields that need it */ esp_init_cmd(sp); /* * Run the command (maybe). */ if ((sp->cmd_pkt.pkt_flags & FLAG_NOINTR) == 0) { /* * Okay- if this is command is *not* a polling command, * and we're not pending any polling commands, *and* * the state is FREE, *then* we can start this command. */ if (esp->e_npolling == 0 && esp->e_state == STATE_FREE) { (void) esp_ustart(esp, slot); } } else { esp_runpoll(esp, slot); } (void) splx(s); return (TRAN_ACCEPT);}static intesp_abort(ap, pkt)struct scsi_address *ap;struct scsi_pkt *pkt;{ register struct esp *esp = (struct esp *) ap->a_cookie; register struct scsi_cmd *sp = (struct scsi_cmd *) pkt; register int s, rval; register short slot; /* * find the slot for this specific address */ slot = (ap->a_target * NLUNS_PER_TARGET) | ap->a_lun; /* * Take care of the easy cases first: * * A specific command was passed as an argument (to be aborted) and * * The command is currently active; we cannot abort now * The command does not exist here. * The command exists here, but hasn't been started yet. * * No specific command was passed as an argument (abort all * commands at this nexus), and * * No commands exist for this nexus. * Commands that exist here haven't been started yet. * */ s = splr(esp->e_tran.tran_spl); if (esp->e_state != STATE_FREE && esp->e_cur_slot == slot) { /* * This isn't right, but it will have to do for now. * If the currently active command is the one to be * aborted, we don't know at this level whether it * is safe, nor how to, queue up the ABORT OPERATION * message. Instead, punt, and let the target driver * decide whether to pull the chain on the bus. */ (void) splx(s); return (FALSE); } if (sp == (struct scsi_cmd *) 0) { sp = esp->e_slots[slot]; } if (esp->e_slots[slot] == (struct scsi_cmd *) 0) { sp = (struct scsi_cmd *) 0; } if (sp && sp == esp->e_slots[slot] && sp->cmd_pkt.pkt_state == 0) { esp->e_slots[slot] = (struct scsi_cmd *) 0; sp->cmd_pkt.pkt_reason = CMD_ABORTED; esp->e_ncmds -= 1; (*sp->cmd_pkt.pkt_comp)(sp); sp = (struct scsi_cmd *) 0; } if (sp == (struct scsi_cmd *) 0) { (void) splx(s); return (TRUE); } /* * Now deal with the hard cases. We have a valid sp for the * single active command at this nexus (XXX later we will have * a list of commands to abort XXX). */ { /* * In this case, the command is active but disconnected */ auto struct scsi_cmd local; register struct scsi_cmd *savesp = sp; int wasdisc; esp->e_slots[slot] = (struct scsi_cmd *) 0; if (sp->cmd_flags & CFLAG_CMDDISC) { wasdisc = 1; esp->e_ndisc -= 1; } else { wasdisc = 0; } esp->e_ncmds -= 1; sp = &local; esp_makeproxy_cmd(sp, ap, MSG_ABORT); IPRINTF2 ("Sending proxy abort message to %d.%d\n", ap->a_target, ap->a_lun); if (esp_start(sp) == TRAN_ACCEPT && sp->cmd_pkt.pkt_reason == CMD_CMPLT && sp->cmd_cdb[ESP_PROXY_RESULT] == TRUE) { IPRINTF2 ("Proxy abort succeeded for %d.%d\n", ap->a_target, ap->a_lun); rval = TRUE; savesp->cmd_pkt.pkt_reason = CMD_ABORTED; (*savesp->cmd_pkt.pkt_comp)(savesp); IPRINTF2 ("Completion called for %d.%d\n", ap->a_target, ap->a_lun); } else { IPRINTF2 ("Proxy abort failed for %d.%d\n", ap->a_target, ap->a_lun); esp->e_ncmds++; if (wasdisc) { esp->e_ndisc++; savesp->cmd_flags |= CFLAG_CMDDISC; } esp->e_slots[slot] = savesp; rval = FALSE; } if (esp->e_state == STATE_FREE) { (void) esp_ustart(esp, NEXTSLOT(slot)); } } (void) splx(s); return (rval);}static intesp_reset(ap, level)struct scsi_address *ap;int level;{ register s, rval; struct esp *esp = (struct esp *) ap->a_cookie; rval = FALSE; s = splr(esp->e_tran.tran_spl); if (level == RESET_ALL) { /* * We know that esp_reset_bus() returns ACTION_RETURN. */ (void) esp_reset_bus(esp); /* * Now call esp_dopoll() to field the reset interrupt * which will than call esp_reset_recovery which will * call completion for all commands. * * XXX: mark that we are in 'polling' mode so that * XXX: esp_reset_recovery just returns up to esp_dopoll() * XXX: with state == STATE_FREE. Gross, but esp_reset_recovery * XXX: will clear the e_npolling flag, but remember that * XXX: we were in 'polling' mode and just return ACTION_RETURN * */ esp->e_npolling++; if (esp_dopoll(esp, POLL_TIMEOUT)) { esplog(esp, LOG_ERR, "reset scsi bus failed"); } else rval = TRUE; } else { short slot = (ap->a_target * NLUNS_PER_TARGET) | ap->a_lun; if (esp->e_state == STATE_FREE && esp->e_slots[slot] == 0 && esp->e_npolling == 0) { auto struct scsi_cmd local; register struct scsi_cmd *sp = &local; IPRINTF2 ("Sending proxy reset message to %d.%d\n", ap->a_target, ap->a_lun); esp_makeproxy_cmd(sp, ap, MSG_DEVICE_RESET); if (esp_start(sp) == TRAN_ACCEPT && sp->cmd_pkt.pkt_reason == CMD_CMPLT && sp->cmd_cdb[ESP_PROXY_RESULT] == TRUE) { IPRINTF2 ("proxy reset of %d.%d ok\n", ap->a_target, ap->a_lun); rval = TRUE; } else { /* * make sure the local packet is not left in * the active slot */ if (esp->e_slots[slot] == &local) { esp->e_slots[slot] = (struct scsi_cmd *) NULL; } } } } if (esp->e_state == STATE_FREE) { (void) esp_ustart(esp, 0); } (void) splx(s); return (rval);}static intesp_commoncap(ap, cap, val, tgtonly, doset)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -