Пример #1
0
static int
scsirio(SDreq* r)
{
	Proc *up = externup();
	/*
	 * Perform an I/O request, returning
	 *	-1	failure
	 *	 0	ok
	 *	 1	no medium present
	 *	 2	retry
	 * The contents of r may be altered so the
	 * caller should re-initialise if necesary.
	 */
	r->status = ~0;
	switch(r->unit->dev->ifc->rio(r)){
	default:
		break;
	case SDcheck:
		if(!(r->flags & SDvalidsense))
			break;
		switch(r->sense[2] & 0x0F){
		case 0x00:		/* no sense */
		case 0x01:		/* recovered error */
			return 2;
		case 0x06:		/* check condition */
			/*
			 * 0x28 - not ready to ready transition,
			 *	  medium may have changed.
			 * 0x29 - power on or some type of reset.
			 */
			if(r->sense[12] == 0x28 && r->sense[13] == 0)
				return 2;
			if(r->sense[12] == 0x29)
				return 2;
			break;
		case 0x02:		/* not ready */
			/*
			 * If no medium present, bail out.
			 * If unit is becoming ready, rather than not
			 * not ready, wait a little then poke it again. 				 */
			if(r->sense[12] == 0x3A)
				break;
			if(r->sense[12] != 0x04 || r->sense[13] != 0x01)
				break;

			while(waserror())
				;
			tsleep(&up->sleep, return0, 0, 500);
			poperror();
			scsitest(r);
			return 2;
		default:
			break;
		}
		break;
	case SDok:
		return 0;
	}
	return -1;
}
Пример #2
0
static void
scsiprobe(Device* d)
{
	Target *tp;
	int nbytes, s;
	uchar *sense;
	int acount;

	if((tp = scsitarget(d)) == 0)
		panic("scsiprobe: device = %Z", d);

	acount = 0;
again:
	s = scsitest(tp, d->wren.lun);
	if(s < STok){
		print("%s: test, status %d\n", tp->id, s);
		return;
	}

	/*
	 * Determine if the drive exists and is not ready or
	 * is simply not responding.
	 * If the status is OK but the drive came back with a 'power on' or
	 * 'reset' status, try the test again to make sure the drive is really
	 * ready.
	 * If the drive is not ready and requires intervention, try to spin it
	 * up.
	 */
	s = scsireqsense(tp, d->wren.lun, &nbytes, acount);
	sense = tp->sense;
	switch(s){
	case STok:
		if ((sense[2] & 0x0F) == 0x06 &&
		    (sense[12] == 0x28 || sense[12] == 0x29))
			if(acount == 0){
				acount = 1;
				goto again;
			}
		break;
	case STcheck:
		if((sense[2] & 0x0F) == 0x02){
			if(sense[12] == 0x3A)
				break;
			if(sense[12] == 0x04 && sense[13] == 0x02){
				print("%s: starting...\n", tp->id);
				if(scsistart(tp, d->wren.lun, 1) == STok)
					break;
				s = scsireqsense(tp, d->wren.lun, &nbytes, 0);
			}
		}
		/*FALLTHROUGH*/
	default:
		print("%s: unavailable, status %d\n", tp->id, s);
		return;
	}

	/*
	 * Inquire to find out what the device is.
	 * Hardware drivers may need some of the info.
	 */
	s = scsiinquiry(tp, d->wren.lun, &nbytes);
	if(s != STok) {
		print("%s: inquiry failed, status %d\n", tp->id, s);
		return;
	}
	print("%s: %s\n", tp->id, (char*)tp->inquiry+8);
	tp->ok = 1;
}
Пример #3
0
static int
scsireqsense(Target* tp, char lun, int* nbytes, int quiet)
{
	char *s;
	int n, status, try;
	uchar cmd[6], *sense;

	sense = tp->sense;
	for(try = 0; try < 20; try++) {
		memset(cmd, 0, sizeof cmd);
		cmd[0] = CMDreqsense;
		cmd[1] = lun<<5;
		cmd[4] = Ninquiry;
		memset(sense, 0, Ninquiry);

		*nbytes = Ninquiry;
		status = scsiexec(tp, SCSIread, cmd, sizeof cmd, sense, nbytes);
		if(status != STok)
			return status;
		*nbytes = sense[0x07]+8;

		switch(sense[2] & 0x0F){
		case 6:					/* unit attention */
			/*
			 * 0x28 - not ready to ready transition,
			 *	  medium may have changed.
			 * 0x29 - power on, RESET or BUS DEVICE RESET occurred.
			 */
			if(sense[12] != 0x28 && sense[12] != 0x29)
				goto buggery;
			/*FALLTHROUGH*/
		case 0:					/* no sense */
		case 1:					/* recovered error */
			return STok;
		case 8:					/* blank data */
			return STblank;
		case 2:					/* not ready */
			if(sense[12] == 0x3A)		/* medium not present */
				goto buggery;
			/*FALLTHROUGH*/
		default:
			/*
			 * If unit is becoming ready, rather than not ready,
			 * then wait a little then poke it again; should this
			 * be here or in the caller?
			 */
			if((sense[12] == 0x04 && sense[13] == 0x01)){
				delay(500);
				scsitest(tp, lun);
				break;
			}
			goto buggery;
		}
	}

buggery:
	if(quiet == 0){
		s = key[sense[2]&0x0F];
		print("%s: reqsense: '%s' code #%2.2ux #%2.2ux\n",
			tp->id, s, sense[12], sense[13]);
		print("%s: byte 2: #%2.2ux, bytes 15-17: #%2.2ux #%2.2ux #%2.2ux\n",
			tp->id, sense[2], sense[15], sense[16], sense[17]);
		print("lastcmd (%d): ", lastcmdsz);
		for(n = 0; n < lastcmdsz; n++)
			print(" #%2.2ux", lastcmd[n]);
		print("\n");
	}

	return STcheck;
}

static Target*
scsitarget(Device* d)
{
	int ctlrno, targetno;

	ctlrno = d->wren.ctrl;
	if(ctlrno < 0 || ctlrno >= MaxScsi /* || scsictlr[ctlrno].io == nil */)
		return 0;
	targetno = d->wren.targ;
	if(targetno < 0 || targetno >= NTarget)
		return 0;
	return &scsictlr[ctlrno].target[targetno];
}
Пример #4
0
int
scsiverify(SDunit* unit)
{
	SDreq *r;
	int i, status;
	uchar *inquiry;

	if((r = malloc(sizeof(SDreq))) == nil)
		return 0;
	if((inquiry = sdmalloc(sizeof(unit->inquiry))) == nil){
		free(r);
		return 0;
	}
	r->unit = unit;
	r->lun = 0;		/* ??? */

	memset(unit->inquiry, 0, sizeof(unit->inquiry));
	r->write = 0;
	r->cmd[0] = 0x12;
	r->cmd[1] = r->lun<<5;
	r->cmd[4] = sizeof(unit->inquiry)-1;
	r->clen = 6;
	r->data = inquiry;
	r->dlen = sizeof(unit->inquiry)-1;
	r->flags = 0;

	r->status = ~0;
	if(unit->dev->ifc->rio(r) != SDok){
		free(r);
		return 0;
	}
	memmove(unit->inquiry, inquiry, r->dlen);
	free(inquiry);

	SET(status);
	for(i = 0; i < 3; i++){
		while((status = scsitest(r)) == SDbusy)
			;
		if(status == SDok || status != SDcheck)
			break;
		if(!(r->flags & SDvalidsense))
			break;
		if((r->sense[2] & 0x0F) != 0x02)
			continue;

		/*
		 * Unit is 'not ready'.
		 * If it is in the process of becoming ready or needs
		 * an initialising command, set status so it will be spun-up
		 * below.
		 * If there's no medium, that's OK too, but don't
		 * try to spin it up.
		 */
		if(r->sense[12] == 0x04){
			if(r->sense[13] == 0x02 || r->sense[13] == 0x01){
				status = SDok;
				break;
			}
		}
		if(r->sense[12] == 0x3A)
			break;
	}

	if(status == SDok){
		/*
		 * Try to ensure a direct-access device is spinning.
		 * Don't wait for completion, ignore the result.
		 */
		if((unit->inquiry[0] & 0x1F) == 0){
			memset(r->cmd, 0, sizeof(r->cmd));
			r->write = 0;
			r->cmd[0] = 0x1B;
			r->cmd[1] = (r->lun<<5)|0x01;
			r->cmd[4] = 1;
			r->clen = 6;
			r->data = nil;
			r->dlen = 0;
			r->flags = 0;

			r->status = ~0;
			unit->dev->ifc->rio(r);
		}
	}
	free(r);

	if(status == SDok || status == SDcheck)
		return 1;
	return 0;
}