Esempio n. 1
0
/* Test if the drive is ready */
status_t scsi_test_ready( SCSI_device_s * psDevice )
{
	SCSI_cmd_s sCmd;
	int nError;

retry:
	nError = 0;

	/* Try to test the state of the unit */
	scsi_init_cmd( &sCmd, psDevice );

	sCmd.nCmd[0] = SCSI_TEST_UNIT_READY;
	if( psDevice->nSCSILevel <= SCSI_2 )
		sCmd.nCmd[1] = ( psDevice->nLun << 5 ) & 0xe0;

	sCmd.nCmdLen = scsi_get_command_size( SCSI_TEST_UNIT_READY );

	/* Send command */
	nError = psDevice->psHost->queue_command( &sCmd );

	if( sCmd.s.sSense.sense_key != SCSI_NO_SENSE || sCmd.nResult != 0 )
	{
		SCSI_sense_s sSense;

		nError = scsi_request_sense( psDevice, &sSense );
		if( nError < 0 )
		{
			kerndbg( KERN_PANIC, "Unable to request sense data from SCSI device, aborting.\n" );
			return -EIO;
		}

		nError = scsi_check_sense( psDevice, &sSense, false );
		switch ( nError )
		{
			case SENSE_OK:
				break;

			case SENSE_RETRY:
				goto retry;

			case SENSE_FATAL:
			{
				kerndbg( KERN_PANIC, "SCSI device reporting fatal error, aborting.\n" );
				return -EIO;
			}
		}
	}

	kerndbg( KERN_DEBUG, "scsi_test_ready(): Device ready\n" );

	return 0;
}
Esempio n. 2
0
int scsi_test_unit_ready(struct scsi_request *srb,
			 struct scsi_transport *tr, void *priv)
{
	int rc = VMM_EFAIL, retries = 10;
	unsigned char *data;
	unsigned long datalen;

	if (!srb || !tr || !tr->transport) {
		return VMM_EINVALID;
	}

	data = srb->data;
	datalen = srb->datalen;
	do {
		memset(&srb->cmd, 0, sizeof(srb->cmd));
		srb->cmd[0] = SCSI_TST_U_RDY;
		srb->cmd[1] = srb->lun << 5;
		srb->data = NULL;
		srb->datalen = 0;
		srb->cmdlen = 12;
		rc = tr->transport(srb, tr, priv);
		if (rc == VMM_OK) {
			break;
		}

		rc = scsi_request_sense(srb, tr, priv);
		if (rc != VMM_OK) {
			return rc;
		}

		/*
		 * Check the Key Code Qualifier, if it matches
		 * "Not Ready - medium not present"
		 * (the sense Key equals 0x2 and the ASC is 0x3a)
		 * return immediately as the medium being absent won't change
		 * unless there is a user action.
		 */
		if ((srb->sense_buf[2] == 0x02) &&
		    (srb->sense_buf[12] == 0x3a)) {
			rc = VMM_ENODEV;
			break;
		}

		vmm_mdelay(100);
		rc = VMM_EFAIL;
	} while (retries--);
	srb->data = data;
	srb->datalen = datalen;

	return rc;
}
Esempio n. 3
0
/*
 * Analyze the IE mode sense page explicitly.  This is only needed if the IE log
 * page is not supported.
 */
static int
analyze_ie_sense(ds_scsi_info_t *sip)
{
	uint_t skey, asc, ascq;
	nvlist_t *nvl;

	/*
	 * Don't bother checking if we weren't able to set our MRIE correctly.
	 */
	if (sip->si_iec_current.ie_mrie != IE_REPORT_ON_REQUEST)
		return (0);

	if (scsi_request_sense(sip, &skey, &asc, &ascq) != 0) {
		printf("failed to request IE page (KEY=0x%x ASC=0x%x "
		    "ASCQ=0x%x)\n", skey, asc, ascq);
		return (scsi_set_errno(sip, EDS_IO));
	} else if (skey == KEY_NO_SENSE) {
		assert(sip->si_dsp->ds_predfail == NULL);
		if (nvlist_alloc(&sip->si_dsp->ds_predfail,
		    NV_UNIQUE_NAME, 0) != 0)
			return (scsi_set_errno(sip, EDS_NOMEM));
		nvl = sip->si_dsp->ds_predfail;

		if (nvlist_add_uint8(nvl,
		    FM_EREPORT_PAYLOAD_SCSI_ASC, asc) != 0 ||
		    nvlist_add_uint8(nvl,
		    FM_EREPORT_PAYLOAD_SCSI_ASCQ, ascq) != 0) {
			nvlist_free(nvl);
			return (scsi_set_errno(sip, EDS_NOMEM));
		}

		if (asc != 0)
			sip->si_dsp->ds_faults |= DS_FAULT_PREDFAIL;
	}

	return (0);
}
Esempio n. 4
0
int
scsi(int argc, char *argv[])
{
	char *p;
	int i, status;

	if (argc < 2) {
		printf("This command is required subcommand !!\n");
		return ST_ERROR;
	}

	if (!strcmp(argv[1], "device")) {
		if (argc > 2) {
			i = 0;
			for (p = argv[2]; *p != '\0' ; p++) {
				i = i * 10 + *p - '0';
			}
			if ( i < 8 && i >= 0) {
				scsi_device = i;
			}
		}
		printf("Current Device ID: %d\n", scsi_device);
	} else if (!strcmp(argv[1], "test_unit_rdy")) {
				/* CTLR  SLAVE  LUN */
		scsi_test_unit_rdy(   0, scsi_device,   0);
	} else if (!strcmp(argv[1], "request_sense")) {
			        /* CTLR  SLAVE  LUN */
		scsi_request_sense(   0, scsi_device,   0, sensbuff, SENSBUFF);
	} else if (!strcmp(argv[1], "inquiry")) {
		if (scsi_immed_command(   0, scsi_device,   0, &inquiry,
		    (u_char *)&inquirybuf, sizeof(inquirybuf)) == 0) {
			printf("Type:\t0x%x\n",		inquirybuf.type);
			printf("Qualifier:\t0x%x\n",	inquirybuf.qual);
			printf("Version:\t0x%x\n",	inquirybuf.version);
			printf("RDF:\t0x%x\n",		inquirybuf.rsvd);

			printf("Vender ID:\t");
			for (i = 0; i < 8; i++)
				printf("%c", inquirybuf.vendor_id[i]);
			printf("\n");

			printf("Product ID:\t");
			for (i = 0; i < 16; i++)
				printf("%c", inquirybuf.product_id[i]);
			printf("\n");

			printf("Revision:\t");
			for (i = 0; i < 4; i++)
				printf("%c", inquirybuf.rev[i]);
			printf("\n");
		}
	} else if (!strcmp(argv[1], "read_capacity")) {
		if (scsi_immed_command(   0, scsi_device,   0, &capacity,
		    (u_char *)&capacitybuf, sizeof(capacitybuf)) == 0) {
			printf("Logical Block Address:\t%ld (0x%lx)\n",
			       capacitybuf[0], capacitybuf[0]);
			printf("Block Length:\t\t%ld (0x%lx)\n",
			       capacitybuf[1], capacitybuf[1]);
		}
	} else if (!strcmp(argv[1], "trace")) {
		for (i = 0; i < 7; i++) {
			printf("SCSI ID %d .... ", i);
			status = scsi_test_unit_rdy( 0, i, 0);
			if (status >= 0)
				printf("found.\n");
			else
				printf("no.\n");
		}
	} else if (!strcmp(argv[1], "format_unit")) {
		i = 0;
		while (i == 0) {
			printf("Do you really want to format SCSI %d device ?"
			    " [y/n]: ", scsi_device);
			i = getchar();
			printf("\n");
			if ((i != 'y') && (i != 'Y') &&
			    (i != 'n') && (i != 'N'))
				i = 0;
		}

		if ((i == 'y') || (i == 'Y'))
			status = scsi_format_unit( 0, scsi_device, 0);
	}

	return ST_NORMAL;
}
Esempio n. 5
0
/* Read capacity of the drive */
status_t scsi_read_capacity( SCSI_device_s * psDevice, unsigned long *pnCapacity )
{
	int nError;
	struct
	{
		uint32 lba;
		uint32 blocklen;
	} sCap;
	SCSI_cmd_s sCmd;

      retry:
	nError = 0;

	scsi_init_cmd( &sCmd, psDevice );

	sCmd.nDirection = SCSI_DATA_READ;
	sCmd.pRequestBuffer = (void*)&sCap;
	sCmd.nRequestSize = sizeof( sCap );

	sCmd.nCmd[0] = SCSI_READ_CAPACITY;
	sCmd.nCmd[1] = ( psDevice->nLun << 5 ) & 0xe0;

	sCmd.nCmdLen = scsi_get_command_size( SCSI_READ_CAPACITY );

	/* Send command */
	nError = psDevice->psHost->queue_command( &sCmd );

	if( sCmd.s.sSense.sense_key != SCSI_NO_SENSE || sCmd.nResult != 0 )
	{
		SCSI_sense_s sSense;

		nError = scsi_request_sense( psDevice, &sSense );
		if( nError < 0 )
		{
			kerndbg( KERN_PANIC, "Unable to request sense data from SCSI device, aborting.\n" );
			goto error;
		}

		nError = scsi_check_sense( psDevice, &sSense, false );
		switch ( nError )
		{
			case SENSE_OK:
				break;

			case SENSE_RETRY:
				goto retry;

			case SENSE_FATAL:
			{
				kerndbg( KERN_PANIC, "SCSI device reporting fatal error, aborting.\n" );
				goto error;
			}
		}
	}

	psDevice->nSectorSize = be32_to_cpu( sCap.blocklen );
	if( psDevice->nSectorSize > 2048 )
		psDevice->nSectorSize = 2048;

	psDevice->nSectors = 1 + be32_to_cpu( sCap.lba );
	psDevice->nSize = psDevice->nSectors * psDevice->nSectorSize;

	if( pnCapacity != NULL )
		*pnCapacity = psDevice->nSize;

	kerndbg( KERN_DEBUG, "scsi_read_capacity(): %d bytes\n", psDevice->nSize );

	return 0;

error:
	psDevice->nSectors = 0;
	psDevice->nSectorSize = 0;
	psDevice->nSize = 0;

	if( pnCapacity != NULL )
		*pnCapacity = psDevice->nSize;

	return -EIO;
}
Esempio n. 6
0
DiscDCB *DevOpen(Device *dev, DiscDevInfo * info)
{
	DiscDCB 	*dcb;
	DriveInfo	*dvi;
	WORD		command_status;
	BYTE sense_data[SENSE_LENGTH];

	/* Create a DiscDCB for File System Server */
	if ((dcb = Malloc(sizeof(DiscDCB))) == NULL)
	{
		IOdebug("File System driver failed to allocate work space");
		return(NULL);
	}

	dvi = (DriveInfo *)RTOA(info->Drives);

	/* Initialise controlling link to the HE1000 */
	if(( dcb->Table = HE1000_init( info->Controller, dvi->DriveId , info->Mode)) < 0)
	{
		IOdebug("File System driver failed to initialise HE1000");
		return(NULL);
	}


	/* Initialise DiscDCB with drive information */
	dcb->DeviceId	 = dvi->DriveId;
	dcb->SectorSize  = dvi->SectorSize;
	dcb->DCB.Device  = dev;
	dcb->DCB.Operate = DevOperate;
	dcb->DCB.Close	 = DevClose;
	dcb->Link	 = info->Controller;
	dcb->BlockSize	 = info->Addressing;
	dcb->SectorsPerTrack	= dvi->SectorsPerTrack;
	dcb->TracksPerCyl	= dvi->TracksPerCyl;
	dcb->Cylinders		= dvi->Cylinders;
	dcb->Mode		= info->Mode;

	scsi_start_stop(
		dcb->Link,
		dcb->Table,
		dcb->DeviceId,
		0,
		1,		/* place head on track 0 */
		&command_status);

	/* Test disc for ready */
	do
	{
		scsi_test_unit_ready(
				dcb->Link,
				dcb->Table,
				dcb->DeviceId,
				0,
				&command_status);

		if( command_status eq CHECK_SENSE )
		{
			scsi_request_sense(
				dcb->Link,
				dcb->Table,
				dcb->DeviceId,
				0,
				SENSE_LENGTH,
				sense_data,
				&command_status);
		}
	} while ( command_status ne 0 );

	/* Initialise the access locking semaphore */
	InitSemaphore(&dcb->Lock, 1);
	/* return DiscDCB */
	return(dcb);
}
Esempio n. 7
0
void DevOperate(DiscDCB *dcb, DiscReq *req)
{
	BYTE	  capacity_data[CAPACITY_LENGTH];
	WORD	  command_status,second_status;
	WORD	  block_addr, block_len;
	WORD	  done = 0;
	WORD	  size;
	BYTE	  *buf = req->Buf;
	INT	  res;
	BYTE sense_data[SENSE_LENGTH];

	FormatReq *freq;

	Wait(&dcb->Lock);

	/* Select the appropriate command */
	switch( req->DevReq.Request & FG_Mask)
	{
		case FG_Read:
#ifdef DEBUG
		IOdebug("read pos = %d size = %d",req->Pos / dcb->SectorSize,req->Size / dcb->SectorSize);
#endif
			size = req->Size;
			while( done < size )
			{
				WORD tfr = size - done;
				WORD position = (req->Pos / dcb->SectorSize) + (done/dcb->SectorSize);
				command_status = 8;/* make loop happen once*/
				if ( tfr > MAX_TFR )
				{
					tfr = MAX_TFR;
				}
				while (command_status == 8)
				  {
				  res = scsi_read(dcb->Link,dcb->Table,dcb->DeviceId,0,position,tfr,dcb->SectorSize,buf,&command_status);
				  }

				if ( ( res < 0 ) || ( command_status ne 0 ))
					{
					 command_status = 8;
					 while (command_status == 8)
					   {
					   res = scsi_read(dcb->Link,dcb->Table,dcb->DeviceId,0,position,tfr,dcb->SectorSize,buf,&command_status);
					   }
				}

				done += tfr;
				buf  += tfr;
			}

			req->DevReq.Result = command_status;
			if ( req->DevReq.Result eq 0 )
				req->Actual = req->Size;
			else
				req->Actual = 0;
			break;

		case FG_Write:
#ifdef DEBUG
			IOdebug("write pos = %d size = %d",req->Pos / dcb->SectorSize,req->Size / dcb->SectorSize);
#endif
			size = req->Size;
			while( done < size )
			{
				WORD tfr = size - done;
				WORD position = (req->Pos / dcb->SectorSize) + (done/dcb->SectorSize);
				command_status = 8; /* make loop happen once*/
				if ( tfr > MAX_TFR )
				{
					tfr = MAX_TFR;
				}
				while (command_status == 8)
				{
				  res = scsi_write(dcb->Link,dcb->Table,dcb->DeviceId,0,position,tfr,dcb->SectorSize,buf,&command_status);
				}
				if ( ( res < 0 ) || ( command_status ne 0 ))
				{
					command_status = 8;
					while (command_status == 8)
					{
					 res = scsi_write(dcb->Link,dcb->Table,dcb->DeviceId,0,position,tfr,dcb->SectorSize,buf,&command_status);
					}
				}
				done += tfr;
				buf  += tfr;
			}


			req->DevReq.Result = command_status;
			if ( req->DevReq.Result eq 0 )
				req->Actual = req->Size;
			else
				req->Actual = 0;
			break;

		case FG_GetSize:
#ifdef DEBUG
			IOdebug("read capacity request");
#endif
			command_status = 8;
			while (command_status == 8)
			{
			scsi_read_capacity(
				dcb->Link,
				dcb->Table,
				dcb->DeviceId,
				0,		/* lun		   */
				8,		/* capacity length */
				capacity_data,
				&command_status);
			}

			if ( command_status eq 0 )
			{
				block_addr = capacity_data[0] * 0x1000000 +
					     capacity_data[1] * 0x10000   +
					     capacity_data[2] * 0x100	  +
					     capacity_data[3];
				block_len  = capacity_data[4] * 0x1000000 +
					     capacity_data[5] * 0x10000   +
					     capacity_data[6] * 0x100	  +
					     capacity_data[7];
				req->DevReq.Result = block_addr * block_len;
			}
			break;
		case FG_Format:
			IOdebug("\rFormatting disk please wait ....");
			freq = (FormatReq *)req;


			command_status = 8;/* so the loop happens once*/
			while (command_status == 8)
			{
			scsi_mode_select(
				dcb->Link,
				dcb->Table,
				dcb->DeviceId,
				0,
				0,			/* format whole disk */
				dcb->SectorSize,
				&command_status);
			}
			command_status = 8;/* so the loop happens once*/
			while (command_status == 8)
			{
			scsi_format(
				dcb->Link,
				dcb->Table,
				dcb->DeviceId,
				0,
				freq->Interleave,
				&command_status);
			}
/* If the disk supports the busy status we need to wait until busy goes away
	before giving the message that we are verifying */

			command_status = 8;
			while (command_status == 8)
			{
			  scsi_test_unit_ready(
				dcb->Link,
				dcb->Table,
				dcb->DeviceId,
				0,
				&command_status);
			}
/* some disks will queue one command so we need to wait twice to cope with this
	*/
			command_status = 8;
			while (command_status != 0)
			{
			  IOdebug("status = %d",command_status);
			  scsi_test_unit_ready(
				dcb->Link,
				dcb->Table,
				dcb->DeviceId,
				0,
				&command_status);

			scsi_request_sense(
				dcb->Link,
				dcb->Table,
				dcb->DeviceId,
				0,
				SENSE_LENGTH,
				sense_data,
				&command_status);
			IOdebug("sense =%x",sense_data[2]);
			}


			{
			WORD	total_blocks;
			WORD	i,j;
			WORD	ten_cent,done = 0;
			BYTE	*data;

			IOdebug("\rVerifying disk please wait ....");
			data = Malloc(dcb->SectorSize);
			command_status = 8; /* do at least once*/
			while (command_status == 8 )
			{
				res = scsi_write(dcb->Link,dcb->Table,dcb->DeviceId,0,1,dcb->SectorSize,dcb->SectorSize,data,&command_status);
			}
			total_blocks = (dcb->SectorsPerTrack * dcb->TracksPerCyl * dcb->Cylinders);
/*			IOdebug("\rdisk size is %d blocks",total_blocks);*/
			ten_cent =  total_blocks  / 10;
			for ( i = 1; i < total_blocks; i++)
			{
			 command_status = 8; /* you know by now*/
			 while (command_status == 8)
			 {
				 res = scsi_write_quick(dcb->Link,dcb->Table,dcb->DeviceId,0,i,&command_status);
			}
			second_status = 8;
			while (second_status == 8)
			{
			 res = scsi_read_quick(dcb->Link,dcb->Table,dcb->DeviceId,0,i,&second_status);
			}
					 if (( i % ten_cent )  eq 0)
				{
					done += 10;
					IOdebug("\rVerified %d percent of disk\v",done);
				}
				if ((command_status ne 0) || (second_status ne 0))
				{
					command_status = 8;
					while (command_status == 8 )
					{
					scsi_write_quick(dcb->Link,dcb->Table,dcb->DeviceId,0,i,&command_status);
					}
					second_status = 8;
					while (second_status == 8)
					{
					scsi_read_quick(dcb->Link,dcb->Table,dcb->DeviceId,0,i,&second_status);
					}
					if (( command_status  ne 0 ) || (second_status ne 0))
					{
						IOdebug("Verifier found bad block at %d",i);
						for( j = 0; j  < 10; j++)
						{
							command_status = 8;
							while (command_status == 8)
							{
							scsi_reassign_block(dcb->Link,dcb->Table,dcb->DeviceId,0,i,&command_status);
							}
							command_status = 8;
							while (command_status == 8)
							{
							scsi_write_quick(dcb->Link,dcb->Table,dcb->DeviceId,0,i,&command_status);
							}
							second_status = 8;
							while (second_status == 8)
							{
							scsi_read_quick(dcb->Link,dcb->Table,dcb->DeviceId,0,i,&second_status);
							}
							if ((command_status eq 0) && (second_status eq 0))break;
						}
						if  (( command_status eq 0 ) && (second_status eq 0))
							IOdebug("Block %d reassigned OK",i);
						else
							IOdebug("Failed to reassign block %d",i);
					}
				}
			}

			}
			IOdebug("Verification complete                         ");
			req->DevReq.Result = 0;
			break;
		default:
			break;
		}
		/* Unlock the driver */
		Signal(&dcb->Lock);
		/* Client action */
		(*req->DevReq.Action)(req);
		return;
}
Esempio n. 8
0
static int
siop_scsi_request(struct siop_adapter *adp, struct scsi_xfer *xs)
{
	void *xfer = adp->xfer;
	int timo, error;

	if (adp->sel_t != xs->target) {
		const int free_lo = __arraycount(siop_script);
		int i;
		void *scriptaddr = (void *)local_to_PCI((u_long)adp->script);

		if (adp->sel_t != -1)
			adp->script[Ent_resel_targ0 / 4 + adp->sel_t * 2] =
			    htoc32(0x800c00ff);

		for (i = 0; i < __arraycount(lun_switch); i++)
			adp->script[free_lo + i] = htoc32(lun_switch[i]);
		adp->script[free_lo + E_abs_lunsw_return_Used[0]] =
		    htoc32(scriptaddr + Ent_lunsw_return);

		siop_add_reselsw(adp, xs->target, free_lo);

		adp->sel_t = xs->target;
	}

restart:

	siop_setuptables(adp, xfer, xs);

	/* load the DMA maps */
	if (xs->datalen != 0)
		_inv((u_long)xs->data, xs->datalen);
	_wbinv((u_long)xs->cmd, xs->cmdlen);

	_wbinv((u_long)xfer, sizeof(struct siop_xfer));
	siop_start(adp, xs);

	adp->xs = xs;
	timo = 0;
	while (!(xs->xs_status & XS_STS_DONE)) {
		delay(1000);
		siop_intr(adp);

		if (timo++ > 3000) {		/* XXXX: 3sec */
			printf("%s: timeout\n", __func__);
			return ETIMEDOUT;
		}
	}

	if (xs->error != XS_NOERROR) {
		if (xs->error == XS_BUSY || xs->status == SCSI_CHECK)
			scsi_request_sense(adp, xs);

		switch (xs->error) {
		case XS_SENSE:
		case XS_SHORTSENSE:
			error = scsi_interpret_sense(adp, xs);
			break;
		case XS_RESOURCE_SHORTAGE:
			printf("adapter resource shortage\n");

			/* FALLTHROUGH */
		case XS_BUSY:
			error = EBUSY;
			break;
		case XS_REQUEUE:
			printf("XXXX: requeue...\n");
			error = ERESTART;
			break;
		case XS_SELTIMEOUT:
		case XS_TIMEOUT:
			error = EIO;
			break;
		case XS_RESET:
			error = EIO;
			break;
		case XS_DRIVER_STUFFUP:
			printf("generic HBA error\n");
			error = EIO;
			break;
		default:
			printf("invalid return code from adapter: %d\n",
			    xs->error);
			error = EIO;
			break;
		}
		if (error == ERESTART) {
			xs->error = XS_NOERROR;
			xs->status = SCSI_OK;
			xs->xs_status &= ~XS_STS_DONE;
			goto restart;
		}
		return error;
	}
	return 0;
}
Esempio n. 9
0
int scsi_parse(uint8_t *block, uint8_t in_len)
{
	/* set new operation */
	if (state == USB_MS_SCSI_STATE_IDLE) {
		state = USB_MS_SCSI_STATE_PARSE;

		op = block[0];
	}

	/* skip operation if sending reply */
	if (state != USB_MS_SCSI_STATE_REPLY) {
		switch (op) {
		case SCSI_INQUIRY:
			scsi_inquiry(block, in_len);
		break;
		case SCSI_MODE_SENSE6:
			scsi_mode_sense6(block, in_len);
		break;
		case SCSI_READ10:
			scsi_read10(block, in_len);
		break;
		case SCSI_READ_CAPACITY10:
			scsi_read_capacity10(block, in_len);
		break;
		case SCSI_READ_FORMAT_CAPACITIES:
			scsi_read_format_capacities(block, in_len);
		break;
		case SCSI_REPORT_LUNS:
			scsi_report_luns(block, in_len);
		break;
		case SCSI_REQUEST_SENSE:
			scsi_request_sense(block, in_len);
		break;
		case SCSI_START_STOP_UNIT:
			scsi_start_stop_unit(block, in_len);
		break;
		case SCSI_SYNCHRONIZE_CACHE10:
			scsi_synchronize_cache10(block, in_len);
		break;
		case SCSI_TEST_UNIT_READY:
			scsi_test_unit_ready(block, in_len);
		break;
		case SCSI_WRITE10:
			scsi_write10(block, in_len);
		break;
		default:
			state = USB_MS_SCSI_STATE_REPLY;
			scsi_sense_code(SCSI_SENSE_ILLEGAL_REQUEST,
				SCSI_SENSE_CODE_INVALID_COMMAND_OPERATION_CODE);
		break;
		}
	}

	/* error during data rx/tx */
	if (((state == USB_MS_SCSI_STATE_DATA_OUT) ||
			(state == USB_MS_SCSI_STATE_DATA_IN)) &&
			scsi_sense_data.key) {
		btable_ep[USB_EP_MS_TX].tx_count = 0;
		state = USB_MS_SCSI_STATE_REPLY;
		return SCSI_STATUS_CONTINUE;
	}

	/* done sending data */
	if (state == USB_MS_SCSI_STATE_REPLY) {
		state = USB_MS_SCSI_STATE_IDLE;
		return scsi_sense_data.key;
	}

	/* still sending/receiving data and no error has occurred */
	return SCSI_STATUS_CONTINUE;
}
Esempio n. 10
0
/*
 * Start/completion routine for disks
 */
void
scdisk_start(
	target_info_t	*tgt,
	boolean_t	done)
{
    register io_req_t	ior = tgt->ior;
#ifdef	CHECKSUM
    register unsigned	secno;
#endif
    register io_req_t	rdone = NULL;
    register unsigned	part, secno;
    scsi_ret_t		ret;

    if (ior == 0)
        return;

    if (tgt->flags & TGT_BBR_ACTIVE) {
        scdisk_bbr_start(tgt, done);
	return;
    }

    if (done) {
        unsigned int		xferred;
	unsigned int		max_dma_data;

	max_dma_data = scsi_softc[(unsigned char)tgt->masterno]->max_dma_data;
	/* see if we must retry */
	if ((tgt->done == SCSI_RET_RETRY) &&
	    ((ior->io_op & IO_INTERNAL) == 0)) {
	    if(tgt->dev_info.disk.b.retry_count++ == DISK_RETRIES) {
		tgt->done = SCSI_RET_DEVICE_DOWN;
	    } else {
		timeout((timeout_fcn_t)wakeup, tgt, hz);
		await(tgt);
		goto start;
	    }
	} 
	/* got a bus reset ? pifff.. */
	if ((tgt->done == (SCSI_RET_ABORTED|SCSI_RET_RETRY)) &&
		((ior->io_op & IO_INTERNAL) == 0)) {
	        if (xferred = ior->io_residual) {
		    /*
		     * No special thing to do for
		     * chained IOs, should work as well
		     */
		    ior->io_data -= xferred;
		    ior->io_count += xferred;
		    ior->io_recnum -= xferred / tgt->block_size;
		    ior->io_residual = 0;
		}
		goto start;
	    } else if ((tgt->cur_cmd == SCSI_CMD_REQUEST_SENSE) &&
		    (!rzpassthru(ior->io_unit))) {
		
	        /*
		 * Quickly check for errors: if anything goes wrong
		 * we do a request sense, see if that is what we did.
		 */
	        scsi_sense_data_t	*sns;
		unsigned int		blockno;
		char			*outcome;

		ior->io_op = ior->io_temporary;
		
		sns = (scsi_sense_data_t *)tgt->cmd_ptr;
		if (sns->addr_valid)
		    blockno = sns->u.xtended.info0 << 24 |
			      sns->u.xtended.info1 << 16 |
			      sns->u.xtended.info2 <<  8 |
			      sns->u.xtended.info3;
		else {
		    part = rzpartition(ior->io_unit);
		    blockno = tgt->dev_info.disk.l.d_partitions[part].p_offset
		      * (tgt->dev_info.disk.l.d_secsize / tgt->block_size);
		    blockno += ior->io_recnum;
		}

		if ((blockno + btodb(ior->io_count + tgt->block_size - 1) 
		     >= tgt->dev_info.disk.l.d_secperunit)) {
		    ior->io_error = D_INVALID_RECNUM;
		    ior->io_op |= IO_ERROR;
		    outcome = "Unrecoverable";
		} else if (scsi_check_sense_data(tgt, sns)) {
		    ior->io_error = 0;
		    if ((tgt->done == SCSI_RET_RETRY) &&
			((ior->io_op & IO_INTERNAL) == 0)) {
			timeout((timeout_fcn_t)wakeup, tgt, hz);
			await(tgt);
			goto start;
		    }
		    outcome = "Recovered";
#if CHAINED_IOS
		} else if (ior->io_op & IO_CHAINED) {
		    /*
		     * Since multiple IOs are chained, split them
		     * and restart prior to error handling
		     */
		    simple_lock(&tgt->target_lock);
		    split_io_reqs(ior);
		    simple_unlock(&tgt->target_lock);
		    ior->io_residual = 0;
		    goto start;
#endif /* CHAINED_IOS */
		} else {
		    outcome = "Unrecoverable";
		    ior->io_error = D_IO_ERROR;
		    ior->io_op |= IO_ERROR;
		}
		if ((tgt->flags & TGT_OPTIONAL_CMD) == 0) {
		    printf("%s Error, rz%d: %s%s%d\n", outcome,
			   tgt->target_id + (tgt->masterno * 8),
			   (ior->io_op & IO_READ) ? "Read" :
			   ((ior->io_op & IO_INTERNAL) ? "(command)" : "Write"),
			   " disk error, phys block no. ", blockno);
		    
		    scsi_print_sense_data(sns); printf("\n");

#ifndef	POWERMAC
		    /*
		     * On fatal read/write errors try replacing the
		     * bad block. The bbr routine will return TRUE
		     * iff it took control over the target for all
		     * subsequent operations. In this event, the
		     * queue of requests is effectively frozen.
		     */
		    if (ior->io_error && 
			((sns->error_class == SCSI_SNS_XTENDED_SENSE_DATA) &&
			 ((sns->u.xtended.sense_key == SCSI_SNS_HW_ERR) ||
			  (sns->u.xtended.sense_key == SCSI_SNS_MEDIUM_ERR))) &&
			scdisk_bad_block_repl(tgt, blockno))
			return;
#endif
		}
	    } else if ((tgt->done != SCSI_RET_SUCCESS) &&
#ifdef	POWERMAC
			(!rzpassthru(ior->io_unit) && (ior->io_op & IO_INTERNAL) == 0)) {
#else
			!rzpassthru(ior->io_unit)) {
#endif

#if CHAINED_IOS
		if (ior->io_op & IO_CHAINED) {
		    /*
		     * Since multiple IOs are chained, split them
		     * and restart prior to error handling
		     */
		    simple_lock(&tgt->target_lock);
		    split_io_reqs(ior);
		    simple_unlock(&tgt->target_lock);
		    ior->io_residual = 0;
		    goto start;
		}
#endif /* CHAINED_IOS */

	        /*
		 * See if we had errors
		 */
	      
	        if (tgt->done == SCSI_RET_NEED_SENSE) {
		    ior->io_temporary = ior->io_op;
		    ior->io_op = IO_INTERNAL;
		    scsi_request_sense(tgt, ior, 0);
		    return;

		} else if (tgt->done == SCSI_RET_DEVICE_DOWN) {
		    part = rzpartition(ior->io_unit);
		    secno = ior->io_recnum;
		    secno += tgt->dev_info.disk.l.d_partitions[part].p_offset
		      * (tgt->dev_info.disk.l.d_secsize / tgt->block_size);
		    secno += btodb(ior->io_count + tgt->block_size - 1);

		    if (secno >= tgt->dev_info.disk.l.d_secperunit)
		        ior->io_error = D_INVALID_RECNUM;
		    else
		        ior->io_error = D_DEVICE_DOWN;
		    ior->io_op |= IO_ERROR;
		} else {
		    printf("%s%x\n", "?rz_disk Disk error, ret=x", tgt->done);
		    ior->io_error = D_IO_ERROR;
		    ior->io_op |= IO_ERROR;
		}
	    } else if (ior->io_count > (xferred = max_dma_data)) {
	        /*
		 * No errors.
		 * See if we requested more than the max
		 * (We use io_residual in a flip-side way here)
		 */
#if CHAINED_IOS
	        if (ior->io_op & IO_CHAINED) {
		    /* Should not happen since we checked
		       max_data & max_segs  before */
		    panic("chained io to large: 1");
		}
#endif /* CHAINED_IOS */
		ior->io_residual += xferred;
		ior->io_count -= xferred;
		ior->io_data += xferred;
		ior->io_recnum += xferred / tgt->block_size;
		goto start;
	    } else if (xferred = ior->io_residual) {
#if CHAINED_IOS
	        if (ior->io_op & IO_CHAINED) {
		    /* Should not happen since we checked
		       max_data & max_segs  before */
		    panic("chained io to large: 2");
		}
#endif /* CHAINED_IOS */
		ior->io_data -= xferred;
		ior->io_count += xferred;
		ior->io_recnum -= xferred / tgt->block_size;
		ior->io_residual = 0;
	    } /* that's it */

#ifdef	CHECKSUM
	if ((ior->io_op & IO_READ) && (ior->io_count < max_checksum_size)) {
	    part = rzpartition(ior->io_unit);
	    secno = ior->io_recnum 
	      + tgt->dev_info.disk.l.d_partitions[part].p_offset
		* (tgt->dev_info.disk.l.d_secsize / tgt->block_size);
	    scdisk_bcheck(secno, ior->io_data, ior->io_count);
	}
#endif	/* CHECKSUM */

	/* If this is a pass-through device, save the target result */
	if (rzpassthru(ior->io_unit))
	    ior->io_error = tgt->done;
	
	/* dequeue next one */
	{
	    io_req_t	next;
	    
	    simple_lock(&tgt->target_lock);
	    next = ior->io_next;
	    tgt->ior = next;
	    simple_unlock(&tgt->target_lock);
	    
	    if (next == 0) {
#if CHAINED_IOS
		if (ior->io_op & IO_CHAINED)
		    chained_iodone(ior);
		else 
#endif	/* CHAINED_IOS */
		    iodone(ior);
		return;
	    }
	    rdone = ior;
	    ior = next;
	}

#ifdef	CHECKSUM
	if (((ior->io_op & IO_READ) == 0) &&
	    (ior->io_count < max_checksum_size)) {
	    part = rzpartition(ior->io_unit);
	    secno = ior->io_recnum 
	      + tgt->dev_info.disk.l.d_partitions[part].p_offset
		* (tgt->dev_info.disk.l.d_secsize / tgt->block_size);
	    scdisk_checksum(secno, ior->io_data, ior->io_count);
	}
#endif	/* CHECKSUM */
    }
Esempio n. 11
0
void scsi_proc(void)
{
    if (USBD_ep_buffer_full(BOMS_EP_DATA_OUT)) {
        if (sizeof(BOMSCmd) == USBD_transfer(BOMS_EP_DATA_OUT, (uint8_t *)&BOMSCmd, sizeof(BOMSCmd))) {
            if (BOMSCmd.dCBWSignature == BOMS_USBC) {
                if (BOMSCmd.CBWCB.unit_ready.op_code == BOMS_SCSI_TEST_UNIT_READY) // SCSI Test Unit Ready
                {
                    scsi_test_unit_ready(&BOMSCmd);
                } 
                else if (BOMSCmd.CBWCB.request_sense.op_code == BOMS_SCSI_READ) // SCSI Read
                {
                    scsi_read(&BOMSCmd);
                }
                else if (BOMSCmd.CBWCB.request_sense.op_code == BOMS_SCSI_WRITE) // SCSI Write
                {
                    scsi_write(&BOMSCmd);
                }
                else if (BOMSCmd.CBWCB.inquiry.op_code == BOMS_SCSI_INQUIRY) // SCSI Inquiry
                {
                    scsi_inquiry(&BOMSCmd);
                }
                else if (BOMSCmd.CBWCB.request_sense.op_code == BOMS_SCSI_REQUEST_SENSE) // SCSI Request Sense
                {
                    scsi_request_sense(&BOMSCmd);
                }
                else if (BOMSCmd.CBWCB.read_capacity.op_code == BOMS_SCSI_READ_CAPACITY) // SCSI Read Capacity (10)
                {
                    scsi_read_capacity(&BOMSCmd);
                }
                else if (BOMSCmd.CBWCB.read_capacity.op_code == BOMS_SCSI_READ_FORMAT_CAPACITY) // SCSI Read Format Capacity (10)
                {
                    scsi_read_format_capacity(&BOMSCmd);
                }
                else if (BOMSCmd.CBWCB.mode_sense.op_code == BOMS_SCSI_MODE_SENSE) // SCSI Mode Sense
                {
                    scsi_mode_sense(&BOMSCmd);
                }
                else if (BOMSCmd.CBWCB.request_sense.op_code == BOMS_SCSI_READ_CAPACITY_16) // SCSI Read Capacity (16)
                {
                    scsi_read_capacity(&BOMSCmd);
                }
                else if (BOMSCmd.CBWCB.request_sense.op_code == BOMS_SCSI_PREVENT_ALLOW_REMOVAL) // SCSI Prevent Allow Removal
                {
                    scsi_prevent_allow_removal(&BOMSCmd);
                }
                else
                {
                    // Send IN a zero length packet.
                    if (BOMSCmd.dCBWDataTransferLength)
                    {
                        USBD_stall_endpoint(BOMS_EP_DATA_IN);
                    }
                    boms_send_status(BOMS_STATUS_COMMAND_FAILED, &BOMSCmd);
                    scsi_sense_illegal_request_command();
                }
            }
            else
            {
                // Was not a USBC signature.
                boms_send_status(BOMS_STATUS_PHASE_ERROR, &BOMSCmd);
                scsi_sense_illegal_request_cdb();
            }
        }else{
            // Wrong command size.
            boms_send_status(BOMS_STATUS_COMMAND_FAILED, &BOMSCmd);
            scsi_sense_illegal_request_parm();
        }
    }
}