1*96c4a178SChris Horne /* 2*96c4a178SChris Horne * CDDL HEADER START 3*96c4a178SChris Horne * 4*96c4a178SChris Horne * The contents of this file are subject to the terms of the 5*96c4a178SChris Horne * Common Development and Distribution License (the "License"). 6*96c4a178SChris Horne * You may not use this file except in compliance with the License. 7*96c4a178SChris Horne * 8*96c4a178SChris Horne * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*96c4a178SChris Horne * or http://www.opensolaris.org/os/licensing. 10*96c4a178SChris Horne * See the License for the specific language governing permissions 11*96c4a178SChris Horne * and limitations under the License. 12*96c4a178SChris Horne * 13*96c4a178SChris Horne * When distributing Covered Code, include this CDDL HEADER in each 14*96c4a178SChris Horne * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*96c4a178SChris Horne * If applicable, add the following below this CDDL HEADER, with the 16*96c4a178SChris Horne * fields enclosed by brackets "[]" replaced with your own identifying 17*96c4a178SChris Horne * information: Portions Copyright [yyyy] [name of copyright owner] 18*96c4a178SChris Horne * 19*96c4a178SChris Horne * CDDL HEADER END 20*96c4a178SChris Horne */ 21*96c4a178SChris Horne 22*96c4a178SChris Horne /* 23*96c4a178SChris Horne * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24*96c4a178SChris Horne * Use is subject to license terms. 25*96c4a178SChris Horne */ 26*96c4a178SChris Horne 27*96c4a178SChris Horne /* 28*96c4a178SChris Horne * These functions are used to encode SAS SMP address data into 29*96c4a178SChris Horne * Solaris devid / guid values. 30*96c4a178SChris Horne */ 31*96c4a178SChris Horne 32*96c4a178SChris Horne #ifndef _KERNEL 33*96c4a178SChris Horne #include <stdio.h> 34*96c4a178SChris Horne #endif /* _KERNEL */ 35*96c4a178SChris Horne 36*96c4a178SChris Horne #include <sys/inttypes.h> 37*96c4a178SChris Horne #include <sys/types.h> 38*96c4a178SChris Horne #include <sys/stropts.h> 39*96c4a178SChris Horne #include <sys/debug.h> 40*96c4a178SChris Horne #include <sys/isa_defs.h> 41*96c4a178SChris Horne #include <sys/dditypes.h> 42*96c4a178SChris Horne #include <sys/ddi_impldefs.h> 43*96c4a178SChris Horne #include <sys/scsi/scsi.h> 44*96c4a178SChris Horne #include <sys/scsi/generic/smp_frames.h> 45*96c4a178SChris Horne #ifndef _KERNEL 46*96c4a178SChris Horne #include <sys/libdevid.h> 47*96c4a178SChris Horne #endif /* !_KERNEL */ 48*96c4a178SChris Horne #include "devid_impl.h" 49*96c4a178SChris Horne 50*96c4a178SChris Horne /* 51*96c4a178SChris Horne * Typically the wwnstr makes a good devid, however in some cases the wwnstr 52*96c4a178SChris Horne * comes form the location of a FRU in the chassis instead of from the identity 53*96c4a178SChris Horne * of the FRU. The table below provides vid/pid information for such cases. 54*96c4a178SChris Horne * These vidpid strings are matched against smp_report_manufacturer_info_resp 55*96c4a178SChris Horne * data. When a match occurs the srmir_vs_52 field, if non-zero, is used 56*96c4a178SChris Horne * to form the devid. 57*96c4a178SChris Horne */ 58*96c4a178SChris Horne char *vidpid_devid_from_srmir_vs_52[] = { 59*96c4a178SChris Horne /* " 111111" */ 60*96c4a178SChris Horne /* "012345670123456789012345" */ 61*96c4a178SChris Horne /* "|-VID--||-----PID------|" */ 62*96c4a178SChris Horne "SUN GENESIS", 63*96c4a178SChris Horne NULL 64*96c4a178SChris Horne }; 65*96c4a178SChris Horne 66*96c4a178SChris Horne /* 67*96c4a178SChris Horne * Function: ddi_/devid_smp_encode 68*96c4a178SChris Horne * 69*96c4a178SChris Horne * Description: This routine finds and encodes a unique devid given the 70*96c4a178SChris Horne * SAS address of an SMP node. 71*96c4a178SChris Horne * 72*96c4a178SChris Horne * Arguments: version - id encode algorithm version 73*96c4a178SChris Horne * driver_name - binding driver name (if ! known use NULL) 74*96c4a178SChris Horne * wwnstr - smp SAS address in wwnstr (unit-address) form. 75*96c4a178SChris Horne * srmir_buf - REPORT MANUFACTURER INFORMATION response. 76*96c4a178SChris Horne * srmir_len - amount of srmir_buf data. 77*96c4a178SChris Horne * devid - id returned 78*96c4a178SChris Horne * 79*96c4a178SChris Horne * Return Code: DEVID_SUCCESS - success 80*96c4a178SChris Horne * DEVID_FAILURE - failure 81*96c4a178SChris Horne */ 82*96c4a178SChris Horne int 83*96c4a178SChris Horne #ifdef _KERNEL 84*96c4a178SChris Horne ddi_devid_smp_encode( 85*96c4a178SChris Horne #else /* ! _KERNEL */ 86*96c4a178SChris Horne devid_smp_encode( 87*96c4a178SChris Horne #endif /* _KERNEL */ 88*96c4a178SChris Horne int version, /* IN */ 89*96c4a178SChris Horne char *driver_name, /* IN */ 90*96c4a178SChris Horne char *wwnstr, /* IN */ 91*96c4a178SChris Horne uchar_t *srmir_buf, /* IN */ 92*96c4a178SChris Horne size_t srmir_len, /* IN */ 93*96c4a178SChris Horne ddi_devid_t *devid) /* OUT */ 94*96c4a178SChris Horne { 95*96c4a178SChris Horne uint64_t wwn; 96*96c4a178SChris Horne ushort_t raw_id_type; 97*96c4a178SChris Horne ushort_t raw_id_len; 98*96c4a178SChris Horne impl_devid_t *i_devid; 99*96c4a178SChris Horne int i_devid_len; 100*96c4a178SChris Horne int i; 101*96c4a178SChris Horne smp_response_frame_t *srs; 102*96c4a178SChris Horne smp_report_manufacturer_info_resp_t *srmir; 103*96c4a178SChris Horne char **vidpid; 104*96c4a178SChris Horne uint8_t *vsp; 105*96c4a178SChris Horne uint64_t s; 106*96c4a178SChris Horne char sbuf[16 + 1]; 107*96c4a178SChris Horne int vlen, plen, slen; 108*96c4a178SChris Horne int driver_name_len = 0; 109*96c4a178SChris Horne 110*96c4a178SChris Horne DEVID_ASSERT(devid != NULL); 111*96c4a178SChris Horne *devid = NULL; 112*96c4a178SChris Horne 113*96c4a178SChris Horne /* verify valid version */ 114*96c4a178SChris Horne if (version > DEVID_SMP_ENCODE_VERSION_LATEST) 115*96c4a178SChris Horne return (DEVID_FAILURE); 116*96c4a178SChris Horne 117*96c4a178SChris Horne if (wwnstr == NULL) 118*96c4a178SChris Horne return (DEVID_FAILURE); 119*96c4a178SChris Horne 120*96c4a178SChris Horne /* convert wwnstr to binary */ 121*96c4a178SChris Horne if (scsi_wwnstr_to_wwn(wwnstr, &wwn) != DDI_SUCCESS) 122*96c4a178SChris Horne return (DEVID_FAILURE); 123*96c4a178SChris Horne 124*96c4a178SChris Horne if (srmir_buf && 125*96c4a178SChris Horne (srmir_len >= ((sizeof (*srs) - sizeof (srs->srf_data)) + 126*96c4a178SChris Horne sizeof (*srmir)))) { 127*96c4a178SChris Horne srs = (smp_response_frame_t *)srmir_buf; 128*96c4a178SChris Horne srmir = (smp_report_manufacturer_info_resp_t *)srs->srf_data; 129*96c4a178SChris Horne 130*96c4a178SChris Horne for (vidpid = vidpid_devid_from_srmir_vs_52; *vidpid; vidpid++) 131*96c4a178SChris Horne if (strncmp(srmir->srmir_vendor_identification, 132*96c4a178SChris Horne *vidpid, strlen(*vidpid)) == 0) 133*96c4a178SChris Horne break; 134*96c4a178SChris Horne 135*96c4a178SChris Horne /* no vid/pid match, use wwn for devid */ 136*96c4a178SChris Horne if (*vidpid == NULL) 137*96c4a178SChris Horne goto usewwn; 138*96c4a178SChris Horne 139*96c4a178SChris Horne /* extract the special vendor-specific 'devid serial number' */ 140*96c4a178SChris Horne vsp = &srmir->srmir_vs_52[0]; 141*96c4a178SChris Horne s = ((uint64_t)vsp[0] << 56) | 142*96c4a178SChris Horne ((uint64_t)vsp[1] << 48) | 143*96c4a178SChris Horne ((uint64_t)vsp[2] << 40) | 144*96c4a178SChris Horne ((uint64_t)vsp[3] << 32) | 145*96c4a178SChris Horne ((uint64_t)vsp[4] << 24) | 146*96c4a178SChris Horne ((uint64_t)vsp[5] << 16) | 147*96c4a178SChris Horne ((uint64_t)vsp[6] << 8) | 148*96c4a178SChris Horne ((uint64_t)vsp[7]); 149*96c4a178SChris Horne 150*96c4a178SChris Horne /* discount zero value */ 151*96c4a178SChris Horne if (s == 0) 152*96c4a178SChris Horne goto usewwn; 153*96c4a178SChris Horne 154*96c4a178SChris Horne /* compute length (with trailing spaces removed) */ 155*96c4a178SChris Horne vlen = scsi_ascii_inquiry_len( 156*96c4a178SChris Horne srmir->srmir_vendor_identification, 157*96c4a178SChris Horne sizeof (srmir->srmir_vendor_identification)); 158*96c4a178SChris Horne plen = scsi_ascii_inquiry_len( 159*96c4a178SChris Horne srmir->srmir_product_identification, 160*96c4a178SChris Horne sizeof (srmir->srmir_product_identification)); 161*96c4a178SChris Horne slen = snprintf(sbuf, sizeof (sbuf), "%016" PRIx64, s); 162*96c4a178SChris Horne if ((vlen <= 0) || (plen <= 0) || ((slen + 1) != sizeof (sbuf))) 163*96c4a178SChris Horne goto usewwn; 164*96c4a178SChris Horne 165*96c4a178SChris Horne /* this is most like a devid formed from inquiry data */ 166*96c4a178SChris Horne raw_id_type = DEVID_SCSI_SERIAL; 167*96c4a178SChris Horne raw_id_len = vlen + 1 + plen + 1 + slen; 168*96c4a178SChris Horne 169*96c4a178SChris Horne i_devid_len = sizeof (*i_devid) + 170*96c4a178SChris Horne raw_id_len - sizeof (i_devid->did_id); 171*96c4a178SChris Horne if ((i_devid = DEVID_MALLOC(i_devid_len)) == NULL) 172*96c4a178SChris Horne return (DEVID_FAILURE); 173*96c4a178SChris Horne bzero(i_devid, i_devid_len); 174*96c4a178SChris Horne 175*96c4a178SChris Horne /* copy the vid to the beginning */ 176*96c4a178SChris Horne bcopy(&srmir->srmir_vendor_identification, 177*96c4a178SChris Horne &i_devid->did_id[0], vlen); 178*96c4a178SChris Horne i_devid->did_id[vlen] = '.'; 179*96c4a178SChris Horne 180*96c4a178SChris Horne /* copy the pid after the "vid." */ 181*96c4a178SChris Horne bcopy(&srmir->srmir_product_identification, 182*96c4a178SChris Horne &i_devid->did_id[vlen + 1], plen); 183*96c4a178SChris Horne i_devid->did_id[vlen + 1 + plen] = '.'; 184*96c4a178SChris Horne 185*96c4a178SChris Horne /* place the 'devid serial number' buffer the "vid.pid." */ 186*96c4a178SChris Horne bcopy(sbuf, &i_devid->did_id[vlen + 1 + plen + 1], slen); 187*96c4a178SChris Horne } else { 188*96c4a178SChris Horne usewwn: raw_id_type = DEVID_SCSI3_WWN; 189*96c4a178SChris Horne raw_id_len = sizeof (wwn); 190*96c4a178SChris Horne 191*96c4a178SChris Horne i_devid_len = sizeof (*i_devid) + 192*96c4a178SChris Horne raw_id_len - sizeof (i_devid->did_id); 193*96c4a178SChris Horne if ((i_devid = DEVID_MALLOC(i_devid_len)) == NULL) 194*96c4a178SChris Horne return (DEVID_FAILURE); 195*96c4a178SChris Horne bzero(i_devid, i_devid_len); 196*96c4a178SChris Horne 197*96c4a178SChris Horne /* binary devid stores wwn bytes in big-endian order */ 198*96c4a178SChris Horne for (i = 0; i < sizeof (wwn); i++) 199*96c4a178SChris Horne i_devid->did_id[i] = 200*96c4a178SChris Horne (wwn >> ((sizeof (wwn) * 8) - 201*96c4a178SChris Horne ((i + 1) * 8))) & 0xFF; 202*96c4a178SChris Horne 203*96c4a178SChris Horne } 204*96c4a178SChris Horne 205*96c4a178SChris Horne i_devid->did_magic_hi = DEVID_MAGIC_MSB; 206*96c4a178SChris Horne i_devid->did_magic_lo = DEVID_MAGIC_LSB; 207*96c4a178SChris Horne i_devid->did_rev_hi = DEVID_REV_MSB; 208*96c4a178SChris Horne i_devid->did_rev_lo = DEVID_REV_LSB; 209*96c4a178SChris Horne DEVID_FORMTYPE(i_devid, raw_id_type); 210*96c4a178SChris Horne DEVID_FORMLEN(i_devid, raw_id_len); 211*96c4a178SChris Horne 212*96c4a178SChris Horne /* fill in driver name hint */ 213*96c4a178SChris Horne bzero(i_devid->did_driver, DEVID_HINT_SIZE); 214*96c4a178SChris Horne if (driver_name != NULL) { 215*96c4a178SChris Horne driver_name_len = strlen(driver_name); 216*96c4a178SChris Horne if (driver_name_len > DEVID_HINT_SIZE) { 217*96c4a178SChris Horne /* pick up last four characters of driver name */ 218*96c4a178SChris Horne driver_name += driver_name_len - DEVID_HINT_SIZE; 219*96c4a178SChris Horne driver_name_len = DEVID_HINT_SIZE; 220*96c4a178SChris Horne } 221*96c4a178SChris Horne bcopy(driver_name, i_devid->did_driver, driver_name_len); 222*96c4a178SChris Horne } 223*96c4a178SChris Horne 224*96c4a178SChris Horne /* return device id */ 225*96c4a178SChris Horne *devid = (ddi_devid_t)i_devid; 226*96c4a178SChris Horne return (DEVID_SUCCESS); 227*96c4a178SChris Horne } 228