void fnvlist_add_int8(nvlist_t *nvl, const char *name, int8_t val) { VERIFY0(nvlist_add_int8(nvl, name, val)); }
/* * 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); }