devid_scsi.c revision 4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6
2N/A * The contents of this file are subject to the terms of the 2N/A * Common Development and Distribution License (the "License"). 2N/A * You may not use this file except in compliance with the License. 2N/A * See the License for the specific language governing permissions 2N/A * and limitations under the License. 2N/A * When distributing Covered Code, include this CDDL HEADER in each 2N/A * If applicable, add the following below this CDDL HEADER, with the 2N/A * fields enclosed by brackets "[]" replaced with your own identifying 2N/A * information: Portions Copyright [yyyy] [name of copyright owner] 2N/A * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 2N/A * Use is subject to license terms. 2N/A * These functions are used to encode SCSI INQUIRY data into 2N/A * Solaris devid / guid values. 2N/A#
endif /* !_KERNEL */ * The max inquiry page 83 size as expected in the code today * is 0xf0 bytes. Defining a constant to make it easy incase * this needs to be changed at a later time. static char ctoi(
char c);
* Description: This routine finds and encodes a unique devid * Arguments: version - id encode algorithm version * driver_name - binding driver name (if ! known use NULL) * inq - standard inquiry buffer * inq_len - standard inquiry buffer length * inq80 - serial number inquiry buffer * inq80_len - serial number inquiry buffer length * inq83 - vpd inquiry buffer * inq83_len - vpd inquiry buffer length * Return Code: DEVID_SUCCESS - success * DEVID_FAILURE - failure * DEVID_RETRY - LUN is in a transitional state. A delay should * occur and then this inquiry data should be re-acquired and * this function should be called again. /* verify valid version */ /* make sure minimum inquiry bytes are available */ * If 0x83 is availible, that is the best choice. Our next choice is * 0x80. If neither are availible, we leave it to the caller to * determine possible alternate ID, although discouraged. In the * case of the target drivers they create a fabricated id which is * stored in the acyl. The HBA drivers should avoid using an * alternate id. Although has already created a hack of using the * node wwn in some cases. Which needs to be carried forward for * Perform page 83 validation tests and report offenders. * We cannot enforce the page 83 specification because * many Sun partners (ex. HDS) do not conform to the * invalid page 83 data. bug 4939576 introduced * handling for EMC non-standard data. * invalid page 83 data. Special hack for HDS * specific device, to suppress the warning msg. * report the page 0x83 standards violation. * If no vpd page is available at this point then we * attempt to use a SCSI serial number from page 0x80. * If no vpd page or serial is available at this point and * it's a SUN disk it conforms to the disk qual. 850 specifications * and we can fabricate a serial number id based on the standard * Function: is_page83_data_valid * Description: This routine is used to validate the page 0x83 data * passed in valid based on the standards specification. * Return Code: DEVID_RET_VALID /* if not large enough fail */ * Ensuring that the Peripheral device type(bits 0 - 4) has * the valid settings - the value 0x1f indicates no device type. * Only this value can be validated since all other fields are * either used or reserved. /* failed-peripheral devtype */ * Ensure that the page length field - third and 4th bytes * contain a non zero length value. Our implementation * does not seem to expect more that 255 bytes of data... * what is to be done if the reported size is > 255 bytes? * Yes the device will return only 255 bytes as we provide * buffer to house only that much data but the standards * prevent the targets from reporting the truncated size * Currently reporting sizes more than 255 as failure. /* length field exceeds expected size of 255 bytes */ * Validation of individual descriptor blocks are done in the * following while loop. It is possible to have multiple * the 'dblk' pointer will be pointing to the start of * each entry of the descriptor block. dblk = &
inq83[
4];
/* start of first decriptor blk */ * Ensure that the length field is non zero * Further length validations will be done * along with the 'identifier type' as some of * the lengths are dependent on it. * ensure that the size of the descriptor block does * not claim to be larger than the entire page83 * data that has been received. /* failed-descr length */ * The spec says that if the PIV field is 0 OR the * association field contains value other than 1 and 2, * then the protocol identifier field should be ignored. * If association field contains a value of 1 or 2 * and the PIV field is set, then the protocol identifier * field has to be validated. * The protocol identifier values 0 - f are either assigned * or reserved. Nothing to validate here, hence skipping * over to the next check. * Check for valid code set values. * All possible values are reserved or assigned. Nothing * to validate - skipping over. * Identifier Type validation * All SPC3rev22 identified types and the expected lengths switch (
dblk[
1] &
0x0f) {
/* No specific length validation required */ /* EUI-64: size is expected to be 8, 12, or 16 bytes */ /* page83 validation failed-EIU64 */ * the size for this varies - * IEEE Registered extended is 16 bytes switch (
dblk[
4] &
0xf0) {
case 0x20:
/* IEEE Ext */ case 0x50:
/* IEEE Reg */ * the codeSet for this MUST if ((
dblk[0] &
0x0f) !=
1) {
case 0x60:
/* IEEE EXT REG */ * the codeSet for this MUST if ((
dblk[0] &
0x0f) !=
1) {
/* failed-Rel target Port length */ /* failed-target Port group length */ /* failed-Logical Unit group length */ /* failed-MD5 Unit grp */ * Now lets advance to the next descriptor block * the descriptor block size is <descr Header> + <descr Data> * <descr Header> is equal to 4 bytes * <descr Data> is available in dlen or dblk[3]. * update the covered_desc_len so that we can ensure that * the 'while' loop terminates. * Function: is_initialized_id * Description: Routine to ensure that the ID calculated is not a * space or zero filled ID. Returning a space / zero * filled ID when the luns on the target are not fully * initialized is a valid response from the target as * per the T10 spec. When a space/zero filled ID is * found its information needs to be polled again * after sometime time to see if the luns are fully * initialized to return a valid guid information. * Return Code: DEVID_VALID - indicates a non space/zero filled id * DEVID_INVALID - indicates id contains uninitialized data * and suggests retry of the collection commands. /* got id length as 0 fetch info again */ /* First lets check if the guid is filled with spaces */ * Lets exit if we find that it contains ALL spaces * saying that it has an uninitialized guid /* guid filled with spaces found */ * Since we have found that it is not filled with spaces * now lets ensure that the guid is not filled with only /* guid filled with zeros found */ * Function: is_page80_data_valid * Description: This routine is used to validate the page 0x80 data * passed in valid based on the standards specification. * Return Code: DEVID_RET_VALID /* if not large enough fail */ * (inq80_len - 4) is the size of the buffer space available * for the product serial number. So inq80[3] (ie. product * serial number) should be <= (inq80_len -4). * Function: encode_devid_page * Description: This routine finds the unique devid if available and * fills the devid and length parameters. * Arguments: version - encode version * inq83 - driver soft state (unit) structure * inq83_len - length of raw inq83 data * Note: DEVID_NONE is returned in the id_type field * if no supported page 83 id is found. /* inq83 length was already validate in is_page83_valid */ /* verify we have enough memory for a ident header */ * Attempt to validate the page data. Once validated, we'll walk * the descriptors, looking for certain identifier types that will * mark this device with a unique id/wwn. Note the comment below * for what we really want to receive. * The format of the inq83 data (Device Identification VPD page) is * a header (containing the total length of the page, from which * descriptor_bytes_left is calculated), followed by a list of * identification descriptors. Each identifcation descriptor has a * header which includes the length of the individual identification * Set the offset to the beginning byte of the first identification * descriptor. We'll index everything from there. * If the raw data states that the data is larger * than what is actually received abort encode. * Otherwise we will run off into unknown memory /* Zero out our offset array */ * According to the scsi spec 8.4.3 SPC-2, there could be several * descriptors associated with each lun. Some we care about and some * we don't. This loop is set up to iterate through the descriptors. * We want the 0x03 case which represents an FC-PH, FC-PH3 or FC-FS * Name_Identifier. The spec mentions nothing about ordering, so we * We need to check if we've finished walking the list of descriptors, * we also perform additional checks to be sure the newly calculated * offset is within the bounds of the buffer, and the identifier length * (as calculated by the length field in the header) is valid. This is * done to protect against devices which return bad page83 data. * Inspect the Identification descriptor list. Store the * offsets in the devid page separately for 0x03, 0x01 and * 0x02. Identifiers 0x00 and 0x04 are not useful as they * don't represent unique identifiers for a lun. We also * check the association by masking with 0x3f because we want * an association of 0x0 - indicating the identifier field is * associated with the addressed physical or logical device /* Devid page undesired id type */ * Calculate the descriptor bytes left and move to * the beginning byte of the next id descriptor. * We can't depend on an order from a device by identifier type, but * once we have them, we'll walk them in the same order to prevent a * firmware upgrade from breaking our algorithm. Start with the one * we want the most: id_offset_type[3]. * We have a valid Device ID page, set the length of the * identifier and copy the value into the wwn. /* In version 1 all page 83 types were grouped */ /* In version 2 we break page 83 apart to be unique */ * Function: encode_scsi3_page83_emc * Description: Routine to handle proprietary page 83 of EMC Symmetrix * device. Called by ssfcp_handle_page83() * Arguments: version - encode version * inq83 - scsi page 83 buffer * inq83_len - scsi page 83 buffer size * id_len - len of raw emc id * id_type - type of emc id /* The initial devid algorithm didn't use EMC page 83 data */ /* EMC page 83 requires atleast 20 bytes */ * The 4th byte in the page 83 info returned is most likely * indicating the length of the id - which 0x10(16 bytes) * and the 5th byte is indicating that the id is of * IEEE Registered Extended Name format(6). Validate * these code prints before proceeding further as the * following proprietary approach is tied to the specific * device type and incase the EMC firmware changes, we will * have to validate for the changed device before we start * supporting such a device. /* unsupported emc symtx device type */ * The GUID returned by the EMC device is * in the IEEE Registered Extended Name format(6) * as a result it is of 16 bytes in length. * An IEEE Registered Name format(5) will be of * 8 bytes which is NOT what is being returned * by the device type for which we are providing /* emc id matches type 3 */ * Function: encode_serialnum * Description: This routine finds the unique devid from the inquiry page * 0x80, serial number page. If available and fills the wwn * Arguments: version - encode version * inq - standard inquiry data * inq80 - serial inquiry data * inq80_len - serial inquiry data len /* verify inq80 buffer is large enough for a header */ * Attempt to validate the page data. Once validated, we'll check /* verify buffer is large enough for serial number */ * Device returns ASCII space (20h) in all the bytes of successful data * transfer, if the product serial number is not available. So we end * up having to check all the bytes for a space until we reach * The serial number is valid, but since this is only vendor * unique, we'll combine the inquiry vid and pid with the * The spec suggests that the command could succeed but return all * spaces if the product serial number is not available. In this case * we need to fail this routine. To accomplish this, we compare our * length to the serial number length. If they are the same, then we * never copied in the vid and updated the length. That being the case, * we must not have found a valid serial number. /* empty unit serial number */ * Function: encode_sun_serialnum * Description: This routine finds the unique devid from the inquiry page * 0x80, serial number page. If available and fills the wwn * Arguments: version - encode version * inq - standard inquiry data * inq_len - standard inquiry data len * Return Code: DEVID_SUCCESS /* verify enough buffer is available */ * VPD pages 0x83 and 0x80 are unavailable. This * is a Sun qualified disks as indicated by * "SUN" in bytes 25-27 of the inquiry data * (bytes 9-11 of the pid). Devid's are created * for Sun qualified disks by combining the * vendor id with the product id with the serial * number located in bytes 36-47 of the inquiry data. /* copy the vid at the beginning */ /* copy the pid after the vid */ /* copy the serial number after the vid and pid */ /* devid formed from inquiry data */ * Function: devid_scsi_init * Description: This routine is used to create a devid for a scsi * Arguments: hint - driver soft state (unit) structure * raw_id - pass by reference variable to hold wwn * raw_id_len - wwn length * Return Code: DEVID_SUCCESS /* Fill in driver name hint */ /* Pick up last four characters of driver name */ * Function: devid_to_guid * Description: This routine extracts a guid string form a devid. * The common use of this guid is for a HBA driver * to pass into mdi_pi_alloc(). * Arguments: devid - devid to extract guid from * Return Code: guid string - success /* NULL devid -> NULL guid */ /* guid is always converted to ascii, append NULL */ /* allocate guid string */ /* perform encode of id to hex string */ num = ((*
dp) >>
4) &
0xF;
* Function: devid_free_guid * Description: This routine frees a guid allocated by * Arguments: guid - guid to free if ((c >=
'0') && (c <=
'9'))
else if ((c >=
'A') && (c <=
'F'))
else if ((c >=
'a') && (c <=
'f'))
/* ====NOTE: The scsi_* interfaces are not related to devids :NOTE==== */ * Function: scsi_wwnstr_to_wwn * Description: This routine translates wwn from wwnstr string to uint64 wwn. * Arguments: wwnstr - the string wwn to be transformed * wwnp - the pointer to 64 bit wwn /* Skip leading 'w' if wwnstr is in unit-address form */ for (i = 0; i <
8; i++) {
if (
cl == -
1 ||
ch == -
1) {
* Function: scsi_wwn_to_wwnstr * Description: This routine translates from a uint64 wwn to a wwnstr * unit_address_form - do we want a leading 'w'? * wwnstr - allow caller to perform wwnstr allocation. * If non-NULL, don't use scsi_free_wwnstr(), * and make sure you provide 18/17 bytes of space. /* make space for leading 'w' */ len =
1 +
16 +
1;
/* "w0123456789abcdef\0" */ len =
16 +
1;
/* "0123456789abcdef\0" */ /* We allocate, caller uses scsi_free_wwnstr(). */ * Function: scsi_wwnstr_hexcase * Description: This routine switches a wwnstr to upper/lower case hex * (a wwnstr uses lower-case hex by default). * wwnstr - the pointer to the wwnstr string. * upper_case_hex - non-zero will convert to upper_case hex * zero will convert to lower case hex. ((c >=
'a') && (c <=
'f')))
c -= (
'a' -
'A');
/* lower to upper */ ((c >=
'A') && (c <=
'F')))
c += (
'a' -
'A');
/* upper to lower */ * Function: scsi_wwnstr_skip_ua_prefix * Description: This routine removes the leading 'w' in wwnstr, * if its in unit-address form. * Arguments: wwnstr - the string wwn to be transformed * Function: scsi_wwnstr_free * Description: This routine frees a wwnstr returned by a call * to scsi_wwn_to_strwwn with a NULL wwnstr argument. * wwnstr - the pointer to the wwnstr string to free. * Description: Convert between normalized (SCSI-3) LUN format, as * described by scsi_lun_t, and a normalized lun64_t * representation (used by Solaris SCSI_ADDR_PROP_LUN64 * "lun64" property). The normalized representation maps * SCSI-3 LUNs are 64 bits. SCSI-2 LUNs are 3 bits (up to * 5 bits in non-compliant implementations). SCSI-3 will * pass a (64-bit) scsi_lun_t, but we need a * representation from which we can for example, make * device names. For unit-address compatibility, we represent * 64-bit LUN numbers in such a way that they appear like they * would have under SCSI-2. This means that the single level * LUN number is in the lowest byte with the second, * third, and fourth level LUNs represented in * successively higher bytes. In particular, if (and only * if) the first byte of a 64 bit LUN is zero, denoting * "Peripheral Device Addressing Method" and "Bus * Identifier" zero, then the target implements LUNs * compatible in spirit with SCSI-2 LUNs (although under * SCSI-3 there may be up to 256 of them). Under SCSI-3 * rules, a target is *required* to use this format if it * contains 256 or fewer Logical Units, none of which are * dependent logical units. These routines have knowledge * of the structure and size of a scsi_lun_t. * NOTE: We tolerate vendors that use "Single level LUN structure using * peripheral device addressing method" with a non-zero bus identifier * (spec says bus identifier must be zero). Described another way, we let * the non-'addressing method' bits of sl_lun1_msb contribute to our lun64 * Check to see if we have a single level lun that uses the * "Peripheral Device" addressing method. If so, the lun64 value is * kept in Solaris 'unit-address compatibility' form. * LUN has Solaris 'unit-address compatibility' form, construct * lun64 value from non-'addressing method' bits of msb and lsb. * LUN does not have a Solaris 'unit-address compatibility' * form, construct lun64 value in full 64 bit LUN format. * lun64 is in Solaris 'unit-address compatibility' form. /* lun64 is in full 64 bit LUN format. */