?? sc.c
字號:
sc_select(sc)register struct scsitwo *sc;{ register struct scsi_cmd *sp = sc->sc_que; register int i; u_short icr_mode; DPRINTF2 ("select %d.%d\n", Tgt(sp), Lun(sp)); /* * make sure scsi bus is not continuously busy */ for (i = SC_WAIT_COUNT; i > 0; i--) { if ((sc->sc_reg->icr & ICR_BUSY) == 0) break; DELAY(10); } if (i == 0) { sc_printf(sc, "scsi bus continuously busy: ICR=0x%b\n", sc->sc_reg->icr, scbits); sp->cmd_pkt.pkt_reason = CMD_INCOMPLETE; screset(sc, 1); /* XXX? */ return (FALSE); } /* * Got the bus... */ sp->cmd_pkt.pkt_state |= STATE_GOT_BUS; /* * select target and wait for response */ sc->sc_reg->icr = 0; /* Make sure SECONDBYTE flag is clear */ /* * Since we aren't an arbitrating initiator, we only * put in the target address and *not* our own as well. */ sc->sc_reg->data = 1 << Tgt(sp); sc->sc_reg->icr = ICR_SELECT; /* * See if target responds to selection */ if (sc_wait((u_short *)&sc->sc_reg->icr, SC_SHORT_WAIT, ICR_BUSY)) { DPRINTF2 ("%d.%d didn't select\n", Tgt(sp), Lun(sp)); sc->sc_reg->data = 0; sc->sc_reg->icr = 0; sp->cmd_pkt.pkt_reason = CMD_INCOMPLETE; return (FALSE); } /* * Got the target... */ sp->cmd_pkt.pkt_state |= STATE_GOT_TARGET; icr_mode = 0; if ((sp->cmd_pkt.pkt_flags & FLAG_NOINTR) == 0) { icr_mode |= ICR_INTERRUPT_ENABLE; } /* * If a data transfer is expected, set it up here... */ if (sp->cmd_dmacount && (sp->cmd_flags&CFLAG_DMAVALID)) { SET_DMA_ADDR (sc->sc_reg, ((int)sp->cmd_data)); sc->sc_reg->dma_count = ~sp->cmd_dmacount; if (((int)sp->cmd_data)&0x1) { DPRINTF ("odd byte DMA address\n"); } else { icr_mode |= ICR_WORD_MODE; } icr_mode |= ICR_DMA_ENABLE; } /* * set the interrupt register */ sc->sc_reg->icr = icr_mode; return (TRUE);}/* * * finish routine * */static voidsc_finish(sc)register struct scsitwo *sc;{ register struct scsi_cmd *sp = sc->sc_que; char dkn, wasintr; sc->sc_reg->icr = 0; /* clear any pending interrupts */ sc->sc_busy = 0; if ((dkn = sp->cmd_pkt.pkt_pmon) >= 0) { dk_busy &= ~(1<<dkn); } DPRINTF1 ("finishing command %d\n", sc->sc_cmdid); sc->sc_cmdid++; sc->sc_que = Nextcmd(sp); if (sp->cmd_pkt.pkt_state & STATE_XFERRED_DATA) { /* * Since we cannot disconnect, we cannot have had more * than one data segment */ if (sp->cmd_subseg.d_next != (struct dataseg *) 0) { panic("sc_finish: more than one segment with data"); /* NOTREACHED */ } sp->cmd_pkt.pkt_resid = sp->cmd_dmacount - sp->cmd_subseg.d_count; } wasintr = (sp->cmd_pkt.pkt_flags & FLAG_NOINTR)? 0: 1; (*sp->cmd_pkt.pkt_comp)(sp); if (wasintr && sc->sc_que && sc->sc_busy == 0) { sc_ustart(sc); }}/* * Interrupt service section */static intsc_dopoll(sc, id)register struct scsitwo *sc;register id;{ register i; struct scsi_cmd *sp = sc->sc_que; for (i = 0; i < 300000 && id == sc->sc_cmdid; i++) { if (INTPENDING(sc->sc_reg)) { scintr(sc); i = 0; } else { DELAY(500); } } if (i >= 300000) { sc_printf(sc, "polled command timeout\n"); sp->cmd_pkt.pkt_reason = CMD_TIMEOUT; screset(sc, 0); sc_finish(sc); }}/* * Handle a polling (autovectored) SCSI bus interrupt. */static intscpoll(){ register struct scsitwo *sc; register int serviced = 0; for (sc = &sc_softc[0]; sc < &sc_softc[NSC]; sc++) { if (sc->sc_reg && INTPENDING(sc->sc_reg)) { serviced += scintr(sc); } } return (serviced);}/* * Handle a scsi bus interrupt. */intscintr(sc)register struct scsitwo *sc;{ register struct scsi_cmd *sp = sc->sc_que; if (sp == 0 || !sc->sc_reg || !(INTPENDING(sc->sc_reg))) { sc_printf(sc, "spurious interrupt\n"); return (0); } DPRINTF2 ("scintr: ICR=0x%b\n", sc->sc_reg->icr, scbits); /* * End of Data phase? Check for bus error first... */ if (sc->sc_reg->icr & ICR_BUS_ERROR) { sc_printf(sc, "Dma BUS Error on address 0x%x\n", sp->cmd_data); sc_abort_cmd(sc); return (1); } else if (sp->cmd_dmacount && (sp->cmd_flags & CFLAG_DMAVALID)) { int resid, reqamt, xfer_amt; resid = (u_short) (~sc->sc_reg->dma_count); reqamt = sp->cmd_dmacount; if (sc->sc_reg->icr & ICR_ODD_LENGTH) { if (sp->cmd_flags & CFLAG_DMASEND) { resid++; } else if (reqamt) { sc_flush(sc, (u_long) (sp->cmd_data + reqamt - resid)); resid--; } } if (xfer_amt = reqamt - resid) { DPRINTF1 ("xferred %d\n", xfer_amt); sp->cmd_data += xfer_amt; sp->cmd_subseg.d_count += xfer_amt; sp->cmd_pkt.pkt_state |= STATE_XFERRED_DATA; } } /* * Now, get status and/or message... */ while (sc->sc_reg->icr & (ICR_BUSY|ICR_REQUEST)) { register u_short pbits; while (((pbits = sc->sc_reg->icr) & ICR_REQUEST) == 0) { if ((pbits & ICR_BUSY) == 0) { sc_printf(sc, "Target %d dropped BUSY\n", Tgt(sp)); sc_abort_cmd(sc); return (1); } } switch (pbits & ICR_BITS) { case ICR_STATUS: *sp->cmd_scbp = sc->sc_reg->cmd_stat; sp->cmd_pkt.pkt_state |= STATE_GOT_STATUS; break; case ICR_MESSAGE_IN: { static char *bad = "Bad Message '0x%x' from Target %d, Lun %d\n"; switch (sc->sc_msgin = sc->sc_reg->cmd_stat) { case MSG_COMMAND_COMPLETE: case MSG_LINK_CMPLT: case MSG_LINK_CMPLT_FLAG: sp->cmd_pkt.pkt_reason = CMD_CMPLT; sc_finish(sc); break; default: sc_printf(sc, bad, sc->sc_msgin, Tgt(sp), Lun(sp)); sc_abort_cmd(sc); break; } return (1); break; } default: sc_printf(sc, "Bad phase: ICR=0x%b\n", pbits, scbits); sc_abort_cmd(sc); return (1); break; } } return (1);}/* * Flush the last byte of an odd length transfer */static voidsc_flush(sc, offset)register struct scsitwo *sc;register u_long offset;{ register u_int pv; u_char *mapaddr; if (MBI_MR(offset) < dvmasize) { DVMA[offset] = sc->sc_reg->data; return; }#ifdef sun3x pv = btop (VME24D16_BASE + (offset & VME24D16_MASK));#else sun3x pv = PGT_VME_D16 | VME24_BASE | btop(offset & VME24_MASK);#endif sun3x mapaddr = (u_char *) ((u_long) kmxtob(sc_kment) | (u_long) MBI_OFFSET(offset)); segkmem_mapin(&kseg, (addr_t) (((int)mapaddr) & PAGEMASK), (u_int) mmu_ptob(1), PROT_READ | PROT_WRITE, pv, 0); *mapaddr = sc->sc_reg->data; segkmem_mapout(&kseg, (addr_t) (((int)mapaddr) & PAGEMASK), (u_int) mmu_ptob(1)); segkmem_mapout(&kseg, (addr_t) mapaddr, (u_int) mmu_btop(1));}/* * Miscellaneous functions */static voidsc_abort_cmd(sc)struct scsitwo *sc;{ sc->sc_que->cmd_pkt.pkt_reason = CMD_RESET; screset(sc, 1); sc_finish(sc);}/* * Wait for a condition to be (de)asserted on the scsi bus. * Returns 0, if successful, else -1; */static intsc_wait(icrp, wait_count, cond) register u_short *icrp; register int wait_count;{ register int i; register u_short icr; for (i = 0; i < wait_count; i++) { icr = *icrp; if ((icr & cond) == cond) { return (0); } else if (icr & ICR_BUS_ERROR) { break; } else DELAY(10); } return (-1);}/* * Put data byte onto the scsi bus if phase match. * Returns: 1 if successful (phase matched) * 0 if incorrect phase, but REQ is present * -1 if no REQ present */staticsc_putbyte(sc, bits, data)register struct scsitwo *sc;register u_short bits;register u_char data;{ register u_short icr; if (sc_wait((u_short *)&sc->sc_reg->icr, SC_WAIT_COUNT, ICR_REQUEST)) { DPRINTF ("sc_putbyte: no REQ\n"); return (-1); } icr = sc->sc_reg->icr; if ((icr & ICR_BITS) != bits) { DPRINTF2 ("sc_putbyte: ICR=0x%b\n", icr, scbits); return (0); } sc->sc_reg->cmd_stat = data; return (1);}/* * Reset SCSI control logic and bus. */static voidscreset(sc, msg_enable)struct scsitwo *sc;int msg_enable;{ if (msg_enable) { sc_printf(sc, "Resetting SCSI bus\n"); } sc->sc_reg->icr = ICR_RESET; DELAY(50); sc->sc_reg->icr = 0; /* give reset scsi devices time to recover (> 2 Sec) */ DELAY(SC_RESET_DELAY);}/*ARGSUSED*/static voidsc_watch(arg)caddr_t arg;{ register s; register struct scsitwo *sc; register struct scsi_cmd *sp; for (sc = &sc_softc[0]; sc < &sc_softc[NSC]; sc++) { if (sc->sc_reg) { s = splr(sc->sc_tran.tran_spl); sp = sc->sc_que; if (sp && (sp->cmd_flags & CFLAG_WATCH)) { if (sp->cmd_timeout == 0) { /* * A pending interrupt * defers the sentence * of death. */ if (INTPENDING(sc->sc_reg)) { sp->cmd_timeout++; (void) splx(s); continue; } sc_printf(sc, "command timeout\n"); sp->cmd_pkt.pkt_reason = CMD_TIMEOUT; sc_reset(sc, 0); sc_finish(sc); (void) splx(s); continue; } else { sp->cmd_timeout -= 1; } } (void) splx(s); } } timeout(sc_watch, (caddr_t) 0, hz);}/*VARARGS*/static voidsc_printf(sc, fmt, a, b, c, d, e, f, g, h)struct scsitwo *sc;char *fmt;int a, b, c, d, e, f, g, h;{ printf("%s%d: ", CNAME, CNUM); printf(fmt, a, b, c, d, e, f, g, h);}#endif (NSC > 0)
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -