Beispiel #1
0
/*
 * 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");
}
Beispiel #2
0
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;
}
Beispiel #3
0
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;
}
Beispiel #4
0
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;
}
Beispiel #5
0
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;
}
Beispiel #6
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;
}