Exemple #1
0
/*
 * Load the current IE mode pages
 */
static int
load_ie_modepage(ds_scsi_info_t *sip)
{
	struct scsi_ms_hdrs junk_hdrs;
	int result;
	uint_t skey, asc, ascq;

	if (!(sip->si_supp_mode & MODEPAGE_SUPP_IEC))
		return (0);

	bzero(&sip->si_iec_current, sizeof (sip->si_iec_current));
	bzero(&sip->si_iec_changeable, sizeof (sip->si_iec_changeable));

	if ((result = scsi_mode_sense(sip,
	    MODEPAGE_INFO_EXCPT, PC_CURRENT, &sip->si_iec_current,
	    MODEPAGE_INFO_EXCPT_LEN, &sip->si_hdrs, &skey, &asc,
	    &ascq)) == 0) {
		result = scsi_mode_sense(sip,
		    MODEPAGE_INFO_EXCPT, PC_CHANGEABLE,
		    &sip->si_iec_changeable,
		    MODEPAGE_INFO_EXCPT_LEN, &junk_hdrs, &skey, &asc, &ascq);
	}

	if (result != 0) {
		printf("failed to get IEC modepage (KEY=0x%x "
		    "ASC=0x%x ASCQ=0x%x)", skey, asc, ascq);
		sip->si_supp_mode &= ~MODEPAGE_SUPP_IEC;
	} else  {
		if (nvlist_add_boolean_value(sip->si_state_iec,
		    "dexcpt", sip->si_iec_current.ie_dexcpt) != 0 ||
		    nvlist_add_boolean_value(sip->si_state_iec,
		    "logerr", sip->si_iec_current.ie_logerr) != 0 ||
		    nvlist_add_uint8(sip->si_state_iec,
		    "mrie", sip->si_iec_current.ie_mrie) != 0 ||
		    nvlist_add_boolean_value(sip->si_state_iec,
		    "test", sip->si_iec_current.ie_test) != 0 ||
		    nvlist_add_boolean_value(sip->si_state_iec,
		    "ewasc", sip->si_iec_current.ie_ewasc) != 0 ||
		    nvlist_add_boolean_value(sip->si_state_iec,
		    "perf", sip->si_iec_current.ie_perf) != 0 ||
		    nvlist_add_boolean_value(sip->si_state_iec,
		    "ebf", sip->si_iec_current.ie_ebf) != 0 ||
		    nvlist_add_uint32(sip->si_state_iec,
		    "interval-timer",
		    BE_32(sip->si_iec_current.ie_interval_timer)) != 0 ||
		    nvlist_add_uint32(sip->si_state_iec,
		    "report-count",
		    BE_32(sip->si_iec_current.ie_report_count)) != 0)
			return (scsi_set_errno(sip, EDS_NOMEM));
	}

	return (0);
}
Exemple #2
0
/*
 * Clear the GLTSD bit, indicating log pages should be saved to non-volatile
 * storage.
 */
static int
clear_gltsd(ds_scsi_info_t *sip)
{
	scsi_ms_hdrs_t hdrs, junk_hdrs;
	struct mode_control_scsi3 control_pg_cur, control_pg_chg;
	int result;
	uint_t skey, asc, ascq;

	bzero(&hdrs, sizeof (hdrs));
	bzero(&control_pg_cur, sizeof (control_pg_cur));
	bzero(&control_pg_chg, sizeof (control_pg_chg));

	result = scsi_mode_sense(sip,
	    MODEPAGE_CTRL_MODE, PC_CURRENT, &control_pg_cur,
	    MODEPAGE_CTRL_MODE_LEN, &hdrs, &skey, &asc, &ascq);

	if (result != 0) {
		printf("failed to read Control mode page (KEY=0x%x "
		    "ASC=0x%x ASCQ=0x%x)\n", skey, asc, ascq);
	} else if (control_pg_cur.mode_page.length !=
	    PAGELENGTH_MODE_CONTROL_SCSI3) {
		printf("SCSI-3 control mode page not supported\n");
	} else if ((result = scsi_mode_sense(sip,
	    MODEPAGE_CTRL_MODE, PC_CHANGEABLE, &control_pg_chg,
	    MODEPAGE_CTRL_MODE_LEN, &junk_hdrs, &skey, &asc, &ascq))
	    != 0) {
		printf("failed to read changeable Control mode page (KEY=0x%x "
		    "ASC=0x%x ASCQ=0x%x)\n", skey, asc, ascq);
	} else if (control_pg_cur.gltsd && !GLTSD_CHANGEABLE(control_pg_chg)) {
		printf("gltsd is set and not changeable\n");
		if (nvlist_add_boolean_value(sip->si_dsp->ds_state,
		    "gltsd", control_pg_cur.gltsd) != 0)
			return (scsi_set_errno(sip, EDS_NOMEM));
	} else if (control_pg_cur.gltsd) {
		control_pg_cur.gltsd = 0;
		result = scsi_mode_select(sip,
		    MODEPAGE_CTRL_MODE, MODE_SELECT_PF, &control_pg_cur,
		    MODEPAGE_CTRL_MODE_LEN, &hdrs, &skey, &asc, &ascq);
		if (result != 0)
			printf("failed to enable GLTSD (KEY=0x%x "
			    "ASC=0x%x ASCQ=0x%x\n", skey, asc, ascq);
		if (nvlist_add_boolean_value(sip->si_dsp->ds_state,
		    "gltsd", control_pg_cur.gltsd) != 0)
			return (scsi_set_errno(sip, EDS_NOMEM));
	}

	return (0);
}
Exemple #3
0
static int
sd_get_simplifiedparms(struct sd_softc *sd)
{
	struct {
		struct scsi_mode_parameter_header_6 header;
		/* no block descriptor */
		uint8_t pg_code; /* page code (should be 6) */
		uint8_t pg_length; /* page length (should be 11) */
		uint8_t wcd; /* bit0: cache disable */
		uint8_t lbs[2]; /* logical block size */
		uint8_t size[5]; /* number of log. blocks */
		uint8_t pp; /* power/performance */
		uint8_t flags;
		uint8_t resvd;
	} scsipi_sense;
	struct disk_parms *dp = &sd->sc_params;
	uint64_t blocks;
	int error, blksize;

	/*
	 * sd_read_capacity (ie "read capacity") and mode sense page 6
	 * give the same information. Do both for now, and check
	 * for consistency.
	 * XXX probably differs for removable media
	 */
	dp->blksize = SD_DEFAULT_BLKSIZE;
	if ((blocks = sd_read_capacity(sd, &blksize)) == 0)
		return SDGP_RESULT_OFFLINE;		/* XXX? */

	error = scsi_mode_sense(sd, SMS_DBD, 6,
	    &scsipi_sense.header, sizeof(scsipi_sense));

	if (error != 0)
		return SDGP_RESULT_OFFLINE;		/* XXX? */

	dp->blksize = blksize;
	if (!sd_validate_blksize(dp->blksize))
		dp->blksize = _2btol(scsipi_sense.lbs);
	if (!sd_validate_blksize(dp->blksize))
		dp->blksize = SD_DEFAULT_BLKSIZE;

	/*
	 * Create a pseudo-geometry.
	 */
	dp->heads = 64;
	dp->sectors = 32;
	dp->cyls = blocks / (dp->heads * dp->sectors);
	dp->disksize = _5btol(scsipi_sense.size);
	if (dp->disksize <= UINT32_MAX && dp->disksize != blocks) {
		printf("RBC size: mode sense=%llu, get cap=%llu\n",
		       (unsigned long long)dp->disksize,
		       (unsigned long long)blocks);
		dp->disksize = blocks;
	}
	dp->disksize512 = (dp->disksize * dp->blksize) / DEV_BSIZE;

	return SDGP_RESULT_OK;
}
Exemple #4
0
static ssize_t
sd_store_cache_type(struct device *dev, struct device_attribute *attr,
		    const char *buf, size_t count)
{
	int i, ct = -1, rcd, wce, sp;
	struct scsi_disk *sdkp = to_scsi_disk(dev);
	struct scsi_device *sdp = sdkp->device;
	char buffer[64];
	char *buffer_data;
	struct scsi_mode_data data;
	struct scsi_sense_hdr sshdr;
	int len;

	if (sdp->type != TYPE_DISK)
		/* no cache control on RBC devices; theoretically they
		 * can do it, but there's probably so many exceptions
		 * it's not worth the risk */
		return -EINVAL;

	for (i = 0; i < ARRAY_SIZE(sd_cache_types); i++) {
		len = strlen(sd_cache_types[i]);
		if (strncmp(sd_cache_types[i], buf, len) == 0 &&
		    buf[len] == '\n') {
			ct = i;
			break;
		}
	}
	if (ct < 0)
		return -EINVAL;
	rcd = ct & 0x01 ? 1 : 0;
	wce = ct & 0x02 ? 1 : 0;
	if (scsi_mode_sense(sdp, 0x08, 8, buffer, sizeof(buffer), SD_TIMEOUT,
			    SD_MAX_RETRIES, &data, NULL))
		return -EINVAL;
	len = min_t(size_t, sizeof(buffer), data.length - data.header_length -
		  data.block_descriptor_length);
	buffer_data = buffer + data.header_length +
		data.block_descriptor_length;
	buffer_data[2] &= ~0x05;
	buffer_data[2] |= wce << 2 | rcd;
	sp = buffer_data[0] & 0x80 ? 1 : 0;

	if (scsi_mode_select(sdp, 1, sp, 8, buffer_data, len, SD_TIMEOUT,
			     SD_MAX_RETRIES, &data, &sshdr)) {
		if (scsi_sense_valid(&sshdr))
			sd_print_sense_hdr(sdkp, &sshdr);
		return -EINVAL;
	}
	revalidate_disk(sdkp->disk);
	return count;
}
Exemple #5
0
/*
 * Load mode pages and check that the appropriate pages are supported.
 *
 * As part of this process, we determine which form of the MODE SENSE / MODE
 * SELECT command to use (the 6-byte or 10-byte version) by executing a MODE
 * SENSE command for a page that should be implemented by the device.
 */
static int
load_modepages(ds_scsi_info_t *sip)
{
	int allpages_buflen;
	uchar_t *allpages;
	scsi_ms_hdrs_t headers;
	int result;
	uint_t skey, asc, ascq;
	int datalength = 0;
	scsi_ms_header_t *smh = &headers.ms_hdr.g0;
	scsi_ms_header_g1_t *smh_g1 = &headers.ms_hdr.g1;
	nvlist_t *nvl;

	allpages_buflen = MAX_BUFLEN(scsi_ms_header_g1_t);
	if ((allpages = calloc(allpages_buflen, 1)) == NULL)
		return (scsi_set_errno(sip, EDS_NOMEM));

	bzero(&headers, sizeof (headers));

	/*
	 * Attempt a mode sense(6).  If that fails, try a mode sense(10)
	 *
	 * allpages is allocated to be of the maximum size for either a mode
	 * sense(6) or mode sense(10) MODEPAGE_ALLPAGES response.
	 *
	 * Note that the length passed into uscsi_mode_sense should be set to
	 * the maximum size of the parameter response, which in this case is
	 * UCHAR_MAX - the size of the headers/block descriptors.
	 */
	sip->si_cdblen = MODE_CMD_LEN_6;
	if ((result = scsi_mode_sense(sip, MODEPAGE_ALLPAGES, PC_CURRENT,
	    (caddr_t)allpages, UCHAR_MAX - sizeof (scsi_ms_header_t),
	    &headers, &skey, &asc, &ascq)) == 0) {
		/*
		 * Compute the data length of the page that contains all mode
		 * sense pages.  This is a bit tricky because the format of the
		 * response from the lun is:
		 *
		 * header: <length> <medium type byte> <dev specific byte>
		 *	   <block descriptor length>
		 *	   [<optional block descriptor>]
		 * data:   [<mode page data> <mode page data> ...]
		 *
		 * Since the length field in the header describes the length of
		 * the entire response.  This includes the header, but NOT
		 * the length field itself, which is 1 or 2 bytes depending on
		 * which mode sense type (6- or 10- byte) is being executed.
		 *
		 * So, the data length equals the length value in the header
		 * plus 1 (because the length byte was not included in the
		 * length count), minus [[the sum of the length of the header
		 * and the length of the block descriptor]].
		 */
		datalength = (smh->ms_header.length +
		    sizeof (smh->ms_header.length)) -
		    (sizeof (struct mode_header) +
		    smh->ms_header.bdesc_length);
	} else if (SCSI_INVALID_OPCODE(skey, asc, ascq)) {
		/*
		 * Fallback and try the 10-byte version of the command.
		 */
		sip->si_cdblen = MODE_CMD_LEN_10;
		result = scsi_mode_sense(sip, MODEPAGE_ALLPAGES,
		    PC_CURRENT, (caddr_t)allpages, allpages_buflen,
		    &headers, &skey, &asc, &ascq);

		if (result == 0) {
			datalength = (BE_16(smh_g1->ms_header.length) +
			    sizeof (smh_g1->ms_header.length)) -
			    (sizeof (struct mode_header_g1) +
			    BE_16(smh_g1->ms_header.bdesc_length));

		}
	}

	if (result == 0 && datalength >= 0) {
		if (nvlist_add_int8(sip->si_dsp->ds_state, "command-length",
		    sip->si_cdblen == MODE_CMD_LEN_6 ? 6 : 10) != 0) {
			free(allpages);
			return (scsi_set_errno(sip, EDS_NOMEM));
		}

		nvl = NULL;
		if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
		    nvlist_add_nvlist(sip->si_dsp->ds_state, "modepages",
		    nvl) != 0) {
			free(allpages);
			nvlist_free(nvl);
			return (scsi_set_errno(sip, EDS_NOMEM));
		}

		nvlist_free(nvl);
		result = nvlist_lookup_nvlist(sip->si_dsp->ds_state,
		    "modepages", &sip->si_state_modepage);
		assert(result == 0);

		/*
		 * One of the sets of the commands (above) succeeded, so now
		 * look for the mode pages we need and record them appropriately
		 */
		if (mode_page_present(allpages, datalength,
		    MODEPAGE_INFO_EXCPT)) {

			nvl = NULL;
			if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
			    nvlist_add_nvlist(sip->si_state_modepage,
			    "informational-exceptions", nvl) != 0) {
				free(allpages);
				nvlist_free(nvl);
				return (scsi_set_errno(sip, EDS_NOMEM));
			}
			nvlist_free(nvl);
			sip->si_supp_mode |= MODEPAGE_SUPP_IEC;
			result = nvlist_lookup_nvlist(sip->si_state_modepage,
			    "informational-exceptions", &sip->si_state_iec);
			assert(result == 0);
		}

	} else {
		/*
		 * If the device failed to respond to one of the basic commands,
		 * then assume it's not a SCSI device or otherwise doesn't
		 * support the necessary transport.
		 */
		if (datalength < 0)
			printf("command returned invalid data length (%d)\n",
			    datalength);
		else
			printf("failed to load modepages (KEY=0x%x "
			    "ASC=0x%x ASCQ=0x%x)\n", skey, asc, ascq);

		result = scsi_set_errno(sip, EDS_NO_TRANSPORT);
	}

	free(allpages);
	return (result);
}
Exemple #6
0
static int
sd_get_parms_page5(struct sd_softc *sd, struct disk_parms *dp)
{
	struct sd_mode_sense_data scsipi_sense;
	union scsi_disk_pages *pages;
	size_t poffset;
	int byte2, error;

	byte2 = SMS_DBD;
again:
	memset(&scsipi_sense, 0, sizeof(scsipi_sense));
	error = scsi_mode_sense(sd, 0, 5, &scsipi_sense.header,
	    (byte2 ? 0 : sizeof(scsipi_sense.blk_desc)) +
				sizeof(scsipi_sense.pages.flex_geometry));
	if (error) {
		if (byte2 == SMS_DBD) {
			/* No result; try once more with DBD off */
			byte2 = 0;
			goto again;
		}
		return error;
	}

	poffset = sizeof(scsipi_sense.header);
	poffset += scsipi_sense.header.blk_desc_len;

	if (poffset > sizeof(scsipi_sense) - sizeof(pages->flex_geometry))
		return ERESTART;

	pages = (void *)((u_long)&scsipi_sense + poffset);
#if 0
	{
		size_t i;
		u_int8_t *p;

		printf("page 5 sense:");
		for (i = sizeof(scsipi_sense), p = (void *)&scsipi_sense; i;
		    i--, p++)
			printf(" %02x", *p);
		printf("\n");
		printf("page 5 pg_code=%d sense=%p/%p\n",
		    pages->flex_geometry.pg_code, &scsipi_sense, pages);
	}
#endif

	if ((pages->flex_geometry.pg_code & PGCODE_MASK) != 5)
		return ERESTART;

	dp->heads = pages->flex_geometry.nheads;
	dp->cyls = _2btol(pages->flex_geometry.ncyl);
	dp->sectors = pages->flex_geometry.ph_sec_tr;
	if (dp->heads == 0 || dp->cyls == 0 || dp->sectors == 0)
		return ERESTART;

	dp->rot_rate = _2btol(pages->rigid_geometry.rpm);
	if (dp->rot_rate == 0)
		dp->rot_rate = 3600;

#if 0
printf("page 5 ok\n");
#endif
	return 0;
}
Exemple #7
0
static int
sd_get_parms_page4(struct sd_softc *sd, struct disk_parms *dp)
{
	struct sd_mode_sense_data scsipi_sense;
	union scsi_disk_pages *pages;
	size_t poffset;
	int byte2, error;

	byte2 = SMS_DBD;
again:
	memset(&scsipi_sense, 0, sizeof(scsipi_sense));
	error = scsi_mode_sense(sd, byte2, 4, &scsipi_sense.header,
	    (byte2 ? 0 : sizeof(scsipi_sense.blk_desc)) +
				sizeof(scsipi_sense.pages.rigid_geometry));
	if (error) {
		if (byte2 == SMS_DBD) {
			/* No result; try once more with DBD off */
			byte2 = 0;
			goto again;
		}
		return error;
	}

	poffset = sizeof(scsipi_sense.header);
	poffset += scsipi_sense.header.blk_desc_len;

	if (poffset > sizeof(scsipi_sense) - sizeof(pages->rigid_geometry))
		return ERESTART;

	pages = (void *)((u_long)&scsipi_sense + poffset);
#if 0
	{
		size_t i;
		u_int8_t *p;

		printf("page 4 sense:");
		for (i = sizeof(scsipi_sense), p = (void *)&scsipi_sense; i;
		    i--, p++)
			printf(" %02x", *p);
		printf("\n");
		printf("page 4 pg_code=%d sense=%p/%p\n",
		    pages->rigid_geometry.pg_code, &scsipi_sense, pages);
	}
#endif

	if ((pages->rigid_geometry.pg_code & PGCODE_MASK) != 4)
		return ERESTART;

	/*
	 * KLUDGE!! (for zone recorded disks)
	 * give a number of sectors so that sec * trks * cyls
	 * is <= disk_size
	 * can lead to wasted space! THINK ABOUT THIS !
	 */
	dp->heads = pages->rigid_geometry.nheads;
	dp->cyls = _3btol(pages->rigid_geometry.ncyl);
	if (dp->heads == 0 || dp->cyls == 0)
		return ERESTART;
	dp->sectors = dp->disksize / (dp->heads * dp->cyls);	/* XXX */

	dp->rot_rate = _2btol(pages->rigid_geometry.rpm);
	if (dp->rot_rate == 0)
		dp->rot_rate = 3600;

#if 0
printf("page 4 ok\n");
#endif
	return 0;
}
Exemple #8
0
/*
 * Get the scsi driver to send a full inquiry to the * device and use the
 * results to fill out the disk parameter structure.
 */
static int
sd_get_capacity(struct sd_softc *sd)
{
	struct disk_parms *dp = &sd->sc_params;
	uint64_t blocks;
	int error, blksize;

	dp->disksize = blocks = sd_read_capacity(sd, &blksize);
	if (blocks == 0) {
		struct scsipi_read_format_capacities cmd;
		struct {
			struct scsipi_capacity_list_header header;
			struct scsipi_capacity_descriptor desc;
		} __packed data;

		memset(&cmd, 0, sizeof(cmd));
		memset(&data, 0, sizeof(data));
		cmd.opcode = READ_FORMAT_CAPACITIES;
		_lto2b(sizeof(data), cmd.length);

		error = scsi_command(sd,
		    (void *)&cmd, sizeof(cmd), (void *)&data, sizeof(data));
		if (error == EFTYPE)
			/* Medium Format Corrupted, handle as not formatted */
			return SDGP_RESULT_UNFORMATTED;
		if (error || data.header.length == 0)
			return SDGP_RESULT_OFFLINE;

		switch (data.desc.byte5 & SCSIPI_CAP_DESC_CODE_MASK) {
		case SCSIPI_CAP_DESC_CODE_RESERVED:
		case SCSIPI_CAP_DESC_CODE_FORMATTED:
			break;

		case SCSIPI_CAP_DESC_CODE_UNFORMATTED:
			return SDGP_RESULT_UNFORMATTED;

		case SCSIPI_CAP_DESC_CODE_NONE:
			return SDGP_RESULT_OFFLINE;
		}

		dp->disksize = blocks = _4btol(data.desc.nblks);
		if (blocks == 0)
			return SDGP_RESULT_OFFLINE;		/* XXX? */

		blksize = _3btol(data.desc.blklen);

	} else if (!sd_validate_blksize(blksize)) {
		struct sd_mode_sense_data scsipi_sense;
		int bsize;

		memset(&scsipi_sense, 0, sizeof(scsipi_sense));
		error = scsi_mode_sense(sd, 0, 0, &scsipi_sense.header,
		    sizeof(struct scsi_mode_parameter_header_6) +
						sizeof(scsipi_sense.blk_desc));
		if (!error) {
			bsize = scsipi_sense.header.blk_desc_len;

			if (bsize >= 8)
				blksize = _3btol(scsipi_sense.blk_desc.blklen);
		}
	}

	if (!sd_validate_blksize(blksize))
		blksize = SD_DEFAULT_BLKSIZE;

	dp->blksize = blksize;
	dp->disksize512 = (blocks * dp->blksize) / DEV_BSIZE;
	return 0;
}
Exemple #9
0
/*ARGSUSED*/
scsi_ret_t
scdisk_open(
	target_info_t		*tgt,
	io_req_t	        req)
{
	register int 	i;
	register scsi_ret_t	ret = SCSI_RET_SUCCESS;
	unsigned int		disk_size, secs_per_cyl, sector_size;
	unsigned int		nsectors, ntracks, ncylinders;
	scsi_rcap_data_t	*cap;
	struct disklabel	*label = 0;
	io_req_t		ior;
	void			(*readfun)(
					target_info_t	*tgt,
					unsigned int	secno,
					io_req_t	ior) = scdisk_read;
	char			*data, *rdata = 0;
	boolean_t		look_for_label;

	if (tgt->flags & TGT_ONLINE)
		return SCSI_RET_SUCCESS;

	tgt->lun = rzlun(req->io_unit);

	/*
	 * Dummy ior for proper sync purposes
	 */
	io_req_alloc(ior);
	bzero((char *)ior, sizeof(*ior));
	simple_lock_init(&(ior)->io_req_lock, ETAP_IO_REQ);

#if 0
	/*
	 * Set the LBN to tgt->block_size with a MODE SELECT.
	 * xxx do a MODE SENSE instead ?
	 */
	/*
	 * Ugh.  Can't use tgt->block_size here -- not set up
	 * yet.  Also can't use DEV_BSIZE.  So...since MK6
	 * dispenses with this command entirely, let's do
	 * so as well.
	 */
	for (i = 0; i < 5; i++) {
		ior->io_op = IO_INTERNAL;
		ior->io_error = 0;
		ret = scdisk_mode_select(tgt, tgt->block_size, ior,0,0,FALSE);
		if (ret == SCSI_RET_SUCCESS)
			break;
		if (ret == SCSI_RET_RETRY) {
			timeout((timeout_fcn_t)wakeup, tgt, 2*hz);
			await(tgt);
		}
		if (ret == SCSI_RET_DEVICE_DOWN)
			goto done;
	}
	if (ret != SCSI_RET_SUCCESS) {
		scsi_error( tgt, SCSI_ERR_MSEL, ret, 0);
		ret = D_INVALID_SIZE;
		goto done;
	}
#endif

#ifdef hp_pa
	if (tgt->flags & TGT_REMOVABLE_MEDIA) {
		scsi_mode_sense_page5_t	*page5;
		unsigned char           mode_save[0xff];
		scsi_mode_select_param_t *parm;
		int length;

		if((ret = scsi_mode_sense(tgt, 0x05, 0xff, 0))
		   != SCSI_RET_SUCCESS) 
			goto done;

		length = *tgt->cmd_ptr + 1;
		bcopy(tgt->cmd_ptr, mode_save, length);

		page5 = (scsi_mode_sense_page5_t *)(mode_save + 4 + mode_save[3]);
#if 1 
		/* force sector size to 512 */
		parm = (scsi_mode_select_param_t *)mode_save;

		parm->reserved1 = 0;
		parm->medium_type = 2;
		parm->device_spec &= ~0x90;
			
		parm->descs[0].density_code = 2; 
		parm->descs[0].nblocks1 = 0;
		parm->descs[0].nblocks2 = 0;
		parm->descs[0].nblocks3 = 0;
		parm->descs[0].reclen1 = 0x2;
		parm->descs[0].reclen2 = 0;
		parm->descs[0].reclen3 = 0;

		page5->ps = 0;
		page5->page_code &= ~0x80;
		
		page5->sectors_per_track = page5->sectors_per_track * 
			(page5->bytes_per_sector_msb << 8 |
			 page5->bytes_per_sector_lsb) /
				 512;
		
		page5->bytes_per_sector_msb = 2;
		page5->bytes_per_sector_lsb = 0;
			
		length -= parm->desc_len;
		parm->desc_len = 0;
		bcopy((const char*)page5, mode_save+4, sizeof(*page5));
		
		if((ret = scdisk_mode_select(tgt, 0, 0, mode_save, length, 0)) 
		   != SCSI_RET_SUCCESS) 
			goto done;

		if((ret = scsi_mode_sense(tgt, 0x05, 0xff, 0))
		   != SCSI_RET_SUCCESS) 
			goto done;

		length = *tgt->cmd_ptr + 1;
		bcopy(tgt->cmd_ptr, mode_save, length);
#endif

		ntracks      = page5->number_of_heads;
		nsectors     = page5->sectors_per_track;
		sector_size  = page5->bytes_per_sector_msb << 8 |
			page5->bytes_per_sector_lsb;
		ncylinders   = page5->number_of_cylinders_msb << 8 |
			page5->number_of_cylinders_lsb;
		secs_per_cyl = nsectors * ntracks;

		look_for_label = FALSE;
		geom_done = TRUE;
	}
#endif

	/*
	 * Do a READ CAPACITY to get max size. Check LBN too.
	 */
	for (i = 0; i < 5; i++) {
		ior->io_op = IO_INTERNAL;
		ior->io_error = 0;
		ret = scsi_read_capacity(tgt, 0, ior);
		if (ret == SCSI_RET_SUCCESS)
			break;
		if (ret == SCSI_RET_RETRY) {
			timeout((timeout_fcn_t)wakeup, tgt, 2*hz);
			await(tgt);
		}
		if (ret == SCSI_RET_DEVICE_DOWN)
			goto done;
	}
	if (ret != SCSI_RET_SUCCESS) {
		scsi_error( tgt, SCSI_ERR_MSEL, ret, 0);
		ret = D_INVALID_SIZE;
		goto done;
	}

	cap = (scsi_rcap_data_t*) tgt->cmd_ptr;
	disk_size = (cap->lba1<<24) |
	  	    (cap->lba2<<16) |
		    (cap->lba3<< 8) |
		     cap->lba4 + 1;
	if (scsi_debug)
		printf("rz%d holds %d blocks\n", tgt->unit_no, disk_size);

	tgt->block_size = (cap->blen1<<24) |
	  		  (cap->blen2<<16) |
	    		  (cap->blen3<<8 ) |
			   cap->blen4;

	if (scsi_debug) {
		printf("rz%d block size is %d bytes/block\n",
			       tgt->unit_no, tgt->block_size);
	}

	if (tgt->block_size > RZDISK_MAX_SECTOR || tgt->block_size <= 0) {
	 	 ret = D_INVALID_SIZE;
	  	goto done;
       	}

        rdata = (char *) kalloc(2*tgt->block_size);
	if (round_page(rdata) == round_page(rdata + tgt->block_size))
	    data = rdata;
	else
	    data = (char *)round_page(rdata);
#ifdef POWERMAC
	/* XXX TODO NMGS remove! must be cache aligned for now */
	if ((unsigned long)data & 0x1f)
		data = (char*)((unsigned long)(data + 0x1f) & ~0x1f);
	if (round_page(data) != round_page(data + tgt->block_size))
		data = (char *)round_page(data);
#endif /* POWERMAC */

	if (disk_size > SCSI_CMD_READ_MAX_LBA)
		tgt->flags |= TGT_BIG;

	/*
	 * Mandatory long-form commands ?
	 */
	if (BGET(scsi_use_long_form,(unsigned char)tgt->masterno,tgt->target_id))
		tgt->flags |= TGT_BIG;
	if (tgt->flags & TGT_BIG)
		readfun = scsi_long_read;

	ior->io_op = IO_INTERNAL;
	ior->io_error = 0;

#ifdef hp_pa
	if(geom_done)
		goto setup_label;
#endif

	/*
	 * Find out about the phys disk geometry
	 */

#if	PARAGON860

	/*
	 * The NCR RAID controller does not support a read capacity command
	 * with the Partial Medium Indicator (PMI) bit set.  Therefore we
	 * have to calculate the number of sectors per cylinder from data
	 * in the mode select pages.  This method should work for standalone
	 * disks as well.
	 */

	/*
	 * Read page 3 to find the number of sectors/track and bytes/sector
	 */
	ret = scsi_mode_sense(tgt, 0x03, 0xff, ior);
	/* scsi_error(...) */
	{
		scsi_mode_sense_page3_t	*page3;

		page3 = (scsi_mode_sense_page3_t *)
			(((scsi_mode_sense_data_t *)tgt->cmd_ptr) + 1);

		nsectors    = (page3->sectors_per_track_msb << 8) |
			       page3->sectors_per_track_lsb;

		sector_size = (page3->bytes_per_sector_msb  << 8) |
			       page3->bytes_per_sector_lsb;
	}

	ior->io_op = IO_INTERNAL;
	ior->io_error = 0;

	/*
	 * Read page 4 to find the number of cylinders and tracks/cylinder
	 */
	ret = scsi_mode_sense(tgt, 0x04, 0xff, ior);
	/* scsi_error(...) */
	{
		scsi_mode_sense_page4_t	*page4;

		page4 = (scsi_mode_sense_page4_t *)
			(((scsi_mode_sense_data_t *)tgt->cmd_ptr) + 1);

		ncylinders = (page4->number_of_cylinders_msb << 16) |
			     (page4->number_of_cylinders     <<  8) |
			      page4->number_of_cylinders_lsb;

		ntracks    = page4->number_of_heads;
	}

	/*
	 * Calculate the sectors per cylinder (sec/track * tracks/cyl)
	 */
	secs_per_cyl = nsectors * ntracks;

	if (scsi_debug) {
		printf("rz%d: %d bytes/sec %d sec/track\n", tgt->unit_no,
			sector_size, nsectors);
		printf("     %d tracks/cyl %d cyl/unit\n",
			ntracks, ncylinders);
	}

#else	/* PARAGON860 */
       /* Read page one to get read / write error recovery info */
       ret = scsi_mode_sense(tgt, 0x01, 0xff, ior);
       if(ret == SCSI_RET_SUCCESS) {
               scsi_mode_sense_page1_t *page1;
               unsigned char           mode_save[0xff];
               int length;

               length = *tgt->cmd_ptr + 1;
               bcopy(tgt->cmd_ptr, mode_save, length);

               page1 = (scsi_mode_sense_page1_t *)(mode_save + 4 + mode_save[3]);

               *mode_save = 0;         /* mode data length */
               page1->ps       = 0;
               page1->flags    = PAGE1_AWRE | PAGE1_ARRE | PAGE1_TB | PAGE1_PER;

               /*
                * Enable automatic reallocation of bad blocks,
                * Report any recovered errors.
                */
               ior->io_op = IO_INTERNAL;
               ior->io_error = 0;
               ret = scdisk_mode_select(tgt, 0, ior, mode_save, length, 0);
               if(ret != SCSI_RET_SUCCESS) {
		       if (scsi_debug)
                       printf("rz%d: Can't change error recovery parameters\n",
                                tgt->unit_no);
	       }
       }

       ior->io_op = IO_INTERNAL;
       ior->io_error = 0;

#ifdef	POWERMAC
	tgt->flags |= TGT_OPTIONAL_CMD;
#endif
		
	ret = scsi_read_capacity( tgt, 1, ior);
#ifdef POWERMAC
	tgt->flags &= ~TGT_OPTIONAL_CMD;
#endif
	/* scsi_error(...) */
	if (ret) {
		secs_per_cyl = 16;
		sector_size = tgt->block_size;
	} else {
		cap = (scsi_rcap_data_t*) tgt->cmd_ptr;
		secs_per_cyl =	(cap->lba1<<24) | (cap->lba2<<16) |
				(cap->lba3<< 8) |  cap->lba4;
		secs_per_cyl += 1;
		sector_size =	(cap->blen1<<24) | (cap->blen2<<16) |
			(cap->blen3<<8 ) |  cap->blen4;
	}
	if (scsi_debug)
	printf("rz%d: %d sect/cyl %d bytes/sec\n", tgt->unit_no,
		secs_per_cyl, sector_size);
#endif	/* PARAGON860 */

#if	NSCSI2 > 0
	/*
	 * ... and a bunch of other things for scsi2
	 */
#endif	/* NSCSI2 > 0 */

	/*
	 * Get partition table off pack
	 */

	if (tgt->dev_ops == &scsi_devsw[SCSI_CDROM]) {
		/* no label on a CD-ROM */
		look_for_label = FALSE;
	} else {
		look_for_label = TRUE;
	}

 setup_label:


	if (look_for_label) {
		/* first look for a BSD label */	
		ior->io_data = data;
		ior->io_count = tgt->block_size;
		ior->io_op = IO_READ;
		ior->io_error = 0;
		tgt->ior = ior;
		(*readfun)( tgt, LABELOFFSET/tgt->block_size, ior);
		iowait(ior);

		if (!ior->io_error) {
			/* Search for BSD label, might be a bit further along */
			register int	j;

			for (i = LABELOFFSET % tgt->block_size;
			     i < (tgt->block_size-sizeof(struct disklabel));
			     i += sizeof(int)) {
				label = (struct disklabel *) &data[i];
				if (label->d_magic  == DISKMAGIC &&
				    label->d_magic2 == DISKMAGIC) {
					break;
				} else
					label = (struct disklabel *) 0;
			}
		}
	} else {
		label = (struct disklabel *) 0;
	}

	if (label) {
		if (scsi_debug)
			printf("{Using BSD label}");
		tgt->dev_info.disk.l = *label;
	} else {
		/* then look for a vendor's label, but first
		   fill in defaults and what we found */

		label = &tgt->dev_info.disk.l;
		*label = scsi_default_label;
		label->d_secsize    = sector_size;
		label->d_nsectors   = nsectors;
		label->d_ntracks    = ntracks;
		label->d_ncylinders = ncylinders;
		label->d_secpercyl  = secs_per_cyl;
		label->d_secperunit = disk_size;

		ior->io_data = data;
		if (!look_for_label || !rz_vendor_label(tgt, label, ior)) {

			if (look_for_label) {
				printf("%s rz%d, %s\n",
				       "WARNING: No valid disk label on",
				       tgt->unit_no,
				       "using defaults");
			}

			/* Validate partitions a and c for initialization */
			tgt->dev_info.disk.l.d_partitions[0].p_offset = 0;
			tgt->dev_info.disk.l.d_partitions[0].p_size   = disk_size;
			tgt->dev_info.disk.l.d_partitions[2].p_offset = 0;
			tgt->dev_info.disk.l.d_partitions[2].p_size   = disk_size;
			tgt->dev_info.disk.l.d_partitions[MAXPARTITIONS].p_offset = 0;
			tgt->dev_info.disk.l.d_partitions[MAXPARTITIONS].p_size   = -1;
		}
		label->d_checksum = 0;
		label->d_checksum = dkcksum(label);
	}

	ret = SCSI_RET_SUCCESS;
done:
        if (rdata)
                kfree((vm_offset_t) rdata, 2 * tgt->block_size);
	io_req_free(ior);
	return ret;
}
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();
        }
    }
}