17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5f01c928dSlh195018 * Common Development and Distribution License (the "License").
6f01c928dSlh195018 * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
21936b7af6Sjw149990
227c478bd9Sstevel@tonic-gate /*
2399025f2eSsrivijitha dugganapalli * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
247c478bd9Sstevel@tonic-gate * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate */
26936b7af6Sjw149990
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate * These functions are used to encode SCSI INQUIRY data into
297c478bd9Sstevel@tonic-gate * Solaris devid / guid values.
307c478bd9Sstevel@tonic-gate */
317c478bd9Sstevel@tonic-gate
32ed141cfcSsrivijitha dugganapalli #ifndef _KERNEL
33ed141cfcSsrivijitha dugganapalli #include <stdio.h>
34ed141cfcSsrivijitha dugganapalli #endif /* _KERNEL */
35ed141cfcSsrivijitha dugganapalli
36ed141cfcSsrivijitha dugganapalli #include <sys/inttypes.h>
377c478bd9Sstevel@tonic-gate #include <sys/types.h>
387c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
397c478bd9Sstevel@tonic-gate #include <sys/debug.h>
407c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h>
417c478bd9Sstevel@tonic-gate #include <sys/dditypes.h>
427c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
437c478bd9Sstevel@tonic-gate #include <sys/scsi/scsi.h>
444c06356bSdh142964 #ifndef _KERNEL
454c06356bSdh142964 #include <sys/libdevid.h>
464c06356bSdh142964 #endif /* !_KERNEL */
477c478bd9Sstevel@tonic-gate #include "devid_impl.h"
487c478bd9Sstevel@tonic-gate
497c478bd9Sstevel@tonic-gate #define SCSI_INQUIRY_VID_POS 9
507c478bd9Sstevel@tonic-gate #define SCSI_INQUIRY_VID_SUN "SUN"
517c478bd9Sstevel@tonic-gate #define SCSI_INQUIRY_VID_SUN_LEN 3
52f01c928dSlh195018 #define SCSI_INQUIRY_VID_HITACHI "HITACHI"
53f01c928dSlh195018 #define SCSI_INQUIRY_VID_HITACHI_LEN 7
54f01c928dSlh195018 #define SCSI_INQUIRY_PID_HITACHI_OPEN "OPEN-"
55f01c928dSlh195018 #define SCSI_INQUIRY_PID_HITACHI_OPEN_LEN 5
567c478bd9Sstevel@tonic-gate #define SCSI_INQUIRY_VID_EMC "EMC "
577c478bd9Sstevel@tonic-gate #define SCSI_INQUIRY_VID_EMC_LEN 8
587c478bd9Sstevel@tonic-gate #define SCSI_INQUIRY_PID_EMC_SYMMETRIX "SYMMETRIX "
597c478bd9Sstevel@tonic-gate #define SCSI_INQUIRY_PID_EMC_SYMMETRIX_LEN 16
607c478bd9Sstevel@tonic-gate
617c478bd9Sstevel@tonic-gate #define MSG_NOT_STANDARDS_COMPLIANT "!Page83 data not standards compliant "
627c478bd9Sstevel@tonic-gate #define MSG_NOT_STANDARDS_COMPLIANT_SIZE ( \
637c478bd9Sstevel@tonic-gate sizeof (MSG_NOT_STANDARDS_COMPLIANT) + \
647c478bd9Sstevel@tonic-gate sizeof (((struct scsi_inquiry *)NULL)->inq_vid) + \
657c478bd9Sstevel@tonic-gate sizeof (((struct scsi_inquiry *)NULL)->inq_pid) + \
667c478bd9Sstevel@tonic-gate sizeof (((struct scsi_inquiry *)NULL)->inq_revision) + 4)
677c478bd9Sstevel@tonic-gate
687c478bd9Sstevel@tonic-gate #define IS_DEVID_GUID_TYPE(type) ((type == DEVID_SCSI3_WWN) || \
697c478bd9Sstevel@tonic-gate (IS_DEVID_SCSI3_VPD_TYPE(type)))
707c478bd9Sstevel@tonic-gate
717c478bd9Sstevel@tonic-gate #define IS_DEVID_SCSI_TYPE(type) ((IS_DEVID_GUID_TYPE(type)) || \
727c478bd9Sstevel@tonic-gate (type == DEVID_SCSI_SERIAL))
737c478bd9Sstevel@tonic-gate
747c478bd9Sstevel@tonic-gate /*
757c478bd9Sstevel@tonic-gate * The max inquiry page 83 size as expected in the code today
767c478bd9Sstevel@tonic-gate * is 0xf0 bytes. Defining a constant to make it easy incase
777c478bd9Sstevel@tonic-gate * this needs to be changed at a later time.
787c478bd9Sstevel@tonic-gate */
797c478bd9Sstevel@tonic-gate
807c478bd9Sstevel@tonic-gate #define SCMD_MAX_INQUIRY_PAGE83_SIZE 0xFF
817c478bd9Sstevel@tonic-gate #define SCMD_MIN_INQUIRY_PAGE83_SIZE 0x08
827c478bd9Sstevel@tonic-gate #define SCMD_INQUIRY_PAGE83_HDR_SIZE 4
837c478bd9Sstevel@tonic-gate #define SCSI_INQUIRY_PAGE83_EMC_SYMMETRIX_ID_LEN 16
847c478bd9Sstevel@tonic-gate
857c478bd9Sstevel@tonic-gate #define SCMD_MAX_INQUIRY_PAGE80_SIZE 0xFF
867c478bd9Sstevel@tonic-gate #define SCMD_MIN_INQUIRY_PAGE80_SIZE 0x04
877c478bd9Sstevel@tonic-gate
887c478bd9Sstevel@tonic-gate #define SCMD_MIN_STANDARD_INQUIRY_SIZE 0x04
897c478bd9Sstevel@tonic-gate
907c478bd9Sstevel@tonic-gate #define SCMD_INQUIRY_PAGE83_IDENT_DESC_HDR_SIZE 4
917c478bd9Sstevel@tonic-gate
927c478bd9Sstevel@tonic-gate #define SCMD_INQUIRY_VPD_TYPE_T10 0x01
937c478bd9Sstevel@tonic-gate #define SCMD_INQUIRY_VPD_TYPE_EUI 0x02
947c478bd9Sstevel@tonic-gate #define SCMD_INQUIRY_VPD_TYPE_NAA 0x03
957c478bd9Sstevel@tonic-gate #define SCMD_INQUIRY_VPD_TYPE_RTP 0x04
967c478bd9Sstevel@tonic-gate #define SCMD_INQUIRY_VPD_TYPE_TPG 0x05
977c478bd9Sstevel@tonic-gate #define SCMD_INQUIRY_VPD_TYPE_LUG 0x06
987c478bd9Sstevel@tonic-gate #define SCMD_INQUIRY_VPD_TYPE_MD5 0x07
997c478bd9Sstevel@tonic-gate #define SCMD_INQUIRY_VPD_TYPE_SSN 0x08
1007c478bd9Sstevel@tonic-gate
1017c478bd9Sstevel@tonic-gate static int is_page83_data_valid(uchar_t *inq83, size_t inq83_len);
1027c478bd9Sstevel@tonic-gate static int is_page80_data_valid(uchar_t *inq80, size_t inq80_len);
1037c478bd9Sstevel@tonic-gate static int is_initialized_id(uchar_t *id, size_t id_len);
1047c478bd9Sstevel@tonic-gate
1057c478bd9Sstevel@tonic-gate static void encode_scsi3_page83(int version, uchar_t *inq83,
1067c478bd9Sstevel@tonic-gate size_t inq83_len, uchar_t **id, size_t *id_len, ushort_t *id_type);
1077c478bd9Sstevel@tonic-gate static void encode_scsi3_page83_emc(int version, uchar_t *inq83,
1087c478bd9Sstevel@tonic-gate size_t inq83_len, uchar_t **id, size_t *id_len, ushort_t *id_type);
1097c478bd9Sstevel@tonic-gate static void encode_serialnum(int version, uchar_t *inq, uchar_t *inq80,
1107c478bd9Sstevel@tonic-gate size_t inq80_len, uchar_t **id, size_t *id_len, ushort_t *id_type);
1117c478bd9Sstevel@tonic-gate static void encode_sun_serialnum(int version, uchar_t *inq,
1127c478bd9Sstevel@tonic-gate size_t inq_len, uchar_t **id, size_t *id_len, ushort_t *id_type);
1137c478bd9Sstevel@tonic-gate
1147c478bd9Sstevel@tonic-gate static int devid_scsi_init(char *driver_name,
1157c478bd9Sstevel@tonic-gate uchar_t *raw_id, size_t raw_id_len, ushort_t raw_id_type,
1167c478bd9Sstevel@tonic-gate ddi_devid_t *ret_devid);
1177c478bd9Sstevel@tonic-gate
118936b7af6Sjw149990 static char ctoi(char c);
119936b7af6Sjw149990
1207c478bd9Sstevel@tonic-gate /*
1217c478bd9Sstevel@tonic-gate * Function: ddi_/devid_scsi_encode
1227c478bd9Sstevel@tonic-gate *
1237c478bd9Sstevel@tonic-gate * Description: This routine finds and encodes a unique devid
1247c478bd9Sstevel@tonic-gate *
1257c478bd9Sstevel@tonic-gate * Arguments: version - id encode algorithm version
1267c478bd9Sstevel@tonic-gate * driver_name - binding driver name (if ! known use NULL)
1277c478bd9Sstevel@tonic-gate * inq - standard inquiry buffer
1287c478bd9Sstevel@tonic-gate * inq_len - standard inquiry buffer length
1297c478bd9Sstevel@tonic-gate * inq80 - serial number inquiry buffer
1307c478bd9Sstevel@tonic-gate * inq80_len - serial number inquiry buffer length
1317c478bd9Sstevel@tonic-gate * inq83 - vpd inquiry buffer
1327c478bd9Sstevel@tonic-gate * inq83_len - vpd inquiry buffer length
1337c478bd9Sstevel@tonic-gate * devid - id returned
1347c478bd9Sstevel@tonic-gate *
1357c478bd9Sstevel@tonic-gate * Return Code: DEVID_SUCCESS - success
1367c478bd9Sstevel@tonic-gate * DEVID_FAILURE - failure
1377c478bd9Sstevel@tonic-gate * DEVID_RETRY - LUN is in a transitional state. A delay should
1387c478bd9Sstevel@tonic-gate * occur and then this inquiry data should be re-acquired and
1397c478bd9Sstevel@tonic-gate * this function should be called again.
1407c478bd9Sstevel@tonic-gate */
1417c478bd9Sstevel@tonic-gate int
1427c478bd9Sstevel@tonic-gate #ifdef _KERNEL
ddi_devid_scsi_encode(int version,char * driver_name,uchar_t * inq,size_t inq_len,uchar_t * inq80,size_t inq80_len,uchar_t * inq83,size_t inq83_len,ddi_devid_t * devid)1437c478bd9Sstevel@tonic-gate ddi_devid_scsi_encode(
1447c478bd9Sstevel@tonic-gate #else /* ! _KERNEL */
1457c478bd9Sstevel@tonic-gate devid_scsi_encode(
1467c478bd9Sstevel@tonic-gate #endif /* _KERNEL */
1477c478bd9Sstevel@tonic-gate int version, /* IN */
1487c478bd9Sstevel@tonic-gate char *driver_name, /* IN */
1497c478bd9Sstevel@tonic-gate uchar_t *inq, /* IN */
1507c478bd9Sstevel@tonic-gate size_t inq_len, /* IN */
1517c478bd9Sstevel@tonic-gate uchar_t *inq80, /* IN */
1527c478bd9Sstevel@tonic-gate size_t inq80_len, /* IN */
1537c478bd9Sstevel@tonic-gate uchar_t *inq83, /* IN */
1547c478bd9Sstevel@tonic-gate size_t inq83_len, /* IN */
1557c478bd9Sstevel@tonic-gate ddi_devid_t *devid) /* OUT */
1567c478bd9Sstevel@tonic-gate {
1577c478bd9Sstevel@tonic-gate int rval = DEVID_FAILURE;
1587c478bd9Sstevel@tonic-gate uchar_t *id = NULL;
1597c478bd9Sstevel@tonic-gate size_t id_len = 0;
1607c478bd9Sstevel@tonic-gate ushort_t id_type = DEVID_NONE;
1617c478bd9Sstevel@tonic-gate struct scsi_inquiry *inq_std = (struct scsi_inquiry *)inq;
1627c478bd9Sstevel@tonic-gate #ifdef _KERNEL
1637c478bd9Sstevel@tonic-gate char *msg = NULL;
1647c478bd9Sstevel@tonic-gate #endif /* _KERNEL */
1657c478bd9Sstevel@tonic-gate
1667c478bd9Sstevel@tonic-gate DEVID_ASSERT(devid != NULL);
1677c478bd9Sstevel@tonic-gate
1687c478bd9Sstevel@tonic-gate /* verify valid version */
1697c478bd9Sstevel@tonic-gate if (version > DEVID_SCSI_ENCODE_VERSION_LATEST) {
1707c478bd9Sstevel@tonic-gate return (rval);
1717c478bd9Sstevel@tonic-gate }
1727c478bd9Sstevel@tonic-gate
1737c478bd9Sstevel@tonic-gate /* make sure minimum inquiry bytes are available */
1747c478bd9Sstevel@tonic-gate if (inq_len < SCMD_MIN_STANDARD_INQUIRY_SIZE) {
1757c478bd9Sstevel@tonic-gate return (rval);
1767c478bd9Sstevel@tonic-gate }
1777c478bd9Sstevel@tonic-gate
1787c478bd9Sstevel@tonic-gate /*
1797c478bd9Sstevel@tonic-gate * If 0x83 is availible, that is the best choice. Our next choice is
1807c478bd9Sstevel@tonic-gate * 0x80. If neither are availible, we leave it to the caller to
1817c478bd9Sstevel@tonic-gate * determine possible alternate ID, although discouraged. In the
1827c478bd9Sstevel@tonic-gate * case of the target drivers they create a fabricated id which is
1837c478bd9Sstevel@tonic-gate * stored in the acyl. The HBA drivers should avoid using an
1847c478bd9Sstevel@tonic-gate * alternate id. Although has already created a hack of using the
1857c478bd9Sstevel@tonic-gate * node wwn in some cases. Which needs to be carried forward for
1867c478bd9Sstevel@tonic-gate * legacy reasons.
1877c478bd9Sstevel@tonic-gate */
1887c478bd9Sstevel@tonic-gate if (inq83 != NULL) {
1897c478bd9Sstevel@tonic-gate /*
1907c478bd9Sstevel@tonic-gate * Perform page 83 validation tests and report offenders.
1917c478bd9Sstevel@tonic-gate * We cannot enforce the page 83 specification because
1927c478bd9Sstevel@tonic-gate * many Sun partners (ex. HDS) do not conform to the
1937c478bd9Sstevel@tonic-gate * standards yet.
1947c478bd9Sstevel@tonic-gate */
1957c478bd9Sstevel@tonic-gate if (is_page83_data_valid(inq83, inq83_len) ==
1967c478bd9Sstevel@tonic-gate DEVID_RET_INVALID) {
1977c478bd9Sstevel@tonic-gate /*
1987c478bd9Sstevel@tonic-gate * invalid page 83 data. bug 4939576 introduced
1997c478bd9Sstevel@tonic-gate * handling for EMC non-standard data.
2007c478bd9Sstevel@tonic-gate */
2017c478bd9Sstevel@tonic-gate if ((bcmp(inq_std->inq_vid, SCSI_INQUIRY_VID_EMC,
2027c478bd9Sstevel@tonic-gate SCSI_INQUIRY_VID_EMC_LEN) == 0) &&
2037c478bd9Sstevel@tonic-gate (bcmp(inq_std->inq_pid,
2047c478bd9Sstevel@tonic-gate SCSI_INQUIRY_PID_EMC_SYMMETRIX,
2057c478bd9Sstevel@tonic-gate SCSI_INQUIRY_PID_EMC_SYMMETRIX_LEN) == 0)) {
2067c478bd9Sstevel@tonic-gate encode_scsi3_page83_emc(version, inq83,
2077c478bd9Sstevel@tonic-gate inq83_len, &id, &id_len, &id_type);
2087c478bd9Sstevel@tonic-gate }
2097c478bd9Sstevel@tonic-gate #ifdef _KERNEL
2107c478bd9Sstevel@tonic-gate /*
211f01c928dSlh195018 * invalid page 83 data. Special hack for HDS
212f01c928dSlh195018 * specific device, to suppress the warning msg.
213f01c928dSlh195018 */
214f01c928dSlh195018 if ((bcmp(inq_std->inq_vid, SCSI_INQUIRY_VID_HITACHI,
215f01c928dSlh195018 SCSI_INQUIRY_VID_HITACHI_LEN) != 0) ||
216f01c928dSlh195018 (bcmp(inq_std->inq_pid,
217f01c928dSlh195018 SCSI_INQUIRY_PID_HITACHI_OPEN,
218f01c928dSlh195018 SCSI_INQUIRY_PID_HITACHI_OPEN_LEN) != 0)) {
219f01c928dSlh195018 /*
2207c478bd9Sstevel@tonic-gate * report the page 0x83 standards violation.
2217c478bd9Sstevel@tonic-gate */
222f01c928dSlh195018 msg = kmem_alloc(
223f01c928dSlh195018 MSG_NOT_STANDARDS_COMPLIANT_SIZE,
2247c478bd9Sstevel@tonic-gate KM_SLEEP);
2257c478bd9Sstevel@tonic-gate (void) strcpy(msg, MSG_NOT_STANDARDS_COMPLIANT);
2267c478bd9Sstevel@tonic-gate (void) strncat(msg, inq_std->inq_vid,
2277c478bd9Sstevel@tonic-gate sizeof (inq_std->inq_vid));
2287c478bd9Sstevel@tonic-gate (void) strcat(msg, " ");
2297c478bd9Sstevel@tonic-gate (void) strncat(msg, inq_std->inq_pid,
2307c478bd9Sstevel@tonic-gate sizeof (inq_std->inq_pid));
2317c478bd9Sstevel@tonic-gate (void) strcat(msg, " ");
2327c478bd9Sstevel@tonic-gate (void) strncat(msg, inq_std->inq_revision,
2337c478bd9Sstevel@tonic-gate sizeof (inq_std->inq_revision));
2347c478bd9Sstevel@tonic-gate (void) strcat(msg, "\n");
2357c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, msg);
236f01c928dSlh195018 kmem_free(msg,
237f01c928dSlh195018 MSG_NOT_STANDARDS_COMPLIANT_SIZE);
238f01c928dSlh195018 }
2397c478bd9Sstevel@tonic-gate #endif /* _KERNEL */
2407c478bd9Sstevel@tonic-gate }
2417c478bd9Sstevel@tonic-gate
2427c478bd9Sstevel@tonic-gate if (id_type == DEVID_NONE) {
2437c478bd9Sstevel@tonic-gate encode_scsi3_page83(version, inq83,
2447c478bd9Sstevel@tonic-gate inq83_len, &id, &id_len, &id_type);
2457c478bd9Sstevel@tonic-gate }
2467c478bd9Sstevel@tonic-gate }
2477c478bd9Sstevel@tonic-gate
2487c478bd9Sstevel@tonic-gate /*
2497c478bd9Sstevel@tonic-gate * If no vpd page is available at this point then we
2507c478bd9Sstevel@tonic-gate * attempt to use a SCSI serial number from page 0x80.
2517c478bd9Sstevel@tonic-gate */
2527c478bd9Sstevel@tonic-gate if ((id_type == DEVID_NONE) &&
2537c478bd9Sstevel@tonic-gate (inq != NULL) &&
2547c478bd9Sstevel@tonic-gate (inq80 != NULL)) {
2557c478bd9Sstevel@tonic-gate if (is_page80_data_valid(inq80, inq80_len) == DEVID_RET_VALID) {
2567c478bd9Sstevel@tonic-gate encode_serialnum(version, inq, inq80,
2577c478bd9Sstevel@tonic-gate inq80_len, &id, &id_len, &id_type);
2587c478bd9Sstevel@tonic-gate }
2597c478bd9Sstevel@tonic-gate }
2607c478bd9Sstevel@tonic-gate
2617c478bd9Sstevel@tonic-gate /*
2627c478bd9Sstevel@tonic-gate * If no vpd page or serial is available at this point and
2637c478bd9Sstevel@tonic-gate * it's a SUN disk it conforms to the disk qual. 850 specifications
2647c478bd9Sstevel@tonic-gate * and we can fabricate a serial number id based on the standard
2657c478bd9Sstevel@tonic-gate * inquiry page.
2667c478bd9Sstevel@tonic-gate */
2677c478bd9Sstevel@tonic-gate if ((id_type == DEVID_NONE) &&
2687c478bd9Sstevel@tonic-gate (inq != NULL)) {
2697c478bd9Sstevel@tonic-gate encode_sun_serialnum(version, inq, inq_len,
2707c478bd9Sstevel@tonic-gate &id, &id_len, &id_type);
2717c478bd9Sstevel@tonic-gate }
2727c478bd9Sstevel@tonic-gate
2737c478bd9Sstevel@tonic-gate if (id_type != DEVID_NONE) {
2747c478bd9Sstevel@tonic-gate if (is_initialized_id(id, id_len) == DEVID_RET_VALID) {
2757c478bd9Sstevel@tonic-gate rval = devid_scsi_init(driver_name,
2767c478bd9Sstevel@tonic-gate id, id_len, id_type, devid);
2777c478bd9Sstevel@tonic-gate } else {
2787c478bd9Sstevel@tonic-gate rval = DEVID_RETRY;
2797c478bd9Sstevel@tonic-gate }
2807c478bd9Sstevel@tonic-gate DEVID_FREE(id, id_len);
2817c478bd9Sstevel@tonic-gate }
2827c478bd9Sstevel@tonic-gate
2837c478bd9Sstevel@tonic-gate return (rval);
2847c478bd9Sstevel@tonic-gate }
2857c478bd9Sstevel@tonic-gate
2867c478bd9Sstevel@tonic-gate
2877c478bd9Sstevel@tonic-gate /*
2887c478bd9Sstevel@tonic-gate * Function: is_page83_data_valid
2897c478bd9Sstevel@tonic-gate *
2907c478bd9Sstevel@tonic-gate * Description: This routine is used to validate the page 0x83 data
2917c478bd9Sstevel@tonic-gate * passed in valid based on the standards specification.
2927c478bd9Sstevel@tonic-gate *
2937c478bd9Sstevel@tonic-gate * Arguments: inq83 -
2947c478bd9Sstevel@tonic-gate * inq83_len -
2957c478bd9Sstevel@tonic-gate *
2967c478bd9Sstevel@tonic-gate * Return Code: DEVID_RET_VALID
2977c478bd9Sstevel@tonic-gate * DEVID_RET_INVALID
2987c478bd9Sstevel@tonic-gate *
2997c478bd9Sstevel@tonic-gate */
3007c478bd9Sstevel@tonic-gate static int
is_page83_data_valid(uchar_t * inq83,size_t inq83_len)3017c478bd9Sstevel@tonic-gate is_page83_data_valid(uchar_t *inq83, size_t inq83_len)
3027c478bd9Sstevel@tonic-gate {
3037c478bd9Sstevel@tonic-gate
3047c478bd9Sstevel@tonic-gate int covered_desc_len = 0;
3057c478bd9Sstevel@tonic-gate int dlen = 0;
3067c478bd9Sstevel@tonic-gate uchar_t *dblk = NULL;
3077c478bd9Sstevel@tonic-gate
3087c478bd9Sstevel@tonic-gate DEVID_ASSERT(inq83 != NULL);
3097c478bd9Sstevel@tonic-gate
3107c478bd9Sstevel@tonic-gate /* if not large enough fail */
3117c478bd9Sstevel@tonic-gate if (inq83_len < SCMD_MIN_INQUIRY_PAGE83_SIZE)
3127c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID);
3137c478bd9Sstevel@tonic-gate
3147c478bd9Sstevel@tonic-gate /*
3157c478bd9Sstevel@tonic-gate * Ensuring that the Peripheral device type(bits 0 - 4) has
3167c478bd9Sstevel@tonic-gate * the valid settings - the value 0x1f indicates no device type.
3177c478bd9Sstevel@tonic-gate * Only this value can be validated since all other fields are
3187c478bd9Sstevel@tonic-gate * either used or reserved.
3197c478bd9Sstevel@tonic-gate */
3207c478bd9Sstevel@tonic-gate if ((inq83[0] & DTYPE_MASK) == DTYPE_UNKNOWN) {
3217c478bd9Sstevel@tonic-gate /* failed-peripheral devtype */
3227c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID);
3237c478bd9Sstevel@tonic-gate }
3247c478bd9Sstevel@tonic-gate
3257c478bd9Sstevel@tonic-gate /*
3267c478bd9Sstevel@tonic-gate * Ensure that the page length field - third and 4th bytes
3277c478bd9Sstevel@tonic-gate * contain a non zero length value. Our implementation
3287c478bd9Sstevel@tonic-gate * does not seem to expect more that 255 bytes of data...
3297c478bd9Sstevel@tonic-gate * what is to be done if the reported size is > 255 bytes?
3307c478bd9Sstevel@tonic-gate * Yes the device will return only 255 bytes as we provide
3317c478bd9Sstevel@tonic-gate * buffer to house only that much data but the standards
3327c478bd9Sstevel@tonic-gate * prevent the targets from reporting the truncated size
3337c478bd9Sstevel@tonic-gate * in this field.
3347c478bd9Sstevel@tonic-gate *
3357c478bd9Sstevel@tonic-gate * Currently reporting sizes more than 255 as failure.
3367c478bd9Sstevel@tonic-gate *
3377c478bd9Sstevel@tonic-gate */
3387c478bd9Sstevel@tonic-gate
3397c478bd9Sstevel@tonic-gate if ((inq83[2] == 0) && (inq83[3] == 0)) {
3407c478bd9Sstevel@tonic-gate /* length field is 0! */
3417c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID);
3427c478bd9Sstevel@tonic-gate }
3437c478bd9Sstevel@tonic-gate if (inq83[3] > (SCMD_MAX_INQUIRY_PAGE83_SIZE - 3)) {
3447c478bd9Sstevel@tonic-gate /* length field exceeds expected size of 255 bytes */
3457c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID);
3467c478bd9Sstevel@tonic-gate }
3477c478bd9Sstevel@tonic-gate
3487c478bd9Sstevel@tonic-gate /*
3497c478bd9Sstevel@tonic-gate * Validation of individual descriptor blocks are done in the
3507c478bd9Sstevel@tonic-gate * following while loop. It is possible to have multiple
3517c478bd9Sstevel@tonic-gate * descriptor blocks.
3527c478bd9Sstevel@tonic-gate * the 'dblk' pointer will be pointing to the start of
3537c478bd9Sstevel@tonic-gate * each entry of the descriptor block.
3547c478bd9Sstevel@tonic-gate */
3557c478bd9Sstevel@tonic-gate covered_desc_len = 0;
3567c478bd9Sstevel@tonic-gate dblk = &inq83[4]; /* start of first decriptor blk */
3577c478bd9Sstevel@tonic-gate while (covered_desc_len < inq83[3]) {
3587c478bd9Sstevel@tonic-gate
3597c478bd9Sstevel@tonic-gate /*
3607c478bd9Sstevel@tonic-gate * Ensure that the length field is non zero
3617c478bd9Sstevel@tonic-gate * Further length validations will be done
3627c478bd9Sstevel@tonic-gate * along with the 'identifier type' as some of
3637c478bd9Sstevel@tonic-gate * the lengths are dependent on it.
3647c478bd9Sstevel@tonic-gate */
3657c478bd9Sstevel@tonic-gate dlen = dblk[3];
3667c478bd9Sstevel@tonic-gate if (dlen == 0) {
3677c478bd9Sstevel@tonic-gate /* descr length is 0 */
3687c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID);
3697c478bd9Sstevel@tonic-gate }
3707c478bd9Sstevel@tonic-gate
3717c478bd9Sstevel@tonic-gate /*
3727c478bd9Sstevel@tonic-gate * ensure that the size of the descriptor block does
3737c478bd9Sstevel@tonic-gate * not claim to be larger than the entire page83
3747c478bd9Sstevel@tonic-gate * data that has been received.
3757c478bd9Sstevel@tonic-gate */
3767c478bd9Sstevel@tonic-gate if ((covered_desc_len + dlen) > inq83[3]) {
3777c478bd9Sstevel@tonic-gate /* failed-descr length */
3787c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID);
3797c478bd9Sstevel@tonic-gate }
3807c478bd9Sstevel@tonic-gate
3817c478bd9Sstevel@tonic-gate /*
3827c478bd9Sstevel@tonic-gate * The spec says that if the PIV field is 0 OR the
3837c478bd9Sstevel@tonic-gate * association field contains value other than 1 and 2,
3847c478bd9Sstevel@tonic-gate * then the protocol identifier field should be ignored.
3857c478bd9Sstevel@tonic-gate * If association field contains a value of 1 or 2
3867c478bd9Sstevel@tonic-gate * and the PIV field is set, then the protocol identifier
3877c478bd9Sstevel@tonic-gate * field has to be validated.
3887c478bd9Sstevel@tonic-gate * The protocol identifier values 0 - f are either assigned
3897c478bd9Sstevel@tonic-gate * or reserved. Nothing to validate here, hence skipping
3907c478bd9Sstevel@tonic-gate * over to the next check.
3917c478bd9Sstevel@tonic-gate */
3927c478bd9Sstevel@tonic-gate
3937c478bd9Sstevel@tonic-gate /*
3947c478bd9Sstevel@tonic-gate * Check for valid code set values.
3957c478bd9Sstevel@tonic-gate * All possible values are reserved or assigned. Nothing
3967c478bd9Sstevel@tonic-gate * to validate - skipping over.
3977c478bd9Sstevel@tonic-gate */
3987c478bd9Sstevel@tonic-gate
3997c478bd9Sstevel@tonic-gate /*
4007c478bd9Sstevel@tonic-gate * Identifier Type validation
4017c478bd9Sstevel@tonic-gate * All SPC3rev22 identified types and the expected lengths
4027c478bd9Sstevel@tonic-gate * are validated.
4037c478bd9Sstevel@tonic-gate */
4047c478bd9Sstevel@tonic-gate switch (dblk[1] & 0x0f) {
4057c478bd9Sstevel@tonic-gate case SCMD_INQUIRY_VPD_TYPE_T10: /* T10 vendor Id */
4067c478bd9Sstevel@tonic-gate /* No specific length validation required */
4077c478bd9Sstevel@tonic-gate break;
4087c478bd9Sstevel@tonic-gate
4097c478bd9Sstevel@tonic-gate case SCMD_INQUIRY_VPD_TYPE_EUI: /* EUI 64 ID */
4107c478bd9Sstevel@tonic-gate /* EUI-64: size is expected to be 8, 12, or 16 bytes */
4117c478bd9Sstevel@tonic-gate if ((dlen != 8) && (dlen != 12) && (dlen != 16)) {
4127c478bd9Sstevel@tonic-gate /* page83 validation failed-EIU64 */
4137c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID);
4147c478bd9Sstevel@tonic-gate }
4157c478bd9Sstevel@tonic-gate break;
4167c478bd9Sstevel@tonic-gate
4177c478bd9Sstevel@tonic-gate case SCMD_INQUIRY_VPD_TYPE_NAA: /* NAA Id type */
4187c478bd9Sstevel@tonic-gate
4197c478bd9Sstevel@tonic-gate /*
4207c478bd9Sstevel@tonic-gate * the size for this varies -
4217c478bd9Sstevel@tonic-gate * IEEE extended/registered is 8 bytes
4227c478bd9Sstevel@tonic-gate * IEEE Registered extended is 16 bytes
4237c478bd9Sstevel@tonic-gate */
4247c478bd9Sstevel@tonic-gate switch (dblk[4] & 0xf0) {
4257c478bd9Sstevel@tonic-gate
4267c478bd9Sstevel@tonic-gate case 0x20: /* IEEE Ext */
4277c478bd9Sstevel@tonic-gate case 0x50: /* IEEE Reg */
4287c478bd9Sstevel@tonic-gate if (dlen != 8) {
4297c478bd9Sstevel@tonic-gate /* failed-IEE E/R len */
4307c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID);
4317c478bd9Sstevel@tonic-gate }
4327c478bd9Sstevel@tonic-gate /*
4337c478bd9Sstevel@tonic-gate * the codeSet for this MUST
4347c478bd9Sstevel@tonic-gate * be set to 1
4357c478bd9Sstevel@tonic-gate */
4367c478bd9Sstevel@tonic-gate if ((dblk[0] & 0x0f) != 1) {
4377c478bd9Sstevel@tonic-gate /*
4387c478bd9Sstevel@tonic-gate * failed-IEEE E/R
4397c478bd9Sstevel@tonic-gate * codeSet != 1.
4407c478bd9Sstevel@tonic-gate */
4417c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID);
4427c478bd9Sstevel@tonic-gate }
4437c478bd9Sstevel@tonic-gate break;
4447c478bd9Sstevel@tonic-gate
4457c478bd9Sstevel@tonic-gate case 0x60: /* IEEE EXT REG */
4467c478bd9Sstevel@tonic-gate if (dlen != 16) {
4477c478bd9Sstevel@tonic-gate /* failed-IEEE ER len */
4487c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID);
4497c478bd9Sstevel@tonic-gate }
4507c478bd9Sstevel@tonic-gate /*
4517c478bd9Sstevel@tonic-gate * the codeSet for this MUST
4527c478bd9Sstevel@tonic-gate * be set to 1
4537c478bd9Sstevel@tonic-gate */
4547c478bd9Sstevel@tonic-gate if ((dblk[0] & 0x0f) != 1) {
4557c478bd9Sstevel@tonic-gate /*
4567c478bd9Sstevel@tonic-gate * failed-IEEE ER
4577c478bd9Sstevel@tonic-gate * codeSet != 1.
4587c478bd9Sstevel@tonic-gate */
4597c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID);
4607c478bd9Sstevel@tonic-gate }
4617c478bd9Sstevel@tonic-gate break;
4627c478bd9Sstevel@tonic-gate
4637c478bd9Sstevel@tonic-gate default:
4647c478bd9Sstevel@tonic-gate /* reserved values */
4657c478bd9Sstevel@tonic-gate break;
4667c478bd9Sstevel@tonic-gate }
4677c478bd9Sstevel@tonic-gate break;
4687c478bd9Sstevel@tonic-gate
4697c478bd9Sstevel@tonic-gate case SCMD_INQUIRY_VPD_TYPE_RTP: /* Relative Target port */
4707c478bd9Sstevel@tonic-gate if (dlen != 4) {
4717c478bd9Sstevel@tonic-gate /* failed-Rel target Port length */
4727c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID);
4737c478bd9Sstevel@tonic-gate }
4747c478bd9Sstevel@tonic-gate break;
4757c478bd9Sstevel@tonic-gate
4767c478bd9Sstevel@tonic-gate case SCMD_INQUIRY_VPD_TYPE_TPG: /* Target port group */
4777c478bd9Sstevel@tonic-gate if (dlen != 4) {
4787c478bd9Sstevel@tonic-gate /* failed-target Port group length */
4797c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID);
4807c478bd9Sstevel@tonic-gate }
4817c478bd9Sstevel@tonic-gate break;
4827c478bd9Sstevel@tonic-gate
4837c478bd9Sstevel@tonic-gate case SCMD_INQUIRY_VPD_TYPE_LUG: /* Logical unit group */
4847c478bd9Sstevel@tonic-gate if (dlen != 4) {
4857c478bd9Sstevel@tonic-gate /* failed-Logical Unit group length */
4867c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID);
4877c478bd9Sstevel@tonic-gate }
4887c478bd9Sstevel@tonic-gate break;
4897c478bd9Sstevel@tonic-gate
4907c478bd9Sstevel@tonic-gate case SCMD_INQUIRY_VPD_TYPE_MD5: /* MD5 unit group */
4917c478bd9Sstevel@tonic-gate if (dlen != 16) {
4927c478bd9Sstevel@tonic-gate /* failed-MD5 Unit grp */
4937c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID);
4947c478bd9Sstevel@tonic-gate }
4957c478bd9Sstevel@tonic-gate break;
4967c478bd9Sstevel@tonic-gate
4977c478bd9Sstevel@tonic-gate default:
4987c478bd9Sstevel@tonic-gate break;
4997c478bd9Sstevel@tonic-gate }
5007c478bd9Sstevel@tonic-gate
5017c478bd9Sstevel@tonic-gate /*
5027c478bd9Sstevel@tonic-gate * Now lets advance to the next descriptor block
5037c478bd9Sstevel@tonic-gate * and validate it.
5047c478bd9Sstevel@tonic-gate * the descriptor block size is <descr Header> + <descr Data>
5057c478bd9Sstevel@tonic-gate * <descr Header> is equal to 4 bytes
5067c478bd9Sstevel@tonic-gate * <descr Data> is available in dlen or dblk[3].
5077c478bd9Sstevel@tonic-gate */
5087c478bd9Sstevel@tonic-gate dblk = &dblk[4 + dlen];
5097c478bd9Sstevel@tonic-gate
5107c478bd9Sstevel@tonic-gate /*
5117c478bd9Sstevel@tonic-gate * update the covered_desc_len so that we can ensure that
5127c478bd9Sstevel@tonic-gate * the 'while' loop terminates.
5137c478bd9Sstevel@tonic-gate */
5147c478bd9Sstevel@tonic-gate covered_desc_len += (dlen + 4);
5157c478bd9Sstevel@tonic-gate }
5167c478bd9Sstevel@tonic-gate return (DEVID_RET_VALID);
5177c478bd9Sstevel@tonic-gate }
5187c478bd9Sstevel@tonic-gate
5197c478bd9Sstevel@tonic-gate
5207c478bd9Sstevel@tonic-gate /*
5217c478bd9Sstevel@tonic-gate * Function: is_initialized_id
5227c478bd9Sstevel@tonic-gate *
5237c478bd9Sstevel@tonic-gate * Description: Routine to ensure that the ID calculated is not a
5247c478bd9Sstevel@tonic-gate * space or zero filled ID. Returning a space / zero
5257c478bd9Sstevel@tonic-gate * filled ID when the luns on the target are not fully
5267c478bd9Sstevel@tonic-gate * initialized is a valid response from the target as
5277c478bd9Sstevel@tonic-gate * per the T10 spec. When a space/zero filled ID is
5287c478bd9Sstevel@tonic-gate * found its information needs to be polled again
5297c478bd9Sstevel@tonic-gate * after sometime time to see if the luns are fully
5307c478bd9Sstevel@tonic-gate * initialized to return a valid guid information.
5317c478bd9Sstevel@tonic-gate *
5327c478bd9Sstevel@tonic-gate * Arguments: id - raw id
5337c478bd9Sstevel@tonic-gate * id_len - raw id len
5347c478bd9Sstevel@tonic-gate *
5357c478bd9Sstevel@tonic-gate * Return Code: DEVID_VALID - indicates a non space/zero filled id
5367c478bd9Sstevel@tonic-gate * DEVID_INVALID - indicates id contains uninitialized data
5377c478bd9Sstevel@tonic-gate * and suggests retry of the collection commands.
5387c478bd9Sstevel@tonic-gate */
5397c478bd9Sstevel@tonic-gate static int
is_initialized_id(uchar_t * id,size_t id_len)5407c478bd9Sstevel@tonic-gate is_initialized_id(uchar_t *id, size_t id_len)
5417c478bd9Sstevel@tonic-gate {
5427c478bd9Sstevel@tonic-gate int idx;
5437c478bd9Sstevel@tonic-gate
5447c478bd9Sstevel@tonic-gate if ((id == NULL) ||
5457c478bd9Sstevel@tonic-gate (id_len == 0)) {
5467c478bd9Sstevel@tonic-gate /* got id length as 0 fetch info again */
5477c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID);
5487c478bd9Sstevel@tonic-gate }
5497c478bd9Sstevel@tonic-gate
5507c478bd9Sstevel@tonic-gate /* First lets check if the guid is filled with spaces */
5517c478bd9Sstevel@tonic-gate for (idx = 0; idx < id_len; idx++) {
5527c478bd9Sstevel@tonic-gate if (id[idx] != ' ') {
5537c478bd9Sstevel@tonic-gate break;
5547c478bd9Sstevel@tonic-gate }
5557c478bd9Sstevel@tonic-gate }
5567c478bd9Sstevel@tonic-gate
5577c478bd9Sstevel@tonic-gate /*
5587c478bd9Sstevel@tonic-gate * Lets exit if we find that it contains ALL spaces
5597c478bd9Sstevel@tonic-gate * saying that it has an uninitialized guid
5607c478bd9Sstevel@tonic-gate */
5617c478bd9Sstevel@tonic-gate if (idx >= id_len) {
5627c478bd9Sstevel@tonic-gate /* guid filled with spaces found */
5637c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID);
5647c478bd9Sstevel@tonic-gate }
5657c478bd9Sstevel@tonic-gate
5667c478bd9Sstevel@tonic-gate /*
5677c478bd9Sstevel@tonic-gate * Since we have found that it is not filled with spaces
5687c478bd9Sstevel@tonic-gate * now lets ensure that the guid is not filled with only
5697c478bd9Sstevel@tonic-gate * zeros.
5707c478bd9Sstevel@tonic-gate */
5717c478bd9Sstevel@tonic-gate for (idx = 0; idx < id_len; idx ++) {
5727c478bd9Sstevel@tonic-gate if (id[idx] != 0) {
5737c478bd9Sstevel@tonic-gate return (DEVID_RET_VALID);
5747c478bd9Sstevel@tonic-gate }
5757c478bd9Sstevel@tonic-gate }
5767c478bd9Sstevel@tonic-gate
5777c478bd9Sstevel@tonic-gate /* guid filled with zeros found */
5787c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID);
5797c478bd9Sstevel@tonic-gate }
5807c478bd9Sstevel@tonic-gate
5817c478bd9Sstevel@tonic-gate
5827c478bd9Sstevel@tonic-gate /*
5837c478bd9Sstevel@tonic-gate * Function: is_page80_data_valid
5847c478bd9Sstevel@tonic-gate *
5857c478bd9Sstevel@tonic-gate * Description: This routine is used to validate the page 0x80 data
5867c478bd9Sstevel@tonic-gate * passed in valid based on the standards specification.
5877c478bd9Sstevel@tonic-gate *
5887c478bd9Sstevel@tonic-gate * Arguments: inq80 -
5897c478bd9Sstevel@tonic-gate * inq80_len -
5907c478bd9Sstevel@tonic-gate *
5917c478bd9Sstevel@tonic-gate * Return Code: DEVID_RET_VALID
5927c478bd9Sstevel@tonic-gate * DEVID_RET_INVALID
5937c478bd9Sstevel@tonic-gate *
5947c478bd9Sstevel@tonic-gate */
5957c478bd9Sstevel@tonic-gate /* ARGSUSED */
5967c478bd9Sstevel@tonic-gate static int
is_page80_data_valid(uchar_t * inq80,size_t inq80_len)5977c478bd9Sstevel@tonic-gate is_page80_data_valid(uchar_t *inq80, size_t inq80_len)
5987c478bd9Sstevel@tonic-gate {
5997c478bd9Sstevel@tonic-gate DEVID_ASSERT(inq80);
6007c478bd9Sstevel@tonic-gate
6017c478bd9Sstevel@tonic-gate /* if not large enough fail */
6027c478bd9Sstevel@tonic-gate if (inq80_len < SCMD_MIN_INQUIRY_PAGE80_SIZE) {
6037c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID);
6047c478bd9Sstevel@tonic-gate }
6057c478bd9Sstevel@tonic-gate
6067c478bd9Sstevel@tonic-gate /*
6077c478bd9Sstevel@tonic-gate * (inq80_len - 4) is the size of the buffer space available
6087c478bd9Sstevel@tonic-gate * for the product serial number. So inq80[3] (ie. product
6097c478bd9Sstevel@tonic-gate * serial number) should be <= (inq80_len -4).
6107c478bd9Sstevel@tonic-gate */
6117c478bd9Sstevel@tonic-gate if (inq80[3] > (inq80_len - 4)) {
6127c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID);
6137c478bd9Sstevel@tonic-gate }
6147c478bd9Sstevel@tonic-gate
6157c478bd9Sstevel@tonic-gate return (DEVID_RET_VALID);
6167c478bd9Sstevel@tonic-gate }
6177c478bd9Sstevel@tonic-gate
6187c478bd9Sstevel@tonic-gate
6197c478bd9Sstevel@tonic-gate /*
6207c478bd9Sstevel@tonic-gate * Function: encode_devid_page
6217c478bd9Sstevel@tonic-gate *
6227c478bd9Sstevel@tonic-gate * Description: This routine finds the unique devid if available and
6237c478bd9Sstevel@tonic-gate * fills the devid and length parameters.
6247c478bd9Sstevel@tonic-gate *
6257c478bd9Sstevel@tonic-gate * Arguments: version - encode version
6267c478bd9Sstevel@tonic-gate * inq83 - driver soft state (unit) structure
6277c478bd9Sstevel@tonic-gate * inq83_len - length of raw inq83 data
6287c478bd9Sstevel@tonic-gate * id - raw id
6297c478bd9Sstevel@tonic-gate * id_len - len of raw id
6307c478bd9Sstevel@tonic-gate * id_type - type of id
6317c478bd9Sstevel@tonic-gate *
6327c478bd9Sstevel@tonic-gate * Note: DEVID_NONE is returned in the id_type field
6337c478bd9Sstevel@tonic-gate * if no supported page 83 id is found.
6347c478bd9Sstevel@tonic-gate */
6357c478bd9Sstevel@tonic-gate static void
encode_scsi3_page83(int version,uchar_t * inq83,size_t inq83_len,uchar_t ** id,size_t * id_len,ushort_t * id_type)6367c478bd9Sstevel@tonic-gate encode_scsi3_page83(int version, uchar_t *inq83, size_t inq83_len,
6377c478bd9Sstevel@tonic-gate uchar_t **id, size_t *id_len, ushort_t *id_type)
6387c478bd9Sstevel@tonic-gate {
6397c478bd9Sstevel@tonic-gate size_t descriptor_bytes_left = 0;
6407c478bd9Sstevel@tonic-gate size_t offset = 0;
6417c478bd9Sstevel@tonic-gate int idx = 0;
6427c478bd9Sstevel@tonic-gate size_t offset_id_type[4];
6437c478bd9Sstevel@tonic-gate
6447c478bd9Sstevel@tonic-gate DEVID_ASSERT(inq83 != NULL);
6457c478bd9Sstevel@tonic-gate /* inq83 length was already validate in is_page83_valid */
6467c478bd9Sstevel@tonic-gate DEVID_ASSERT(id != NULL);
6477c478bd9Sstevel@tonic-gate DEVID_ASSERT(id_len != NULL);
6487c478bd9Sstevel@tonic-gate DEVID_ASSERT(id_type != NULL);
6497c478bd9Sstevel@tonic-gate
6507c478bd9Sstevel@tonic-gate /* preset defaults */
6517c478bd9Sstevel@tonic-gate *id = NULL;
6527c478bd9Sstevel@tonic-gate *id_len = 0;
6537c478bd9Sstevel@tonic-gate *id_type = DEVID_NONE;
6547c478bd9Sstevel@tonic-gate
6557c478bd9Sstevel@tonic-gate /* verify we have enough memory for a ident header */
6567c478bd9Sstevel@tonic-gate if (inq83_len < SCMD_INQUIRY_PAGE83_HDR_SIZE) {
6577c478bd9Sstevel@tonic-gate return;
6587c478bd9Sstevel@tonic-gate }
6597c478bd9Sstevel@tonic-gate
6607c478bd9Sstevel@tonic-gate /*
6617c478bd9Sstevel@tonic-gate * Attempt to validate the page data. Once validated, we'll walk
6627c478bd9Sstevel@tonic-gate * the descriptors, looking for certain identifier types that will
6637c478bd9Sstevel@tonic-gate * mark this device with a unique id/wwn. Note the comment below
6647c478bd9Sstevel@tonic-gate * for what we really want to receive.
6657c478bd9Sstevel@tonic-gate */
6667c478bd9Sstevel@tonic-gate
6677c478bd9Sstevel@tonic-gate /*
6687c478bd9Sstevel@tonic-gate * The format of the inq83 data (Device Identification VPD page) is
6697c478bd9Sstevel@tonic-gate * a header (containing the total length of the page, from which
6707c478bd9Sstevel@tonic-gate * descriptor_bytes_left is calculated), followed by a list of
6717c478bd9Sstevel@tonic-gate * identification descriptors. Each identifcation descriptor has a
6727c478bd9Sstevel@tonic-gate * header which includes the length of the individual identification
6737c478bd9Sstevel@tonic-gate * descriptor).
6747c478bd9Sstevel@tonic-gate *
6757c478bd9Sstevel@tonic-gate * Set the offset to the beginning byte of the first identification
6767c478bd9Sstevel@tonic-gate * descriptor. We'll index everything from there.
6777c478bd9Sstevel@tonic-gate */
6787c478bd9Sstevel@tonic-gate offset = SCMD_INQUIRY_PAGE83_HDR_SIZE;
6797c478bd9Sstevel@tonic-gate descriptor_bytes_left = (size_t)((inq83[2] << 8) | inq83[3]);
6807c478bd9Sstevel@tonic-gate
6817c478bd9Sstevel@tonic-gate /*
6827c478bd9Sstevel@tonic-gate * If the raw data states that the data is larger
6837c478bd9Sstevel@tonic-gate * than what is actually received abort encode.
6847c478bd9Sstevel@tonic-gate * Otherwise we will run off into unknown memory
6857c478bd9Sstevel@tonic-gate * on the decode.
6867c478bd9Sstevel@tonic-gate */
6877c478bd9Sstevel@tonic-gate if ((descriptor_bytes_left + offset) > inq83_len) {
6887c478bd9Sstevel@tonic-gate return;
6897c478bd9Sstevel@tonic-gate }
6907c478bd9Sstevel@tonic-gate
6917c478bd9Sstevel@tonic-gate
6927c478bd9Sstevel@tonic-gate /* Zero out our offset array */
6937c478bd9Sstevel@tonic-gate bzero(offset_id_type, sizeof (offset_id_type));
6947c478bd9Sstevel@tonic-gate
6957c478bd9Sstevel@tonic-gate /*
6967c478bd9Sstevel@tonic-gate * According to the scsi spec 8.4.3 SPC-2, there could be several
6977c478bd9Sstevel@tonic-gate * descriptors associated with each lun. Some we care about and some
6987c478bd9Sstevel@tonic-gate * we don't. This loop is set up to iterate through the descriptors.
6997c478bd9Sstevel@tonic-gate * We want the 0x03 case which represents an FC-PH, FC-PH3 or FC-FS
7007c478bd9Sstevel@tonic-gate * Name_Identifier. The spec mentions nothing about ordering, so we
7017c478bd9Sstevel@tonic-gate * don't assume any.
7027c478bd9Sstevel@tonic-gate *
7037c478bd9Sstevel@tonic-gate * We need to check if we've finished walking the list of descriptors,
7047c478bd9Sstevel@tonic-gate * we also perform additional checks to be sure the newly calculated
7057c478bd9Sstevel@tonic-gate * offset is within the bounds of the buffer, and the identifier length
7067c478bd9Sstevel@tonic-gate * (as calculated by the length field in the header) is valid. This is
7077c478bd9Sstevel@tonic-gate * done to protect against devices which return bad page83 data.
7087c478bd9Sstevel@tonic-gate */
7097c478bd9Sstevel@tonic-gate while ((descriptor_bytes_left > 0) && (offset_id_type[3] == 0) &&
7107c478bd9Sstevel@tonic-gate (offset + SCMD_INQUIRY_PAGE83_IDENT_DESC_HDR_SIZE <= inq83_len) &&
7117c478bd9Sstevel@tonic-gate (offset + SCMD_INQUIRY_PAGE83_IDENT_DESC_HDR_SIZE +
7127c478bd9Sstevel@tonic-gate (size_t)inq83[offset + 3] <= inq83_len)) {
7137c478bd9Sstevel@tonic-gate /*
7147c478bd9Sstevel@tonic-gate * Inspect the Identification descriptor list. Store the
7157c478bd9Sstevel@tonic-gate * offsets in the devid page separately for 0x03, 0x01 and
7167c478bd9Sstevel@tonic-gate * 0x02. Identifiers 0x00 and 0x04 are not useful as they
7177c478bd9Sstevel@tonic-gate * don't represent unique identifiers for a lun. We also
7187c478bd9Sstevel@tonic-gate * check the association by masking with 0x3f because we want
7197c478bd9Sstevel@tonic-gate * an association of 0x0 - indicating the identifier field is
7207c478bd9Sstevel@tonic-gate * associated with the addressed physical or logical device
7217c478bd9Sstevel@tonic-gate * and not the port.
7227c478bd9Sstevel@tonic-gate */
7237c478bd9Sstevel@tonic-gate switch ((inq83[offset + 1] & 0x3f)) {
7247c478bd9Sstevel@tonic-gate case SCMD_INQUIRY_VPD_TYPE_T10:
7257c478bd9Sstevel@tonic-gate offset_id_type[SCMD_INQUIRY_VPD_TYPE_T10] = offset;
7267c478bd9Sstevel@tonic-gate break;
7277c478bd9Sstevel@tonic-gate case SCMD_INQUIRY_VPD_TYPE_EUI:
7287c478bd9Sstevel@tonic-gate offset_id_type[SCMD_INQUIRY_VPD_TYPE_EUI] = offset;
7297c478bd9Sstevel@tonic-gate break;
7307c478bd9Sstevel@tonic-gate case SCMD_INQUIRY_VPD_TYPE_NAA:
7317c478bd9Sstevel@tonic-gate offset_id_type[SCMD_INQUIRY_VPD_TYPE_NAA] = offset;
7327c478bd9Sstevel@tonic-gate break;
7337c478bd9Sstevel@tonic-gate default:
7347c478bd9Sstevel@tonic-gate /* Devid page undesired id type */
7357c478bd9Sstevel@tonic-gate break;
7367c478bd9Sstevel@tonic-gate }
7377c478bd9Sstevel@tonic-gate /*
7387c478bd9Sstevel@tonic-gate * Calculate the descriptor bytes left and move to
7397c478bd9Sstevel@tonic-gate * the beginning byte of the next id descriptor.
7407c478bd9Sstevel@tonic-gate */
7417c478bd9Sstevel@tonic-gate descriptor_bytes_left -= (size_t)(inq83[offset + 3] +
7427c478bd9Sstevel@tonic-gate SCMD_INQUIRY_PAGE83_IDENT_DESC_HDR_SIZE);
7437c478bd9Sstevel@tonic-gate offset += (SCMD_INQUIRY_PAGE83_IDENT_DESC_HDR_SIZE +
7447c478bd9Sstevel@tonic-gate (size_t)inq83[offset + 3]);
7457c478bd9Sstevel@tonic-gate }
7467c478bd9Sstevel@tonic-gate
7477c478bd9Sstevel@tonic-gate offset = 0;
7487c478bd9Sstevel@tonic-gate
7497c478bd9Sstevel@tonic-gate /*
7507c478bd9Sstevel@tonic-gate * We can't depend on an order from a device by identifier type, but
7517c478bd9Sstevel@tonic-gate * once we have them, we'll walk them in the same order to prevent a
7527c478bd9Sstevel@tonic-gate * firmware upgrade from breaking our algorithm. Start with the one
7537c478bd9Sstevel@tonic-gate * we want the most: id_offset_type[3].
7547c478bd9Sstevel@tonic-gate */
7557c478bd9Sstevel@tonic-gate for (idx = 3; idx > 0; idx--) {
7567c478bd9Sstevel@tonic-gate if (offset_id_type[idx] > 0) {
7577c478bd9Sstevel@tonic-gate offset = offset_id_type[idx];
7587c478bd9Sstevel@tonic-gate break;
7597c478bd9Sstevel@tonic-gate }
7607c478bd9Sstevel@tonic-gate }
7617c478bd9Sstevel@tonic-gate
7627c478bd9Sstevel@tonic-gate /*
7637c478bd9Sstevel@tonic-gate * We have a valid Device ID page, set the length of the
7647c478bd9Sstevel@tonic-gate * identifier and copy the value into the wwn.
7657c478bd9Sstevel@tonic-gate */
7667c478bd9Sstevel@tonic-gate if (offset > 0) {
7677c478bd9Sstevel@tonic-gate *id_len = (size_t)inq83[offset + 3];
7687c478bd9Sstevel@tonic-gate if ((*id = DEVID_MALLOC(*id_len)) == NULL) {
7697c478bd9Sstevel@tonic-gate *id_len = 0;
7707c478bd9Sstevel@tonic-gate return;
7717c478bd9Sstevel@tonic-gate }
7727c478bd9Sstevel@tonic-gate bcopy(&inq83[offset + SCMD_INQUIRY_PAGE83_IDENT_DESC_HDR_SIZE],
7737c478bd9Sstevel@tonic-gate *id, *id_len);
7747c478bd9Sstevel@tonic-gate
7757c478bd9Sstevel@tonic-gate /* set devid type */
7767c478bd9Sstevel@tonic-gate switch (version) {
7777c478bd9Sstevel@tonic-gate /* In version 1 all page 83 types were grouped */
7787c478bd9Sstevel@tonic-gate case DEVID_SCSI_ENCODE_VERSION1:
7797c478bd9Sstevel@tonic-gate *id_type = DEVID_SCSI3_WWN;
7807c478bd9Sstevel@tonic-gate break;
7817c478bd9Sstevel@tonic-gate /* In version 2 we break page 83 apart to be unique */
7827c478bd9Sstevel@tonic-gate case DEVID_SCSI_ENCODE_VERSION2:
7837c478bd9Sstevel@tonic-gate switch (idx) {
7847c478bd9Sstevel@tonic-gate case 3:
7857c478bd9Sstevel@tonic-gate *id_type = DEVID_SCSI3_VPD_NAA;
7867c478bd9Sstevel@tonic-gate break;
7877c478bd9Sstevel@tonic-gate case 2:
7887c478bd9Sstevel@tonic-gate *id_type = DEVID_SCSI3_VPD_EUI;
7897c478bd9Sstevel@tonic-gate break;
7907c478bd9Sstevel@tonic-gate case 1:
7917c478bd9Sstevel@tonic-gate *id_type = DEVID_SCSI3_VPD_T10;
7927c478bd9Sstevel@tonic-gate break;
7937c478bd9Sstevel@tonic-gate default:
7947c478bd9Sstevel@tonic-gate DEVID_FREE(*id, *id_len);
7957c478bd9Sstevel@tonic-gate *id_len = 0;
7967c478bd9Sstevel@tonic-gate break;
7977c478bd9Sstevel@tonic-gate }
7987c478bd9Sstevel@tonic-gate break;
7997c478bd9Sstevel@tonic-gate default:
8007c478bd9Sstevel@tonic-gate DEVID_FREE(*id, *id_len);
8017c478bd9Sstevel@tonic-gate *id_len = 0;
8027c478bd9Sstevel@tonic-gate break;
8037c478bd9Sstevel@tonic-gate }
8047c478bd9Sstevel@tonic-gate }
8057c478bd9Sstevel@tonic-gate }
8067c478bd9Sstevel@tonic-gate
8077c478bd9Sstevel@tonic-gate
8087c478bd9Sstevel@tonic-gate /*
8097c478bd9Sstevel@tonic-gate * Function: encode_scsi3_page83_emc
8107c478bd9Sstevel@tonic-gate *
8117c478bd9Sstevel@tonic-gate * Description: Routine to handle proprietary page 83 of EMC Symmetrix
8127c478bd9Sstevel@tonic-gate * device. Called by ssfcp_handle_page83()
8137c478bd9Sstevel@tonic-gate *
8147c478bd9Sstevel@tonic-gate * Arguments: version - encode version
8157c478bd9Sstevel@tonic-gate * inq83 - scsi page 83 buffer
8167c478bd9Sstevel@tonic-gate * inq83_len - scsi page 83 buffer size
8177c478bd9Sstevel@tonic-gate * id - raw emc id
8187c478bd9Sstevel@tonic-gate * id_len - len of raw emc id
8197c478bd9Sstevel@tonic-gate * id_type - type of emc id
8207c478bd9Sstevel@tonic-gate */
8217c478bd9Sstevel@tonic-gate static void
encode_scsi3_page83_emc(int version,uchar_t * inq83,size_t inq83_len,uchar_t ** id,size_t * id_len,ushort_t * id_type)8227c478bd9Sstevel@tonic-gate encode_scsi3_page83_emc(int version, uchar_t *inq83,
8237c478bd9Sstevel@tonic-gate size_t inq83_len, uchar_t **id, size_t *id_len, ushort_t *id_type)
8247c478bd9Sstevel@tonic-gate {
8257c478bd9Sstevel@tonic-gate uchar_t *guidp = NULL;
8267c478bd9Sstevel@tonic-gate
8277c478bd9Sstevel@tonic-gate DEVID_ASSERT(inq83 != NULL);
8287c478bd9Sstevel@tonic-gate DEVID_ASSERT(id != NULL);
8297c478bd9Sstevel@tonic-gate DEVID_ASSERT(id_len != NULL);
8307c478bd9Sstevel@tonic-gate DEVID_ASSERT(id_type != NULL);
8317c478bd9Sstevel@tonic-gate
8327c478bd9Sstevel@tonic-gate /* preset defaults */
8337c478bd9Sstevel@tonic-gate *id = NULL;
8347c478bd9Sstevel@tonic-gate *id_len = 0;
8357c478bd9Sstevel@tonic-gate *id_type = DEVID_NONE;
8367c478bd9Sstevel@tonic-gate
8377c478bd9Sstevel@tonic-gate /* The initial devid algorithm didn't use EMC page 83 data */
8387c478bd9Sstevel@tonic-gate if (version == DEVID_SCSI_ENCODE_VERSION1) {
8397c478bd9Sstevel@tonic-gate return;
8407c478bd9Sstevel@tonic-gate }
8417c478bd9Sstevel@tonic-gate
8427c478bd9Sstevel@tonic-gate /* EMC page 83 requires atleast 20 bytes */
8437c478bd9Sstevel@tonic-gate if (inq83_len < (SCMD_INQUIRY_PAGE83_HDR_SIZE +
8447c478bd9Sstevel@tonic-gate SCSI_INQUIRY_PAGE83_EMC_SYMMETRIX_ID_LEN)) {
8457c478bd9Sstevel@tonic-gate return;
8467c478bd9Sstevel@tonic-gate }
8477c478bd9Sstevel@tonic-gate
8487c478bd9Sstevel@tonic-gate /*
8497c478bd9Sstevel@tonic-gate * The 4th byte in the page 83 info returned is most likely
8507c478bd9Sstevel@tonic-gate * indicating the length of the id - which 0x10(16 bytes)
8517c478bd9Sstevel@tonic-gate * and the 5th byte is indicating that the id is of
8527c478bd9Sstevel@tonic-gate * IEEE Registered Extended Name format(6). Validate
8537c478bd9Sstevel@tonic-gate * these code prints before proceeding further as the
8547c478bd9Sstevel@tonic-gate * following proprietary approach is tied to the specific
8557c478bd9Sstevel@tonic-gate * device type and incase the EMC firmware changes, we will
8567c478bd9Sstevel@tonic-gate * have to validate for the changed device before we start
8577c478bd9Sstevel@tonic-gate * supporting such a device.
8587c478bd9Sstevel@tonic-gate */
8597c478bd9Sstevel@tonic-gate if ((inq83[3] != 0x10) || (inq83[4] != 0x60)) {
8607c478bd9Sstevel@tonic-gate /* unsupported emc symtx device type */
8617c478bd9Sstevel@tonic-gate return;
8627c478bd9Sstevel@tonic-gate } else {
8637c478bd9Sstevel@tonic-gate guidp = &inq83[SCMD_INQUIRY_PAGE83_HDR_SIZE];
8647c478bd9Sstevel@tonic-gate /*
8657c478bd9Sstevel@tonic-gate * The GUID returned by the EMC device is
8667c478bd9Sstevel@tonic-gate * in the IEEE Registered Extended Name format(6)
8677c478bd9Sstevel@tonic-gate * as a result it is of 16 bytes in length.
8687c478bd9Sstevel@tonic-gate * An IEEE Registered Name format(5) will be of
8697c478bd9Sstevel@tonic-gate * 8 bytes which is NOT what is being returned
8707c478bd9Sstevel@tonic-gate * by the device type for which we are providing
8717c478bd9Sstevel@tonic-gate * the support.
8727c478bd9Sstevel@tonic-gate */
8737c478bd9Sstevel@tonic-gate *id_len = SCSI_INQUIRY_PAGE83_EMC_SYMMETRIX_ID_LEN;
8747c478bd9Sstevel@tonic-gate if ((*id = DEVID_MALLOC(*id_len)) == NULL) {
8757c478bd9Sstevel@tonic-gate *id_len = 0;
8767c478bd9Sstevel@tonic-gate return;
8777c478bd9Sstevel@tonic-gate }
8787c478bd9Sstevel@tonic-gate bcopy(guidp, *id, *id_len);
8797c478bd9Sstevel@tonic-gate
8807c478bd9Sstevel@tonic-gate /* emc id matches type 3 */
8817c478bd9Sstevel@tonic-gate *id_type = DEVID_SCSI3_VPD_NAA;
8827c478bd9Sstevel@tonic-gate }
8837c478bd9Sstevel@tonic-gate }
8847c478bd9Sstevel@tonic-gate
8857c478bd9Sstevel@tonic-gate
8867c478bd9Sstevel@tonic-gate /*
8877c478bd9Sstevel@tonic-gate * Function: encode_serialnum
8887c478bd9Sstevel@tonic-gate *
8897c478bd9Sstevel@tonic-gate * Description: This routine finds the unique devid from the inquiry page
8907c478bd9Sstevel@tonic-gate * 0x80, serial number page. If available and fills the wwn
8917c478bd9Sstevel@tonic-gate * and length parameters.
8927c478bd9Sstevel@tonic-gate *
8937c478bd9Sstevel@tonic-gate * Arguments: version - encode version
8947c478bd9Sstevel@tonic-gate * inq - standard inquiry data
8957c478bd9Sstevel@tonic-gate * inq80 - serial inquiry data
8967c478bd9Sstevel@tonic-gate * inq80_len - serial inquiry data len
8977c478bd9Sstevel@tonic-gate * id - raw id
8987c478bd9Sstevel@tonic-gate * id_len - raw id len
8997c478bd9Sstevel@tonic-gate * id_type - raw id type
9007c478bd9Sstevel@tonic-gate */
9017c478bd9Sstevel@tonic-gate /* ARGSUSED */
9027c478bd9Sstevel@tonic-gate static void
encode_serialnum(int version,uchar_t * inq,uchar_t * inq80,size_t inq80_len,uchar_t ** id,size_t * id_len,ushort_t * id_type)9037c478bd9Sstevel@tonic-gate encode_serialnum(int version, uchar_t *inq, uchar_t *inq80,
9047c478bd9Sstevel@tonic-gate size_t inq80_len, uchar_t **id, size_t *id_len, ushort_t *id_type)
9057c478bd9Sstevel@tonic-gate {
9067c478bd9Sstevel@tonic-gate struct scsi_inquiry *inq_std = (struct scsi_inquiry *)inq;
9077c478bd9Sstevel@tonic-gate int idx = 0;
9087c478bd9Sstevel@tonic-gate
9097c478bd9Sstevel@tonic-gate DEVID_ASSERT(inq != NULL);
9107c478bd9Sstevel@tonic-gate DEVID_ASSERT(inq80 != NULL);
9117c478bd9Sstevel@tonic-gate DEVID_ASSERT(id != NULL);
9127c478bd9Sstevel@tonic-gate DEVID_ASSERT(id_len != NULL);
9137c478bd9Sstevel@tonic-gate DEVID_ASSERT(id_type != NULL);
9147c478bd9Sstevel@tonic-gate
9157c478bd9Sstevel@tonic-gate /* preset defaults */
9167c478bd9Sstevel@tonic-gate *id = NULL;
9177c478bd9Sstevel@tonic-gate *id_len = 0;
9187c478bd9Sstevel@tonic-gate *id_type = DEVID_NONE;
9197c478bd9Sstevel@tonic-gate
9207c478bd9Sstevel@tonic-gate /* verify inq80 buffer is large enough for a header */
9217c478bd9Sstevel@tonic-gate if (inq80_len < SCMD_MIN_INQUIRY_PAGE80_SIZE) {
9227c478bd9Sstevel@tonic-gate return;
9237c478bd9Sstevel@tonic-gate }
9247c478bd9Sstevel@tonic-gate
9257c478bd9Sstevel@tonic-gate /*
9267c478bd9Sstevel@tonic-gate * Attempt to validate the page data. Once validated, we'll check
9277c478bd9Sstevel@tonic-gate * the serial number.
9287c478bd9Sstevel@tonic-gate */
9297c478bd9Sstevel@tonic-gate *id_len = (size_t)inq80[3]; /* Store Product Serial Number length */
9307c478bd9Sstevel@tonic-gate
9317c478bd9Sstevel@tonic-gate /* verify buffer is large enough for serial number */
9327c478bd9Sstevel@tonic-gate if (inq80_len < (*id_len + SCMD_MIN_INQUIRY_PAGE80_SIZE)) {
9337c478bd9Sstevel@tonic-gate return;
9347c478bd9Sstevel@tonic-gate }
9357c478bd9Sstevel@tonic-gate
9367c478bd9Sstevel@tonic-gate /*
9377c478bd9Sstevel@tonic-gate * Device returns ASCII space (20h) in all the bytes of successful data
9387c478bd9Sstevel@tonic-gate * transfer, if the product serial number is not available. So we end
9397c478bd9Sstevel@tonic-gate * up having to check all the bytes for a space until we reach
9407c478bd9Sstevel@tonic-gate * something else.
9417c478bd9Sstevel@tonic-gate */
9427c478bd9Sstevel@tonic-gate for (idx = 0; idx < *id_len; idx++) {
9437c478bd9Sstevel@tonic-gate if (inq80[4 + idx] == ' ') {
9447c478bd9Sstevel@tonic-gate continue;
9457c478bd9Sstevel@tonic-gate }
9467c478bd9Sstevel@tonic-gate /*
9477c478bd9Sstevel@tonic-gate * The serial number is valid, but since this is only vendor
9487c478bd9Sstevel@tonic-gate * unique, we'll combine the inquiry vid and pid with the
9497c478bd9Sstevel@tonic-gate * serial number.
9507c478bd9Sstevel@tonic-gate */
9517c478bd9Sstevel@tonic-gate *id_len += sizeof (inq_std->inq_vid);
9527c478bd9Sstevel@tonic-gate *id_len += sizeof (inq_std->inq_pid);
9537c478bd9Sstevel@tonic-gate
9547c478bd9Sstevel@tonic-gate if ((*id = DEVID_MALLOC(*id_len)) == NULL) {
9557c478bd9Sstevel@tonic-gate *id_len = 0;
9567c478bd9Sstevel@tonic-gate return;
9577c478bd9Sstevel@tonic-gate }
9587c478bd9Sstevel@tonic-gate
9597c478bd9Sstevel@tonic-gate bcopy(&inq_std->inq_vid, *id, sizeof (inq_std->inq_vid));
9607c478bd9Sstevel@tonic-gate bcopy(&inq_std->inq_pid, &(*id)[sizeof (inq_std->inq_vid)],
9617c478bd9Sstevel@tonic-gate sizeof (inq_std->inq_pid));
9627c478bd9Sstevel@tonic-gate bcopy(&inq80[4], &(*id)[sizeof (inq_std->inq_vid) +
9637c478bd9Sstevel@tonic-gate sizeof (inq_std->inq_pid)], inq80[3]);
9647c478bd9Sstevel@tonic-gate
9657c478bd9Sstevel@tonic-gate *id_type = DEVID_SCSI_SERIAL;
9667c478bd9Sstevel@tonic-gate break;
9677c478bd9Sstevel@tonic-gate }
9687c478bd9Sstevel@tonic-gate
9697c478bd9Sstevel@tonic-gate /*
9707c478bd9Sstevel@tonic-gate * The spec suggests that the command could succeed but return all
9717c478bd9Sstevel@tonic-gate * spaces if the product serial number is not available. In this case
9727c478bd9Sstevel@tonic-gate * we need to fail this routine. To accomplish this, we compare our
9737c478bd9Sstevel@tonic-gate * length to the serial number length. If they are the same, then we
9747c478bd9Sstevel@tonic-gate * never copied in the vid and updated the length. That being the case,
9757c478bd9Sstevel@tonic-gate * we must not have found a valid serial number.
9767c478bd9Sstevel@tonic-gate */
9777c478bd9Sstevel@tonic-gate if (*id_len == (size_t)inq80[3]) {
9787c478bd9Sstevel@tonic-gate /* empty unit serial number */
979f5689c9eSbg159949 if (*id != NULL) {
9807c478bd9Sstevel@tonic-gate DEVID_FREE(*id, *id_len);
981f5689c9eSbg159949 }
9827c478bd9Sstevel@tonic-gate *id = NULL;
9837c478bd9Sstevel@tonic-gate *id_len = 0;
9847c478bd9Sstevel@tonic-gate }
9857c478bd9Sstevel@tonic-gate }
9867c478bd9Sstevel@tonic-gate
9877c478bd9Sstevel@tonic-gate
9887c478bd9Sstevel@tonic-gate /*
9897c478bd9Sstevel@tonic-gate * Function: encode_sun_serialnum
9907c478bd9Sstevel@tonic-gate *
9917c478bd9Sstevel@tonic-gate * Description: This routine finds the unique devid from the inquiry page
9927c478bd9Sstevel@tonic-gate * 0x80, serial number page. If available and fills the wwn
9937c478bd9Sstevel@tonic-gate * and length parameters.
9947c478bd9Sstevel@tonic-gate *
9957c478bd9Sstevel@tonic-gate * Arguments: version - encode version
9967c478bd9Sstevel@tonic-gate * inq - standard inquiry data
9977c478bd9Sstevel@tonic-gate * inq_len - standard inquiry data len
9987c478bd9Sstevel@tonic-gate * id - raw id
9997c478bd9Sstevel@tonic-gate * id_len - raw id len
10007c478bd9Sstevel@tonic-gate * id_type - raw id type
10017c478bd9Sstevel@tonic-gate *
10027c478bd9Sstevel@tonic-gate * Return Code: DEVID_SUCCESS
10037c478bd9Sstevel@tonic-gate * DEVID_FAILURE
10047c478bd9Sstevel@tonic-gate */
10057c478bd9Sstevel@tonic-gate /* ARGSUSED */
10067c478bd9Sstevel@tonic-gate static void
encode_sun_serialnum(int version,uchar_t * inq,size_t inq_len,uchar_t ** id,size_t * id_len,ushort_t * id_type)10077c478bd9Sstevel@tonic-gate encode_sun_serialnum(int version, uchar_t *inq,
10087c478bd9Sstevel@tonic-gate size_t inq_len, uchar_t **id, size_t *id_len, ushort_t *id_type)
10097c478bd9Sstevel@tonic-gate {
10107c478bd9Sstevel@tonic-gate struct scsi_inquiry *inq_std = (struct scsi_inquiry *)inq;
10117c478bd9Sstevel@tonic-gate
10127c478bd9Sstevel@tonic-gate DEVID_ASSERT(inq != NULL);
10137c478bd9Sstevel@tonic-gate DEVID_ASSERT(id != NULL);
10147c478bd9Sstevel@tonic-gate DEVID_ASSERT(id_len != NULL);
10157c478bd9Sstevel@tonic-gate DEVID_ASSERT(id_type != NULL);
10167c478bd9Sstevel@tonic-gate
10177c478bd9Sstevel@tonic-gate /* verify enough buffer is available */
10187c478bd9Sstevel@tonic-gate if (inq_len < SCMD_MIN_STANDARD_INQUIRY_SIZE) {
10197c478bd9Sstevel@tonic-gate return;
10207c478bd9Sstevel@tonic-gate }
10217c478bd9Sstevel@tonic-gate
10227c478bd9Sstevel@tonic-gate /* sun qual drive */
10237c478bd9Sstevel@tonic-gate if ((inq_std != NULL) &&
10247c478bd9Sstevel@tonic-gate (bcmp(&inq_std->inq_pid[SCSI_INQUIRY_VID_POS],
10257c478bd9Sstevel@tonic-gate SCSI_INQUIRY_VID_SUN, SCSI_INQUIRY_VID_SUN_LEN) == 0)) {
10267c478bd9Sstevel@tonic-gate /*
10277c478bd9Sstevel@tonic-gate * VPD pages 0x83 and 0x80 are unavailable. This
1028*96c4a178SChris Horne * is a Sun qualified disk as indicated by
10297c478bd9Sstevel@tonic-gate * "SUN" in bytes 25-27 of the inquiry data
10307c478bd9Sstevel@tonic-gate * (bytes 9-11 of the pid). Devid's are created
10317c478bd9Sstevel@tonic-gate * for Sun qualified disks by combining the
10327c478bd9Sstevel@tonic-gate * vendor id with the product id with the serial
10337c478bd9Sstevel@tonic-gate * number located in bytes 36-47 of the inquiry data.
10347c478bd9Sstevel@tonic-gate */
10357c478bd9Sstevel@tonic-gate
10367c478bd9Sstevel@tonic-gate /* get data size */
10377c478bd9Sstevel@tonic-gate *id_len = sizeof (inq_std->inq_vid) +
10387c478bd9Sstevel@tonic-gate sizeof (inq_std->inq_pid) +
10397c478bd9Sstevel@tonic-gate sizeof (inq_std->inq_serial);
10407c478bd9Sstevel@tonic-gate
10417c478bd9Sstevel@tonic-gate if ((*id = DEVID_MALLOC(*id_len)) == NULL) {
10427c478bd9Sstevel@tonic-gate *id_len = 0;
10437c478bd9Sstevel@tonic-gate return;
10447c478bd9Sstevel@tonic-gate }
10457c478bd9Sstevel@tonic-gate
10467c478bd9Sstevel@tonic-gate /* copy the vid at the beginning */
10477c478bd9Sstevel@tonic-gate bcopy(&inq_std->inq_vid, *id,
10487c478bd9Sstevel@tonic-gate sizeof (inq_std->inq_vid));
1049*96c4a178SChris Horne
10507c478bd9Sstevel@tonic-gate /* copy the pid after the vid */
10517c478bd9Sstevel@tonic-gate bcopy(&inq_std->inq_pid,
10527c478bd9Sstevel@tonic-gate &(*id)[sizeof (inq_std->inq_vid)],
10537c478bd9Sstevel@tonic-gate sizeof (inq_std->inq_pid));
1054*96c4a178SChris Horne
10557c478bd9Sstevel@tonic-gate /* copy the serial number after the vid and pid */
10567c478bd9Sstevel@tonic-gate bcopy(&inq_std->inq_serial,
10577c478bd9Sstevel@tonic-gate &(*id)[sizeof (inq_std->inq_vid) +
10587c478bd9Sstevel@tonic-gate sizeof (inq_std->inq_pid)],
10597c478bd9Sstevel@tonic-gate sizeof (inq_std->inq_serial));
1060*96c4a178SChris Horne
10617c478bd9Sstevel@tonic-gate /* devid formed from inquiry data */
10627c478bd9Sstevel@tonic-gate *id_type = DEVID_SCSI_SERIAL;
10637c478bd9Sstevel@tonic-gate }
10647c478bd9Sstevel@tonic-gate }
10657c478bd9Sstevel@tonic-gate
10667c478bd9Sstevel@tonic-gate
10677c478bd9Sstevel@tonic-gate /*
10687c478bd9Sstevel@tonic-gate * Function: devid_scsi_init
10697c478bd9Sstevel@tonic-gate *
10707c478bd9Sstevel@tonic-gate * Description: This routine is used to create a devid for a scsi
10717c478bd9Sstevel@tonic-gate * devid type.
10727c478bd9Sstevel@tonic-gate *
10737c478bd9Sstevel@tonic-gate * Arguments: hint - driver soft state (unit) structure
10747c478bd9Sstevel@tonic-gate * raw_id - pass by reference variable to hold wwn
10757c478bd9Sstevel@tonic-gate * raw_id_len - wwn length
10767c478bd9Sstevel@tonic-gate * raw_id_type -
10777c478bd9Sstevel@tonic-gate * ret_devid -
10787c478bd9Sstevel@tonic-gate *
10797c478bd9Sstevel@tonic-gate * Return Code: DEVID_SUCCESS
10807c478bd9Sstevel@tonic-gate * DEVID_FAILURE
10817c478bd9Sstevel@tonic-gate *
10827c478bd9Sstevel@tonic-gate */
10837c478bd9Sstevel@tonic-gate static int
devid_scsi_init(char * driver_name,uchar_t * raw_id,size_t raw_id_len,ushort_t raw_id_type,ddi_devid_t * ret_devid)10847c478bd9Sstevel@tonic-gate devid_scsi_init(
10857c478bd9Sstevel@tonic-gate char *driver_name,
10867c478bd9Sstevel@tonic-gate uchar_t *raw_id,
10877c478bd9Sstevel@tonic-gate size_t raw_id_len,
10887c478bd9Sstevel@tonic-gate ushort_t raw_id_type,
10897c478bd9Sstevel@tonic-gate ddi_devid_t *ret_devid)
10907c478bd9Sstevel@tonic-gate {
10917c478bd9Sstevel@tonic-gate impl_devid_t *i_devid = NULL;
10927c478bd9Sstevel@tonic-gate int i_devid_len = 0;
10937c478bd9Sstevel@tonic-gate int driver_name_len = 0;
10947c478bd9Sstevel@tonic-gate ushort_t u_raw_id_len = 0;
10957c478bd9Sstevel@tonic-gate
10967c478bd9Sstevel@tonic-gate DEVID_ASSERT(raw_id != NULL);
10977c478bd9Sstevel@tonic-gate DEVID_ASSERT(ret_devid != NULL);
10987c478bd9Sstevel@tonic-gate
10997c478bd9Sstevel@tonic-gate if (!IS_DEVID_SCSI_TYPE(raw_id_type)) {
11007c478bd9Sstevel@tonic-gate *ret_devid = NULL;
11017c478bd9Sstevel@tonic-gate return (DEVID_FAILURE);
11027c478bd9Sstevel@tonic-gate }
11037c478bd9Sstevel@tonic-gate
11047c478bd9Sstevel@tonic-gate i_devid_len = sizeof (*i_devid) + raw_id_len - sizeof (i_devid->did_id);
11057c478bd9Sstevel@tonic-gate if ((i_devid = DEVID_MALLOC(i_devid_len)) == NULL) {
11067c478bd9Sstevel@tonic-gate *ret_devid = NULL;
11077c478bd9Sstevel@tonic-gate return (DEVID_FAILURE);
11087c478bd9Sstevel@tonic-gate }
11097c478bd9Sstevel@tonic-gate
11107c478bd9Sstevel@tonic-gate i_devid->did_magic_hi = DEVID_MAGIC_MSB;
11117c478bd9Sstevel@tonic-gate i_devid->did_magic_lo = DEVID_MAGIC_LSB;
11127c478bd9Sstevel@tonic-gate i_devid->did_rev_hi = DEVID_REV_MSB;
11137c478bd9Sstevel@tonic-gate i_devid->did_rev_lo = DEVID_REV_LSB;
11147c478bd9Sstevel@tonic-gate DEVID_FORMTYPE(i_devid, raw_id_type);
11157c478bd9Sstevel@tonic-gate u_raw_id_len = raw_id_len;
11167c478bd9Sstevel@tonic-gate DEVID_FORMLEN(i_devid, u_raw_id_len);
11177c478bd9Sstevel@tonic-gate
11187c478bd9Sstevel@tonic-gate /* Fill in driver name hint */
111999025f2eSsrivijitha dugganapalli bzero(i_devid->did_driver, DEVID_HINT_SIZE);
11207c478bd9Sstevel@tonic-gate if (driver_name != NULL) {
11217c478bd9Sstevel@tonic-gate driver_name_len = strlen(driver_name);
11227c478bd9Sstevel@tonic-gate if (driver_name_len > DEVID_HINT_SIZE) {
11237c478bd9Sstevel@tonic-gate /* Pick up last four characters of driver name */
11247c478bd9Sstevel@tonic-gate driver_name += driver_name_len - DEVID_HINT_SIZE;
11257c478bd9Sstevel@tonic-gate driver_name_len = DEVID_HINT_SIZE;
11267c478bd9Sstevel@tonic-gate }
11277c478bd9Sstevel@tonic-gate bcopy(driver_name, i_devid->did_driver, driver_name_len);
11287c478bd9Sstevel@tonic-gate }
11297c478bd9Sstevel@tonic-gate
11307c478bd9Sstevel@tonic-gate bcopy(raw_id, i_devid->did_id, raw_id_len);
11317c478bd9Sstevel@tonic-gate
11327c478bd9Sstevel@tonic-gate /* return device id */
11337c478bd9Sstevel@tonic-gate *ret_devid = (ddi_devid_t)i_devid;
11347c478bd9Sstevel@tonic-gate return (DEVID_SUCCESS);
11357c478bd9Sstevel@tonic-gate }
11367c478bd9Sstevel@tonic-gate
11377c478bd9Sstevel@tonic-gate
11387c478bd9Sstevel@tonic-gate /*
11397c478bd9Sstevel@tonic-gate * Function: devid_to_guid
11407c478bd9Sstevel@tonic-gate *
11417c478bd9Sstevel@tonic-gate * Description: This routine extracts a guid string form a devid.
11427c478bd9Sstevel@tonic-gate * The common use of this guid is for a HBA driver
11437c478bd9Sstevel@tonic-gate * to pass into mdi_pi_alloc().
11447c478bd9Sstevel@tonic-gate *
11457c478bd9Sstevel@tonic-gate * Arguments: devid - devid to extract guid from
11467c478bd9Sstevel@tonic-gate *
11477c478bd9Sstevel@tonic-gate * Return Code: guid string - success
11487c478bd9Sstevel@tonic-gate * NULL - failure
11497c478bd9Sstevel@tonic-gate */
11507c478bd9Sstevel@tonic-gate char *
11517c478bd9Sstevel@tonic-gate #ifdef _KERNEL
ddi_devid_to_guid(ddi_devid_t devid)11527c478bd9Sstevel@tonic-gate ddi_devid_to_guid(ddi_devid_t devid)
11537c478bd9Sstevel@tonic-gate #else /* !_KERNEL */
11547c478bd9Sstevel@tonic-gate devid_to_guid(ddi_devid_t devid)
11557c478bd9Sstevel@tonic-gate #endif /* _KERNEL */
11567c478bd9Sstevel@tonic-gate {
11577c478bd9Sstevel@tonic-gate impl_devid_t *id = (impl_devid_t *)devid;
11587c478bd9Sstevel@tonic-gate int len = 0;
11597c478bd9Sstevel@tonic-gate int idx = 0;
11607c478bd9Sstevel@tonic-gate int num = 0;
11617c478bd9Sstevel@tonic-gate char *guid = NULL;
11627c478bd9Sstevel@tonic-gate char *ptr = NULL;
11637c478bd9Sstevel@tonic-gate char *dp = NULL;
11647c478bd9Sstevel@tonic-gate
11657c478bd9Sstevel@tonic-gate DEVID_ASSERT(devid != NULL);
11667c478bd9Sstevel@tonic-gate
11677c478bd9Sstevel@tonic-gate /* NULL devid -> NULL guid */
11687c478bd9Sstevel@tonic-gate if (devid == NULL)
11697c478bd9Sstevel@tonic-gate return (NULL);
11707c478bd9Sstevel@tonic-gate
11717c478bd9Sstevel@tonic-gate if (!IS_DEVID_GUID_TYPE(DEVID_GETTYPE(id)))
11727c478bd9Sstevel@tonic-gate return (NULL);
11737c478bd9Sstevel@tonic-gate
11747c478bd9Sstevel@tonic-gate /* guid is always converted to ascii, append NULL */
11757c478bd9Sstevel@tonic-gate len = DEVID_GETLEN(id);
11767c478bd9Sstevel@tonic-gate
11777c478bd9Sstevel@tonic-gate /* allocate guid string */
11787c478bd9Sstevel@tonic-gate if ((guid = DEVID_MALLOC((len * 2) + 1)) == NULL)
11797c478bd9Sstevel@tonic-gate return (NULL);
11807c478bd9Sstevel@tonic-gate
11817c478bd9Sstevel@tonic-gate /* perform encode of id to hex string */
11827c478bd9Sstevel@tonic-gate ptr = guid;
11837c478bd9Sstevel@tonic-gate for (idx = 0, dp = &id->did_id[0]; idx < len; idx++, dp++) {
11847c478bd9Sstevel@tonic-gate num = ((*dp) >> 4) & 0xF;
11857c478bd9Sstevel@tonic-gate *ptr++ = (num < 10) ? (num + '0') : (num + ('a' - 10));
11867c478bd9Sstevel@tonic-gate num = (*dp) & 0xF;
11877c478bd9Sstevel@tonic-gate *ptr++ = (num < 10) ? (num + '0') : (num + ('a' - 10));
11887c478bd9Sstevel@tonic-gate }
11897c478bd9Sstevel@tonic-gate *ptr = 0;
11907c478bd9Sstevel@tonic-gate
11917c478bd9Sstevel@tonic-gate return (guid);
11927c478bd9Sstevel@tonic-gate }
11937c478bd9Sstevel@tonic-gate
11947c478bd9Sstevel@tonic-gate /*
11957c478bd9Sstevel@tonic-gate * Function: devid_free_guid
11967c478bd9Sstevel@tonic-gate *
11977c478bd9Sstevel@tonic-gate * Description: This routine frees a guid allocated by
11987c478bd9Sstevel@tonic-gate * devid_to_guid().
11997c478bd9Sstevel@tonic-gate *
12007c478bd9Sstevel@tonic-gate * Arguments: guid - guid to free
12017c478bd9Sstevel@tonic-gate */
12027c478bd9Sstevel@tonic-gate void
12037c478bd9Sstevel@tonic-gate #ifdef _KERNEL
ddi_devid_free_guid(char * guid)12047c478bd9Sstevel@tonic-gate ddi_devid_free_guid(char *guid)
12057c478bd9Sstevel@tonic-gate #else /* !_KERNEL */
12067c478bd9Sstevel@tonic-gate devid_free_guid(char *guid)
12077c478bd9Sstevel@tonic-gate #endif /* _KERNEL */
12087c478bd9Sstevel@tonic-gate {
12097c478bd9Sstevel@tonic-gate if (guid != NULL) {
12107c478bd9Sstevel@tonic-gate DEVID_FREE(guid, strlen(guid) + 1);
12117c478bd9Sstevel@tonic-gate }
12127c478bd9Sstevel@tonic-gate }
1213936b7af6Sjw149990
1214936b7af6Sjw149990 static char
ctoi(char c)1215936b7af6Sjw149990 ctoi(char c)
1216936b7af6Sjw149990 {
1217936b7af6Sjw149990 if ((c >= '0') && (c <= '9'))
1218936b7af6Sjw149990 c -= '0';
1219936b7af6Sjw149990 else if ((c >= 'A') && (c <= 'F'))
1220936b7af6Sjw149990 c = c - 'A' + 10;
1221936b7af6Sjw149990 else if ((c >= 'a') && (c <= 'f'))
1222936b7af6Sjw149990 c = c - 'a' + 10;
1223936b7af6Sjw149990 else
1224936b7af6Sjw149990 c = -1;
1225936b7af6Sjw149990 return (c);
1226936b7af6Sjw149990 }
1227936b7af6Sjw149990
1228ed141cfcSsrivijitha dugganapalli /* ====NOTE: The scsi_* interfaces are not related to devids :NOTE==== */
1229ed141cfcSsrivijitha dugganapalli
1230936b7af6Sjw149990 /*
1231ed141cfcSsrivijitha dugganapalli * Function: scsi_wwnstr_to_wwn
1232936b7af6Sjw149990 *
1233ed141cfcSsrivijitha dugganapalli * Description: This routine translates wwn from wwnstr string to uint64 wwn.
1234936b7af6Sjw149990 *
1235ed141cfcSsrivijitha dugganapalli * Arguments: wwnstr - the string wwn to be transformed
1236ed141cfcSsrivijitha dugganapalli * wwnp - the pointer to 64 bit wwn
1237936b7af6Sjw149990 */
1238936b7af6Sjw149990 int
scsi_wwnstr_to_wwn(const char * wwnstr,uint64_t * wwnp)1239ed141cfcSsrivijitha dugganapalli scsi_wwnstr_to_wwn(const char *wwnstr, uint64_t *wwnp)
1240936b7af6Sjw149990 {
1241936b7af6Sjw149990 int i;
1242936b7af6Sjw149990 char cl, ch;
1243936b7af6Sjw149990 uint64_t tmp;
1244936b7af6Sjw149990
1245ed141cfcSsrivijitha dugganapalli if (wwnp == NULL)
1246936b7af6Sjw149990 return (DDI_FAILURE);
1247ed141cfcSsrivijitha dugganapalli *wwnp = 0;
1248936b7af6Sjw149990
1249ed141cfcSsrivijitha dugganapalli if (wwnstr == NULL)
1250ed141cfcSsrivijitha dugganapalli return (DDI_FAILURE);
1251ed141cfcSsrivijitha dugganapalli
1252ed141cfcSsrivijitha dugganapalli /* Skip leading 'w' if wwnstr is in unit-address form */
12534c06356bSdh142964 wwnstr = scsi_wwnstr_skip_ua_prefix(wwnstr);
1254ed141cfcSsrivijitha dugganapalli
1255ed141cfcSsrivijitha dugganapalli if (strlen(wwnstr) != 16)
1256ed141cfcSsrivijitha dugganapalli return (DDI_FAILURE);
1257ed141cfcSsrivijitha dugganapalli
1258936b7af6Sjw149990 for (i = 0; i < 8; i++) {
1259ed141cfcSsrivijitha dugganapalli ch = ctoi(*wwnstr++);
1260ed141cfcSsrivijitha dugganapalli cl = ctoi(*wwnstr++);
1261936b7af6Sjw149990 if (cl == -1 || ch == -1) {
1262936b7af6Sjw149990 return (DDI_FAILURE);
1263936b7af6Sjw149990 }
1264936b7af6Sjw149990 tmp = (ch << 4) + cl;
1265ed141cfcSsrivijitha dugganapalli *wwnp = (*wwnp << 8) | tmp;
1266936b7af6Sjw149990 }
1267936b7af6Sjw149990 return (DDI_SUCCESS);
1268936b7af6Sjw149990 }
1269ed141cfcSsrivijitha dugganapalli
1270ed141cfcSsrivijitha dugganapalli /*
1271ed141cfcSsrivijitha dugganapalli * Function: scsi_wwn_to_wwnstr
1272ed141cfcSsrivijitha dugganapalli *
1273ed141cfcSsrivijitha dugganapalli * Description: This routine translates from a uint64 wwn to a wwnstr
1274ed141cfcSsrivijitha dugganapalli *
1275ed141cfcSsrivijitha dugganapalli * Arguments:
1276ed141cfcSsrivijitha dugganapalli * wwn - the 64 bit wwn
1277ed141cfcSsrivijitha dugganapalli * unit_address_form - do we want a leading 'w'?
1278ed141cfcSsrivijitha dugganapalli * wwnstr - allow caller to perform wwnstr allocation.
1279ed141cfcSsrivijitha dugganapalli * If non-NULL, don't use scsi_free_wwnstr(),
1280ed141cfcSsrivijitha dugganapalli * and make sure you provide 18/17 bytes of space.
1281ed141cfcSsrivijitha dugganapalli */
1282ed141cfcSsrivijitha dugganapalli char *
scsi_wwn_to_wwnstr(uint64_t wwn,int unit_address_form,char * wwnstr)1283ed141cfcSsrivijitha dugganapalli scsi_wwn_to_wwnstr(uint64_t wwn, int unit_address_form, char *wwnstr)
1284ed141cfcSsrivijitha dugganapalli {
1285ed141cfcSsrivijitha dugganapalli int len;
1286ed141cfcSsrivijitha dugganapalli
1287ed141cfcSsrivijitha dugganapalli /* make space for leading 'w' */
1288ed141cfcSsrivijitha dugganapalli if (unit_address_form)
1289ed141cfcSsrivijitha dugganapalli len = 1 + 16 + 1; /* "w0123456789abcdef\0" */
1290ed141cfcSsrivijitha dugganapalli else
1291ed141cfcSsrivijitha dugganapalli len = 16 + 1; /* "0123456789abcdef\0" */
1292ed141cfcSsrivijitha dugganapalli
1293ed141cfcSsrivijitha dugganapalli if (wwnstr == NULL) {
1294ed141cfcSsrivijitha dugganapalli /* We allocate, caller uses scsi_free_wwnstr(). */
1295ed141cfcSsrivijitha dugganapalli if ((wwnstr = DEVID_MALLOC(len)) == NULL)
1296ed141cfcSsrivijitha dugganapalli return (NULL);
1297ed141cfcSsrivijitha dugganapalli }
1298ed141cfcSsrivijitha dugganapalli
1299ed141cfcSsrivijitha dugganapalli if (unit_address_form)
1300ed141cfcSsrivijitha dugganapalli (void) snprintf(wwnstr, len, "w%016" PRIx64, wwn);
1301ed141cfcSsrivijitha dugganapalli else
1302ed141cfcSsrivijitha dugganapalli (void) snprintf(wwnstr, len, "%016" PRIx64, wwn);
1303ed141cfcSsrivijitha dugganapalli return (wwnstr);
1304ed141cfcSsrivijitha dugganapalli }
1305ed141cfcSsrivijitha dugganapalli
1306ed141cfcSsrivijitha dugganapalli /*
1307ed141cfcSsrivijitha dugganapalli * Function: scsi_wwnstr_hexcase
1308ed141cfcSsrivijitha dugganapalli *
1309ed141cfcSsrivijitha dugganapalli * Description: This routine switches a wwnstr to upper/lower case hex
1310ed141cfcSsrivijitha dugganapalli * (a wwnstr uses lower-case hex by default).
1311ed141cfcSsrivijitha dugganapalli *
1312ed141cfcSsrivijitha dugganapalli * Arguments:
1313ed141cfcSsrivijitha dugganapalli * wwnstr - the pointer to the wwnstr string.
1314ed141cfcSsrivijitha dugganapalli * upper_case_hex - non-zero will convert to upper_case hex
1315ed141cfcSsrivijitha dugganapalli * zero will convert to lower case hex.
1316ed141cfcSsrivijitha dugganapalli */
1317ed141cfcSsrivijitha dugganapalli void
scsi_wwnstr_hexcase(char * wwnstr,int upper_case_hex)1318ed141cfcSsrivijitha dugganapalli scsi_wwnstr_hexcase(char *wwnstr, int upper_case_hex)
1319ed141cfcSsrivijitha dugganapalli {
1320ed141cfcSsrivijitha dugganapalli char *s;
1321ed141cfcSsrivijitha dugganapalli char c;
1322ed141cfcSsrivijitha dugganapalli
1323ed141cfcSsrivijitha dugganapalli for (s = wwnstr; *s; s++) {
1324ed141cfcSsrivijitha dugganapalli c = *s;
1325ed141cfcSsrivijitha dugganapalli if ((upper_case_hex != 0) &&
1326ed141cfcSsrivijitha dugganapalli ((c >= 'a') && (c <= 'f')))
1327ed141cfcSsrivijitha dugganapalli c -= ('a' - 'A'); /* lower to upper */
1328ed141cfcSsrivijitha dugganapalli else if ((upper_case_hex == 0) &&
1329ed141cfcSsrivijitha dugganapalli ((c >= 'A') && (c <= 'F')))
1330ed141cfcSsrivijitha dugganapalli c += ('a' - 'A'); /* upper to lower */
1331ed141cfcSsrivijitha dugganapalli *s = c;
1332ed141cfcSsrivijitha dugganapalli }
1333ed141cfcSsrivijitha dugganapalli }
1334ed141cfcSsrivijitha dugganapalli
1335ed141cfcSsrivijitha dugganapalli /*
13364c06356bSdh142964 * Function: scsi_wwnstr_skip_ua_prefix
13374c06356bSdh142964 *
13384c06356bSdh142964 * Description: This routine removes the leading 'w' in wwnstr,
13394c06356bSdh142964 * if its in unit-address form.
13404c06356bSdh142964 *
13414c06356bSdh142964 * Arguments: wwnstr - the string wwn to be transformed
13424c06356bSdh142964 *
13434c06356bSdh142964 */
13444c06356bSdh142964 const char *
scsi_wwnstr_skip_ua_prefix(const char * wwnstr)13454c06356bSdh142964 scsi_wwnstr_skip_ua_prefix(const char *wwnstr)
13464c06356bSdh142964 {
13474c06356bSdh142964 if (*wwnstr == 'w')
13484c06356bSdh142964 wwnstr++;
13494c06356bSdh142964 return (wwnstr);
13504c06356bSdh142964 }
13514c06356bSdh142964
13524c06356bSdh142964 /*
1353ed141cfcSsrivijitha dugganapalli * Function: scsi_wwnstr_free
1354ed141cfcSsrivijitha dugganapalli *
1355ed141cfcSsrivijitha dugganapalli * Description: This routine frees a wwnstr returned by a call
1356ed141cfcSsrivijitha dugganapalli * to scsi_wwn_to_strwwn with a NULL wwnstr argument.
1357ed141cfcSsrivijitha dugganapalli *
1358ed141cfcSsrivijitha dugganapalli * Arguments:
1359ed141cfcSsrivijitha dugganapalli * wwnstr - the pointer to the wwnstr string to free.
1360ed141cfcSsrivijitha dugganapalli */
1361ed141cfcSsrivijitha dugganapalli void
scsi_free_wwnstr(char * wwnstr)1362ed141cfcSsrivijitha dugganapalli scsi_free_wwnstr(char *wwnstr)
1363ed141cfcSsrivijitha dugganapalli {
1364ed141cfcSsrivijitha dugganapalli #ifdef _KERNEL
1365ed141cfcSsrivijitha dugganapalli kmem_free(wwnstr, strlen(wwnstr) + 1);
1366ed141cfcSsrivijitha dugganapalli #else /* _KERNEL */
1367ed141cfcSsrivijitha dugganapalli free(wwnstr);
1368ed141cfcSsrivijitha dugganapalli #endif /* _KERNEL */
1369ed141cfcSsrivijitha dugganapalli }
1370ed141cfcSsrivijitha dugganapalli
1371ed141cfcSsrivijitha dugganapalli /*
1372ed141cfcSsrivijitha dugganapalli * Function: scsi_lun_to_lun64/scsi_lun64_to_lun
1373ed141cfcSsrivijitha dugganapalli *
1374ed141cfcSsrivijitha dugganapalli * Description: Convert between normalized (SCSI-3) LUN format, as
1375ed141cfcSsrivijitha dugganapalli * described by scsi_lun_t, and a normalized lun64_t
1376ed141cfcSsrivijitha dugganapalli * representation (used by Solaris SCSI_ADDR_PROP_LUN64
1377ed141cfcSsrivijitha dugganapalli * "lun64" property). The normalized representation maps
1378ed141cfcSsrivijitha dugganapalli * in a compatible way to SCSI-2 LUNs. See scsi_address.h
1379ed141cfcSsrivijitha dugganapalli *
1380ed141cfcSsrivijitha dugganapalli * SCSI-3 LUNs are 64 bits. SCSI-2 LUNs are 3 bits (up to
1381ed141cfcSsrivijitha dugganapalli * 5 bits in non-compliant implementations). SCSI-3 will
1382ed141cfcSsrivijitha dugganapalli * pass a (64-bit) scsi_lun_t, but we need a
1383ed141cfcSsrivijitha dugganapalli * representation from which we can for example, make
1384ed141cfcSsrivijitha dugganapalli * device names. For unit-address compatibility, we represent
1385ed141cfcSsrivijitha dugganapalli * 64-bit LUN numbers in such a way that they appear like they
1386ed141cfcSsrivijitha dugganapalli * would have under SCSI-2. This means that the single level
1387ed141cfcSsrivijitha dugganapalli * LUN number is in the lowest byte with the second,
1388ed141cfcSsrivijitha dugganapalli * third, and fourth level LUNs represented in
1389ed141cfcSsrivijitha dugganapalli * successively higher bytes. In particular, if (and only
1390ed141cfcSsrivijitha dugganapalli * if) the first byte of a 64 bit LUN is zero, denoting
1391ed141cfcSsrivijitha dugganapalli * "Peripheral Device Addressing Method" and "Bus
1392ed141cfcSsrivijitha dugganapalli * Identifier" zero, then the target implements LUNs
1393ed141cfcSsrivijitha dugganapalli * compatible in spirit with SCSI-2 LUNs (although under
1394ed141cfcSsrivijitha dugganapalli * SCSI-3 there may be up to 256 of them). Under SCSI-3
1395ed141cfcSsrivijitha dugganapalli * rules, a target is *required* to use this format if it
1396ed141cfcSsrivijitha dugganapalli * contains 256 or fewer Logical Units, none of which are
1397ed141cfcSsrivijitha dugganapalli * dependent logical units. These routines have knowledge
1398ed141cfcSsrivijitha dugganapalli * of the structure and size of a scsi_lun_t.
1399ed141cfcSsrivijitha dugganapalli *
1400ed141cfcSsrivijitha dugganapalli * NOTE: We tolerate vendors that use "Single level LUN structure using
1401ed141cfcSsrivijitha dugganapalli * peripheral device addressing method" with a non-zero bus identifier
1402ed141cfcSsrivijitha dugganapalli * (spec says bus identifier must be zero). Described another way, we let
1403ed141cfcSsrivijitha dugganapalli * the non-'addressing method' bits of sl_lun1_msb contribute to our lun64
1404ed141cfcSsrivijitha dugganapalli * value).
1405ed141cfcSsrivijitha dugganapalli */
1406ed141cfcSsrivijitha dugganapalli scsi_lun64_t
scsi_lun_to_lun64(scsi_lun_t lun)1407ed141cfcSsrivijitha dugganapalli scsi_lun_to_lun64(scsi_lun_t lun)
1408ed141cfcSsrivijitha dugganapalli {
1409ed141cfcSsrivijitha dugganapalli scsi_lun64_t lun64;
1410ed141cfcSsrivijitha dugganapalli
1411ed141cfcSsrivijitha dugganapalli /*
1412ed141cfcSsrivijitha dugganapalli * Check to see if we have a single level lun that uses the
1413ed141cfcSsrivijitha dugganapalli * "Peripheral Device" addressing method. If so, the lun64 value is
1414ed141cfcSsrivijitha dugganapalli * kept in Solaris 'unit-address compatibility' form.
1415ed141cfcSsrivijitha dugganapalli */
1416ed141cfcSsrivijitha dugganapalli if (((lun.sl_lun2_msb == 0) && (lun.sl_lun2_lsb == 0) &&
1417ed141cfcSsrivijitha dugganapalli (lun.sl_lun3_msb == 0) && (lun.sl_lun3_lsb == 0) &&
1418ed141cfcSsrivijitha dugganapalli (lun.sl_lun4_msb == 0) && (lun.sl_lun4_lsb == 0)) &&
1419ed141cfcSsrivijitha dugganapalli ((lun.sl_lun1_msb & SCSI_LUN_AM_MASK) == SCSI_LUN_AM_PDEV)) {
1420ed141cfcSsrivijitha dugganapalli /*
1421ed141cfcSsrivijitha dugganapalli * LUN has Solaris 'unit-address compatibility' form, construct
1422ed141cfcSsrivijitha dugganapalli * lun64 value from non-'addressing method' bits of msb and lsb.
1423ed141cfcSsrivijitha dugganapalli */
1424ed141cfcSsrivijitha dugganapalli lun64 = ((lun.sl_lun1_msb & ~SCSI_LUN_AM_MASK) << 8) |
1425ed141cfcSsrivijitha dugganapalli lun.sl_lun1_lsb;
1426ed141cfcSsrivijitha dugganapalli } else {
1427ed141cfcSsrivijitha dugganapalli /*
1428ed141cfcSsrivijitha dugganapalli * LUN does not have a Solaris 'unit-address compatibility'
1429ed141cfcSsrivijitha dugganapalli * form, construct lun64 value in full 64 bit LUN format.
1430ed141cfcSsrivijitha dugganapalli */
1431ed141cfcSsrivijitha dugganapalli lun64 =
1432ed141cfcSsrivijitha dugganapalli ((scsi_lun64_t)lun.sl_lun1_msb << 56) |
1433ed141cfcSsrivijitha dugganapalli ((scsi_lun64_t)lun.sl_lun1_lsb << 48) |
1434ed141cfcSsrivijitha dugganapalli ((scsi_lun64_t)lun.sl_lun2_msb << 40) |
1435ed141cfcSsrivijitha dugganapalli ((scsi_lun64_t)lun.sl_lun2_lsb << 32) |
1436ed141cfcSsrivijitha dugganapalli ((scsi_lun64_t)lun.sl_lun3_msb << 24) |
1437ed141cfcSsrivijitha dugganapalli ((scsi_lun64_t)lun.sl_lun3_lsb << 16) |
1438ed141cfcSsrivijitha dugganapalli ((scsi_lun64_t)lun.sl_lun4_msb << 8) |
1439ed141cfcSsrivijitha dugganapalli (scsi_lun64_t)lun.sl_lun4_lsb;
1440ed141cfcSsrivijitha dugganapalli }
1441ed141cfcSsrivijitha dugganapalli return (lun64);
1442ed141cfcSsrivijitha dugganapalli }
1443ed141cfcSsrivijitha dugganapalli
1444ed141cfcSsrivijitha dugganapalli scsi_lun_t
scsi_lun64_to_lun(scsi_lun64_t lun64)1445ed141cfcSsrivijitha dugganapalli scsi_lun64_to_lun(scsi_lun64_t lun64)
1446ed141cfcSsrivijitha dugganapalli {
1447ed141cfcSsrivijitha dugganapalli scsi_lun_t lun;
1448ed141cfcSsrivijitha dugganapalli
1449ed141cfcSsrivijitha dugganapalli if (lun64 <= (((0xFF & ~SCSI_LUN_AM_MASK) << 8) | 0xFF)) {
1450ed141cfcSsrivijitha dugganapalli /*
1451ed141cfcSsrivijitha dugganapalli * lun64 is in Solaris 'unit-address compatibility' form.
1452ed141cfcSsrivijitha dugganapalli */
1453ed141cfcSsrivijitha dugganapalli lun.sl_lun1_msb = SCSI_LUN_AM_PDEV | (lun64 >> 8);
1454ed141cfcSsrivijitha dugganapalli lun.sl_lun1_lsb = (uchar_t)lun64;
1455ed141cfcSsrivijitha dugganapalli lun.sl_lun2_msb = 0;
1456ed141cfcSsrivijitha dugganapalli lun.sl_lun2_lsb = 0;
1457ed141cfcSsrivijitha dugganapalli lun.sl_lun3_msb = 0;
1458ed141cfcSsrivijitha dugganapalli lun.sl_lun3_lsb = 0;
1459ed141cfcSsrivijitha dugganapalli lun.sl_lun4_msb = 0;
1460ed141cfcSsrivijitha dugganapalli lun.sl_lun4_lsb = 0;
1461ed141cfcSsrivijitha dugganapalli } else {
1462ed141cfcSsrivijitha dugganapalli /* lun64 is in full 64 bit LUN format. */
1463ed141cfcSsrivijitha dugganapalli lun.sl_lun1_msb = (uchar_t)(lun64 >> 56);
1464ed141cfcSsrivijitha dugganapalli lun.sl_lun1_lsb = (uchar_t)(lun64 >> 48);
1465ed141cfcSsrivijitha dugganapalli lun.sl_lun2_msb = (uchar_t)(lun64 >> 40);
1466ed141cfcSsrivijitha dugganapalli lun.sl_lun2_lsb = (uchar_t)(lun64 >> 32);
1467ed141cfcSsrivijitha dugganapalli lun.sl_lun3_msb = (uchar_t)(lun64 >> 24);
1468ed141cfcSsrivijitha dugganapalli lun.sl_lun3_lsb = (uchar_t)(lun64 >> 16);
1469ed141cfcSsrivijitha dugganapalli lun.sl_lun4_msb = (uchar_t)(lun64 >> 8);
1470ed141cfcSsrivijitha dugganapalli lun.sl_lun4_lsb = (uchar_t)(lun64);
1471ed141cfcSsrivijitha dugganapalli }
1472ed141cfcSsrivijitha dugganapalli return (lun);
1473ed141cfcSsrivijitha dugganapalli }
1474*96c4a178SChris Horne
1475*96c4a178SChris Horne /*
1476*96c4a178SChris Horne * This routine returns the true length of the ascii inquiry fields that are to
1477*96c4a178SChris Horne * be created by removing the padded spaces at the end of the inquiry data.
1478*96c4a178SChris Horne * This routine was designed for trimming spaces from the vid, pid and revision
1479*96c4a178SChris Horne * which are defined as being left aligned. In addition, we return 0 length
1480*96c4a178SChris Horne * if the field is full of all 0's or spaces, indicating to the caller that
1481*96c4a178SChris Horne * the device was not ready to return the inquiry data as per note 65 in
1482*96c4a178SChris Horne * the scsi-2 spec.
1483*96c4a178SChris Horne */
1484*96c4a178SChris Horne int
scsi_ascii_inquiry_len(char * field,size_t length)1485*96c4a178SChris Horne scsi_ascii_inquiry_len(char *field, size_t length)
1486*96c4a178SChris Horne {
1487*96c4a178SChris Horne int retval;
1488*96c4a178SChris Horne int trailer;
1489*96c4a178SChris Horne char *p;
1490*96c4a178SChris Horne
1491*96c4a178SChris Horne retval = length;
1492*96c4a178SChris Horne
1493*96c4a178SChris Horne /*
1494*96c4a178SChris Horne * The vid, pid and revision are left-aligned ascii fields within the
1495*96c4a178SChris Horne * inquiry data. Here we trim the end of these fields by discounting
1496*96c4a178SChris Horne * length associated with trailing spaces or NULL bytes. The remaining
1497*96c4a178SChris Horne * bytes shall be only graphics codes - 0x20 through 0x7e as per the
1498*96c4a178SChris Horne * scsi spec definition. If we have all 0's or spaces, we return 0
1499*96c4a178SChris Horne * length. For devices that store inquiry data on the device, they
1500*96c4a178SChris Horne * can return 0's or spaces in these fields until the data is avail-
1501*96c4a178SChris Horne * able from the device (See NOTE 65 in the scsi-2 specification
1502*96c4a178SChris Horne * around the inquiry command.) We don't want to create a field in
1503*96c4a178SChris Horne * the case of a device not able to return valid data.
1504*96c4a178SChris Horne */
1505*96c4a178SChris Horne trailer = 1;
1506*96c4a178SChris Horne for (p = field + length - 1; p >= field; p--) {
1507*96c4a178SChris Horne if (trailer) {
1508*96c4a178SChris Horne if ((*p == ' ') || (*p == '\0')) {
1509*96c4a178SChris Horne retval--;
1510*96c4a178SChris Horne continue;
1511*96c4a178SChris Horne }
1512*96c4a178SChris Horne trailer = 0;
1513*96c4a178SChris Horne }
1514*96c4a178SChris Horne
1515*96c4a178SChris Horne /* each char must be within 0x20 - 0x7e */
1516*96c4a178SChris Horne if (*p < 0x20 || *p > 0x7e) {
1517*96c4a178SChris Horne retval = -1;
1518*96c4a178SChris Horne break;
1519*96c4a178SChris Horne }
1520*96c4a178SChris Horne
1521*96c4a178SChris Horne }
1522*96c4a178SChris Horne
1523*96c4a178SChris Horne return (retval);
1524*96c4a178SChris Horne }
1525