Print this page
12093 devid_scsi_encode() should use a static format string
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/common/devid/devid_scsi.c
+++ new/usr/src/common/devid/devid_scsi.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
↓ open down ↓ |
17 lines elided |
↑ open up ↑ |
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 27 /*
28 + * Copyright 2019 Joyent, Inc.
29 + */
30 +
31 +/*
28 32 * These functions are used to encode SCSI INQUIRY data into
29 33 * Solaris devid / guid values.
30 34 */
31 35
32 36 #ifndef _KERNEL
33 37 #include <stdio.h>
34 38 #endif /* _KERNEL */
35 39
36 40 #include <sys/inttypes.h>
37 41 #include <sys/types.h>
38 42 #include <sys/stropts.h>
39 43 #include <sys/debug.h>
40 44 #include <sys/isa_defs.h>
41 45 #include <sys/dditypes.h>
42 46 #include <sys/ddi_impldefs.h>
43 47 #include <sys/scsi/scsi.h>
44 48 #ifndef _KERNEL
45 49 #include <sys/libdevid.h>
46 50 #endif /* !_KERNEL */
47 51 #include "devid_impl.h"
48 52
49 53 #define SCSI_INQUIRY_VID_POS 9
50 54 #define SCSI_INQUIRY_VID_SUN "SUN"
51 55 #define SCSI_INQUIRY_VID_SUN_LEN 3
52 56 #define SCSI_INQUIRY_VID_HITACHI "HITACHI"
53 57 #define SCSI_INQUIRY_VID_HITACHI_LEN 7
54 58 #define SCSI_INQUIRY_PID_HITACHI_OPEN "OPEN-"
55 59 #define SCSI_INQUIRY_PID_HITACHI_OPEN_LEN 5
56 60 #define SCSI_INQUIRY_VID_EMC "EMC "
57 61 #define SCSI_INQUIRY_VID_EMC_LEN 8
58 62 #define SCSI_INQUIRY_PID_EMC_SYMMETRIX "SYMMETRIX "
59 63 #define SCSI_INQUIRY_PID_EMC_SYMMETRIX_LEN 16
60 64
61 65 #define MSG_NOT_STANDARDS_COMPLIANT "!Page83 data not standards compliant "
62 66 #define MSG_NOT_STANDARDS_COMPLIANT_SIZE ( \
63 67 sizeof (MSG_NOT_STANDARDS_COMPLIANT) + \
64 68 sizeof (((struct scsi_inquiry *)NULL)->inq_vid) + \
65 69 sizeof (((struct scsi_inquiry *)NULL)->inq_pid) + \
66 70 sizeof (((struct scsi_inquiry *)NULL)->inq_revision) + 4)
67 71
68 72 #define IS_DEVID_GUID_TYPE(type) ((type == DEVID_SCSI3_WWN) || \
69 73 (IS_DEVID_SCSI3_VPD_TYPE(type)))
70 74
71 75 #define IS_DEVID_SCSI_TYPE(type) ((IS_DEVID_GUID_TYPE(type)) || \
72 76 (type == DEVID_SCSI_SERIAL))
73 77
74 78 /*
75 79 * The max inquiry page 83 size as expected in the code today
76 80 * is 0xf0 bytes. Defining a constant to make it easy incase
77 81 * this needs to be changed at a later time.
78 82 */
79 83
80 84 #define SCMD_MAX_INQUIRY_PAGE83_SIZE 0xFF
81 85 #define SCMD_MIN_INQUIRY_PAGE83_SIZE 0x08
82 86 #define SCMD_INQUIRY_PAGE83_HDR_SIZE 4
83 87 #define SCSI_INQUIRY_PAGE83_EMC_SYMMETRIX_ID_LEN 16
84 88
85 89 #define SCMD_MAX_INQUIRY_PAGE80_SIZE 0xFF
86 90 #define SCMD_MIN_INQUIRY_PAGE80_SIZE 0x04
87 91
88 92 #define SCMD_MIN_STANDARD_INQUIRY_SIZE 0x04
89 93
90 94 #define SCMD_INQUIRY_PAGE83_IDENT_DESC_HDR_SIZE 4
91 95
92 96 #define SCMD_INQUIRY_VPD_TYPE_T10 0x01
93 97 #define SCMD_INQUIRY_VPD_TYPE_EUI 0x02
94 98 #define SCMD_INQUIRY_VPD_TYPE_NAA 0x03
95 99 #define SCMD_INQUIRY_VPD_TYPE_RTP 0x04
96 100 #define SCMD_INQUIRY_VPD_TYPE_TPG 0x05
97 101 #define SCMD_INQUIRY_VPD_TYPE_LUG 0x06
98 102 #define SCMD_INQUIRY_VPD_TYPE_MD5 0x07
99 103 #define SCMD_INQUIRY_VPD_TYPE_SSN 0x08
100 104
101 105 static int is_page83_data_valid(uchar_t *inq83, size_t inq83_len);
102 106 static int is_page80_data_valid(uchar_t *inq80, size_t inq80_len);
103 107 static int is_initialized_id(uchar_t *id, size_t id_len);
104 108
105 109 static void encode_scsi3_page83(int version, uchar_t *inq83,
106 110 size_t inq83_len, uchar_t **id, size_t *id_len, ushort_t *id_type);
107 111 static void encode_scsi3_page83_emc(int version, uchar_t *inq83,
108 112 size_t inq83_len, uchar_t **id, size_t *id_len, ushort_t *id_type);
109 113 static void encode_serialnum(int version, uchar_t *inq, uchar_t *inq80,
110 114 size_t inq80_len, uchar_t **id, size_t *id_len, ushort_t *id_type);
111 115 static void encode_sun_serialnum(int version, uchar_t *inq,
112 116 size_t inq_len, uchar_t **id, size_t *id_len, ushort_t *id_type);
113 117
114 118 static int devid_scsi_init(char *driver_name,
115 119 uchar_t *raw_id, size_t raw_id_len, ushort_t raw_id_type,
116 120 ddi_devid_t *ret_devid);
117 121
118 122 static char ctoi(char c);
119 123
120 124 /*
121 125 * Function: ddi_/devid_scsi_encode
122 126 *
123 127 * Description: This routine finds and encodes a unique devid
124 128 *
125 129 * Arguments: version - id encode algorithm version
126 130 * driver_name - binding driver name (if ! known use NULL)
127 131 * inq - standard inquiry buffer
128 132 * inq_len - standard inquiry buffer length
129 133 * inq80 - serial number inquiry buffer
130 134 * inq80_len - serial number inquiry buffer length
131 135 * inq83 - vpd inquiry buffer
132 136 * inq83_len - vpd inquiry buffer length
133 137 * devid - id returned
134 138 *
135 139 * Return Code: DEVID_SUCCESS - success
136 140 * DEVID_FAILURE - failure
137 141 * DEVID_RETRY - LUN is in a transitional state. A delay should
138 142 * occur and then this inquiry data should be re-acquired and
139 143 * this function should be called again.
140 144 */
141 145 int
142 146 #ifdef _KERNEL
143 147 ddi_devid_scsi_encode(
144 148 #else /* ! _KERNEL */
145 149 devid_scsi_encode(
146 150 #endif /* _KERNEL */
147 151 int version, /* IN */
148 152 char *driver_name, /* IN */
149 153 uchar_t *inq, /* IN */
150 154 size_t inq_len, /* IN */
151 155 uchar_t *inq80, /* IN */
152 156 size_t inq80_len, /* IN */
153 157 uchar_t *inq83, /* IN */
154 158 size_t inq83_len, /* IN */
155 159 ddi_devid_t *devid) /* OUT */
156 160 {
157 161 int rval = DEVID_FAILURE;
158 162 uchar_t *id = NULL;
159 163 size_t id_len = 0;
160 164 ushort_t id_type = DEVID_NONE;
161 165 struct scsi_inquiry *inq_std = (struct scsi_inquiry *)inq;
162 166 #ifdef _KERNEL
163 167 char *msg = NULL;
164 168 #endif /* _KERNEL */
165 169
166 170 DEVID_ASSERT(devid != NULL);
167 171
168 172 /* verify valid version */
169 173 if (version > DEVID_SCSI_ENCODE_VERSION_LATEST) {
170 174 return (rval);
171 175 }
172 176
173 177 /* make sure minimum inquiry bytes are available */
174 178 if (inq_len < SCMD_MIN_STANDARD_INQUIRY_SIZE) {
175 179 return (rval);
176 180 }
177 181
178 182 /*
179 183 * If 0x83 is availible, that is the best choice. Our next choice is
180 184 * 0x80. If neither are availible, we leave it to the caller to
181 185 * determine possible alternate ID, although discouraged. In the
182 186 * case of the target drivers they create a fabricated id which is
183 187 * stored in the acyl. The HBA drivers should avoid using an
184 188 * alternate id. Although has already created a hack of using the
185 189 * node wwn in some cases. Which needs to be carried forward for
186 190 * legacy reasons.
187 191 */
188 192 if (inq83 != NULL) {
189 193 /*
190 194 * Perform page 83 validation tests and report offenders.
191 195 * We cannot enforce the page 83 specification because
192 196 * many Sun partners (ex. HDS) do not conform to the
193 197 * standards yet.
194 198 */
195 199 if (is_page83_data_valid(inq83, inq83_len) ==
196 200 DEVID_RET_INVALID) {
197 201 /*
198 202 * invalid page 83 data. bug 4939576 introduced
199 203 * handling for EMC non-standard data.
200 204 */
201 205 if ((bcmp(inq_std->inq_vid, SCSI_INQUIRY_VID_EMC,
202 206 SCSI_INQUIRY_VID_EMC_LEN) == 0) &&
203 207 (bcmp(inq_std->inq_pid,
204 208 SCSI_INQUIRY_PID_EMC_SYMMETRIX,
205 209 SCSI_INQUIRY_PID_EMC_SYMMETRIX_LEN) == 0)) {
206 210 encode_scsi3_page83_emc(version, inq83,
207 211 inq83_len, &id, &id_len, &id_type);
208 212 }
209 213 #ifdef _KERNEL
210 214 /*
211 215 * invalid page 83 data. Special hack for HDS
212 216 * specific device, to suppress the warning msg.
213 217 */
214 218 if ((bcmp(inq_std->inq_vid, SCSI_INQUIRY_VID_HITACHI,
215 219 SCSI_INQUIRY_VID_HITACHI_LEN) != 0) ||
216 220 (bcmp(inq_std->inq_pid,
217 221 SCSI_INQUIRY_PID_HITACHI_OPEN,
218 222 SCSI_INQUIRY_PID_HITACHI_OPEN_LEN) != 0)) {
219 223 /*
220 224 * report the page 0x83 standards violation.
221 225 */
222 226 msg = kmem_alloc(
223 227 MSG_NOT_STANDARDS_COMPLIANT_SIZE,
224 228 KM_SLEEP);
↓ open down ↓ |
187 lines elided |
↑ open up ↑ |
225 229 (void) strcpy(msg, MSG_NOT_STANDARDS_COMPLIANT);
226 230 (void) strncat(msg, inq_std->inq_vid,
227 231 sizeof (inq_std->inq_vid));
228 232 (void) strcat(msg, " ");
229 233 (void) strncat(msg, inq_std->inq_pid,
230 234 sizeof (inq_std->inq_pid));
231 235 (void) strcat(msg, " ");
232 236 (void) strncat(msg, inq_std->inq_revision,
233 237 sizeof (inq_std->inq_revision));
234 238 (void) strcat(msg, "\n");
235 - cmn_err(CE_WARN, msg);
239 + cmn_err(CE_WARN, "%s", msg);
236 240 kmem_free(msg,
237 241 MSG_NOT_STANDARDS_COMPLIANT_SIZE);
238 242 }
239 243 #endif /* _KERNEL */
240 244 }
241 245
242 246 if (id_type == DEVID_NONE) {
243 247 encode_scsi3_page83(version, inq83,
244 248 inq83_len, &id, &id_len, &id_type);
245 249 }
246 250 }
247 251
248 252 /*
249 253 * If no vpd page is available at this point then we
250 254 * attempt to use a SCSI serial number from page 0x80.
251 255 */
252 256 if ((id_type == DEVID_NONE) &&
253 257 (inq != NULL) &&
254 258 (inq80 != NULL)) {
255 259 if (is_page80_data_valid(inq80, inq80_len) == DEVID_RET_VALID) {
256 260 encode_serialnum(version, inq, inq80,
257 261 inq80_len, &id, &id_len, &id_type);
258 262 }
259 263 }
260 264
261 265 /*
262 266 * If no vpd page or serial is available at this point and
263 267 * it's a SUN disk it conforms to the disk qual. 850 specifications
264 268 * and we can fabricate a serial number id based on the standard
265 269 * inquiry page.
266 270 */
267 271 if ((id_type == DEVID_NONE) &&
268 272 (inq != NULL)) {
269 273 encode_sun_serialnum(version, inq, inq_len,
270 274 &id, &id_len, &id_type);
271 275 }
272 276
273 277 if (id_type != DEVID_NONE) {
274 278 if (is_initialized_id(id, id_len) == DEVID_RET_VALID) {
275 279 rval = devid_scsi_init(driver_name,
276 280 id, id_len, id_type, devid);
277 281 } else {
278 282 rval = DEVID_RETRY;
279 283 }
280 284 DEVID_FREE(id, id_len);
281 285 }
282 286
283 287 return (rval);
284 288 }
285 289
286 290
287 291 /*
288 292 * Function: is_page83_data_valid
289 293 *
290 294 * Description: This routine is used to validate the page 0x83 data
291 295 * passed in valid based on the standards specification.
292 296 *
293 297 * Arguments: inq83 -
↓ open down ↓ |
48 lines elided |
↑ open up ↑ |
294 298 * inq83_len -
295 299 *
296 300 * Return Code: DEVID_RET_VALID
297 301 * DEVID_RET_INVALID
298 302 *
299 303 */
300 304 static int
301 305 is_page83_data_valid(uchar_t *inq83, size_t inq83_len)
302 306 {
303 307
304 - int covered_desc_len = 0;
308 + int covered_desc_len = 0;
305 309 int dlen = 0;
306 310 uchar_t *dblk = NULL;
307 311
308 312 DEVID_ASSERT(inq83 != NULL);
309 313
310 314 /* if not large enough fail */
311 315 if (inq83_len < SCMD_MIN_INQUIRY_PAGE83_SIZE)
312 316 return (DEVID_RET_INVALID);
313 317
314 318 /*
315 319 * Ensuring that the Peripheral device type(bits 0 - 4) has
316 320 * the valid settings - the value 0x1f indicates no device type.
317 321 * Only this value can be validated since all other fields are
318 322 * either used or reserved.
319 323 */
320 324 if ((inq83[0] & DTYPE_MASK) == DTYPE_UNKNOWN) {
321 325 /* failed-peripheral devtype */
322 326 return (DEVID_RET_INVALID);
323 327 }
324 328
325 329 /*
326 330 * Ensure that the page length field - third and 4th bytes
327 331 * contain a non zero length value. Our implementation
328 332 * does not seem to expect more that 255 bytes of data...
329 333 * what is to be done if the reported size is > 255 bytes?
330 334 * Yes the device will return only 255 bytes as we provide
331 335 * buffer to house only that much data but the standards
332 336 * prevent the targets from reporting the truncated size
333 337 * in this field.
334 338 *
335 339 * Currently reporting sizes more than 255 as failure.
336 340 *
337 341 */
338 342
339 343 if ((inq83[2] == 0) && (inq83[3] == 0)) {
340 344 /* length field is 0! */
341 345 return (DEVID_RET_INVALID);
342 346 }
343 347 if (inq83[3] > (SCMD_MAX_INQUIRY_PAGE83_SIZE - 3)) {
344 348 /* length field exceeds expected size of 255 bytes */
345 349 return (DEVID_RET_INVALID);
346 350 }
347 351
348 352 /*
349 353 * Validation of individual descriptor blocks are done in the
350 354 * following while loop. It is possible to have multiple
351 355 * descriptor blocks.
352 356 * the 'dblk' pointer will be pointing to the start of
353 357 * each entry of the descriptor block.
354 358 */
355 359 covered_desc_len = 0;
356 360 dblk = &inq83[4]; /* start of first decriptor blk */
357 361 while (covered_desc_len < inq83[3]) {
358 362
359 363 /*
360 364 * Ensure that the length field is non zero
361 365 * Further length validations will be done
362 366 * along with the 'identifier type' as some of
363 367 * the lengths are dependent on it.
364 368 */
365 369 dlen = dblk[3];
366 370 if (dlen == 0) {
367 371 /* descr length is 0 */
368 372 return (DEVID_RET_INVALID);
369 373 }
370 374
371 375 /*
372 376 * ensure that the size of the descriptor block does
373 377 * not claim to be larger than the entire page83
374 378 * data that has been received.
375 379 */
376 380 if ((covered_desc_len + dlen) > inq83[3]) {
377 381 /* failed-descr length */
378 382 return (DEVID_RET_INVALID);
379 383 }
380 384
381 385 /*
382 386 * The spec says that if the PIV field is 0 OR the
383 387 * association field contains value other than 1 and 2,
384 388 * then the protocol identifier field should be ignored.
385 389 * If association field contains a value of 1 or 2
386 390 * and the PIV field is set, then the protocol identifier
387 391 * field has to be validated.
388 392 * The protocol identifier values 0 - f are either assigned
389 393 * or reserved. Nothing to validate here, hence skipping
390 394 * over to the next check.
391 395 */
392 396
393 397 /*
394 398 * Check for valid code set values.
395 399 * All possible values are reserved or assigned. Nothing
396 400 * to validate - skipping over.
397 401 */
398 402
399 403 /*
400 404 * Identifier Type validation
401 405 * All SPC3rev22 identified types and the expected lengths
402 406 * are validated.
403 407 */
404 408 switch (dblk[1] & 0x0f) {
405 409 case SCMD_INQUIRY_VPD_TYPE_T10: /* T10 vendor Id */
406 410 /* No specific length validation required */
407 411 break;
408 412
409 413 case SCMD_INQUIRY_VPD_TYPE_EUI: /* EUI 64 ID */
410 414 /* EUI-64: size is expected to be 8, 12, or 16 bytes */
411 415 if ((dlen != 8) && (dlen != 12) && (dlen != 16)) {
412 416 /* page83 validation failed-EIU64 */
413 417 return (DEVID_RET_INVALID);
414 418 }
415 419 break;
416 420
417 421 case SCMD_INQUIRY_VPD_TYPE_NAA: /* NAA Id type */
418 422
419 423 /*
420 424 * the size for this varies -
421 425 * IEEE extended/registered is 8 bytes
422 426 * IEEE Registered extended is 16 bytes
423 427 */
424 428 switch (dblk[4] & 0xf0) {
425 429
426 430 case 0x20: /* IEEE Ext */
427 431 case 0x50: /* IEEE Reg */
428 432 if (dlen != 8) {
429 433 /* failed-IEE E/R len */
430 434 return (DEVID_RET_INVALID);
431 435 }
432 436 /*
433 437 * the codeSet for this MUST
434 438 * be set to 1
435 439 */
436 440 if ((dblk[0] & 0x0f) != 1) {
437 441 /*
438 442 * failed-IEEE E/R
439 443 * codeSet != 1.
440 444 */
441 445 return (DEVID_RET_INVALID);
442 446 }
443 447 break;
444 448
445 449 case 0x60: /* IEEE EXT REG */
446 450 if (dlen != 16) {
447 451 /* failed-IEEE ER len */
448 452 return (DEVID_RET_INVALID);
449 453 }
450 454 /*
451 455 * the codeSet for this MUST
452 456 * be set to 1
453 457 */
454 458 if ((dblk[0] & 0x0f) != 1) {
455 459 /*
456 460 * failed-IEEE ER
457 461 * codeSet != 1.
458 462 */
459 463 return (DEVID_RET_INVALID);
460 464 }
461 465 break;
462 466
463 467 default:
464 468 /* reserved values */
465 469 break;
466 470 }
467 471 break;
468 472
469 473 case SCMD_INQUIRY_VPD_TYPE_RTP: /* Relative Target port */
470 474 if (dlen != 4) {
471 475 /* failed-Rel target Port length */
472 476 return (DEVID_RET_INVALID);
473 477 }
474 478 break;
475 479
476 480 case SCMD_INQUIRY_VPD_TYPE_TPG: /* Target port group */
477 481 if (dlen != 4) {
478 482 /* failed-target Port group length */
479 483 return (DEVID_RET_INVALID);
480 484 }
481 485 break;
482 486
483 487 case SCMD_INQUIRY_VPD_TYPE_LUG: /* Logical unit group */
484 488 if (dlen != 4) {
485 489 /* failed-Logical Unit group length */
486 490 return (DEVID_RET_INVALID);
487 491 }
488 492 break;
489 493
490 494 case SCMD_INQUIRY_VPD_TYPE_MD5: /* MD5 unit group */
491 495 if (dlen != 16) {
492 496 /* failed-MD5 Unit grp */
493 497 return (DEVID_RET_INVALID);
494 498 }
495 499 break;
496 500
497 501 default:
498 502 break;
499 503 }
500 504
501 505 /*
502 506 * Now lets advance to the next descriptor block
503 507 * and validate it.
504 508 * the descriptor block size is <descr Header> + <descr Data>
505 509 * <descr Header> is equal to 4 bytes
506 510 * <descr Data> is available in dlen or dblk[3].
507 511 */
508 512 dblk = &dblk[4 + dlen];
509 513
510 514 /*
511 515 * update the covered_desc_len so that we can ensure that
512 516 * the 'while' loop terminates.
513 517 */
514 518 covered_desc_len += (dlen + 4);
515 519 }
516 520 return (DEVID_RET_VALID);
517 521 }
518 522
519 523
520 524 /*
521 525 * Function: is_initialized_id
522 526 *
523 527 * Description: Routine to ensure that the ID calculated is not a
524 528 * space or zero filled ID. Returning a space / zero
525 529 * filled ID when the luns on the target are not fully
526 530 * initialized is a valid response from the target as
527 531 * per the T10 spec. When a space/zero filled ID is
528 532 * found its information needs to be polled again
529 533 * after sometime time to see if the luns are fully
530 534 * initialized to return a valid guid information.
531 535 *
532 536 * Arguments: id - raw id
533 537 * id_len - raw id len
534 538 *
535 539 * Return Code: DEVID_VALID - indicates a non space/zero filled id
536 540 * DEVID_INVALID - indicates id contains uninitialized data
537 541 * and suggests retry of the collection commands.
538 542 */
539 543 static int
540 544 is_initialized_id(uchar_t *id, size_t id_len)
541 545 {
542 546 int idx;
543 547
544 548 if ((id == NULL) ||
545 549 (id_len == 0)) {
546 550 /* got id length as 0 fetch info again */
547 551 return (DEVID_RET_INVALID);
548 552 }
549 553
550 554 /* First lets check if the guid is filled with spaces */
551 555 for (idx = 0; idx < id_len; idx++) {
552 556 if (id[idx] != ' ') {
553 557 break;
554 558 }
555 559 }
556 560
557 561 /*
558 562 * Lets exit if we find that it contains ALL spaces
559 563 * saying that it has an uninitialized guid
560 564 */
561 565 if (idx >= id_len) {
562 566 /* guid filled with spaces found */
563 567 return (DEVID_RET_INVALID);
564 568 }
565 569
566 570 /*
567 571 * Since we have found that it is not filled with spaces
568 572 * now lets ensure that the guid is not filled with only
569 573 * zeros.
570 574 */
571 575 for (idx = 0; idx < id_len; idx ++) {
572 576 if (id[idx] != 0) {
573 577 return (DEVID_RET_VALID);
574 578 }
575 579 }
576 580
577 581 /* guid filled with zeros found */
578 582 return (DEVID_RET_INVALID);
579 583 }
580 584
581 585
582 586 /*
583 587 * Function: is_page80_data_valid
584 588 *
585 589 * Description: This routine is used to validate the page 0x80 data
586 590 * passed in valid based on the standards specification.
587 591 *
588 592 * Arguments: inq80 -
589 593 * inq80_len -
590 594 *
591 595 * Return Code: DEVID_RET_VALID
592 596 * DEVID_RET_INVALID
593 597 *
594 598 */
595 599 /* ARGSUSED */
596 600 static int
597 601 is_page80_data_valid(uchar_t *inq80, size_t inq80_len)
598 602 {
599 603 DEVID_ASSERT(inq80);
600 604
601 605 /* if not large enough fail */
602 606 if (inq80_len < SCMD_MIN_INQUIRY_PAGE80_SIZE) {
603 607 return (DEVID_RET_INVALID);
604 608 }
605 609
606 610 /*
607 611 * (inq80_len - 4) is the size of the buffer space available
608 612 * for the product serial number. So inq80[3] (ie. product
609 613 * serial number) should be <= (inq80_len -4).
610 614 */
611 615 if (inq80[3] > (inq80_len - 4)) {
612 616 return (DEVID_RET_INVALID);
613 617 }
614 618
615 619 return (DEVID_RET_VALID);
616 620 }
617 621
618 622
619 623 /*
620 624 * Function: encode_devid_page
621 625 *
622 626 * Description: This routine finds the unique devid if available and
623 627 * fills the devid and length parameters.
624 628 *
625 629 * Arguments: version - encode version
626 630 * inq83 - driver soft state (unit) structure
627 631 * inq83_len - length of raw inq83 data
628 632 * id - raw id
629 633 * id_len - len of raw id
630 634 * id_type - type of id
631 635 *
632 636 * Note: DEVID_NONE is returned in the id_type field
633 637 * if no supported page 83 id is found.
634 638 */
635 639 static void
636 640 encode_scsi3_page83(int version, uchar_t *inq83, size_t inq83_len,
637 641 uchar_t **id, size_t *id_len, ushort_t *id_type)
638 642 {
639 643 size_t descriptor_bytes_left = 0;
640 644 size_t offset = 0;
641 645 int idx = 0;
642 646 size_t offset_id_type[4];
643 647
644 648 DEVID_ASSERT(inq83 != NULL);
645 649 /* inq83 length was already validate in is_page83_valid */
646 650 DEVID_ASSERT(id != NULL);
647 651 DEVID_ASSERT(id_len != NULL);
648 652 DEVID_ASSERT(id_type != NULL);
649 653
650 654 /* preset defaults */
651 655 *id = NULL;
652 656 *id_len = 0;
653 657 *id_type = DEVID_NONE;
654 658
655 659 /* verify we have enough memory for a ident header */
656 660 if (inq83_len < SCMD_INQUIRY_PAGE83_HDR_SIZE) {
657 661 return;
658 662 }
659 663
660 664 /*
661 665 * Attempt to validate the page data. Once validated, we'll walk
662 666 * the descriptors, looking for certain identifier types that will
663 667 * mark this device with a unique id/wwn. Note the comment below
664 668 * for what we really want to receive.
665 669 */
666 670
667 671 /*
668 672 * The format of the inq83 data (Device Identification VPD page) is
669 673 * a header (containing the total length of the page, from which
670 674 * descriptor_bytes_left is calculated), followed by a list of
671 675 * identification descriptors. Each identifcation descriptor has a
672 676 * header which includes the length of the individual identification
673 677 * descriptor).
674 678 *
675 679 * Set the offset to the beginning byte of the first identification
676 680 * descriptor. We'll index everything from there.
677 681 */
678 682 offset = SCMD_INQUIRY_PAGE83_HDR_SIZE;
679 683 descriptor_bytes_left = (size_t)((inq83[2] << 8) | inq83[3]);
680 684
681 685 /*
682 686 * If the raw data states that the data is larger
683 687 * than what is actually received abort encode.
684 688 * Otherwise we will run off into unknown memory
685 689 * on the decode.
686 690 */
687 691 if ((descriptor_bytes_left + offset) > inq83_len) {
688 692 return;
689 693 }
690 694
691 695
692 696 /* Zero out our offset array */
693 697 bzero(offset_id_type, sizeof (offset_id_type));
694 698
695 699 /*
696 700 * According to the scsi spec 8.4.3 SPC-2, there could be several
697 701 * descriptors associated with each lun. Some we care about and some
698 702 * we don't. This loop is set up to iterate through the descriptors.
699 703 * We want the 0x03 case which represents an FC-PH, FC-PH3 or FC-FS
700 704 * Name_Identifier. The spec mentions nothing about ordering, so we
701 705 * don't assume any.
702 706 *
703 707 * We need to check if we've finished walking the list of descriptors,
704 708 * we also perform additional checks to be sure the newly calculated
705 709 * offset is within the bounds of the buffer, and the identifier length
706 710 * (as calculated by the length field in the header) is valid. This is
707 711 * done to protect against devices which return bad page83 data.
708 712 */
709 713 while ((descriptor_bytes_left > 0) && (offset_id_type[3] == 0) &&
710 714 (offset + SCMD_INQUIRY_PAGE83_IDENT_DESC_HDR_SIZE <= inq83_len) &&
711 715 (offset + SCMD_INQUIRY_PAGE83_IDENT_DESC_HDR_SIZE +
712 716 (size_t)inq83[offset + 3] <= inq83_len)) {
713 717 /*
714 718 * Inspect the Identification descriptor list. Store the
715 719 * offsets in the devid page separately for 0x03, 0x01 and
716 720 * 0x02. Identifiers 0x00 and 0x04 are not useful as they
717 721 * don't represent unique identifiers for a lun. We also
718 722 * check the association by masking with 0x3f because we want
719 723 * an association of 0x0 - indicating the identifier field is
720 724 * associated with the addressed physical or logical device
721 725 * and not the port.
722 726 */
723 727 switch ((inq83[offset + 1] & 0x3f)) {
724 728 case SCMD_INQUIRY_VPD_TYPE_T10:
725 729 offset_id_type[SCMD_INQUIRY_VPD_TYPE_T10] = offset;
726 730 break;
727 731 case SCMD_INQUIRY_VPD_TYPE_EUI:
728 732 offset_id_type[SCMD_INQUIRY_VPD_TYPE_EUI] = offset;
729 733 break;
730 734 case SCMD_INQUIRY_VPD_TYPE_NAA:
731 735 offset_id_type[SCMD_INQUIRY_VPD_TYPE_NAA] = offset;
732 736 break;
733 737 default:
734 738 /* Devid page undesired id type */
735 739 break;
736 740 }
737 741 /*
738 742 * Calculate the descriptor bytes left and move to
739 743 * the beginning byte of the next id descriptor.
740 744 */
741 745 descriptor_bytes_left -= (size_t)(inq83[offset + 3] +
742 746 SCMD_INQUIRY_PAGE83_IDENT_DESC_HDR_SIZE);
743 747 offset += (SCMD_INQUIRY_PAGE83_IDENT_DESC_HDR_SIZE +
744 748 (size_t)inq83[offset + 3]);
745 749 }
746 750
747 751 offset = 0;
748 752
749 753 /*
750 754 * We can't depend on an order from a device by identifier type, but
751 755 * once we have them, we'll walk them in the same order to prevent a
752 756 * firmware upgrade from breaking our algorithm. Start with the one
753 757 * we want the most: id_offset_type[3].
754 758 */
755 759 for (idx = 3; idx > 0; idx--) {
756 760 if (offset_id_type[idx] > 0) {
757 761 offset = offset_id_type[idx];
758 762 break;
759 763 }
760 764 }
761 765
762 766 /*
763 767 * We have a valid Device ID page, set the length of the
764 768 * identifier and copy the value into the wwn.
765 769 */
766 770 if (offset > 0) {
767 771 *id_len = (size_t)inq83[offset + 3];
768 772 if ((*id = DEVID_MALLOC(*id_len)) == NULL) {
769 773 *id_len = 0;
770 774 return;
771 775 }
772 776 bcopy(&inq83[offset + SCMD_INQUIRY_PAGE83_IDENT_DESC_HDR_SIZE],
773 777 *id, *id_len);
774 778
775 779 /* set devid type */
776 780 switch (version) {
777 781 /* In version 1 all page 83 types were grouped */
778 782 case DEVID_SCSI_ENCODE_VERSION1:
779 783 *id_type = DEVID_SCSI3_WWN;
780 784 break;
781 785 /* In version 2 we break page 83 apart to be unique */
782 786 case DEVID_SCSI_ENCODE_VERSION2:
783 787 switch (idx) {
784 788 case 3:
785 789 *id_type = DEVID_SCSI3_VPD_NAA;
786 790 break;
787 791 case 2:
788 792 *id_type = DEVID_SCSI3_VPD_EUI;
789 793 break;
790 794 case 1:
791 795 *id_type = DEVID_SCSI3_VPD_T10;
792 796 break;
793 797 default:
794 798 DEVID_FREE(*id, *id_len);
795 799 *id_len = 0;
796 800 break;
797 801 }
798 802 break;
799 803 default:
800 804 DEVID_FREE(*id, *id_len);
801 805 *id_len = 0;
802 806 break;
803 807 }
804 808 }
805 809 }
806 810
807 811
808 812 /*
809 813 * Function: encode_scsi3_page83_emc
810 814 *
811 815 * Description: Routine to handle proprietary page 83 of EMC Symmetrix
812 816 * device. Called by ssfcp_handle_page83()
813 817 *
814 818 * Arguments: version - encode version
815 819 * inq83 - scsi page 83 buffer
816 820 * inq83_len - scsi page 83 buffer size
817 821 * id - raw emc id
818 822 * id_len - len of raw emc id
819 823 * id_type - type of emc id
820 824 */
821 825 static void
822 826 encode_scsi3_page83_emc(int version, uchar_t *inq83,
823 827 size_t inq83_len, uchar_t **id, size_t *id_len, ushort_t *id_type)
824 828 {
825 829 uchar_t *guidp = NULL;
826 830
827 831 DEVID_ASSERT(inq83 != NULL);
828 832 DEVID_ASSERT(id != NULL);
829 833 DEVID_ASSERT(id_len != NULL);
830 834 DEVID_ASSERT(id_type != NULL);
831 835
832 836 /* preset defaults */
833 837 *id = NULL;
834 838 *id_len = 0;
835 839 *id_type = DEVID_NONE;
836 840
837 841 /* The initial devid algorithm didn't use EMC page 83 data */
838 842 if (version == DEVID_SCSI_ENCODE_VERSION1) {
839 843 return;
840 844 }
841 845
842 846 /* EMC page 83 requires atleast 20 bytes */
843 847 if (inq83_len < (SCMD_INQUIRY_PAGE83_HDR_SIZE +
844 848 SCSI_INQUIRY_PAGE83_EMC_SYMMETRIX_ID_LEN)) {
845 849 return;
846 850 }
847 851
848 852 /*
849 853 * The 4th byte in the page 83 info returned is most likely
850 854 * indicating the length of the id - which 0x10(16 bytes)
851 855 * and the 5th byte is indicating that the id is of
852 856 * IEEE Registered Extended Name format(6). Validate
853 857 * these code prints before proceeding further as the
854 858 * following proprietary approach is tied to the specific
855 859 * device type and incase the EMC firmware changes, we will
856 860 * have to validate for the changed device before we start
857 861 * supporting such a device.
858 862 */
859 863 if ((inq83[3] != 0x10) || (inq83[4] != 0x60)) {
860 864 /* unsupported emc symtx device type */
861 865 return;
862 866 } else {
863 867 guidp = &inq83[SCMD_INQUIRY_PAGE83_HDR_SIZE];
864 868 /*
865 869 * The GUID returned by the EMC device is
866 870 * in the IEEE Registered Extended Name format(6)
867 871 * as a result it is of 16 bytes in length.
868 872 * An IEEE Registered Name format(5) will be of
869 873 * 8 bytes which is NOT what is being returned
870 874 * by the device type for which we are providing
871 875 * the support.
872 876 */
873 877 *id_len = SCSI_INQUIRY_PAGE83_EMC_SYMMETRIX_ID_LEN;
874 878 if ((*id = DEVID_MALLOC(*id_len)) == NULL) {
875 879 *id_len = 0;
876 880 return;
877 881 }
878 882 bcopy(guidp, *id, *id_len);
879 883
880 884 /* emc id matches type 3 */
881 885 *id_type = DEVID_SCSI3_VPD_NAA;
882 886 }
883 887 }
884 888
885 889
886 890 /*
887 891 * Function: encode_serialnum
888 892 *
889 893 * Description: This routine finds the unique devid from the inquiry page
890 894 * 0x80, serial number page. If available and fills the wwn
891 895 * and length parameters.
892 896 *
893 897 * Arguments: version - encode version
894 898 * inq - standard inquiry data
895 899 * inq80 - serial inquiry data
896 900 * inq80_len - serial inquiry data len
897 901 * id - raw id
898 902 * id_len - raw id len
899 903 * id_type - raw id type
900 904 */
901 905 /* ARGSUSED */
902 906 static void
903 907 encode_serialnum(int version, uchar_t *inq, uchar_t *inq80,
904 908 size_t inq80_len, uchar_t **id, size_t *id_len, ushort_t *id_type)
905 909 {
906 910 struct scsi_inquiry *inq_std = (struct scsi_inquiry *)inq;
907 911 int idx = 0;
908 912
909 913 DEVID_ASSERT(inq != NULL);
910 914 DEVID_ASSERT(inq80 != NULL);
911 915 DEVID_ASSERT(id != NULL);
912 916 DEVID_ASSERT(id_len != NULL);
913 917 DEVID_ASSERT(id_type != NULL);
914 918
915 919 /* preset defaults */
916 920 *id = NULL;
917 921 *id_len = 0;
918 922 *id_type = DEVID_NONE;
919 923
920 924 /* verify inq80 buffer is large enough for a header */
921 925 if (inq80_len < SCMD_MIN_INQUIRY_PAGE80_SIZE) {
922 926 return;
923 927 }
924 928
925 929 /*
926 930 * Attempt to validate the page data. Once validated, we'll check
927 931 * the serial number.
928 932 */
929 933 *id_len = (size_t)inq80[3]; /* Store Product Serial Number length */
930 934
931 935 /* verify buffer is large enough for serial number */
932 936 if (inq80_len < (*id_len + SCMD_MIN_INQUIRY_PAGE80_SIZE)) {
933 937 return;
934 938 }
935 939
936 940 /*
937 941 * Device returns ASCII space (20h) in all the bytes of successful data
938 942 * transfer, if the product serial number is not available. So we end
939 943 * up having to check all the bytes for a space until we reach
940 944 * something else.
941 945 */
942 946 for (idx = 0; idx < *id_len; idx++) {
943 947 if (inq80[4 + idx] == ' ') {
944 948 continue;
945 949 }
946 950 /*
947 951 * The serial number is valid, but since this is only vendor
948 952 * unique, we'll combine the inquiry vid and pid with the
949 953 * serial number.
950 954 */
951 955 *id_len += sizeof (inq_std->inq_vid);
952 956 *id_len += sizeof (inq_std->inq_pid);
953 957
954 958 if ((*id = DEVID_MALLOC(*id_len)) == NULL) {
955 959 *id_len = 0;
956 960 return;
957 961 }
958 962
959 963 bcopy(&inq_std->inq_vid, *id, sizeof (inq_std->inq_vid));
960 964 bcopy(&inq_std->inq_pid, &(*id)[sizeof (inq_std->inq_vid)],
961 965 sizeof (inq_std->inq_pid));
962 966 bcopy(&inq80[4], &(*id)[sizeof (inq_std->inq_vid) +
963 967 sizeof (inq_std->inq_pid)], inq80[3]);
964 968
965 969 *id_type = DEVID_SCSI_SERIAL;
966 970 break;
967 971 }
968 972
969 973 /*
970 974 * The spec suggests that the command could succeed but return all
971 975 * spaces if the product serial number is not available. In this case
972 976 * we need to fail this routine. To accomplish this, we compare our
973 977 * length to the serial number length. If they are the same, then we
974 978 * never copied in the vid and updated the length. That being the case,
975 979 * we must not have found a valid serial number.
976 980 */
977 981 if (*id_len == (size_t)inq80[3]) {
978 982 /* empty unit serial number */
979 983 if (*id != NULL) {
980 984 DEVID_FREE(*id, *id_len);
981 985 }
982 986 *id = NULL;
983 987 *id_len = 0;
984 988 }
985 989 }
986 990
987 991
988 992 /*
989 993 * Function: encode_sun_serialnum
990 994 *
991 995 * Description: This routine finds the unique devid from the inquiry page
992 996 * 0x80, serial number page. If available and fills the wwn
993 997 * and length parameters.
994 998 *
995 999 * Arguments: version - encode version
996 1000 * inq - standard inquiry data
997 1001 * inq_len - standard inquiry data len
998 1002 * id - raw id
999 1003 * id_len - raw id len
1000 1004 * id_type - raw id type
1001 1005 *
1002 1006 * Return Code: DEVID_SUCCESS
1003 1007 * DEVID_FAILURE
1004 1008 */
1005 1009 /* ARGSUSED */
1006 1010 static void
1007 1011 encode_sun_serialnum(int version, uchar_t *inq,
1008 1012 size_t inq_len, uchar_t **id, size_t *id_len, ushort_t *id_type)
1009 1013 {
1010 1014 struct scsi_inquiry *inq_std = (struct scsi_inquiry *)inq;
1011 1015
1012 1016 DEVID_ASSERT(inq != NULL);
1013 1017 DEVID_ASSERT(id != NULL);
1014 1018 DEVID_ASSERT(id_len != NULL);
1015 1019 DEVID_ASSERT(id_type != NULL);
1016 1020
1017 1021 /* verify enough buffer is available */
1018 1022 if (inq_len < SCMD_MIN_STANDARD_INQUIRY_SIZE) {
1019 1023 return;
1020 1024 }
1021 1025
1022 1026 /* sun qual drive */
1023 1027 if ((inq_std != NULL) &&
1024 1028 (bcmp(&inq_std->inq_pid[SCSI_INQUIRY_VID_POS],
1025 1029 SCSI_INQUIRY_VID_SUN, SCSI_INQUIRY_VID_SUN_LEN) == 0)) {
1026 1030 /*
1027 1031 * VPD pages 0x83 and 0x80 are unavailable. This
1028 1032 * is a Sun qualified disk as indicated by
1029 1033 * "SUN" in bytes 25-27 of the inquiry data
1030 1034 * (bytes 9-11 of the pid). Devid's are created
1031 1035 * for Sun qualified disks by combining the
1032 1036 * vendor id with the product id with the serial
1033 1037 * number located in bytes 36-47 of the inquiry data.
1034 1038 */
1035 1039
1036 1040 /* get data size */
1037 1041 *id_len = sizeof (inq_std->inq_vid) +
1038 1042 sizeof (inq_std->inq_pid) +
1039 1043 sizeof (inq_std->inq_serial);
1040 1044
1041 1045 if ((*id = DEVID_MALLOC(*id_len)) == NULL) {
1042 1046 *id_len = 0;
1043 1047 return;
1044 1048 }
1045 1049
1046 1050 /* copy the vid at the beginning */
1047 1051 bcopy(&inq_std->inq_vid, *id,
1048 1052 sizeof (inq_std->inq_vid));
1049 1053
1050 1054 /* copy the pid after the vid */
1051 1055 bcopy(&inq_std->inq_pid,
1052 1056 &(*id)[sizeof (inq_std->inq_vid)],
1053 1057 sizeof (inq_std->inq_pid));
1054 1058
1055 1059 /* copy the serial number after the vid and pid */
1056 1060 bcopy(&inq_std->inq_serial,
1057 1061 &(*id)[sizeof (inq_std->inq_vid) +
1058 1062 sizeof (inq_std->inq_pid)],
1059 1063 sizeof (inq_std->inq_serial));
1060 1064
1061 1065 /* devid formed from inquiry data */
1062 1066 *id_type = DEVID_SCSI_SERIAL;
1063 1067 }
1064 1068 }
1065 1069
1066 1070
1067 1071 /*
1068 1072 * Function: devid_scsi_init
1069 1073 *
1070 1074 * Description: This routine is used to create a devid for a scsi
1071 1075 * devid type.
1072 1076 *
1073 1077 * Arguments: hint - driver soft state (unit) structure
1074 1078 * raw_id - pass by reference variable to hold wwn
1075 1079 * raw_id_len - wwn length
1076 1080 * raw_id_type -
1077 1081 * ret_devid -
1078 1082 *
1079 1083 * Return Code: DEVID_SUCCESS
1080 1084 * DEVID_FAILURE
1081 1085 *
1082 1086 */
1083 1087 static int
1084 1088 devid_scsi_init(
1085 1089 char *driver_name,
1086 1090 uchar_t *raw_id,
1087 1091 size_t raw_id_len,
1088 1092 ushort_t raw_id_type,
1089 1093 ddi_devid_t *ret_devid)
1090 1094 {
1091 1095 impl_devid_t *i_devid = NULL;
1092 1096 int i_devid_len = 0;
1093 1097 int driver_name_len = 0;
1094 1098 ushort_t u_raw_id_len = 0;
1095 1099
1096 1100 DEVID_ASSERT(raw_id != NULL);
1097 1101 DEVID_ASSERT(ret_devid != NULL);
1098 1102
1099 1103 if (!IS_DEVID_SCSI_TYPE(raw_id_type)) {
1100 1104 *ret_devid = NULL;
1101 1105 return (DEVID_FAILURE);
1102 1106 }
1103 1107
1104 1108 i_devid_len = sizeof (*i_devid) + raw_id_len - sizeof (i_devid->did_id);
1105 1109 if ((i_devid = DEVID_MALLOC(i_devid_len)) == NULL) {
1106 1110 *ret_devid = NULL;
1107 1111 return (DEVID_FAILURE);
1108 1112 }
1109 1113
1110 1114 i_devid->did_magic_hi = DEVID_MAGIC_MSB;
1111 1115 i_devid->did_magic_lo = DEVID_MAGIC_LSB;
1112 1116 i_devid->did_rev_hi = DEVID_REV_MSB;
1113 1117 i_devid->did_rev_lo = DEVID_REV_LSB;
1114 1118 DEVID_FORMTYPE(i_devid, raw_id_type);
1115 1119 u_raw_id_len = raw_id_len;
1116 1120 DEVID_FORMLEN(i_devid, u_raw_id_len);
1117 1121
1118 1122 /* Fill in driver name hint */
1119 1123 bzero(i_devid->did_driver, DEVID_HINT_SIZE);
1120 1124 if (driver_name != NULL) {
1121 1125 driver_name_len = strlen(driver_name);
1122 1126 if (driver_name_len > DEVID_HINT_SIZE) {
1123 1127 /* Pick up last four characters of driver name */
1124 1128 driver_name += driver_name_len - DEVID_HINT_SIZE;
1125 1129 driver_name_len = DEVID_HINT_SIZE;
1126 1130 }
1127 1131 bcopy(driver_name, i_devid->did_driver, driver_name_len);
1128 1132 }
1129 1133
1130 1134 bcopy(raw_id, i_devid->did_id, raw_id_len);
1131 1135
1132 1136 /* return device id */
1133 1137 *ret_devid = (ddi_devid_t)i_devid;
1134 1138 return (DEVID_SUCCESS);
1135 1139 }
1136 1140
1137 1141
1138 1142 /*
1139 1143 * Function: devid_to_guid
1140 1144 *
1141 1145 * Description: This routine extracts a guid string form a devid.
1142 1146 * The common use of this guid is for a HBA driver
1143 1147 * to pass into mdi_pi_alloc().
1144 1148 *
1145 1149 * Arguments: devid - devid to extract guid from
1146 1150 *
1147 1151 * Return Code: guid string - success
1148 1152 * NULL - failure
1149 1153 */
1150 1154 char *
1151 1155 #ifdef _KERNEL
1152 1156 ddi_devid_to_guid(ddi_devid_t devid)
1153 1157 #else /* !_KERNEL */
1154 1158 devid_to_guid(ddi_devid_t devid)
1155 1159 #endif /* _KERNEL */
1156 1160 {
1157 1161 impl_devid_t *id = (impl_devid_t *)devid;
1158 1162 int len = 0;
1159 1163 int idx = 0;
1160 1164 int num = 0;
1161 1165 char *guid = NULL;
1162 1166 char *ptr = NULL;
1163 1167 char *dp = NULL;
1164 1168
1165 1169 DEVID_ASSERT(devid != NULL);
1166 1170
1167 1171 /* NULL devid -> NULL guid */
1168 1172 if (devid == NULL)
1169 1173 return (NULL);
1170 1174
1171 1175 if (!IS_DEVID_GUID_TYPE(DEVID_GETTYPE(id)))
1172 1176 return (NULL);
1173 1177
1174 1178 /* guid is always converted to ascii, append NULL */
1175 1179 len = DEVID_GETLEN(id);
1176 1180
1177 1181 /* allocate guid string */
1178 1182 if ((guid = DEVID_MALLOC((len * 2) + 1)) == NULL)
1179 1183 return (NULL);
1180 1184
1181 1185 /* perform encode of id to hex string */
1182 1186 ptr = guid;
1183 1187 for (idx = 0, dp = &id->did_id[0]; idx < len; idx++, dp++) {
1184 1188 num = ((*dp) >> 4) & 0xF;
1185 1189 *ptr++ = (num < 10) ? (num + '0') : (num + ('a' - 10));
1186 1190 num = (*dp) & 0xF;
1187 1191 *ptr++ = (num < 10) ? (num + '0') : (num + ('a' - 10));
1188 1192 }
1189 1193 *ptr = 0;
1190 1194
1191 1195 return (guid);
1192 1196 }
1193 1197
1194 1198 /*
1195 1199 * Function: devid_free_guid
1196 1200 *
1197 1201 * Description: This routine frees a guid allocated by
1198 1202 * devid_to_guid().
1199 1203 *
1200 1204 * Arguments: guid - guid to free
1201 1205 */
1202 1206 void
1203 1207 #ifdef _KERNEL
1204 1208 ddi_devid_free_guid(char *guid)
1205 1209 #else /* !_KERNEL */
1206 1210 devid_free_guid(char *guid)
1207 1211 #endif /* _KERNEL */
1208 1212 {
1209 1213 if (guid != NULL) {
1210 1214 DEVID_FREE(guid, strlen(guid) + 1);
1211 1215 }
1212 1216 }
1213 1217
1214 1218 static char
1215 1219 ctoi(char c)
1216 1220 {
1217 1221 if ((c >= '0') && (c <= '9'))
1218 1222 c -= '0';
1219 1223 else if ((c >= 'A') && (c <= 'F'))
1220 1224 c = c - 'A' + 10;
1221 1225 else if ((c >= 'a') && (c <= 'f'))
1222 1226 c = c - 'a' + 10;
1223 1227 else
1224 1228 c = -1;
1225 1229 return (c);
1226 1230 }
1227 1231
1228 1232 /* ====NOTE: The scsi_* interfaces are not related to devids :NOTE==== */
1229 1233
1230 1234 /*
1231 1235 * Function: scsi_wwnstr_to_wwn
1232 1236 *
1233 1237 * Description: This routine translates wwn from wwnstr string to uint64 wwn.
1234 1238 *
1235 1239 * Arguments: wwnstr - the string wwn to be transformed
1236 1240 * wwnp - the pointer to 64 bit wwn
1237 1241 */
1238 1242 int
1239 1243 scsi_wwnstr_to_wwn(const char *wwnstr, uint64_t *wwnp)
1240 1244 {
1241 1245 int i;
1242 1246 char cl, ch;
1243 1247 uint64_t tmp;
1244 1248
1245 1249 if (wwnp == NULL)
1246 1250 return (DDI_FAILURE);
1247 1251 *wwnp = 0;
1248 1252
1249 1253 if (wwnstr == NULL)
1250 1254 return (DDI_FAILURE);
1251 1255
1252 1256 /* Skip leading 'w' if wwnstr is in unit-address form */
1253 1257 wwnstr = scsi_wwnstr_skip_ua_prefix(wwnstr);
1254 1258
1255 1259 if (strlen(wwnstr) != 16)
1256 1260 return (DDI_FAILURE);
1257 1261
1258 1262 for (i = 0; i < 8; i++) {
1259 1263 ch = ctoi(*wwnstr++);
1260 1264 cl = ctoi(*wwnstr++);
1261 1265 if (cl == -1 || ch == -1) {
1262 1266 return (DDI_FAILURE);
1263 1267 }
1264 1268 tmp = (ch << 4) + cl;
1265 1269 *wwnp = (*wwnp << 8) | tmp;
1266 1270 }
1267 1271 return (DDI_SUCCESS);
1268 1272 }
1269 1273
1270 1274 /*
1271 1275 * Function: scsi_wwn_to_wwnstr
1272 1276 *
1273 1277 * Description: This routine translates from a uint64 wwn to a wwnstr
1274 1278 *
1275 1279 * Arguments:
1276 1280 * wwn - the 64 bit wwn
1277 1281 * unit_address_form - do we want a leading 'w'?
1278 1282 * wwnstr - allow caller to perform wwnstr allocation.
1279 1283 * If non-NULL, don't use scsi_free_wwnstr(),
1280 1284 * and make sure you provide 18/17 bytes of space.
1281 1285 */
1282 1286 char *
1283 1287 scsi_wwn_to_wwnstr(uint64_t wwn, int unit_address_form, char *wwnstr)
1284 1288 {
1285 1289 int len;
1286 1290
1287 1291 /* make space for leading 'w' */
1288 1292 if (unit_address_form)
1289 1293 len = 1 + 16 + 1; /* "w0123456789abcdef\0" */
1290 1294 else
1291 1295 len = 16 + 1; /* "0123456789abcdef\0" */
1292 1296
1293 1297 if (wwnstr == NULL) {
1294 1298 /* We allocate, caller uses scsi_free_wwnstr(). */
1295 1299 if ((wwnstr = DEVID_MALLOC(len)) == NULL)
1296 1300 return (NULL);
1297 1301 }
1298 1302
1299 1303 if (unit_address_form)
1300 1304 (void) snprintf(wwnstr, len, "w%016" PRIx64, wwn);
1301 1305 else
1302 1306 (void) snprintf(wwnstr, len, "%016" PRIx64, wwn);
1303 1307 return (wwnstr);
1304 1308 }
1305 1309
1306 1310 /*
1307 1311 * Function: scsi_wwnstr_hexcase
1308 1312 *
1309 1313 * Description: This routine switches a wwnstr to upper/lower case hex
1310 1314 * (a wwnstr uses lower-case hex by default).
1311 1315 *
1312 1316 * Arguments:
1313 1317 * wwnstr - the pointer to the wwnstr string.
1314 1318 * upper_case_hex - non-zero will convert to upper_case hex
1315 1319 * zero will convert to lower case hex.
1316 1320 */
1317 1321 void
1318 1322 scsi_wwnstr_hexcase(char *wwnstr, int upper_case_hex)
1319 1323 {
1320 1324 char *s;
1321 1325 char c;
1322 1326
1323 1327 for (s = wwnstr; *s; s++) {
1324 1328 c = *s;
1325 1329 if ((upper_case_hex != 0) &&
1326 1330 ((c >= 'a') && (c <= 'f')))
1327 1331 c -= ('a' - 'A'); /* lower to upper */
1328 1332 else if ((upper_case_hex == 0) &&
↓ open down ↓ |
1014 lines elided |
↑ open up ↑ |
1329 1333 ((c >= 'A') && (c <= 'F')))
1330 1334 c += ('a' - 'A'); /* upper to lower */
1331 1335 *s = c;
1332 1336 }
1333 1337 }
1334 1338
1335 1339 /*
1336 1340 * Function: scsi_wwnstr_skip_ua_prefix
1337 1341 *
1338 1342 * Description: This routine removes the leading 'w' in wwnstr,
1339 - * if its in unit-address form.
1343 + * if its in unit-address form.
1340 1344 *
1341 1345 * Arguments: wwnstr - the string wwn to be transformed
1342 1346 *
1343 1347 */
1344 1348 const char *
1345 1349 scsi_wwnstr_skip_ua_prefix(const char *wwnstr)
1346 1350 {
1347 1351 if (*wwnstr == 'w')
1348 1352 wwnstr++;
1349 1353 return (wwnstr);
1350 1354 }
1351 1355
1352 1356 /*
1353 1357 * Function: scsi_wwnstr_free
1354 1358 *
1355 1359 * Description: This routine frees a wwnstr returned by a call
1356 1360 * to scsi_wwn_to_strwwn with a NULL wwnstr argument.
1357 1361 *
1358 1362 * Arguments:
1359 1363 * wwnstr - the pointer to the wwnstr string to free.
1360 1364 */
1361 1365 void
1362 1366 scsi_free_wwnstr(char *wwnstr)
1363 1367 {
1364 1368 #ifdef _KERNEL
1365 1369 kmem_free(wwnstr, strlen(wwnstr) + 1);
1366 1370 #else /* _KERNEL */
1367 1371 free(wwnstr);
1368 1372 #endif /* _KERNEL */
1369 1373 }
1370 1374
1371 1375 /*
1372 1376 * Function: scsi_lun_to_lun64/scsi_lun64_to_lun
1373 1377 *
1374 1378 * Description: Convert between normalized (SCSI-3) LUN format, as
1375 1379 * described by scsi_lun_t, and a normalized lun64_t
1376 1380 * representation (used by Solaris SCSI_ADDR_PROP_LUN64
1377 1381 * "lun64" property). The normalized representation maps
1378 1382 * in a compatible way to SCSI-2 LUNs. See scsi_address.h
1379 1383 *
1380 1384 * SCSI-3 LUNs are 64 bits. SCSI-2 LUNs are 3 bits (up to
1381 1385 * 5 bits in non-compliant implementations). SCSI-3 will
1382 1386 * pass a (64-bit) scsi_lun_t, but we need a
1383 1387 * representation from which we can for example, make
1384 1388 * device names. For unit-address compatibility, we represent
1385 1389 * 64-bit LUN numbers in such a way that they appear like they
1386 1390 * would have under SCSI-2. This means that the single level
1387 1391 * LUN number is in the lowest byte with the second,
1388 1392 * third, and fourth level LUNs represented in
1389 1393 * successively higher bytes. In particular, if (and only
1390 1394 * if) the first byte of a 64 bit LUN is zero, denoting
1391 1395 * "Peripheral Device Addressing Method" and "Bus
1392 1396 * Identifier" zero, then the target implements LUNs
1393 1397 * compatible in spirit with SCSI-2 LUNs (although under
1394 1398 * SCSI-3 there may be up to 256 of them). Under SCSI-3
1395 1399 * rules, a target is *required* to use this format if it
1396 1400 * contains 256 or fewer Logical Units, none of which are
1397 1401 * dependent logical units. These routines have knowledge
1398 1402 * of the structure and size of a scsi_lun_t.
1399 1403 *
1400 1404 * NOTE: We tolerate vendors that use "Single level LUN structure using
1401 1405 * peripheral device addressing method" with a non-zero bus identifier
1402 1406 * (spec says bus identifier must be zero). Described another way, we let
1403 1407 * the non-'addressing method' bits of sl_lun1_msb contribute to our lun64
1404 1408 * value).
1405 1409 */
1406 1410 scsi_lun64_t
1407 1411 scsi_lun_to_lun64(scsi_lun_t lun)
1408 1412 {
1409 1413 scsi_lun64_t lun64;
1410 1414
1411 1415 /*
1412 1416 * Check to see if we have a single level lun that uses the
1413 1417 * "Peripheral Device" addressing method. If so, the lun64 value is
1414 1418 * kept in Solaris 'unit-address compatibility' form.
1415 1419 */
1416 1420 if (((lun.sl_lun2_msb == 0) && (lun.sl_lun2_lsb == 0) &&
1417 1421 (lun.sl_lun3_msb == 0) && (lun.sl_lun3_lsb == 0) &&
1418 1422 (lun.sl_lun4_msb == 0) && (lun.sl_lun4_lsb == 0)) &&
1419 1423 ((lun.sl_lun1_msb & SCSI_LUN_AM_MASK) == SCSI_LUN_AM_PDEV)) {
1420 1424 /*
1421 1425 * LUN has Solaris 'unit-address compatibility' form, construct
1422 1426 * lun64 value from non-'addressing method' bits of msb and lsb.
1423 1427 */
1424 1428 lun64 = ((lun.sl_lun1_msb & ~SCSI_LUN_AM_MASK) << 8) |
1425 1429 lun.sl_lun1_lsb;
1426 1430 } else {
1427 1431 /*
1428 1432 * LUN does not have a Solaris 'unit-address compatibility'
1429 1433 * form, construct lun64 value in full 64 bit LUN format.
1430 1434 */
1431 1435 lun64 =
1432 1436 ((scsi_lun64_t)lun.sl_lun1_msb << 56) |
1433 1437 ((scsi_lun64_t)lun.sl_lun1_lsb << 48) |
1434 1438 ((scsi_lun64_t)lun.sl_lun2_msb << 40) |
1435 1439 ((scsi_lun64_t)lun.sl_lun2_lsb << 32) |
1436 1440 ((scsi_lun64_t)lun.sl_lun3_msb << 24) |
1437 1441 ((scsi_lun64_t)lun.sl_lun3_lsb << 16) |
1438 1442 ((scsi_lun64_t)lun.sl_lun4_msb << 8) |
1439 1443 (scsi_lun64_t)lun.sl_lun4_lsb;
1440 1444 }
1441 1445 return (lun64);
1442 1446 }
1443 1447
1444 1448 scsi_lun_t
1445 1449 scsi_lun64_to_lun(scsi_lun64_t lun64)
1446 1450 {
1447 1451 scsi_lun_t lun;
1448 1452
1449 1453 if (lun64 <= (((0xFF & ~SCSI_LUN_AM_MASK) << 8) | 0xFF)) {
1450 1454 /*
1451 1455 * lun64 is in Solaris 'unit-address compatibility' form.
1452 1456 */
1453 1457 lun.sl_lun1_msb = SCSI_LUN_AM_PDEV | (lun64 >> 8);
1454 1458 lun.sl_lun1_lsb = (uchar_t)lun64;
1455 1459 lun.sl_lun2_msb = 0;
1456 1460 lun.sl_lun2_lsb = 0;
1457 1461 lun.sl_lun3_msb = 0;
1458 1462 lun.sl_lun3_lsb = 0;
1459 1463 lun.sl_lun4_msb = 0;
1460 1464 lun.sl_lun4_lsb = 0;
1461 1465 } else {
1462 1466 /* lun64 is in full 64 bit LUN format. */
1463 1467 lun.sl_lun1_msb = (uchar_t)(lun64 >> 56);
1464 1468 lun.sl_lun1_lsb = (uchar_t)(lun64 >> 48);
1465 1469 lun.sl_lun2_msb = (uchar_t)(lun64 >> 40);
1466 1470 lun.sl_lun2_lsb = (uchar_t)(lun64 >> 32);
1467 1471 lun.sl_lun3_msb = (uchar_t)(lun64 >> 24);
1468 1472 lun.sl_lun3_lsb = (uchar_t)(lun64 >> 16);
1469 1473 lun.sl_lun4_msb = (uchar_t)(lun64 >> 8);
1470 1474 lun.sl_lun4_lsb = (uchar_t)(lun64);
1471 1475 }
1472 1476 return (lun);
1473 1477 }
1474 1478
1475 1479 /*
1476 1480 * This routine returns the true length of the ascii inquiry fields that are to
1477 1481 * be created by removing the padded spaces at the end of the inquiry data.
1478 1482 * This routine was designed for trimming spaces from the vid, pid and revision
1479 1483 * which are defined as being left aligned. In addition, we return 0 length
1480 1484 * if the field is full of all 0's or spaces, indicating to the caller that
1481 1485 * the device was not ready to return the inquiry data as per note 65 in
1482 1486 * the scsi-2 spec.
1483 1487 */
1484 1488 int
1485 1489 scsi_ascii_inquiry_len(char *field, size_t length)
1486 1490 {
1487 1491 int retval;
1488 1492 int trailer;
1489 1493 char *p;
1490 1494
1491 1495 retval = length;
1492 1496
1493 1497 /*
1494 1498 * The vid, pid and revision are left-aligned ascii fields within the
1495 1499 * inquiry data. Here we trim the end of these fields by discounting
1496 1500 * length associated with trailing spaces or NULL bytes. The remaining
1497 1501 * bytes shall be only graphics codes - 0x20 through 0x7e as per the
1498 1502 * scsi spec definition. If we have all 0's or spaces, we return 0
1499 1503 * length. For devices that store inquiry data on the device, they
1500 1504 * can return 0's or spaces in these fields until the data is avail-
1501 1505 * able from the device (See NOTE 65 in the scsi-2 specification
1502 1506 * around the inquiry command.) We don't want to create a field in
1503 1507 * the case of a device not able to return valid data.
1504 1508 */
1505 1509 trailer = 1;
1506 1510 for (p = field + length - 1; p >= field; p--) {
1507 1511 if (trailer) {
1508 1512 if ((*p == ' ') || (*p == '\0')) {
1509 1513 retval--;
1510 1514 continue;
1511 1515 }
1512 1516 trailer = 0;
1513 1517 }
1514 1518
1515 1519 /* each char must be within 0x20 - 0x7e */
1516 1520 if (*p < 0x20 || *p > 0x7e) {
1517 1521 retval = -1;
1518 1522 break;
1519 1523 }
1520 1524
1521 1525 }
1522 1526
1523 1527 return (retval);
1524 1528 }
↓ open down ↓ |
175 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX