/* * use libdisk to read /sys/lib/scsicodes */ void makesense(ScsiReq *rp) { char *s; int i; Bprint(&bout, "sense data: %s", key[rp->sense[2] & 0x0F]); if(rp->sense[7] >= 5 && (s = scsierror(rp->sense[0xc], rp->sense[0xd]))) Bprint(&bout, ": %s", s); Bprint(&bout, "\n\t"); for(i = 0; i < 8+rp->sense[7]; i++) Bprint(&bout, " %2.2ux", rp->sense[i]); Bprint(&bout, "\n"); }
int scsi(Scsi *s, uchar *cmd, int ccount, void *v, int dcount, int io) { uchar req[6], sense[255], *data; int tries, code, key, n; char *p; data = v; SET(key); SET(code); qlock(&s->lk); for(tries=0; tries<2; tries++) { n = _scsicmd(s, cmd, ccount, data, dcount, io, 0); if(n >= 0) { qunlock(&s->lk); return n; } /* * request sense */ memset(req, 0, sizeof(req)); req[0] = 0x03; req[4] = sizeof(sense); memset(sense, 0xFF, sizeof(sense)); if((n=_scsicmd(s, req, sizeof(req), sense, sizeof(sense), Sread, 0)) < 14) if(scsiverbose) fprint(2, "reqsense scsicmd %d: %r\n", n); if(_scsiready(s, 0) < 0) if(scsiverbose) fprint(2, "unit not ready\n"); key = sense[2]; code = sense[12]; if(code == 0x17 || code == 0x18) { /* recovered errors */ qunlock(&s->lk); return dcount; } if(code == 0x28 && cmd[0] == 0x43) { /* get info and media changed */ s->nchange++; s->changetime = time(0); continue; } } /* drive not ready, or medium not present */ if(cmd[0] == 0x43 && key == 2 && (code == 0x3a || code == 0x04)) { s->changetime = 0; qunlock(&s->lk); return -1; } qunlock(&s->lk); if(cmd[0] == 0x43 && key == 5 && code == 0x24) /* blank media */ return -1; p = scsierror(code, sense[13]); werrstr("cmd #%.2ux: %s", cmd[0], p); if(scsiverbose) fprint(2, "scsi cmd #%.2ux: %.2ux %.2ux %.2ux: %s\n", cmd[0], key, code, sense[13], p); /* if(key == 0) */ /* return dcount; */ return -1; }
int scsi(Scsi *s, uchar *cmd, int ccount, void *v, int dcount, int io) { uchar req[6], sense[255], *data; int tries, code, key, n; char *p; data = v; SET(key, code); qlock(s); for(tries=0; tries<2; tries++) { n = _scsicmd(s, cmd, ccount, data, dcount, io, 0); if(n >= 0) { qunlock(s); return n; } /* * request sense */ memset(req, 0, sizeof(req)); req[0] = Reqsense; req[4] = sizeof(sense); memset(sense, 0xFF, sizeof(sense)); if((n=_scsicmd(s, req, sizeof(req), sense, sizeof(sense), Sread, 0)) < 14) if(scsiverbose) fprint(2, "reqsense scsicmd %d: %r\n", n); if(_scsiready(s, 0) < 0) if(scsiverbose) fprint(2, "unit not ready\n"); key = sense[2] & 0xf; code = sense[12]; /* asc */ if(code == Recovnoecc || code == Recovecc) { /* recovered errors */ qunlock(s); return dcount; } /* retry various odd cases */ if(code == Newmedium && cmd[0] == Readtoc) { /* read toc and media changed */ s->nchange++; s->changetime = time(0); } else if((cmd[0] == Write10 || cmd[0] == Writever10) && key == Sensenotrdy && code == Lunnotrdy && sense[13] == 0x08) { /* long write in progress, per mmc-6 */ tries = 0; sleep(1); } } /* drive not ready, or medium not present */ if(cmd[0] == Readtoc && key == Sensenotrdy && (code == Nomedium || code == Lunnotrdy)) { s->changetime = 0; qunlock(s); return -1; } qunlock(s); if(cmd[0] == Readtoc && key == Sensebadreq && code == Badcdb) return -1; /* blank media */ p = scsierror(code, sense[13]); werrstr("cmd #%.2ux: %s", cmd[0], p); if(scsiverbose) fprint(2, "scsi cmd #%.2ux: %.2ux %.2ux %.2ux: %s\n", cmd[0], key, code, sense[13], p); // if(key == Sensenone) // return dcount; return -1; }
int dma_done(void) { volatile caddr_t sr; struct dma_dev *dma; int count, state; sr = P_SCSI; dma = (struct dma_dev *)P_SCSI_CSR; state = dma->dd_csr & (DMACSR_BUSEXC | DMACSR_COMPLETE | DMACSR_SUPDATE | DMACSR_ENABLE); count = sr[ESP_TCM]<<8 | sr[ESP_TCL]; DPRINTF(("dma state = 0x%x, remain = %d.\n", state, count)); if (state & DMACSR_ENABLE) { DPRINTF(("dma still enabled, flushing DCTL.\n")); sr[ESP_DCTL] = ESPDCTL_20MHZ | ESPDCTL_INTENB | ESPDCTL_DMAMOD | ESPDCTL_DMARD | ESPDCTL_FLUSH; /* DELAY(5); */ sr[ESP_DCTL] = ESPDCTL_20MHZ | ESPDCTL_INTENB | ESPDCTL_DMAMOD | ESPDCTL_DMARD; /* DELAY(5); */ return 0; } sr[ESP_DCTL] = ESPDCTL_20MHZ | ESPDCTL_INTENB; count = sr[ESP_TCM]<<8 | sr[ESP_TCL]; dma->dd_csr = DMACSR_RESET; DPRINTF(("dma done. remain = %d, state = 0x%x.\n", count, state)); if (count != 0) { printf("WARNING: unexpected %d characters remain in dma\n",count); scsierror("dma transfer incomplete"); #if 0 return -1; #endif } if (state & DMACSR_COMPLETE) { bcopy(dma_buffer, sc->dma_addr, sc->dma_len); sc->sc_state = SCSI_HASBUS; return 0; } if (state & DMACSR_BUSEXC) { scsierror("dma failed"); return -1; } scsierror("dma not completed\n"); return -1; }
int dma_start(char *addr, int len) { volatile caddr_t sr; struct dma_dev *dma; sr = P_SCSI; dma = (struct dma_dev *)P_SCSI_CSR; if (len > MAX_DMASIZE) { scsierror("dma too long"); return -1; } if (addr == NULL || len == 0) { #if 0 /* I'd take that as an error in my code */ DPRINTF(("hmm ... no dma requested.\n")); sr[ESP_TCL] = 0; sr[ESP_TCM] = 1; sr[ESP_CMD] = ESPCMD_NOP; sr[ESP_CMD] = ESPCMD_DMA | ESPCMD_TRPAD; return 0; #else scsierror("unrequested dma"); return -1; #endif } DPRINTF(("dma start: %lx, %d byte.\n", (long)addr, len)); DPRINTF(("dma_bufffer: start: 0x%lx end: 0x%lx \n", (long)dma_buffer,(long)DMA_ENDALIGN(char *, dma_buffer+len))); sc->dma_addr = addr; sc->dma_len = len; sr[ESP_TCL] = len & 0xff; sr[ESP_TCM] = len >> 8; sr[ESP_CMD] = ESPCMD_DMA | ESPCMD_NOP; sr[ESP_CMD] = ESPCMD_DMA | ESPCMD_TRANS; #if 0 dma->dd_csr = DMACSR_READ | DMACSR_RESET; dma->dd_next_initbuf = dma_buffer; dma->dd_limit = DMA_ENDALIGN(char *, dma_buffer+len); dma->dd_csr = DMACSR_READ | DMACSR_SETENABLE; #else dma->dd_csr = 0; dma->dd_csr = DMACSR_INITBUF | DMACSR_READ | DMACSR_RESET; dma->dd_next_initbuf = dma_buffer; dma->dd_limit = DMA_ENDALIGN(char *, dma_buffer+len); dma->dd_csr = DMACSR_READ | DMACSR_SETENABLE; #endif sr[ESP_DCTL] = ESPDCTL_20MHZ|ESPDCTL_INTENB|ESPDCTL_DMAMOD|ESPDCTL_DMARD; sc->sc_state = SCSI_DMA; return 0; }
int scsiicmd(char target, char lun, u_char *cbuf, int clen, char *addr, int len) { volatile caddr_t sr; int i; DPRINTF(("scsiicmd: [%x, %d] -> %d (%lx, %d)\n",*cbuf, clen, target, (long)addr, len)); sr = P_SCSI; if (sc->sc_state != SCSI_IDLE) { scsierror("scsiiscmd: bad state"); return EIO; } sc->sc_result = 0; /* select target */ sr[ESP_CMD] = ESPCMD_FLUSH; DELAY(10); sr[ESP_SELID] = target; sr[ESP_FIFO] = MSG_IDENTIFY(lun, 0); for (i=0; i<clen; i++) sr[ESP_FIFO] = cbuf[i]; sr[ESP_CMD] = ESPCMD_SELATN; sc->sc_state = SCSI_SELECTING; while(sc->sc_state != SCSI_DONE) { if (scsi_wait_for_intr()) /* maybe we'd better use real intrs ? */ return EIO; if (sc->sc_state == SCSI_DMA) { /* registers are not valid on dma intr */ sc->sc_status = sc->sc_seqstep = sc->sc_intrstatus = 0; DPRINTF(("scsiicmd: dma intr\n")); } else { /* scsi processing */ sc->sc_status = sr[ESP_STAT]; sc->sc_seqstep = sr[ESP_STEP]; sc->sc_intrstatus = sr[ESP_INTR]; DPRINTF(("scsiicmd: regs[intr=%x, stat=%x, step=%x]\n", sc->sc_intrstatus, sc->sc_status, sc->sc_seqstep)); } if (sc->sc_intrstatus & ESPINTR_SBR) { scsierror("scsi bus reset"); return EIO; } if ((sc->sc_status & ESPSTAT_GE) || (sc->sc_intrstatus & ESPINTR_ILL)) { scsierror("software error"); return EIO; } if (sc->sc_status & ESPSTAT_PE) { scsierror("parity error"); return EIO; } switch(sc->sc_state) { case SCSI_SELECTING: if (sc->sc_intrstatus & ESPINTR_DIS) { sc->sc_state = SCSI_IDLE; return EUNIT; /* device not present */ } #define ESPINTR_DONE (ESPINTR_BS | ESPINTR_FC) if ((sc->sc_intrstatus & ESPINTR_DONE) != ESPINTR_DONE) { scsierror("selection failed"); return EIO; } sc->sc_state = SCSI_HASBUS; break; case SCSI_HASBUS: if (sc->sc_intrstatus & ESPINTR_DIS) { scsierror("target disconnected"); return EIO; } break; case SCSI_DMA: if (sc->sc_intrstatus & ESPINTR_DIS) { scsierror("target disconnected"); return EIO; } if (dma_done() != 0) return EIO; continue; case SCSI_CLEANUP: if (sc->sc_intrstatus & ESPINTR_DIS) { sc->sc_state = SCSI_DONE; continue; } DPRINTF(("hmm ... no disconnect on cleanup?\n")); sc->sc_state = SCSI_DONE; /* maybe ... */ break; } /* transfer information now */ switch(sc->sc_status & ESPSTAT_PHASE) { case DATA_IN_PHASE: if (dma_start(addr, len) != 0) return EIO; break; case DATA_OUT_PHASE: scsierror("data out phase not implemented"); return EIO; case STATUS_PHASE: DPRINTF(("status phase: ")); sr[ESP_CMD] = ESPCMD_ICCS; sc->sc_result = scsi_getbyte(sr); DPRINTF(("status is 0x%x.\n", sc->sc_result)); break; case MSG_IN_PHASE: if (scsi_msgin() != 0) return EIO; break; default: DPRINTF(("phase not implemented: 0x%x.\n", sc->sc_status & ESPSTAT_PHASE)); scsierror("bad phase"); return EIO; } } sc->sc_state = SCSI_IDLE; return -sc->sc_result; }