diff options
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/cmd/stmsboot/stmsboot_util.c | 3 | ||||
-rw-r--r-- | usr/src/common/devid/devid_scsi.c | 236 | ||||
-rw-r--r-- | usr/src/head/devid.h | 11 | ||||
-rw-r--r-- | usr/src/lib/libdevid/libdevid.h | 27 | ||||
-rw-r--r-- | usr/src/lib/libdevid/mapfile-vers | 6 | ||||
-rw-r--r-- | usr/src/uts/common/io/scsi/impl/scsi_hba.c | 98 | ||||
-rw-r--r-- | usr/src/uts/common/sys/scsi/scsi_address.h | 21 | ||||
-rw-r--r-- | usr/src/uts/common/sys/sunddi.h | 3 |
8 files changed, 270 insertions, 135 deletions
diff --git a/usr/src/cmd/stmsboot/stmsboot_util.c b/usr/src/cmd/stmsboot/stmsboot_util.c index 06af0ca964..97c14fae44 100644 --- a/usr/src/cmd/stmsboot/stmsboot_util.c +++ b/usr/src/cmd/stmsboot/stmsboot_util.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -39,6 +39,7 @@ #include <locale.h> #include <libintl.h> #include <devid.h> +#include <sys/libdevid.h> #include <sys/modctl.h> /* for MAXMODCONFNAME */ #include <sys/scsi/adapters/scsi_vhci.h> diff --git a/usr/src/common/devid/devid_scsi.c b/usr/src/common/devid/devid_scsi.c index 38c0192098..45aaacbf0d 100644 --- a/usr/src/common/devid/devid_scsi.c +++ b/usr/src/common/devid/devid_scsi.c @@ -29,6 +29,11 @@ * Solaris devid / guid values. */ +#ifndef _KERNEL +#include <stdio.h> +#endif /* _KERNEL */ + +#include <sys/inttypes.h> #include <sys/types.h> #include <sys/stropts.h> #include <sys/debug.h> @@ -1214,38 +1219,233 @@ ctoi(char c) return (c); } +/* ====NOTE: The scsi_* interfaces are not related to devids :NOTE==== */ + /* - * Function: devid_str_to_wwn + * Function: scsi_wwnstr_to_wwn * - * Description: This routine translates wwn from string to uint64 type. + * Description: This routine translates wwn from wwnstr string to uint64 wwn. * - * Arguments: string - the string wwn to be transformed - * wwn - the pointer to 64 bit wwn + * Arguments: wwnstr - the string wwn to be transformed + * wwnp - the pointer to 64 bit wwn */ int -#ifdef _KERNEL -ddi_devid_str_to_wwn(const char *string, uint64_t *wwn) -#else /* !_KERNEL */ -devid_str_to_wwn(const char *string, uint64_t *wwn) -#endif /* _KERNEL */ +scsi_wwnstr_to_wwn(const char *wwnstr, uint64_t *wwnp) { - int i; - char cl, ch; - uint64_t tmp; + int i; + char cl, ch; + uint64_t tmp; - if (wwn == NULL || strlen(string) != 16) { + if (wwnp == NULL) + return (DDI_FAILURE); + *wwnp = 0; + + if (wwnstr == NULL) + return (DDI_FAILURE); + + /* Skip leading 'w' if wwnstr is in unit-address form */ + if (*wwnstr == 'w') + wwnstr++; + + if (strlen(wwnstr) != 16) return (DDI_FAILURE); - } - *wwn = 0; for (i = 0; i < 8; i++) { - ch = ctoi(*string++); - cl = ctoi(*string++); + ch = ctoi(*wwnstr++); + cl = ctoi(*wwnstr++); if (cl == -1 || ch == -1) { return (DDI_FAILURE); } tmp = (ch << 4) + cl; - *wwn = (*wwn << 8) | tmp; + *wwnp = (*wwnp << 8) | tmp; } return (DDI_SUCCESS); } + +/* + * Function: scsi_wwn_to_wwnstr + * + * Description: This routine translates from a uint64 wwn to a wwnstr + * + * Arguments: + * wwn - the 64 bit wwn + * 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. + */ +char * +scsi_wwn_to_wwnstr(uint64_t wwn, int unit_address_form, char *wwnstr) +{ + int len; + + /* make space for leading 'w' */ + if (unit_address_form) + len = 1 + 16 + 1; /* "w0123456789abcdef\0" */ + else + len = 16 + 1; /* "0123456789abcdef\0" */ + + if (wwnstr == NULL) { + /* We allocate, caller uses scsi_free_wwnstr(). */ + if ((wwnstr = DEVID_MALLOC(len)) == NULL) + return (NULL); + } + + if (unit_address_form) + (void) snprintf(wwnstr, len, "w%016" PRIx64, wwn); + else + (void) snprintf(wwnstr, len, "%016" PRIx64, wwn); + return (wwnstr); +} + +/* + * Function: scsi_wwnstr_hexcase + * + * Description: This routine switches a wwnstr to upper/lower case hex + * (a wwnstr uses lower-case hex by default). + * + * Arguments: + * 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. + */ +void +scsi_wwnstr_hexcase(char *wwnstr, int upper_case_hex) +{ + char *s; + char c; + + for (s = wwnstr; *s; s++) { + c = *s; + if ((upper_case_hex != 0) && + ((c >= 'a') && (c <= 'f'))) + c -= ('a' - 'A'); /* lower to upper */ + else if ((upper_case_hex == 0) && + ((c >= 'A') && (c <= 'F'))) + c += ('a' - 'A'); /* upper to lower */ + *s = c; + } +} + +/* + * Function: scsi_wwnstr_free + * + * Description: This routine frees a wwnstr returned by a call + * to scsi_wwn_to_strwwn with a NULL wwnstr argument. + * + * Arguments: + * wwnstr - the pointer to the wwnstr string to free. + */ +void +scsi_free_wwnstr(char *wwnstr) +{ +#ifdef _KERNEL + kmem_free(wwnstr, strlen(wwnstr) + 1); +#else /* _KERNEL */ + free(wwnstr); +#endif /* _KERNEL */ +} + +/* + * Function: scsi_lun_to_lun64/scsi_lun64_to_lun + * + * 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 + * in a compatible way to SCSI-2 LUNs. See scsi_address.h + * + * 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 + * value). + */ +scsi_lun64_t +scsi_lun_to_lun64(scsi_lun_t lun) +{ + scsi_lun64_t 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. + */ + if (((lun.sl_lun2_msb == 0) && (lun.sl_lun2_lsb == 0) && + (lun.sl_lun3_msb == 0) && (lun.sl_lun3_lsb == 0) && + (lun.sl_lun4_msb == 0) && (lun.sl_lun4_lsb == 0)) && + ((lun.sl_lun1_msb & SCSI_LUN_AM_MASK) == SCSI_LUN_AM_PDEV)) { + /* + * LUN has Solaris 'unit-address compatibility' form, construct + * lun64 value from non-'addressing method' bits of msb and lsb. + */ + lun64 = ((lun.sl_lun1_msb & ~SCSI_LUN_AM_MASK) << 8) | + lun.sl_lun1_lsb; + } else { + /* + * LUN does not have a Solaris 'unit-address compatibility' + * form, construct lun64 value in full 64 bit LUN format. + */ + lun64 = + ((scsi_lun64_t)lun.sl_lun1_msb << 56) | + ((scsi_lun64_t)lun.sl_lun1_lsb << 48) | + ((scsi_lun64_t)lun.sl_lun2_msb << 40) | + ((scsi_lun64_t)lun.sl_lun2_lsb << 32) | + ((scsi_lun64_t)lun.sl_lun3_msb << 24) | + ((scsi_lun64_t)lun.sl_lun3_lsb << 16) | + ((scsi_lun64_t)lun.sl_lun4_msb << 8) | + (scsi_lun64_t)lun.sl_lun4_lsb; + } + return (lun64); +} + +scsi_lun_t +scsi_lun64_to_lun(scsi_lun64_t lun64) +{ + scsi_lun_t lun; + + if (lun64 <= (((0xFF & ~SCSI_LUN_AM_MASK) << 8) | 0xFF)) { + /* + * lun64 is in Solaris 'unit-address compatibility' form. + */ + lun.sl_lun1_msb = SCSI_LUN_AM_PDEV | (lun64 >> 8); + lun.sl_lun1_lsb = (uchar_t)lun64; + lun.sl_lun2_msb = 0; + lun.sl_lun2_lsb = 0; + lun.sl_lun3_msb = 0; + lun.sl_lun3_lsb = 0; + lun.sl_lun4_msb = 0; + lun.sl_lun4_lsb = 0; + } else { + /* lun64 is in full 64 bit LUN format. */ + lun.sl_lun1_msb = (uchar_t)(lun64 >> 56); + lun.sl_lun1_lsb = (uchar_t)(lun64 >> 48); + lun.sl_lun2_msb = (uchar_t)(lun64 >> 40); + lun.sl_lun2_lsb = (uchar_t)(lun64 >> 32); + lun.sl_lun3_msb = (uchar_t)(lun64 >> 24); + lun.sl_lun3_lsb = (uchar_t)(lun64 >> 16); + lun.sl_lun4_msb = (uchar_t)(lun64 >> 8); + lun.sl_lun4_lsb = (uchar_t)(lun64); + } + return (lun); +} diff --git a/usr/src/head/devid.h b/usr/src/head/devid.h index 55ff93df64..b8129d1da0 100644 --- a/usr/src/head/devid.h +++ b/usr/src/head/devid.h @@ -20,15 +20,13 @@ */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _DEVID_H #define _DEVID_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifndef _KERNEL #include <sys/types.h> #endif /* _KERNEL */ @@ -57,13 +55,6 @@ extern char *devid_str_encode(ddi_devid_t devid, char *minor_name); extern int devid_str_decode(char *devidstr, ddi_devid_t *retdevid, char **retminor_name); extern void devid_str_free(char *devidstr); -extern int devid_scsi_encode(int version, char *driver_name, - uchar_t *inq, size_t inq_len, uchar_t *inq80, - size_t inq80_len, uchar_t *inq83, size_t inq83_len, - ddi_devid_t *ret_devid); -extern char *devid_to_guid(ddi_devid_t devid); -extern void devid_free_guid(char *guid); -extern int devid_str_to_wwn(const char *string, uint64_t *wwn); #ifdef __cplusplus } diff --git a/usr/src/lib/libdevid/libdevid.h b/usr/src/lib/libdevid/libdevid.h index 348d602ecd..f5df7c10e6 100644 --- a/usr/src/lib/libdevid/libdevid.h +++ b/usr/src/lib/libdevid/libdevid.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,15 +19,13 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _LIBDEVID_H #define _LIBDEVID_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include <errno.h> #include <sys/param.h> #include <sys/sunddi.h> @@ -45,6 +42,24 @@ extern "C" { */ extern int devid_str_compare(char *devid1_str, char *devid2_str); +extern int devid_scsi_encode(int version, char *driver_name, uchar_t *inq, + size_t inq_len, uchar_t *inq80, size_t inq80_len, + uchar_t *inq83, size_t inq83_len, ddi_devid_t *devid); + +extern char *devid_to_guid(ddi_devid_t devid); +extern void devid_free_guid(char *guid); + +extern int scsi_wwnstr_to_wwn(const char *wwnstr, uint64_t *wwnp); +extern char *scsi_wwn_to_wwnstr(uint64_t wwn, + int unit_address_form, char *wwnstr); +extern void scsi_wwnstr_hexcase(char *wwnstr, int lower_case); +extern void scsi_free_wwnstr(char *wwnstr); + +#ifdef SCSI_ADDR_PROP_LUN64 +extern scsi_lun64_t scsi_lun_to_lun64(scsi_lun_t lun); +extern scsi_lun_t scsi_lun64_to_lun(scsi_lun64_t lun64); +#endif /* SCSI_ADDR_PROP_LUN64 */ + #ifdef __cplusplus } #endif diff --git a/usr/src/lib/libdevid/mapfile-vers b/usr/src/lib/libdevid/mapfile-vers index ff4526da63..48d9e987ad 100644 --- a/usr/src/lib/libdevid/mapfile-vers +++ b/usr/src/lib/libdevid/mapfile-vers @@ -62,6 +62,12 @@ SUNWprivate_1.1 { devid_scsi_encode; devid_str_compare; devid_to_guid; + scsi_free_wwnstr; + scsi_lun64_to_lun; + scsi_lun_to_lun64; + scsi_wwn_to_wwnstr; + scsi_wwnstr_hexcase; + scsi_wwnstr_to_wwn; local: *; }; diff --git a/usr/src/uts/common/io/scsi/impl/scsi_hba.c b/usr/src/uts/common/io/scsi/impl/scsi_hba.c index a25dfb4266..8ddf03a11b 100644 --- a/usr/src/uts/common/io/scsi/impl/scsi_hba.c +++ b/usr/src/uts/common/io/scsi/impl/scsi_hba.c @@ -1302,7 +1302,7 @@ smp_busctl_initchild(dev_info_t *child) goto failure; } - if (ddi_devid_str_to_wwn(smp_wwn, &wwn)) { + if (scsi_wwnstr_to_wwn(smp_wwn, &wwn)) { goto failure; } @@ -2750,102 +2750,6 @@ scsi_hba_bus_power(dev_info_t *self, void *impl_arg, pm_bus_power_op_t op, } /* - * Convert between normalized (SCSI-3) LUN format, as described by - * scsi_lun_t, and a normalized lun64_t representation. The normalized - * representation maps in a compatible way to SCSI-2 LUNs. - * - * SCSI-3 LUNs are 64 bits. SCSI-2 LUNs are 3 bits (up to 5 bits in - * some 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 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. - * - * XXX Should these function be rewritten to take the scsi_lun_t *? - */ -scsi_lun64_t -scsi_lun_to_lun64(scsi_lun_t lun) -{ - scsi_lun64_t lun64; - - /* check address method and bus identifier */ - if (lun.sl_lun1_msb == 0) { - /* single-level LUN */ - lun64 = lun.sl_lun1_lsb; /* extract the 8-bit LUN */ - - /* Ensure rest of LUN is zero, which it is supposed to be */ - if ((lun.sl_lun2_msb == 0) && (lun.sl_lun2_lsb == 0) && - (lun.sl_lun3_msb == 0) && (lun.sl_lun3_lsb == 0) && - (lun.sl_lun4_msb == 0) && (lun.sl_lun4_lsb == 0)) { - return (lun64); - } - - /* Oops, we got a bad scsi_lun_t. Leave it in 64-bit form */ - SCSI_HBA_LOG((_LOG(WARN), NULL, NULL, - "lun_to_lun64 bad lun %" PRIx64, *(scsi_lun64_t *)&lun)); - } - - /* - * We have a big LUN that is not backward compatible. - * Construct a 64 bit number using the right byte order. - */ - lun64 = - ((scsi_lun64_t)lun.sl_lun1_msb << 56) | - ((scsi_lun64_t)lun.sl_lun1_lsb << 48) | - ((scsi_lun64_t)lun.sl_lun2_msb << 40) | - ((scsi_lun64_t)lun.sl_lun2_lsb << 32) | - ((scsi_lun64_t)lun.sl_lun3_msb << 24) | - ((scsi_lun64_t)lun.sl_lun3_lsb << 16) | - ((scsi_lun64_t)lun.sl_lun4_msb << 8) | - (scsi_lun64_t)lun.sl_lun4_lsb; - return (lun64); -} - -scsi_lun_t -scsi_lun64_to_lun(scsi_lun64_t lun64) -{ - scsi_lun_t lun; - - if (lun64 < 256) { - /* This LUN is in compatibility format */ - lun.sl_lun1_msb = 0; - lun.sl_lun1_lsb = (uchar_t)lun64; - lun.sl_lun2_msb = 0; - lun.sl_lun2_lsb = 0; - lun.sl_lun3_msb = 0; - lun.sl_lun3_lsb = 0; - lun.sl_lun4_msb = 0; - lun.sl_lun4_lsb = 0; - } else { - /* This in full 64 bit LUN format */ - lun.sl_lun1_msb = (uchar_t)(lun64 >> 56); - lun.sl_lun1_lsb = (uchar_t)(lun64 >> 48); - lun.sl_lun2_msb = (uchar_t)(lun64 >> 40); - lun.sl_lun2_lsb = (uchar_t)(lun64 >> 32); - lun.sl_lun3_msb = (uchar_t)(lun64 >> 24); - lun.sl_lun3_lsb = (uchar_t)(lun64 >> 16); - lun.sl_lun4_msb = (uchar_t)(lun64 >> 8); - lun.sl_lun4_lsb = (uchar_t)(lun64); - - /* Oops, bad LUN -- this is required to be nonzero */ - if (lun.sl_lun1_msb == 0) - SCSI_HBA_LOG((_LOG(WARN), NULL, NULL, - "lun64_to_lun bad lun %" PRIlun64, lun64)); - } - return (lun); -} - -/* * Return the lun from an address string. Either the lun is after the * first ',' or the entire addr is the lun. Return SCSI_LUN64_ILLEGAL * if the format is incorrect. diff --git a/usr/src/uts/common/sys/scsi/scsi_address.h b/usr/src/uts/common/sys/scsi/scsi_address.h index ce6078b4fa..ec70e72b78 100644 --- a/usr/src/uts/common/sys/scsi/scsi_address.h +++ b/usr/src/uts/common/sys/scsi/scsi_address.h @@ -147,6 +147,27 @@ typedef struct scsi_lun { uchar_t sl_lun4_lsb; /* fourth level */ } scsi_lun_t; +/* SCSI standard defined lun addressing methods (in sl_lunX_msb) */ +#define SCSI_LUN_AM_MASK 0xC0 /* Address Method Mask */ +#define SCSI_LUN_AM_PDEV 0x00 /* Peripheral device AM */ +#define SCSI_LUN_AM_FLAT 0x40 /* Flat space AM */ +#define SCSI_LUN_AM_LUN 0x80 /* Logical unit AM */ +#define SCSI_LUN_AM_EFLAT 0xC0 /* Extended flat space AM */ +#define SCSI_LUN_AM_ELUN 0xC0 /* Extended logical unit AM */ + +#ifdef _KERNEL +/* SCSI LUN conversion between SCSI_ADDR_PROP_LUN64 and SCSI standard forms */ +scsi_lun64_t scsi_lun_to_lun64(scsi_lun_t lun); +scsi_lun_t scsi_lun64_to_lun(scsi_lun64_t lun64); + +/* SCSI WWN conversion (property values should be in unit_address form) */ +int scsi_wwnstr_to_wwn(const char *wwnstr, uint64_t *wwnp); +char *scsi_wwn_to_wwnstr(uint64_t wwn, + int unit_address_form, char *wwnstr); +void scsi_wwnstr_hexcase(char *wwnstr, int lower_case); +void scsi_free_wwnstr(char *wwnstr); +#endif /* _KERNEL */ + #ifdef __cplusplus } #endif diff --git a/usr/src/uts/common/sys/sunddi.h b/usr/src/uts/common/sys/sunddi.h index c82df79adc..ad7f568090 100644 --- a/usr/src/uts/common/sys/sunddi.h +++ b/usr/src/uts/common/sys/sunddi.h @@ -2012,9 +2012,6 @@ void ddi_devid_free_guid(char *guid); int -ddi_devid_str_to_wwn(const char *string, uint64_t *wwn); - -int ddi_lyr_get_devid(dev_t dev, ddi_devid_t *ret_devid); int |