1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 27*7c478bd9Sstevel@tonic-gate 28*7c478bd9Sstevel@tonic-gate /* 29*7c478bd9Sstevel@tonic-gate * These functions are used to encode SCSI INQUIRY data into 30*7c478bd9Sstevel@tonic-gate * Solaris devid / guid values. 31*7c478bd9Sstevel@tonic-gate */ 32*7c478bd9Sstevel@tonic-gate 33*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/stropts.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/debug.h> 36*7c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h> 37*7c478bd9Sstevel@tonic-gate #include <sys/dditypes.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/scsi/scsi.h> 40*7c478bd9Sstevel@tonic-gate #include "devid_impl.h" 41*7c478bd9Sstevel@tonic-gate 42*7c478bd9Sstevel@tonic-gate #define SCSI_INQUIRY_VID_POS 9 43*7c478bd9Sstevel@tonic-gate #define SCSI_INQUIRY_VID_SUN "SUN" 44*7c478bd9Sstevel@tonic-gate #define SCSI_INQUIRY_VID_SUN_LEN 3 45*7c478bd9Sstevel@tonic-gate #define SCSI_INQUIRY_VID_EMC "EMC " 46*7c478bd9Sstevel@tonic-gate #define SCSI_INQUIRY_VID_EMC_LEN 8 47*7c478bd9Sstevel@tonic-gate #define SCSI_INQUIRY_PID_EMC_SYMMETRIX "SYMMETRIX " 48*7c478bd9Sstevel@tonic-gate #define SCSI_INQUIRY_PID_EMC_SYMMETRIX_LEN 16 49*7c478bd9Sstevel@tonic-gate 50*7c478bd9Sstevel@tonic-gate #define MSG_NOT_STANDARDS_COMPLIANT "!Page83 data not standards compliant " 51*7c478bd9Sstevel@tonic-gate #define MSG_NOT_STANDARDS_COMPLIANT_SIZE ( \ 52*7c478bd9Sstevel@tonic-gate sizeof (MSG_NOT_STANDARDS_COMPLIANT) + \ 53*7c478bd9Sstevel@tonic-gate sizeof (((struct scsi_inquiry *)NULL)->inq_vid) + \ 54*7c478bd9Sstevel@tonic-gate sizeof (((struct scsi_inquiry *)NULL)->inq_pid) + \ 55*7c478bd9Sstevel@tonic-gate sizeof (((struct scsi_inquiry *)NULL)->inq_revision) + 4) 56*7c478bd9Sstevel@tonic-gate 57*7c478bd9Sstevel@tonic-gate #define IS_DEVID_GUID_TYPE(type) ((type == DEVID_SCSI3_WWN) || \ 58*7c478bd9Sstevel@tonic-gate (IS_DEVID_SCSI3_VPD_TYPE(type))) 59*7c478bd9Sstevel@tonic-gate 60*7c478bd9Sstevel@tonic-gate #define IS_DEVID_SCSI_TYPE(type) ((IS_DEVID_GUID_TYPE(type)) || \ 61*7c478bd9Sstevel@tonic-gate (type == DEVID_SCSI_SERIAL)) 62*7c478bd9Sstevel@tonic-gate 63*7c478bd9Sstevel@tonic-gate /* 64*7c478bd9Sstevel@tonic-gate * The max inquiry page 83 size as expected in the code today 65*7c478bd9Sstevel@tonic-gate * is 0xf0 bytes. Defining a constant to make it easy incase 66*7c478bd9Sstevel@tonic-gate * this needs to be changed at a later time. 67*7c478bd9Sstevel@tonic-gate */ 68*7c478bd9Sstevel@tonic-gate 69*7c478bd9Sstevel@tonic-gate #define SCMD_MAX_INQUIRY_PAGE83_SIZE 0xFF 70*7c478bd9Sstevel@tonic-gate #define SCMD_MIN_INQUIRY_PAGE83_SIZE 0x08 71*7c478bd9Sstevel@tonic-gate #define SCMD_INQUIRY_PAGE83_HDR_SIZE 4 72*7c478bd9Sstevel@tonic-gate #define SCSI_INQUIRY_PAGE83_EMC_SYMMETRIX_ID_LEN 16 73*7c478bd9Sstevel@tonic-gate 74*7c478bd9Sstevel@tonic-gate #define SCMD_MAX_INQUIRY_PAGE80_SIZE 0xFF 75*7c478bd9Sstevel@tonic-gate #define SCMD_MIN_INQUIRY_PAGE80_SIZE 0x04 76*7c478bd9Sstevel@tonic-gate 77*7c478bd9Sstevel@tonic-gate #define SCMD_MIN_STANDARD_INQUIRY_SIZE 0x04 78*7c478bd9Sstevel@tonic-gate 79*7c478bd9Sstevel@tonic-gate #define SCMD_INQUIRY_PAGE83_IDENT_DESC_HDR_SIZE 4 80*7c478bd9Sstevel@tonic-gate 81*7c478bd9Sstevel@tonic-gate #define SCMD_INQUIRY_VPD_TYPE_T10 0x01 82*7c478bd9Sstevel@tonic-gate #define SCMD_INQUIRY_VPD_TYPE_EUI 0x02 83*7c478bd9Sstevel@tonic-gate #define SCMD_INQUIRY_VPD_TYPE_NAA 0x03 84*7c478bd9Sstevel@tonic-gate #define SCMD_INQUIRY_VPD_TYPE_RTP 0x04 85*7c478bd9Sstevel@tonic-gate #define SCMD_INQUIRY_VPD_TYPE_TPG 0x05 86*7c478bd9Sstevel@tonic-gate #define SCMD_INQUIRY_VPD_TYPE_LUG 0x06 87*7c478bd9Sstevel@tonic-gate #define SCMD_INQUIRY_VPD_TYPE_MD5 0x07 88*7c478bd9Sstevel@tonic-gate #define SCMD_INQUIRY_VPD_TYPE_SSN 0x08 89*7c478bd9Sstevel@tonic-gate 90*7c478bd9Sstevel@tonic-gate static int is_page83_data_valid(uchar_t *inq83, size_t inq83_len); 91*7c478bd9Sstevel@tonic-gate static int is_page80_data_valid(uchar_t *inq80, size_t inq80_len); 92*7c478bd9Sstevel@tonic-gate static int is_initialized_id(uchar_t *id, size_t id_len); 93*7c478bd9Sstevel@tonic-gate 94*7c478bd9Sstevel@tonic-gate static void encode_scsi3_page83(int version, uchar_t *inq83, 95*7c478bd9Sstevel@tonic-gate size_t inq83_len, uchar_t **id, size_t *id_len, ushort_t *id_type); 96*7c478bd9Sstevel@tonic-gate static void encode_scsi3_page83_emc(int version, uchar_t *inq83, 97*7c478bd9Sstevel@tonic-gate size_t inq83_len, uchar_t **id, size_t *id_len, ushort_t *id_type); 98*7c478bd9Sstevel@tonic-gate static void encode_serialnum(int version, uchar_t *inq, uchar_t *inq80, 99*7c478bd9Sstevel@tonic-gate size_t inq80_len, uchar_t **id, size_t *id_len, ushort_t *id_type); 100*7c478bd9Sstevel@tonic-gate static void encode_sun_serialnum(int version, uchar_t *inq, 101*7c478bd9Sstevel@tonic-gate size_t inq_len, uchar_t **id, size_t *id_len, ushort_t *id_type); 102*7c478bd9Sstevel@tonic-gate 103*7c478bd9Sstevel@tonic-gate static int devid_scsi_init(char *driver_name, 104*7c478bd9Sstevel@tonic-gate uchar_t *raw_id, size_t raw_id_len, ushort_t raw_id_type, 105*7c478bd9Sstevel@tonic-gate ddi_devid_t *ret_devid); 106*7c478bd9Sstevel@tonic-gate 107*7c478bd9Sstevel@tonic-gate /* 108*7c478bd9Sstevel@tonic-gate * Function: ddi_/devid_scsi_encode 109*7c478bd9Sstevel@tonic-gate * 110*7c478bd9Sstevel@tonic-gate * Description: This routine finds and encodes a unique devid 111*7c478bd9Sstevel@tonic-gate * 112*7c478bd9Sstevel@tonic-gate * Arguments: version - id encode algorithm version 113*7c478bd9Sstevel@tonic-gate * driver_name - binding driver name (if ! known use NULL) 114*7c478bd9Sstevel@tonic-gate * inq - standard inquiry buffer 115*7c478bd9Sstevel@tonic-gate * inq_len - standard inquiry buffer length 116*7c478bd9Sstevel@tonic-gate * inq80 - serial number inquiry buffer 117*7c478bd9Sstevel@tonic-gate * inq80_len - serial number inquiry buffer length 118*7c478bd9Sstevel@tonic-gate * inq83 - vpd inquiry buffer 119*7c478bd9Sstevel@tonic-gate * inq83_len - vpd inquiry buffer length 120*7c478bd9Sstevel@tonic-gate * devid - id returned 121*7c478bd9Sstevel@tonic-gate * 122*7c478bd9Sstevel@tonic-gate * Return Code: DEVID_SUCCESS - success 123*7c478bd9Sstevel@tonic-gate * DEVID_FAILURE - failure 124*7c478bd9Sstevel@tonic-gate * DEVID_RETRY - LUN is in a transitional state. A delay should 125*7c478bd9Sstevel@tonic-gate * occur and then this inquiry data should be re-acquired and 126*7c478bd9Sstevel@tonic-gate * this function should be called again. 127*7c478bd9Sstevel@tonic-gate */ 128*7c478bd9Sstevel@tonic-gate int 129*7c478bd9Sstevel@tonic-gate #ifdef _KERNEL 130*7c478bd9Sstevel@tonic-gate ddi_devid_scsi_encode( 131*7c478bd9Sstevel@tonic-gate #else /* ! _KERNEL */ 132*7c478bd9Sstevel@tonic-gate devid_scsi_encode( 133*7c478bd9Sstevel@tonic-gate #endif /* _KERNEL */ 134*7c478bd9Sstevel@tonic-gate int version, /* IN */ 135*7c478bd9Sstevel@tonic-gate char *driver_name, /* IN */ 136*7c478bd9Sstevel@tonic-gate uchar_t *inq, /* IN */ 137*7c478bd9Sstevel@tonic-gate size_t inq_len, /* IN */ 138*7c478bd9Sstevel@tonic-gate uchar_t *inq80, /* IN */ 139*7c478bd9Sstevel@tonic-gate size_t inq80_len, /* IN */ 140*7c478bd9Sstevel@tonic-gate uchar_t *inq83, /* IN */ 141*7c478bd9Sstevel@tonic-gate size_t inq83_len, /* IN */ 142*7c478bd9Sstevel@tonic-gate ddi_devid_t *devid) /* OUT */ 143*7c478bd9Sstevel@tonic-gate { 144*7c478bd9Sstevel@tonic-gate int rval = DEVID_FAILURE; 145*7c478bd9Sstevel@tonic-gate uchar_t *id = NULL; 146*7c478bd9Sstevel@tonic-gate size_t id_len = 0; 147*7c478bd9Sstevel@tonic-gate ushort_t id_type = DEVID_NONE; 148*7c478bd9Sstevel@tonic-gate struct scsi_inquiry *inq_std = (struct scsi_inquiry *)inq; 149*7c478bd9Sstevel@tonic-gate #ifdef _KERNEL 150*7c478bd9Sstevel@tonic-gate char *msg = NULL; 151*7c478bd9Sstevel@tonic-gate #endif /* _KERNEL */ 152*7c478bd9Sstevel@tonic-gate 153*7c478bd9Sstevel@tonic-gate DEVID_ASSERT(devid != NULL); 154*7c478bd9Sstevel@tonic-gate 155*7c478bd9Sstevel@tonic-gate /* verify valid version */ 156*7c478bd9Sstevel@tonic-gate if (version > DEVID_SCSI_ENCODE_VERSION_LATEST) { 157*7c478bd9Sstevel@tonic-gate return (rval); 158*7c478bd9Sstevel@tonic-gate } 159*7c478bd9Sstevel@tonic-gate 160*7c478bd9Sstevel@tonic-gate /* make sure minimum inquiry bytes are available */ 161*7c478bd9Sstevel@tonic-gate if (inq_len < SCMD_MIN_STANDARD_INQUIRY_SIZE) { 162*7c478bd9Sstevel@tonic-gate return (rval); 163*7c478bd9Sstevel@tonic-gate } 164*7c478bd9Sstevel@tonic-gate 165*7c478bd9Sstevel@tonic-gate /* 166*7c478bd9Sstevel@tonic-gate * If 0x83 is availible, that is the best choice. Our next choice is 167*7c478bd9Sstevel@tonic-gate * 0x80. If neither are availible, we leave it to the caller to 168*7c478bd9Sstevel@tonic-gate * determine possible alternate ID, although discouraged. In the 169*7c478bd9Sstevel@tonic-gate * case of the target drivers they create a fabricated id which is 170*7c478bd9Sstevel@tonic-gate * stored in the acyl. The HBA drivers should avoid using an 171*7c478bd9Sstevel@tonic-gate * alternate id. Although has already created a hack of using the 172*7c478bd9Sstevel@tonic-gate * node wwn in some cases. Which needs to be carried forward for 173*7c478bd9Sstevel@tonic-gate * legacy reasons. 174*7c478bd9Sstevel@tonic-gate */ 175*7c478bd9Sstevel@tonic-gate if (inq83 != NULL) { 176*7c478bd9Sstevel@tonic-gate /* 177*7c478bd9Sstevel@tonic-gate * Perform page 83 validation tests and report offenders. 178*7c478bd9Sstevel@tonic-gate * We cannot enforce the page 83 specification because 179*7c478bd9Sstevel@tonic-gate * many Sun partners (ex. HDS) do not conform to the 180*7c478bd9Sstevel@tonic-gate * standards yet. 181*7c478bd9Sstevel@tonic-gate */ 182*7c478bd9Sstevel@tonic-gate if (is_page83_data_valid(inq83, inq83_len) == 183*7c478bd9Sstevel@tonic-gate DEVID_RET_INVALID) { 184*7c478bd9Sstevel@tonic-gate /* 185*7c478bd9Sstevel@tonic-gate * invalid page 83 data. bug 4939576 introduced 186*7c478bd9Sstevel@tonic-gate * handling for EMC non-standard data. 187*7c478bd9Sstevel@tonic-gate */ 188*7c478bd9Sstevel@tonic-gate if ((bcmp(inq_std->inq_vid, SCSI_INQUIRY_VID_EMC, 189*7c478bd9Sstevel@tonic-gate SCSI_INQUIRY_VID_EMC_LEN) == 0) && 190*7c478bd9Sstevel@tonic-gate (bcmp(inq_std->inq_pid, 191*7c478bd9Sstevel@tonic-gate SCSI_INQUIRY_PID_EMC_SYMMETRIX, 192*7c478bd9Sstevel@tonic-gate SCSI_INQUIRY_PID_EMC_SYMMETRIX_LEN) == 0)) { 193*7c478bd9Sstevel@tonic-gate encode_scsi3_page83_emc(version, inq83, 194*7c478bd9Sstevel@tonic-gate inq83_len, &id, &id_len, &id_type); 195*7c478bd9Sstevel@tonic-gate } 196*7c478bd9Sstevel@tonic-gate 197*7c478bd9Sstevel@tonic-gate #ifdef _KERNEL 198*7c478bd9Sstevel@tonic-gate /* 199*7c478bd9Sstevel@tonic-gate * report the page 0x83 standards violation. 200*7c478bd9Sstevel@tonic-gate */ 201*7c478bd9Sstevel@tonic-gate msg = kmem_alloc(MSG_NOT_STANDARDS_COMPLIANT_SIZE, 202*7c478bd9Sstevel@tonic-gate KM_SLEEP); 203*7c478bd9Sstevel@tonic-gate (void) strcpy(msg, MSG_NOT_STANDARDS_COMPLIANT); 204*7c478bd9Sstevel@tonic-gate (void) strncat(msg, inq_std->inq_vid, 205*7c478bd9Sstevel@tonic-gate sizeof (inq_std->inq_vid)); 206*7c478bd9Sstevel@tonic-gate (void) strcat(msg, " "); 207*7c478bd9Sstevel@tonic-gate (void) strncat(msg, inq_std->inq_pid, 208*7c478bd9Sstevel@tonic-gate sizeof (inq_std->inq_pid)); 209*7c478bd9Sstevel@tonic-gate (void) strcat(msg, " "); 210*7c478bd9Sstevel@tonic-gate (void) strncat(msg, inq_std->inq_revision, 211*7c478bd9Sstevel@tonic-gate sizeof (inq_std->inq_revision)); 212*7c478bd9Sstevel@tonic-gate (void) strcat(msg, "\n"); 213*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, msg); 214*7c478bd9Sstevel@tonic-gate kmem_free(msg, MSG_NOT_STANDARDS_COMPLIANT_SIZE); 215*7c478bd9Sstevel@tonic-gate #endif /* _KERNEL */ 216*7c478bd9Sstevel@tonic-gate } 217*7c478bd9Sstevel@tonic-gate 218*7c478bd9Sstevel@tonic-gate if (id_type == DEVID_NONE) { 219*7c478bd9Sstevel@tonic-gate encode_scsi3_page83(version, inq83, 220*7c478bd9Sstevel@tonic-gate inq83_len, &id, &id_len, &id_type); 221*7c478bd9Sstevel@tonic-gate } 222*7c478bd9Sstevel@tonic-gate } 223*7c478bd9Sstevel@tonic-gate 224*7c478bd9Sstevel@tonic-gate /* 225*7c478bd9Sstevel@tonic-gate * If no vpd page is available at this point then we 226*7c478bd9Sstevel@tonic-gate * attempt to use a SCSI serial number from page 0x80. 227*7c478bd9Sstevel@tonic-gate */ 228*7c478bd9Sstevel@tonic-gate if ((id_type == DEVID_NONE) && 229*7c478bd9Sstevel@tonic-gate (inq != NULL) && 230*7c478bd9Sstevel@tonic-gate (inq80 != NULL)) { 231*7c478bd9Sstevel@tonic-gate if (is_page80_data_valid(inq80, inq80_len) == DEVID_RET_VALID) { 232*7c478bd9Sstevel@tonic-gate encode_serialnum(version, inq, inq80, 233*7c478bd9Sstevel@tonic-gate inq80_len, &id, &id_len, &id_type); 234*7c478bd9Sstevel@tonic-gate } 235*7c478bd9Sstevel@tonic-gate } 236*7c478bd9Sstevel@tonic-gate 237*7c478bd9Sstevel@tonic-gate /* 238*7c478bd9Sstevel@tonic-gate * If no vpd page or serial is available at this point and 239*7c478bd9Sstevel@tonic-gate * it's a SUN disk it conforms to the disk qual. 850 specifications 240*7c478bd9Sstevel@tonic-gate * and we can fabricate a serial number id based on the standard 241*7c478bd9Sstevel@tonic-gate * inquiry page. 242*7c478bd9Sstevel@tonic-gate */ 243*7c478bd9Sstevel@tonic-gate if ((id_type == DEVID_NONE) && 244*7c478bd9Sstevel@tonic-gate (inq != NULL)) { 245*7c478bd9Sstevel@tonic-gate encode_sun_serialnum(version, inq, inq_len, 246*7c478bd9Sstevel@tonic-gate &id, &id_len, &id_type); 247*7c478bd9Sstevel@tonic-gate } 248*7c478bd9Sstevel@tonic-gate 249*7c478bd9Sstevel@tonic-gate if (id_type != DEVID_NONE) { 250*7c478bd9Sstevel@tonic-gate if (is_initialized_id(id, id_len) == DEVID_RET_VALID) { 251*7c478bd9Sstevel@tonic-gate rval = devid_scsi_init(driver_name, 252*7c478bd9Sstevel@tonic-gate id, id_len, id_type, devid); 253*7c478bd9Sstevel@tonic-gate } else { 254*7c478bd9Sstevel@tonic-gate rval = DEVID_RETRY; 255*7c478bd9Sstevel@tonic-gate } 256*7c478bd9Sstevel@tonic-gate DEVID_FREE(id, id_len); 257*7c478bd9Sstevel@tonic-gate } 258*7c478bd9Sstevel@tonic-gate 259*7c478bd9Sstevel@tonic-gate return (rval); 260*7c478bd9Sstevel@tonic-gate } 261*7c478bd9Sstevel@tonic-gate 262*7c478bd9Sstevel@tonic-gate 263*7c478bd9Sstevel@tonic-gate /* 264*7c478bd9Sstevel@tonic-gate * Function: is_page83_data_valid 265*7c478bd9Sstevel@tonic-gate * 266*7c478bd9Sstevel@tonic-gate * Description: This routine is used to validate the page 0x83 data 267*7c478bd9Sstevel@tonic-gate * passed in valid based on the standards specification. 268*7c478bd9Sstevel@tonic-gate * 269*7c478bd9Sstevel@tonic-gate * Arguments: inq83 - 270*7c478bd9Sstevel@tonic-gate * inq83_len - 271*7c478bd9Sstevel@tonic-gate * 272*7c478bd9Sstevel@tonic-gate * Return Code: DEVID_RET_VALID 273*7c478bd9Sstevel@tonic-gate * DEVID_RET_INVALID 274*7c478bd9Sstevel@tonic-gate * 275*7c478bd9Sstevel@tonic-gate */ 276*7c478bd9Sstevel@tonic-gate static int 277*7c478bd9Sstevel@tonic-gate is_page83_data_valid(uchar_t *inq83, size_t inq83_len) 278*7c478bd9Sstevel@tonic-gate { 279*7c478bd9Sstevel@tonic-gate 280*7c478bd9Sstevel@tonic-gate int covered_desc_len = 0; 281*7c478bd9Sstevel@tonic-gate int dlen = 0; 282*7c478bd9Sstevel@tonic-gate uchar_t *dblk = NULL; 283*7c478bd9Sstevel@tonic-gate 284*7c478bd9Sstevel@tonic-gate DEVID_ASSERT(inq83 != NULL); 285*7c478bd9Sstevel@tonic-gate 286*7c478bd9Sstevel@tonic-gate /* if not large enough fail */ 287*7c478bd9Sstevel@tonic-gate if (inq83_len < SCMD_MIN_INQUIRY_PAGE83_SIZE) 288*7c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID); 289*7c478bd9Sstevel@tonic-gate 290*7c478bd9Sstevel@tonic-gate /* 291*7c478bd9Sstevel@tonic-gate * Ensuring that the Peripheral device type(bits 0 - 4) has 292*7c478bd9Sstevel@tonic-gate * the valid settings - the value 0x1f indicates no device type. 293*7c478bd9Sstevel@tonic-gate * Only this value can be validated since all other fields are 294*7c478bd9Sstevel@tonic-gate * either used or reserved. 295*7c478bd9Sstevel@tonic-gate */ 296*7c478bd9Sstevel@tonic-gate if ((inq83[0] & DTYPE_MASK) == DTYPE_UNKNOWN) { 297*7c478bd9Sstevel@tonic-gate /* failed-peripheral devtype */ 298*7c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID); 299*7c478bd9Sstevel@tonic-gate } 300*7c478bd9Sstevel@tonic-gate 301*7c478bd9Sstevel@tonic-gate /* 302*7c478bd9Sstevel@tonic-gate * Ensure that the page length field - third and 4th bytes 303*7c478bd9Sstevel@tonic-gate * contain a non zero length value. Our implementation 304*7c478bd9Sstevel@tonic-gate * does not seem to expect more that 255 bytes of data... 305*7c478bd9Sstevel@tonic-gate * what is to be done if the reported size is > 255 bytes? 306*7c478bd9Sstevel@tonic-gate * Yes the device will return only 255 bytes as we provide 307*7c478bd9Sstevel@tonic-gate * buffer to house only that much data but the standards 308*7c478bd9Sstevel@tonic-gate * prevent the targets from reporting the truncated size 309*7c478bd9Sstevel@tonic-gate * in this field. 310*7c478bd9Sstevel@tonic-gate * 311*7c478bd9Sstevel@tonic-gate * Currently reporting sizes more than 255 as failure. 312*7c478bd9Sstevel@tonic-gate * 313*7c478bd9Sstevel@tonic-gate */ 314*7c478bd9Sstevel@tonic-gate 315*7c478bd9Sstevel@tonic-gate if ((inq83[2] == 0) && (inq83[3] == 0)) { 316*7c478bd9Sstevel@tonic-gate /* length field is 0! */ 317*7c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID); 318*7c478bd9Sstevel@tonic-gate } 319*7c478bd9Sstevel@tonic-gate if (inq83[3] > (SCMD_MAX_INQUIRY_PAGE83_SIZE - 3)) { 320*7c478bd9Sstevel@tonic-gate /* length field exceeds expected size of 255 bytes */ 321*7c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID); 322*7c478bd9Sstevel@tonic-gate } 323*7c478bd9Sstevel@tonic-gate 324*7c478bd9Sstevel@tonic-gate /* 325*7c478bd9Sstevel@tonic-gate * Validation of individual descriptor blocks are done in the 326*7c478bd9Sstevel@tonic-gate * following while loop. It is possible to have multiple 327*7c478bd9Sstevel@tonic-gate * descriptor blocks. 328*7c478bd9Sstevel@tonic-gate * the 'dblk' pointer will be pointing to the start of 329*7c478bd9Sstevel@tonic-gate * each entry of the descriptor block. 330*7c478bd9Sstevel@tonic-gate */ 331*7c478bd9Sstevel@tonic-gate covered_desc_len = 0; 332*7c478bd9Sstevel@tonic-gate dblk = &inq83[4]; /* start of first decriptor blk */ 333*7c478bd9Sstevel@tonic-gate while (covered_desc_len < inq83[3]) { 334*7c478bd9Sstevel@tonic-gate 335*7c478bd9Sstevel@tonic-gate /* 336*7c478bd9Sstevel@tonic-gate * Ensure that the length field is non zero 337*7c478bd9Sstevel@tonic-gate * Further length validations will be done 338*7c478bd9Sstevel@tonic-gate * along with the 'identifier type' as some of 339*7c478bd9Sstevel@tonic-gate * the lengths are dependent on it. 340*7c478bd9Sstevel@tonic-gate */ 341*7c478bd9Sstevel@tonic-gate dlen = dblk[3]; 342*7c478bd9Sstevel@tonic-gate if (dlen == 0) { 343*7c478bd9Sstevel@tonic-gate /* descr length is 0 */ 344*7c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID); 345*7c478bd9Sstevel@tonic-gate } 346*7c478bd9Sstevel@tonic-gate 347*7c478bd9Sstevel@tonic-gate /* 348*7c478bd9Sstevel@tonic-gate * ensure that the size of the descriptor block does 349*7c478bd9Sstevel@tonic-gate * not claim to be larger than the entire page83 350*7c478bd9Sstevel@tonic-gate * data that has been received. 351*7c478bd9Sstevel@tonic-gate */ 352*7c478bd9Sstevel@tonic-gate if ((covered_desc_len + dlen) > inq83[3]) { 353*7c478bd9Sstevel@tonic-gate /* failed-descr length */ 354*7c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID); 355*7c478bd9Sstevel@tonic-gate } 356*7c478bd9Sstevel@tonic-gate 357*7c478bd9Sstevel@tonic-gate /* 358*7c478bd9Sstevel@tonic-gate * The spec says that if the PIV field is 0 OR the 359*7c478bd9Sstevel@tonic-gate * association field contains value other than 1 and 2, 360*7c478bd9Sstevel@tonic-gate * then the protocol identifier field should be ignored. 361*7c478bd9Sstevel@tonic-gate * If association field contains a value of 1 or 2 362*7c478bd9Sstevel@tonic-gate * and the PIV field is set, then the protocol identifier 363*7c478bd9Sstevel@tonic-gate * field has to be validated. 364*7c478bd9Sstevel@tonic-gate * The protocol identifier values 0 - f are either assigned 365*7c478bd9Sstevel@tonic-gate * or reserved. Nothing to validate here, hence skipping 366*7c478bd9Sstevel@tonic-gate * over to the next check. 367*7c478bd9Sstevel@tonic-gate */ 368*7c478bd9Sstevel@tonic-gate 369*7c478bd9Sstevel@tonic-gate /* 370*7c478bd9Sstevel@tonic-gate * Check for valid code set values. 371*7c478bd9Sstevel@tonic-gate * All possible values are reserved or assigned. Nothing 372*7c478bd9Sstevel@tonic-gate * to validate - skipping over. 373*7c478bd9Sstevel@tonic-gate */ 374*7c478bd9Sstevel@tonic-gate 375*7c478bd9Sstevel@tonic-gate /* 376*7c478bd9Sstevel@tonic-gate * Identifier Type validation 377*7c478bd9Sstevel@tonic-gate * All SPC3rev22 identified types and the expected lengths 378*7c478bd9Sstevel@tonic-gate * are validated. 379*7c478bd9Sstevel@tonic-gate */ 380*7c478bd9Sstevel@tonic-gate switch (dblk[1] & 0x0f) { 381*7c478bd9Sstevel@tonic-gate case SCMD_INQUIRY_VPD_TYPE_T10: /* T10 vendor Id */ 382*7c478bd9Sstevel@tonic-gate /* No specific length validation required */ 383*7c478bd9Sstevel@tonic-gate break; 384*7c478bd9Sstevel@tonic-gate 385*7c478bd9Sstevel@tonic-gate case SCMD_INQUIRY_VPD_TYPE_EUI: /* EUI 64 ID */ 386*7c478bd9Sstevel@tonic-gate /* EUI-64: size is expected to be 8, 12, or 16 bytes */ 387*7c478bd9Sstevel@tonic-gate if ((dlen != 8) && (dlen != 12) && (dlen != 16)) { 388*7c478bd9Sstevel@tonic-gate /* page83 validation failed-EIU64 */ 389*7c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID); 390*7c478bd9Sstevel@tonic-gate } 391*7c478bd9Sstevel@tonic-gate break; 392*7c478bd9Sstevel@tonic-gate 393*7c478bd9Sstevel@tonic-gate case SCMD_INQUIRY_VPD_TYPE_NAA: /* NAA Id type */ 394*7c478bd9Sstevel@tonic-gate 395*7c478bd9Sstevel@tonic-gate /* 396*7c478bd9Sstevel@tonic-gate * the size for this varies - 397*7c478bd9Sstevel@tonic-gate * IEEE extended/registered is 8 bytes 398*7c478bd9Sstevel@tonic-gate * IEEE Registered extended is 16 bytes 399*7c478bd9Sstevel@tonic-gate */ 400*7c478bd9Sstevel@tonic-gate switch (dblk[4] & 0xf0) { 401*7c478bd9Sstevel@tonic-gate 402*7c478bd9Sstevel@tonic-gate case 0x20: /* IEEE Ext */ 403*7c478bd9Sstevel@tonic-gate case 0x50: /* IEEE Reg */ 404*7c478bd9Sstevel@tonic-gate if (dlen != 8) { 405*7c478bd9Sstevel@tonic-gate /* failed-IEE E/R len */ 406*7c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID); 407*7c478bd9Sstevel@tonic-gate } 408*7c478bd9Sstevel@tonic-gate /* 409*7c478bd9Sstevel@tonic-gate * the codeSet for this MUST 410*7c478bd9Sstevel@tonic-gate * be set to 1 411*7c478bd9Sstevel@tonic-gate */ 412*7c478bd9Sstevel@tonic-gate if ((dblk[0] & 0x0f) != 1) { 413*7c478bd9Sstevel@tonic-gate /* 414*7c478bd9Sstevel@tonic-gate * failed-IEEE E/R 415*7c478bd9Sstevel@tonic-gate * codeSet != 1. 416*7c478bd9Sstevel@tonic-gate */ 417*7c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID); 418*7c478bd9Sstevel@tonic-gate } 419*7c478bd9Sstevel@tonic-gate break; 420*7c478bd9Sstevel@tonic-gate 421*7c478bd9Sstevel@tonic-gate case 0x60: /* IEEE EXT REG */ 422*7c478bd9Sstevel@tonic-gate if (dlen != 16) { 423*7c478bd9Sstevel@tonic-gate /* failed-IEEE ER len */ 424*7c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID); 425*7c478bd9Sstevel@tonic-gate } 426*7c478bd9Sstevel@tonic-gate /* 427*7c478bd9Sstevel@tonic-gate * the codeSet for this MUST 428*7c478bd9Sstevel@tonic-gate * be set to 1 429*7c478bd9Sstevel@tonic-gate */ 430*7c478bd9Sstevel@tonic-gate if ((dblk[0] & 0x0f) != 1) { 431*7c478bd9Sstevel@tonic-gate /* 432*7c478bd9Sstevel@tonic-gate * failed-IEEE ER 433*7c478bd9Sstevel@tonic-gate * codeSet != 1. 434*7c478bd9Sstevel@tonic-gate */ 435*7c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID); 436*7c478bd9Sstevel@tonic-gate } 437*7c478bd9Sstevel@tonic-gate break; 438*7c478bd9Sstevel@tonic-gate 439*7c478bd9Sstevel@tonic-gate default: 440*7c478bd9Sstevel@tonic-gate /* reserved values */ 441*7c478bd9Sstevel@tonic-gate break; 442*7c478bd9Sstevel@tonic-gate } 443*7c478bd9Sstevel@tonic-gate break; 444*7c478bd9Sstevel@tonic-gate 445*7c478bd9Sstevel@tonic-gate case SCMD_INQUIRY_VPD_TYPE_RTP: /* Relative Target port */ 446*7c478bd9Sstevel@tonic-gate if (dlen != 4) { 447*7c478bd9Sstevel@tonic-gate /* failed-Rel target Port length */ 448*7c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID); 449*7c478bd9Sstevel@tonic-gate } 450*7c478bd9Sstevel@tonic-gate break; 451*7c478bd9Sstevel@tonic-gate 452*7c478bd9Sstevel@tonic-gate case SCMD_INQUIRY_VPD_TYPE_TPG: /* Target port group */ 453*7c478bd9Sstevel@tonic-gate if (dlen != 4) { 454*7c478bd9Sstevel@tonic-gate /* failed-target Port group length */ 455*7c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID); 456*7c478bd9Sstevel@tonic-gate } 457*7c478bd9Sstevel@tonic-gate break; 458*7c478bd9Sstevel@tonic-gate 459*7c478bd9Sstevel@tonic-gate case SCMD_INQUIRY_VPD_TYPE_LUG: /* Logical unit group */ 460*7c478bd9Sstevel@tonic-gate if (dlen != 4) { 461*7c478bd9Sstevel@tonic-gate /* failed-Logical Unit group length */ 462*7c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID); 463*7c478bd9Sstevel@tonic-gate } 464*7c478bd9Sstevel@tonic-gate break; 465*7c478bd9Sstevel@tonic-gate 466*7c478bd9Sstevel@tonic-gate case SCMD_INQUIRY_VPD_TYPE_MD5: /* MD5 unit group */ 467*7c478bd9Sstevel@tonic-gate if (dlen != 16) { 468*7c478bd9Sstevel@tonic-gate /* failed-MD5 Unit grp */ 469*7c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID); 470*7c478bd9Sstevel@tonic-gate } 471*7c478bd9Sstevel@tonic-gate break; 472*7c478bd9Sstevel@tonic-gate 473*7c478bd9Sstevel@tonic-gate default: 474*7c478bd9Sstevel@tonic-gate break; 475*7c478bd9Sstevel@tonic-gate } 476*7c478bd9Sstevel@tonic-gate 477*7c478bd9Sstevel@tonic-gate /* 478*7c478bd9Sstevel@tonic-gate * Now lets advance to the next descriptor block 479*7c478bd9Sstevel@tonic-gate * and validate it. 480*7c478bd9Sstevel@tonic-gate * the descriptor block size is <descr Header> + <descr Data> 481*7c478bd9Sstevel@tonic-gate * <descr Header> is equal to 4 bytes 482*7c478bd9Sstevel@tonic-gate * <descr Data> is available in dlen or dblk[3]. 483*7c478bd9Sstevel@tonic-gate */ 484*7c478bd9Sstevel@tonic-gate dblk = &dblk[4 + dlen]; 485*7c478bd9Sstevel@tonic-gate 486*7c478bd9Sstevel@tonic-gate /* 487*7c478bd9Sstevel@tonic-gate * update the covered_desc_len so that we can ensure that 488*7c478bd9Sstevel@tonic-gate * the 'while' loop terminates. 489*7c478bd9Sstevel@tonic-gate */ 490*7c478bd9Sstevel@tonic-gate covered_desc_len += (dlen + 4); 491*7c478bd9Sstevel@tonic-gate } 492*7c478bd9Sstevel@tonic-gate return (DEVID_RET_VALID); 493*7c478bd9Sstevel@tonic-gate } 494*7c478bd9Sstevel@tonic-gate 495*7c478bd9Sstevel@tonic-gate 496*7c478bd9Sstevel@tonic-gate /* 497*7c478bd9Sstevel@tonic-gate * Function: is_initialized_id 498*7c478bd9Sstevel@tonic-gate * 499*7c478bd9Sstevel@tonic-gate * Description: Routine to ensure that the ID calculated is not a 500*7c478bd9Sstevel@tonic-gate * space or zero filled ID. Returning a space / zero 501*7c478bd9Sstevel@tonic-gate * filled ID when the luns on the target are not fully 502*7c478bd9Sstevel@tonic-gate * initialized is a valid response from the target as 503*7c478bd9Sstevel@tonic-gate * per the T10 spec. When a space/zero filled ID is 504*7c478bd9Sstevel@tonic-gate * found its information needs to be polled again 505*7c478bd9Sstevel@tonic-gate * after sometime time to see if the luns are fully 506*7c478bd9Sstevel@tonic-gate * initialized to return a valid guid information. 507*7c478bd9Sstevel@tonic-gate * 508*7c478bd9Sstevel@tonic-gate * Arguments: id - raw id 509*7c478bd9Sstevel@tonic-gate * id_len - raw id len 510*7c478bd9Sstevel@tonic-gate * 511*7c478bd9Sstevel@tonic-gate * Return Code: DEVID_VALID - indicates a non space/zero filled id 512*7c478bd9Sstevel@tonic-gate * DEVID_INVALID - indicates id contains uninitialized data 513*7c478bd9Sstevel@tonic-gate * and suggests retry of the collection commands. 514*7c478bd9Sstevel@tonic-gate */ 515*7c478bd9Sstevel@tonic-gate static int 516*7c478bd9Sstevel@tonic-gate is_initialized_id(uchar_t *id, size_t id_len) 517*7c478bd9Sstevel@tonic-gate { 518*7c478bd9Sstevel@tonic-gate int idx; 519*7c478bd9Sstevel@tonic-gate 520*7c478bd9Sstevel@tonic-gate if ((id == NULL) || 521*7c478bd9Sstevel@tonic-gate (id_len == 0)) { 522*7c478bd9Sstevel@tonic-gate /* got id length as 0 fetch info again */ 523*7c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID); 524*7c478bd9Sstevel@tonic-gate } 525*7c478bd9Sstevel@tonic-gate 526*7c478bd9Sstevel@tonic-gate /* First lets check if the guid is filled with spaces */ 527*7c478bd9Sstevel@tonic-gate for (idx = 0; idx < id_len; idx++) { 528*7c478bd9Sstevel@tonic-gate if (id[idx] != ' ') { 529*7c478bd9Sstevel@tonic-gate break; 530*7c478bd9Sstevel@tonic-gate } 531*7c478bd9Sstevel@tonic-gate } 532*7c478bd9Sstevel@tonic-gate 533*7c478bd9Sstevel@tonic-gate /* 534*7c478bd9Sstevel@tonic-gate * Lets exit if we find that it contains ALL spaces 535*7c478bd9Sstevel@tonic-gate * saying that it has an uninitialized guid 536*7c478bd9Sstevel@tonic-gate */ 537*7c478bd9Sstevel@tonic-gate if (idx >= id_len) { 538*7c478bd9Sstevel@tonic-gate /* guid filled with spaces found */ 539*7c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID); 540*7c478bd9Sstevel@tonic-gate } 541*7c478bd9Sstevel@tonic-gate 542*7c478bd9Sstevel@tonic-gate /* 543*7c478bd9Sstevel@tonic-gate * Since we have found that it is not filled with spaces 544*7c478bd9Sstevel@tonic-gate * now lets ensure that the guid is not filled with only 545*7c478bd9Sstevel@tonic-gate * zeros. 546*7c478bd9Sstevel@tonic-gate */ 547*7c478bd9Sstevel@tonic-gate for (idx = 0; idx < id_len; idx ++) { 548*7c478bd9Sstevel@tonic-gate if (id[idx] != 0) { 549*7c478bd9Sstevel@tonic-gate return (DEVID_RET_VALID); 550*7c478bd9Sstevel@tonic-gate } 551*7c478bd9Sstevel@tonic-gate } 552*7c478bd9Sstevel@tonic-gate 553*7c478bd9Sstevel@tonic-gate /* guid filled with zeros found */ 554*7c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID); 555*7c478bd9Sstevel@tonic-gate } 556*7c478bd9Sstevel@tonic-gate 557*7c478bd9Sstevel@tonic-gate 558*7c478bd9Sstevel@tonic-gate /* 559*7c478bd9Sstevel@tonic-gate * Function: is_page80_data_valid 560*7c478bd9Sstevel@tonic-gate * 561*7c478bd9Sstevel@tonic-gate * Description: This routine is used to validate the page 0x80 data 562*7c478bd9Sstevel@tonic-gate * passed in valid based on the standards specification. 563*7c478bd9Sstevel@tonic-gate * 564*7c478bd9Sstevel@tonic-gate * Arguments: inq80 - 565*7c478bd9Sstevel@tonic-gate * inq80_len - 566*7c478bd9Sstevel@tonic-gate * 567*7c478bd9Sstevel@tonic-gate * Return Code: DEVID_RET_VALID 568*7c478bd9Sstevel@tonic-gate * DEVID_RET_INVALID 569*7c478bd9Sstevel@tonic-gate * 570*7c478bd9Sstevel@tonic-gate */ 571*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 572*7c478bd9Sstevel@tonic-gate static int 573*7c478bd9Sstevel@tonic-gate is_page80_data_valid(uchar_t *inq80, size_t inq80_len) 574*7c478bd9Sstevel@tonic-gate { 575*7c478bd9Sstevel@tonic-gate DEVID_ASSERT(inq80); 576*7c478bd9Sstevel@tonic-gate 577*7c478bd9Sstevel@tonic-gate /* if not large enough fail */ 578*7c478bd9Sstevel@tonic-gate if (inq80_len < SCMD_MIN_INQUIRY_PAGE80_SIZE) { 579*7c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID); 580*7c478bd9Sstevel@tonic-gate } 581*7c478bd9Sstevel@tonic-gate 582*7c478bd9Sstevel@tonic-gate /* 583*7c478bd9Sstevel@tonic-gate * (inq80_len - 4) is the size of the buffer space available 584*7c478bd9Sstevel@tonic-gate * for the product serial number. So inq80[3] (ie. product 585*7c478bd9Sstevel@tonic-gate * serial number) should be <= (inq80_len -4). 586*7c478bd9Sstevel@tonic-gate */ 587*7c478bd9Sstevel@tonic-gate if (inq80[3] > (inq80_len - 4)) { 588*7c478bd9Sstevel@tonic-gate return (DEVID_RET_INVALID); 589*7c478bd9Sstevel@tonic-gate } 590*7c478bd9Sstevel@tonic-gate 591*7c478bd9Sstevel@tonic-gate return (DEVID_RET_VALID); 592*7c478bd9Sstevel@tonic-gate } 593*7c478bd9Sstevel@tonic-gate 594*7c478bd9Sstevel@tonic-gate 595*7c478bd9Sstevel@tonic-gate /* 596*7c478bd9Sstevel@tonic-gate * Function: encode_devid_page 597*7c478bd9Sstevel@tonic-gate * 598*7c478bd9Sstevel@tonic-gate * Description: This routine finds the unique devid if available and 599*7c478bd9Sstevel@tonic-gate * fills the devid and length parameters. 600*7c478bd9Sstevel@tonic-gate * 601*7c478bd9Sstevel@tonic-gate * Arguments: version - encode version 602*7c478bd9Sstevel@tonic-gate * inq83 - driver soft state (unit) structure 603*7c478bd9Sstevel@tonic-gate * inq83_len - length of raw inq83 data 604*7c478bd9Sstevel@tonic-gate * id - raw id 605*7c478bd9Sstevel@tonic-gate * id_len - len of raw id 606*7c478bd9Sstevel@tonic-gate * id_type - type of id 607*7c478bd9Sstevel@tonic-gate * 608*7c478bd9Sstevel@tonic-gate * Note: DEVID_NONE is returned in the id_type field 609*7c478bd9Sstevel@tonic-gate * if no supported page 83 id is found. 610*7c478bd9Sstevel@tonic-gate */ 611*7c478bd9Sstevel@tonic-gate static void 612*7c478bd9Sstevel@tonic-gate encode_scsi3_page83(int version, uchar_t *inq83, size_t inq83_len, 613*7c478bd9Sstevel@tonic-gate uchar_t **id, size_t *id_len, ushort_t *id_type) 614*7c478bd9Sstevel@tonic-gate { 615*7c478bd9Sstevel@tonic-gate size_t descriptor_bytes_left = 0; 616*7c478bd9Sstevel@tonic-gate size_t offset = 0; 617*7c478bd9Sstevel@tonic-gate int idx = 0; 618*7c478bd9Sstevel@tonic-gate size_t offset_id_type[4]; 619*7c478bd9Sstevel@tonic-gate 620*7c478bd9Sstevel@tonic-gate DEVID_ASSERT(inq83 != NULL); 621*7c478bd9Sstevel@tonic-gate /* inq83 length was already validate in is_page83_valid */ 622*7c478bd9Sstevel@tonic-gate DEVID_ASSERT(id != NULL); 623*7c478bd9Sstevel@tonic-gate DEVID_ASSERT(id_len != NULL); 624*7c478bd9Sstevel@tonic-gate DEVID_ASSERT(id_type != NULL); 625*7c478bd9Sstevel@tonic-gate 626*7c478bd9Sstevel@tonic-gate /* preset defaults */ 627*7c478bd9Sstevel@tonic-gate *id = NULL; 628*7c478bd9Sstevel@tonic-gate *id_len = 0; 629*7c478bd9Sstevel@tonic-gate *id_type = DEVID_NONE; 630*7c478bd9Sstevel@tonic-gate 631*7c478bd9Sstevel@tonic-gate /* verify we have enough memory for a ident header */ 632*7c478bd9Sstevel@tonic-gate if (inq83_len < SCMD_INQUIRY_PAGE83_HDR_SIZE) { 633*7c478bd9Sstevel@tonic-gate return; 634*7c478bd9Sstevel@tonic-gate } 635*7c478bd9Sstevel@tonic-gate 636*7c478bd9Sstevel@tonic-gate /* 637*7c478bd9Sstevel@tonic-gate * Attempt to validate the page data. Once validated, we'll walk 638*7c478bd9Sstevel@tonic-gate * the descriptors, looking for certain identifier types that will 639*7c478bd9Sstevel@tonic-gate * mark this device with a unique id/wwn. Note the comment below 640*7c478bd9Sstevel@tonic-gate * for what we really want to receive. 641*7c478bd9Sstevel@tonic-gate */ 642*7c478bd9Sstevel@tonic-gate 643*7c478bd9Sstevel@tonic-gate /* 644*7c478bd9Sstevel@tonic-gate * The format of the inq83 data (Device Identification VPD page) is 645*7c478bd9Sstevel@tonic-gate * a header (containing the total length of the page, from which 646*7c478bd9Sstevel@tonic-gate * descriptor_bytes_left is calculated), followed by a list of 647*7c478bd9Sstevel@tonic-gate * identification descriptors. Each identifcation descriptor has a 648*7c478bd9Sstevel@tonic-gate * header which includes the length of the individual identification 649*7c478bd9Sstevel@tonic-gate * descriptor). 650*7c478bd9Sstevel@tonic-gate * 651*7c478bd9Sstevel@tonic-gate * Set the offset to the beginning byte of the first identification 652*7c478bd9Sstevel@tonic-gate * descriptor. We'll index everything from there. 653*7c478bd9Sstevel@tonic-gate */ 654*7c478bd9Sstevel@tonic-gate offset = SCMD_INQUIRY_PAGE83_HDR_SIZE; 655*7c478bd9Sstevel@tonic-gate descriptor_bytes_left = (size_t)((inq83[2] << 8) | inq83[3]); 656*7c478bd9Sstevel@tonic-gate 657*7c478bd9Sstevel@tonic-gate /* 658*7c478bd9Sstevel@tonic-gate * If the raw data states that the data is larger 659*7c478bd9Sstevel@tonic-gate * than what is actually received abort encode. 660*7c478bd9Sstevel@tonic-gate * Otherwise we will run off into unknown memory 661*7c478bd9Sstevel@tonic-gate * on the decode. 662*7c478bd9Sstevel@tonic-gate */ 663*7c478bd9Sstevel@tonic-gate if ((descriptor_bytes_left + offset) > inq83_len) { 664*7c478bd9Sstevel@tonic-gate return; 665*7c478bd9Sstevel@tonic-gate } 666*7c478bd9Sstevel@tonic-gate 667*7c478bd9Sstevel@tonic-gate 668*7c478bd9Sstevel@tonic-gate /* Zero out our offset array */ 669*7c478bd9Sstevel@tonic-gate bzero(offset_id_type, sizeof (offset_id_type)); 670*7c478bd9Sstevel@tonic-gate 671*7c478bd9Sstevel@tonic-gate /* 672*7c478bd9Sstevel@tonic-gate * According to the scsi spec 8.4.3 SPC-2, there could be several 673*7c478bd9Sstevel@tonic-gate * descriptors associated with each lun. Some we care about and some 674*7c478bd9Sstevel@tonic-gate * we don't. This loop is set up to iterate through the descriptors. 675*7c478bd9Sstevel@tonic-gate * We want the 0x03 case which represents an FC-PH, FC-PH3 or FC-FS 676*7c478bd9Sstevel@tonic-gate * Name_Identifier. The spec mentions nothing about ordering, so we 677*7c478bd9Sstevel@tonic-gate * don't assume any. 678*7c478bd9Sstevel@tonic-gate * 679*7c478bd9Sstevel@tonic-gate * We need to check if we've finished walking the list of descriptors, 680*7c478bd9Sstevel@tonic-gate * we also perform additional checks to be sure the newly calculated 681*7c478bd9Sstevel@tonic-gate * offset is within the bounds of the buffer, and the identifier length 682*7c478bd9Sstevel@tonic-gate * (as calculated by the length field in the header) is valid. This is 683*7c478bd9Sstevel@tonic-gate * done to protect against devices which return bad page83 data. 684*7c478bd9Sstevel@tonic-gate */ 685*7c478bd9Sstevel@tonic-gate while ((descriptor_bytes_left > 0) && (offset_id_type[3] == 0) && 686*7c478bd9Sstevel@tonic-gate (offset + SCMD_INQUIRY_PAGE83_IDENT_DESC_HDR_SIZE <= inq83_len) && 687*7c478bd9Sstevel@tonic-gate (offset + SCMD_INQUIRY_PAGE83_IDENT_DESC_HDR_SIZE + 688*7c478bd9Sstevel@tonic-gate (size_t)inq83[offset + 3] <= inq83_len)) { 689*7c478bd9Sstevel@tonic-gate /* 690*7c478bd9Sstevel@tonic-gate * Inspect the Identification descriptor list. Store the 691*7c478bd9Sstevel@tonic-gate * offsets in the devid page separately for 0x03, 0x01 and 692*7c478bd9Sstevel@tonic-gate * 0x02. Identifiers 0x00 and 0x04 are not useful as they 693*7c478bd9Sstevel@tonic-gate * don't represent unique identifiers for a lun. We also 694*7c478bd9Sstevel@tonic-gate * check the association by masking with 0x3f because we want 695*7c478bd9Sstevel@tonic-gate * an association of 0x0 - indicating the identifier field is 696*7c478bd9Sstevel@tonic-gate * associated with the addressed physical or logical device 697*7c478bd9Sstevel@tonic-gate * and not the port. 698*7c478bd9Sstevel@tonic-gate */ 699*7c478bd9Sstevel@tonic-gate switch ((inq83[offset + 1] & 0x3f)) { 700*7c478bd9Sstevel@tonic-gate case SCMD_INQUIRY_VPD_TYPE_T10: 701*7c478bd9Sstevel@tonic-gate offset_id_type[SCMD_INQUIRY_VPD_TYPE_T10] = offset; 702*7c478bd9Sstevel@tonic-gate break; 703*7c478bd9Sstevel@tonic-gate case SCMD_INQUIRY_VPD_TYPE_EUI: 704*7c478bd9Sstevel@tonic-gate offset_id_type[SCMD_INQUIRY_VPD_TYPE_EUI] = offset; 705*7c478bd9Sstevel@tonic-gate break; 706*7c478bd9Sstevel@tonic-gate case SCMD_INQUIRY_VPD_TYPE_NAA: 707*7c478bd9Sstevel@tonic-gate offset_id_type[SCMD_INQUIRY_VPD_TYPE_NAA] = offset; 708*7c478bd9Sstevel@tonic-gate break; 709*7c478bd9Sstevel@tonic-gate default: 710*7c478bd9Sstevel@tonic-gate /* Devid page undesired id type */ 711*7c478bd9Sstevel@tonic-gate break; 712*7c478bd9Sstevel@tonic-gate } 713*7c478bd9Sstevel@tonic-gate /* 714*7c478bd9Sstevel@tonic-gate * Calculate the descriptor bytes left and move to 715*7c478bd9Sstevel@tonic-gate * the beginning byte of the next id descriptor. 716*7c478bd9Sstevel@tonic-gate */ 717*7c478bd9Sstevel@tonic-gate descriptor_bytes_left -= (size_t)(inq83[offset + 3] + 718*7c478bd9Sstevel@tonic-gate SCMD_INQUIRY_PAGE83_IDENT_DESC_HDR_SIZE); 719*7c478bd9Sstevel@tonic-gate offset += (SCMD_INQUIRY_PAGE83_IDENT_DESC_HDR_SIZE + 720*7c478bd9Sstevel@tonic-gate (size_t)inq83[offset + 3]); 721*7c478bd9Sstevel@tonic-gate } 722*7c478bd9Sstevel@tonic-gate 723*7c478bd9Sstevel@tonic-gate offset = 0; 724*7c478bd9Sstevel@tonic-gate 725*7c478bd9Sstevel@tonic-gate /* 726*7c478bd9Sstevel@tonic-gate * We can't depend on an order from a device by identifier type, but 727*7c478bd9Sstevel@tonic-gate * once we have them, we'll walk them in the same order to prevent a 728*7c478bd9Sstevel@tonic-gate * firmware upgrade from breaking our algorithm. Start with the one 729*7c478bd9Sstevel@tonic-gate * we want the most: id_offset_type[3]. 730*7c478bd9Sstevel@tonic-gate */ 731*7c478bd9Sstevel@tonic-gate for (idx = 3; idx > 0; idx--) { 732*7c478bd9Sstevel@tonic-gate if (offset_id_type[idx] > 0) { 733*7c478bd9Sstevel@tonic-gate offset = offset_id_type[idx]; 734*7c478bd9Sstevel@tonic-gate break; 735*7c478bd9Sstevel@tonic-gate } 736*7c478bd9Sstevel@tonic-gate } 737*7c478bd9Sstevel@tonic-gate 738*7c478bd9Sstevel@tonic-gate /* 739*7c478bd9Sstevel@tonic-gate * We have a valid Device ID page, set the length of the 740*7c478bd9Sstevel@tonic-gate * identifier and copy the value into the wwn. 741*7c478bd9Sstevel@tonic-gate */ 742*7c478bd9Sstevel@tonic-gate if (offset > 0) { 743*7c478bd9Sstevel@tonic-gate *id_len = (size_t)inq83[offset + 3]; 744*7c478bd9Sstevel@tonic-gate if ((*id = DEVID_MALLOC(*id_len)) == NULL) { 745*7c478bd9Sstevel@tonic-gate *id_len = 0; 746*7c478bd9Sstevel@tonic-gate return; 747*7c478bd9Sstevel@tonic-gate } 748*7c478bd9Sstevel@tonic-gate bcopy(&inq83[offset + SCMD_INQUIRY_PAGE83_IDENT_DESC_HDR_SIZE], 749*7c478bd9Sstevel@tonic-gate *id, *id_len); 750*7c478bd9Sstevel@tonic-gate 751*7c478bd9Sstevel@tonic-gate /* set devid type */ 752*7c478bd9Sstevel@tonic-gate switch (version) { 753*7c478bd9Sstevel@tonic-gate /* In version 1 all page 83 types were grouped */ 754*7c478bd9Sstevel@tonic-gate case DEVID_SCSI_ENCODE_VERSION1: 755*7c478bd9Sstevel@tonic-gate *id_type = DEVID_SCSI3_WWN; 756*7c478bd9Sstevel@tonic-gate break; 757*7c478bd9Sstevel@tonic-gate /* In version 2 we break page 83 apart to be unique */ 758*7c478bd9Sstevel@tonic-gate case DEVID_SCSI_ENCODE_VERSION2: 759*7c478bd9Sstevel@tonic-gate switch (idx) { 760*7c478bd9Sstevel@tonic-gate case 3: 761*7c478bd9Sstevel@tonic-gate *id_type = DEVID_SCSI3_VPD_NAA; 762*7c478bd9Sstevel@tonic-gate break; 763*7c478bd9Sstevel@tonic-gate case 2: 764*7c478bd9Sstevel@tonic-gate *id_type = DEVID_SCSI3_VPD_EUI; 765*7c478bd9Sstevel@tonic-gate break; 766*7c478bd9Sstevel@tonic-gate case 1: 767*7c478bd9Sstevel@tonic-gate *id_type = DEVID_SCSI3_VPD_T10; 768*7c478bd9Sstevel@tonic-gate break; 769*7c478bd9Sstevel@tonic-gate default: 770*7c478bd9Sstevel@tonic-gate DEVID_FREE(*id, *id_len); 771*7c478bd9Sstevel@tonic-gate *id_len = 0; 772*7c478bd9Sstevel@tonic-gate break; 773*7c478bd9Sstevel@tonic-gate } 774*7c478bd9Sstevel@tonic-gate break; 775*7c478bd9Sstevel@tonic-gate default: 776*7c478bd9Sstevel@tonic-gate DEVID_FREE(*id, *id_len); 777*7c478bd9Sstevel@tonic-gate *id_len = 0; 778*7c478bd9Sstevel@tonic-gate break; 779*7c478bd9Sstevel@tonic-gate } 780*7c478bd9Sstevel@tonic-gate } 781*7c478bd9Sstevel@tonic-gate } 782*7c478bd9Sstevel@tonic-gate 783*7c478bd9Sstevel@tonic-gate 784*7c478bd9Sstevel@tonic-gate /* 785*7c478bd9Sstevel@tonic-gate * Function: encode_scsi3_page83_emc 786*7c478bd9Sstevel@tonic-gate * 787*7c478bd9Sstevel@tonic-gate * Description: Routine to handle proprietary page 83 of EMC Symmetrix 788*7c478bd9Sstevel@tonic-gate * device. Called by ssfcp_handle_page83() 789*7c478bd9Sstevel@tonic-gate * 790*7c478bd9Sstevel@tonic-gate * Arguments: version - encode version 791*7c478bd9Sstevel@tonic-gate * inq83 - scsi page 83 buffer 792*7c478bd9Sstevel@tonic-gate * inq83_len - scsi page 83 buffer size 793*7c478bd9Sstevel@tonic-gate * id - raw emc id 794*7c478bd9Sstevel@tonic-gate * id_len - len of raw emc id 795*7c478bd9Sstevel@tonic-gate * id_type - type of emc id 796*7c478bd9Sstevel@tonic-gate */ 797*7c478bd9Sstevel@tonic-gate static void 798*7c478bd9Sstevel@tonic-gate encode_scsi3_page83_emc(int version, uchar_t *inq83, 799*7c478bd9Sstevel@tonic-gate size_t inq83_len, uchar_t **id, size_t *id_len, ushort_t *id_type) 800*7c478bd9Sstevel@tonic-gate { 801*7c478bd9Sstevel@tonic-gate uchar_t *guidp = NULL; 802*7c478bd9Sstevel@tonic-gate 803*7c478bd9Sstevel@tonic-gate DEVID_ASSERT(inq83 != NULL); 804*7c478bd9Sstevel@tonic-gate DEVID_ASSERT(id != NULL); 805*7c478bd9Sstevel@tonic-gate DEVID_ASSERT(id_len != NULL); 806*7c478bd9Sstevel@tonic-gate DEVID_ASSERT(id_type != NULL); 807*7c478bd9Sstevel@tonic-gate 808*7c478bd9Sstevel@tonic-gate /* preset defaults */ 809*7c478bd9Sstevel@tonic-gate *id = NULL; 810*7c478bd9Sstevel@tonic-gate *id_len = 0; 811*7c478bd9Sstevel@tonic-gate *id_type = DEVID_NONE; 812*7c478bd9Sstevel@tonic-gate 813*7c478bd9Sstevel@tonic-gate /* The initial devid algorithm didn't use EMC page 83 data */ 814*7c478bd9Sstevel@tonic-gate if (version == DEVID_SCSI_ENCODE_VERSION1) { 815*7c478bd9Sstevel@tonic-gate return; 816*7c478bd9Sstevel@tonic-gate } 817*7c478bd9Sstevel@tonic-gate 818*7c478bd9Sstevel@tonic-gate /* EMC page 83 requires atleast 20 bytes */ 819*7c478bd9Sstevel@tonic-gate if (inq83_len < (SCMD_INQUIRY_PAGE83_HDR_SIZE + 820*7c478bd9Sstevel@tonic-gate SCSI_INQUIRY_PAGE83_EMC_SYMMETRIX_ID_LEN)) { 821*7c478bd9Sstevel@tonic-gate return; 822*7c478bd9Sstevel@tonic-gate } 823*7c478bd9Sstevel@tonic-gate 824*7c478bd9Sstevel@tonic-gate /* 825*7c478bd9Sstevel@tonic-gate * The 4th byte in the page 83 info returned is most likely 826*7c478bd9Sstevel@tonic-gate * indicating the length of the id - which 0x10(16 bytes) 827*7c478bd9Sstevel@tonic-gate * and the 5th byte is indicating that the id is of 828*7c478bd9Sstevel@tonic-gate * IEEE Registered Extended Name format(6). Validate 829*7c478bd9Sstevel@tonic-gate * these code prints before proceeding further as the 830*7c478bd9Sstevel@tonic-gate * following proprietary approach is tied to the specific 831*7c478bd9Sstevel@tonic-gate * device type and incase the EMC firmware changes, we will 832*7c478bd9Sstevel@tonic-gate * have to validate for the changed device before we start 833*7c478bd9Sstevel@tonic-gate * supporting such a device. 834*7c478bd9Sstevel@tonic-gate */ 835*7c478bd9Sstevel@tonic-gate if ((inq83[3] != 0x10) || (inq83[4] != 0x60)) { 836*7c478bd9Sstevel@tonic-gate /* unsupported emc symtx device type */ 837*7c478bd9Sstevel@tonic-gate return; 838*7c478bd9Sstevel@tonic-gate } else { 839*7c478bd9Sstevel@tonic-gate guidp = &inq83[SCMD_INQUIRY_PAGE83_HDR_SIZE]; 840*7c478bd9Sstevel@tonic-gate /* 841*7c478bd9Sstevel@tonic-gate * The GUID returned by the EMC device is 842*7c478bd9Sstevel@tonic-gate * in the IEEE Registered Extended Name format(6) 843*7c478bd9Sstevel@tonic-gate * as a result it is of 16 bytes in length. 844*7c478bd9Sstevel@tonic-gate * An IEEE Registered Name format(5) will be of 845*7c478bd9Sstevel@tonic-gate * 8 bytes which is NOT what is being returned 846*7c478bd9Sstevel@tonic-gate * by the device type for which we are providing 847*7c478bd9Sstevel@tonic-gate * the support. 848*7c478bd9Sstevel@tonic-gate */ 849*7c478bd9Sstevel@tonic-gate *id_len = SCSI_INQUIRY_PAGE83_EMC_SYMMETRIX_ID_LEN; 850*7c478bd9Sstevel@tonic-gate if ((*id = DEVID_MALLOC(*id_len)) == NULL) { 851*7c478bd9Sstevel@tonic-gate *id_len = 0; 852*7c478bd9Sstevel@tonic-gate return; 853*7c478bd9Sstevel@tonic-gate } 854*7c478bd9Sstevel@tonic-gate bcopy(guidp, *id, *id_len); 855*7c478bd9Sstevel@tonic-gate 856*7c478bd9Sstevel@tonic-gate /* emc id matches type 3 */ 857*7c478bd9Sstevel@tonic-gate *id_type = DEVID_SCSI3_VPD_NAA; 858*7c478bd9Sstevel@tonic-gate } 859*7c478bd9Sstevel@tonic-gate } 860*7c478bd9Sstevel@tonic-gate 861*7c478bd9Sstevel@tonic-gate 862*7c478bd9Sstevel@tonic-gate /* 863*7c478bd9Sstevel@tonic-gate * Function: encode_serialnum 864*7c478bd9Sstevel@tonic-gate * 865*7c478bd9Sstevel@tonic-gate * Description: This routine finds the unique devid from the inquiry page 866*7c478bd9Sstevel@tonic-gate * 0x80, serial number page. If available and fills the wwn 867*7c478bd9Sstevel@tonic-gate * and length parameters. 868*7c478bd9Sstevel@tonic-gate * 869*7c478bd9Sstevel@tonic-gate * Arguments: version - encode version 870*7c478bd9Sstevel@tonic-gate * inq - standard inquiry data 871*7c478bd9Sstevel@tonic-gate * inq80 - serial inquiry data 872*7c478bd9Sstevel@tonic-gate * inq80_len - serial inquiry data len 873*7c478bd9Sstevel@tonic-gate * id - raw id 874*7c478bd9Sstevel@tonic-gate * id_len - raw id len 875*7c478bd9Sstevel@tonic-gate * id_type - raw id type 876*7c478bd9Sstevel@tonic-gate */ 877*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 878*7c478bd9Sstevel@tonic-gate static void 879*7c478bd9Sstevel@tonic-gate encode_serialnum(int version, uchar_t *inq, uchar_t *inq80, 880*7c478bd9Sstevel@tonic-gate size_t inq80_len, uchar_t **id, size_t *id_len, ushort_t *id_type) 881*7c478bd9Sstevel@tonic-gate { 882*7c478bd9Sstevel@tonic-gate struct scsi_inquiry *inq_std = (struct scsi_inquiry *)inq; 883*7c478bd9Sstevel@tonic-gate int idx = 0; 884*7c478bd9Sstevel@tonic-gate 885*7c478bd9Sstevel@tonic-gate DEVID_ASSERT(inq != NULL); 886*7c478bd9Sstevel@tonic-gate DEVID_ASSERT(inq80 != NULL); 887*7c478bd9Sstevel@tonic-gate DEVID_ASSERT(id != NULL); 888*7c478bd9Sstevel@tonic-gate DEVID_ASSERT(id_len != NULL); 889*7c478bd9Sstevel@tonic-gate DEVID_ASSERT(id_type != NULL); 890*7c478bd9Sstevel@tonic-gate 891*7c478bd9Sstevel@tonic-gate /* preset defaults */ 892*7c478bd9Sstevel@tonic-gate *id = NULL; 893*7c478bd9Sstevel@tonic-gate *id_len = 0; 894*7c478bd9Sstevel@tonic-gate *id_type = DEVID_NONE; 895*7c478bd9Sstevel@tonic-gate 896*7c478bd9Sstevel@tonic-gate /* verify inq80 buffer is large enough for a header */ 897*7c478bd9Sstevel@tonic-gate if (inq80_len < SCMD_MIN_INQUIRY_PAGE80_SIZE) { 898*7c478bd9Sstevel@tonic-gate return; 899*7c478bd9Sstevel@tonic-gate } 900*7c478bd9Sstevel@tonic-gate 901*7c478bd9Sstevel@tonic-gate /* 902*7c478bd9Sstevel@tonic-gate * Attempt to validate the page data. Once validated, we'll check 903*7c478bd9Sstevel@tonic-gate * the serial number. 904*7c478bd9Sstevel@tonic-gate */ 905*7c478bd9Sstevel@tonic-gate *id_len = (size_t)inq80[3]; /* Store Product Serial Number length */ 906*7c478bd9Sstevel@tonic-gate 907*7c478bd9Sstevel@tonic-gate /* verify buffer is large enough for serial number */ 908*7c478bd9Sstevel@tonic-gate if (inq80_len < (*id_len + SCMD_MIN_INQUIRY_PAGE80_SIZE)) { 909*7c478bd9Sstevel@tonic-gate return; 910*7c478bd9Sstevel@tonic-gate } 911*7c478bd9Sstevel@tonic-gate 912*7c478bd9Sstevel@tonic-gate /* 913*7c478bd9Sstevel@tonic-gate * Device returns ASCII space (20h) in all the bytes of successful data 914*7c478bd9Sstevel@tonic-gate * transfer, if the product serial number is not available. So we end 915*7c478bd9Sstevel@tonic-gate * up having to check all the bytes for a space until we reach 916*7c478bd9Sstevel@tonic-gate * something else. 917*7c478bd9Sstevel@tonic-gate */ 918*7c478bd9Sstevel@tonic-gate for (idx = 0; idx < *id_len; idx++) { 919*7c478bd9Sstevel@tonic-gate if (inq80[4 + idx] == ' ') { 920*7c478bd9Sstevel@tonic-gate continue; 921*7c478bd9Sstevel@tonic-gate } 922*7c478bd9Sstevel@tonic-gate /* 923*7c478bd9Sstevel@tonic-gate * The serial number is valid, but since this is only vendor 924*7c478bd9Sstevel@tonic-gate * unique, we'll combine the inquiry vid and pid with the 925*7c478bd9Sstevel@tonic-gate * serial number. 926*7c478bd9Sstevel@tonic-gate */ 927*7c478bd9Sstevel@tonic-gate *id_len += sizeof (inq_std->inq_vid); 928*7c478bd9Sstevel@tonic-gate *id_len += sizeof (inq_std->inq_pid); 929*7c478bd9Sstevel@tonic-gate 930*7c478bd9Sstevel@tonic-gate if ((*id = DEVID_MALLOC(*id_len)) == NULL) { 931*7c478bd9Sstevel@tonic-gate *id_len = 0; 932*7c478bd9Sstevel@tonic-gate return; 933*7c478bd9Sstevel@tonic-gate } 934*7c478bd9Sstevel@tonic-gate 935*7c478bd9Sstevel@tonic-gate bcopy(&inq_std->inq_vid, *id, sizeof (inq_std->inq_vid)); 936*7c478bd9Sstevel@tonic-gate bcopy(&inq_std->inq_pid, &(*id)[sizeof (inq_std->inq_vid)], 937*7c478bd9Sstevel@tonic-gate sizeof (inq_std->inq_pid)); 938*7c478bd9Sstevel@tonic-gate bcopy(&inq80[4], &(*id)[sizeof (inq_std->inq_vid) + 939*7c478bd9Sstevel@tonic-gate sizeof (inq_std->inq_pid)], inq80[3]); 940*7c478bd9Sstevel@tonic-gate 941*7c478bd9Sstevel@tonic-gate *id_type = DEVID_SCSI_SERIAL; 942*7c478bd9Sstevel@tonic-gate break; 943*7c478bd9Sstevel@tonic-gate } 944*7c478bd9Sstevel@tonic-gate 945*7c478bd9Sstevel@tonic-gate /* 946*7c478bd9Sstevel@tonic-gate * The spec suggests that the command could succeed but return all 947*7c478bd9Sstevel@tonic-gate * spaces if the product serial number is not available. In this case 948*7c478bd9Sstevel@tonic-gate * we need to fail this routine. To accomplish this, we compare our 949*7c478bd9Sstevel@tonic-gate * length to the serial number length. If they are the same, then we 950*7c478bd9Sstevel@tonic-gate * never copied in the vid and updated the length. That being the case, 951*7c478bd9Sstevel@tonic-gate * we must not have found a valid serial number. 952*7c478bd9Sstevel@tonic-gate */ 953*7c478bd9Sstevel@tonic-gate if (*id_len == (size_t)inq80[3]) { 954*7c478bd9Sstevel@tonic-gate /* empty unit serial number */ 955*7c478bd9Sstevel@tonic-gate DEVID_FREE(*id, *id_len); 956*7c478bd9Sstevel@tonic-gate *id = NULL; 957*7c478bd9Sstevel@tonic-gate *id_len = 0; 958*7c478bd9Sstevel@tonic-gate } 959*7c478bd9Sstevel@tonic-gate } 960*7c478bd9Sstevel@tonic-gate 961*7c478bd9Sstevel@tonic-gate 962*7c478bd9Sstevel@tonic-gate /* 963*7c478bd9Sstevel@tonic-gate * Function: encode_sun_serialnum 964*7c478bd9Sstevel@tonic-gate * 965*7c478bd9Sstevel@tonic-gate * Description: This routine finds the unique devid from the inquiry page 966*7c478bd9Sstevel@tonic-gate * 0x80, serial number page. If available and fills the wwn 967*7c478bd9Sstevel@tonic-gate * and length parameters. 968*7c478bd9Sstevel@tonic-gate * 969*7c478bd9Sstevel@tonic-gate * Arguments: version - encode version 970*7c478bd9Sstevel@tonic-gate * inq - standard inquiry data 971*7c478bd9Sstevel@tonic-gate * inq_len - standard inquiry data len 972*7c478bd9Sstevel@tonic-gate * id - raw id 973*7c478bd9Sstevel@tonic-gate * id_len - raw id len 974*7c478bd9Sstevel@tonic-gate * id_type - raw id type 975*7c478bd9Sstevel@tonic-gate * 976*7c478bd9Sstevel@tonic-gate * Return Code: DEVID_SUCCESS 977*7c478bd9Sstevel@tonic-gate * DEVID_FAILURE 978*7c478bd9Sstevel@tonic-gate */ 979*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 980*7c478bd9Sstevel@tonic-gate static void 981*7c478bd9Sstevel@tonic-gate encode_sun_serialnum(int version, uchar_t *inq, 982*7c478bd9Sstevel@tonic-gate size_t inq_len, uchar_t **id, size_t *id_len, ushort_t *id_type) 983*7c478bd9Sstevel@tonic-gate { 984*7c478bd9Sstevel@tonic-gate struct scsi_inquiry *inq_std = (struct scsi_inquiry *)inq; 985*7c478bd9Sstevel@tonic-gate 986*7c478bd9Sstevel@tonic-gate DEVID_ASSERT(inq != NULL); 987*7c478bd9Sstevel@tonic-gate DEVID_ASSERT(id != NULL); 988*7c478bd9Sstevel@tonic-gate DEVID_ASSERT(id_len != NULL); 989*7c478bd9Sstevel@tonic-gate DEVID_ASSERT(id_type != NULL); 990*7c478bd9Sstevel@tonic-gate 991*7c478bd9Sstevel@tonic-gate /* verify enough buffer is available */ 992*7c478bd9Sstevel@tonic-gate if (inq_len < SCMD_MIN_STANDARD_INQUIRY_SIZE) { 993*7c478bd9Sstevel@tonic-gate return; 994*7c478bd9Sstevel@tonic-gate } 995*7c478bd9Sstevel@tonic-gate 996*7c478bd9Sstevel@tonic-gate /* sun qual drive */ 997*7c478bd9Sstevel@tonic-gate if ((inq_std != NULL) && 998*7c478bd9Sstevel@tonic-gate (bcmp(&inq_std->inq_pid[SCSI_INQUIRY_VID_POS], 999*7c478bd9Sstevel@tonic-gate SCSI_INQUIRY_VID_SUN, SCSI_INQUIRY_VID_SUN_LEN) == 0)) { 1000*7c478bd9Sstevel@tonic-gate /* 1001*7c478bd9Sstevel@tonic-gate * VPD pages 0x83 and 0x80 are unavailable. This 1002*7c478bd9Sstevel@tonic-gate * is a Sun qualified disks as indicated by 1003*7c478bd9Sstevel@tonic-gate * "SUN" in bytes 25-27 of the inquiry data 1004*7c478bd9Sstevel@tonic-gate * (bytes 9-11 of the pid). Devid's are created 1005*7c478bd9Sstevel@tonic-gate * for Sun qualified disks by combining the 1006*7c478bd9Sstevel@tonic-gate * vendor id with the product id with the serial 1007*7c478bd9Sstevel@tonic-gate * number located in bytes 36-47 of the inquiry data. 1008*7c478bd9Sstevel@tonic-gate */ 1009*7c478bd9Sstevel@tonic-gate 1010*7c478bd9Sstevel@tonic-gate /* get data size */ 1011*7c478bd9Sstevel@tonic-gate *id_len = sizeof (inq_std->inq_vid) + 1012*7c478bd9Sstevel@tonic-gate sizeof (inq_std->inq_pid) + 1013*7c478bd9Sstevel@tonic-gate sizeof (inq_std->inq_serial); 1014*7c478bd9Sstevel@tonic-gate 1015*7c478bd9Sstevel@tonic-gate if ((*id = DEVID_MALLOC(*id_len)) == NULL) { 1016*7c478bd9Sstevel@tonic-gate *id_len = 0; 1017*7c478bd9Sstevel@tonic-gate return; 1018*7c478bd9Sstevel@tonic-gate } 1019*7c478bd9Sstevel@tonic-gate 1020*7c478bd9Sstevel@tonic-gate /* copy the vid at the beginning */ 1021*7c478bd9Sstevel@tonic-gate bcopy(&inq_std->inq_vid, *id, 1022*7c478bd9Sstevel@tonic-gate sizeof (inq_std->inq_vid)); 1023*7c478bd9Sstevel@tonic-gate /* copy the pid after the vid */ 1024*7c478bd9Sstevel@tonic-gate bcopy(&inq_std->inq_pid, 1025*7c478bd9Sstevel@tonic-gate &(*id)[sizeof (inq_std->inq_vid)], 1026*7c478bd9Sstevel@tonic-gate sizeof (inq_std->inq_pid)); 1027*7c478bd9Sstevel@tonic-gate /* copy the serial number after the vid and pid */ 1028*7c478bd9Sstevel@tonic-gate bcopy(&inq_std->inq_serial, 1029*7c478bd9Sstevel@tonic-gate &(*id)[sizeof (inq_std->inq_vid) + 1030*7c478bd9Sstevel@tonic-gate sizeof (inq_std->inq_pid)], 1031*7c478bd9Sstevel@tonic-gate sizeof (inq_std->inq_serial)); 1032*7c478bd9Sstevel@tonic-gate /* devid formed from inquiry data */ 1033*7c478bd9Sstevel@tonic-gate *id_type = DEVID_SCSI_SERIAL; 1034*7c478bd9Sstevel@tonic-gate } 1035*7c478bd9Sstevel@tonic-gate } 1036*7c478bd9Sstevel@tonic-gate 1037*7c478bd9Sstevel@tonic-gate 1038*7c478bd9Sstevel@tonic-gate /* 1039*7c478bd9Sstevel@tonic-gate * Function: devid_scsi_init 1040*7c478bd9Sstevel@tonic-gate * 1041*7c478bd9Sstevel@tonic-gate * Description: This routine is used to create a devid for a scsi 1042*7c478bd9Sstevel@tonic-gate * devid type. 1043*7c478bd9Sstevel@tonic-gate * 1044*7c478bd9Sstevel@tonic-gate * Arguments: hint - driver soft state (unit) structure 1045*7c478bd9Sstevel@tonic-gate * raw_id - pass by reference variable to hold wwn 1046*7c478bd9Sstevel@tonic-gate * raw_id_len - wwn length 1047*7c478bd9Sstevel@tonic-gate * raw_id_type - 1048*7c478bd9Sstevel@tonic-gate * ret_devid - 1049*7c478bd9Sstevel@tonic-gate * 1050*7c478bd9Sstevel@tonic-gate * Return Code: DEVID_SUCCESS 1051*7c478bd9Sstevel@tonic-gate * DEVID_FAILURE 1052*7c478bd9Sstevel@tonic-gate * 1053*7c478bd9Sstevel@tonic-gate */ 1054*7c478bd9Sstevel@tonic-gate static int 1055*7c478bd9Sstevel@tonic-gate devid_scsi_init( 1056*7c478bd9Sstevel@tonic-gate char *driver_name, 1057*7c478bd9Sstevel@tonic-gate uchar_t *raw_id, 1058*7c478bd9Sstevel@tonic-gate size_t raw_id_len, 1059*7c478bd9Sstevel@tonic-gate ushort_t raw_id_type, 1060*7c478bd9Sstevel@tonic-gate ddi_devid_t *ret_devid) 1061*7c478bd9Sstevel@tonic-gate { 1062*7c478bd9Sstevel@tonic-gate impl_devid_t *i_devid = NULL; 1063*7c478bd9Sstevel@tonic-gate int i_devid_len = 0; 1064*7c478bd9Sstevel@tonic-gate int driver_name_len = 0; 1065*7c478bd9Sstevel@tonic-gate ushort_t u_raw_id_len = 0; 1066*7c478bd9Sstevel@tonic-gate 1067*7c478bd9Sstevel@tonic-gate DEVID_ASSERT(raw_id != NULL); 1068*7c478bd9Sstevel@tonic-gate DEVID_ASSERT(ret_devid != NULL); 1069*7c478bd9Sstevel@tonic-gate 1070*7c478bd9Sstevel@tonic-gate if (!IS_DEVID_SCSI_TYPE(raw_id_type)) { 1071*7c478bd9Sstevel@tonic-gate *ret_devid = NULL; 1072*7c478bd9Sstevel@tonic-gate return (DEVID_FAILURE); 1073*7c478bd9Sstevel@tonic-gate } 1074*7c478bd9Sstevel@tonic-gate 1075*7c478bd9Sstevel@tonic-gate i_devid_len = sizeof (*i_devid) + raw_id_len - sizeof (i_devid->did_id); 1076*7c478bd9Sstevel@tonic-gate if ((i_devid = DEVID_MALLOC(i_devid_len)) == NULL) { 1077*7c478bd9Sstevel@tonic-gate *ret_devid = NULL; 1078*7c478bd9Sstevel@tonic-gate return (DEVID_FAILURE); 1079*7c478bd9Sstevel@tonic-gate } 1080*7c478bd9Sstevel@tonic-gate 1081*7c478bd9Sstevel@tonic-gate i_devid->did_magic_hi = DEVID_MAGIC_MSB; 1082*7c478bd9Sstevel@tonic-gate i_devid->did_magic_lo = DEVID_MAGIC_LSB; 1083*7c478bd9Sstevel@tonic-gate i_devid->did_rev_hi = DEVID_REV_MSB; 1084*7c478bd9Sstevel@tonic-gate i_devid->did_rev_lo = DEVID_REV_LSB; 1085*7c478bd9Sstevel@tonic-gate DEVID_FORMTYPE(i_devid, raw_id_type); 1086*7c478bd9Sstevel@tonic-gate u_raw_id_len = raw_id_len; 1087*7c478bd9Sstevel@tonic-gate DEVID_FORMLEN(i_devid, u_raw_id_len); 1088*7c478bd9Sstevel@tonic-gate 1089*7c478bd9Sstevel@tonic-gate /* Fill in driver name hint */ 1090*7c478bd9Sstevel@tonic-gate if (driver_name != NULL) { 1091*7c478bd9Sstevel@tonic-gate driver_name_len = strlen(driver_name); 1092*7c478bd9Sstevel@tonic-gate if (driver_name_len > DEVID_HINT_SIZE) { 1093*7c478bd9Sstevel@tonic-gate /* Pick up last four characters of driver name */ 1094*7c478bd9Sstevel@tonic-gate driver_name += driver_name_len - DEVID_HINT_SIZE; 1095*7c478bd9Sstevel@tonic-gate driver_name_len = DEVID_HINT_SIZE; 1096*7c478bd9Sstevel@tonic-gate } 1097*7c478bd9Sstevel@tonic-gate bcopy(driver_name, i_devid->did_driver, driver_name_len); 1098*7c478bd9Sstevel@tonic-gate } else { 1099*7c478bd9Sstevel@tonic-gate bzero(i_devid->did_driver, DEVID_HINT_SIZE); 1100*7c478bd9Sstevel@tonic-gate } 1101*7c478bd9Sstevel@tonic-gate 1102*7c478bd9Sstevel@tonic-gate bcopy(raw_id, i_devid->did_id, raw_id_len); 1103*7c478bd9Sstevel@tonic-gate 1104*7c478bd9Sstevel@tonic-gate /* return device id */ 1105*7c478bd9Sstevel@tonic-gate *ret_devid = (ddi_devid_t)i_devid; 1106*7c478bd9Sstevel@tonic-gate return (DEVID_SUCCESS); 1107*7c478bd9Sstevel@tonic-gate } 1108*7c478bd9Sstevel@tonic-gate 1109*7c478bd9Sstevel@tonic-gate 1110*7c478bd9Sstevel@tonic-gate /* 1111*7c478bd9Sstevel@tonic-gate * Function: devid_to_guid 1112*7c478bd9Sstevel@tonic-gate * 1113*7c478bd9Sstevel@tonic-gate * Description: This routine extracts a guid string form a devid. 1114*7c478bd9Sstevel@tonic-gate * The common use of this guid is for a HBA driver 1115*7c478bd9Sstevel@tonic-gate * to pass into mdi_pi_alloc(). 1116*7c478bd9Sstevel@tonic-gate * 1117*7c478bd9Sstevel@tonic-gate * Arguments: devid - devid to extract guid from 1118*7c478bd9Sstevel@tonic-gate * 1119*7c478bd9Sstevel@tonic-gate * Return Code: guid string - success 1120*7c478bd9Sstevel@tonic-gate * NULL - failure 1121*7c478bd9Sstevel@tonic-gate */ 1122*7c478bd9Sstevel@tonic-gate char * 1123*7c478bd9Sstevel@tonic-gate #ifdef _KERNEL 1124*7c478bd9Sstevel@tonic-gate ddi_devid_to_guid(ddi_devid_t devid) 1125*7c478bd9Sstevel@tonic-gate #else /* !_KERNEL */ 1126*7c478bd9Sstevel@tonic-gate devid_to_guid(ddi_devid_t devid) 1127*7c478bd9Sstevel@tonic-gate #endif /* _KERNEL */ 1128*7c478bd9Sstevel@tonic-gate { 1129*7c478bd9Sstevel@tonic-gate impl_devid_t *id = (impl_devid_t *)devid; 1130*7c478bd9Sstevel@tonic-gate int len = 0; 1131*7c478bd9Sstevel@tonic-gate int idx = 0; 1132*7c478bd9Sstevel@tonic-gate int num = 0; 1133*7c478bd9Sstevel@tonic-gate char *guid = NULL; 1134*7c478bd9Sstevel@tonic-gate char *ptr = NULL; 1135*7c478bd9Sstevel@tonic-gate char *dp = NULL; 1136*7c478bd9Sstevel@tonic-gate 1137*7c478bd9Sstevel@tonic-gate DEVID_ASSERT(devid != NULL); 1138*7c478bd9Sstevel@tonic-gate 1139*7c478bd9Sstevel@tonic-gate /* NULL devid -> NULL guid */ 1140*7c478bd9Sstevel@tonic-gate if (devid == NULL) 1141*7c478bd9Sstevel@tonic-gate return (NULL); 1142*7c478bd9Sstevel@tonic-gate 1143*7c478bd9Sstevel@tonic-gate if (!IS_DEVID_GUID_TYPE(DEVID_GETTYPE(id))) 1144*7c478bd9Sstevel@tonic-gate return (NULL); 1145*7c478bd9Sstevel@tonic-gate 1146*7c478bd9Sstevel@tonic-gate /* guid is always converted to ascii, append NULL */ 1147*7c478bd9Sstevel@tonic-gate len = DEVID_GETLEN(id); 1148*7c478bd9Sstevel@tonic-gate 1149*7c478bd9Sstevel@tonic-gate /* allocate guid string */ 1150*7c478bd9Sstevel@tonic-gate if ((guid = DEVID_MALLOC((len * 2) + 1)) == NULL) 1151*7c478bd9Sstevel@tonic-gate return (NULL); 1152*7c478bd9Sstevel@tonic-gate 1153*7c478bd9Sstevel@tonic-gate /* perform encode of id to hex string */ 1154*7c478bd9Sstevel@tonic-gate ptr = guid; 1155*7c478bd9Sstevel@tonic-gate for (idx = 0, dp = &id->did_id[0]; idx < len; idx++, dp++) { 1156*7c478bd9Sstevel@tonic-gate num = ((*dp) >> 4) & 0xF; 1157*7c478bd9Sstevel@tonic-gate *ptr++ = (num < 10) ? (num + '0') : (num + ('a' - 10)); 1158*7c478bd9Sstevel@tonic-gate num = (*dp) & 0xF; 1159*7c478bd9Sstevel@tonic-gate *ptr++ = (num < 10) ? (num + '0') : (num + ('a' - 10)); 1160*7c478bd9Sstevel@tonic-gate } 1161*7c478bd9Sstevel@tonic-gate *ptr = 0; 1162*7c478bd9Sstevel@tonic-gate 1163*7c478bd9Sstevel@tonic-gate return (guid); 1164*7c478bd9Sstevel@tonic-gate } 1165*7c478bd9Sstevel@tonic-gate 1166*7c478bd9Sstevel@tonic-gate /* 1167*7c478bd9Sstevel@tonic-gate * Function: devid_free_guid 1168*7c478bd9Sstevel@tonic-gate * 1169*7c478bd9Sstevel@tonic-gate * Description: This routine frees a guid allocated by 1170*7c478bd9Sstevel@tonic-gate * devid_to_guid(). 1171*7c478bd9Sstevel@tonic-gate * 1172*7c478bd9Sstevel@tonic-gate * Arguments: guid - guid to free 1173*7c478bd9Sstevel@tonic-gate */ 1174*7c478bd9Sstevel@tonic-gate void 1175*7c478bd9Sstevel@tonic-gate #ifdef _KERNEL 1176*7c478bd9Sstevel@tonic-gate ddi_devid_free_guid(char *guid) 1177*7c478bd9Sstevel@tonic-gate #else /* !_KERNEL */ 1178*7c478bd9Sstevel@tonic-gate devid_free_guid(char *guid) 1179*7c478bd9Sstevel@tonic-gate #endif /* _KERNEL */ 1180*7c478bd9Sstevel@tonic-gate { 1181*7c478bd9Sstevel@tonic-gate if (guid != NULL) { 1182*7c478bd9Sstevel@tonic-gate DEVID_FREE(guid, strlen(guid) + 1); 1183*7c478bd9Sstevel@tonic-gate } 1184*7c478bd9Sstevel@tonic-gate } 1185