Ejemplo n.º 1
0
void
fnvlist_add_int8(nvlist_t *nvl, const char *name, int8_t val)
{
	VERIFY0(nvlist_add_int8(nvl, name, val));
}
Ejemplo n.º 2
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);
}