1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26
27 /*LINTLIBRARY*/
28
29 /*
30 * I18N message number ranges
31 * This file: 9000 - 9499
32 * Shared common messages: 1 - 1999
33 */
34
35 /*
36 * This module is part of the photon library
37 */
38 /* Includes */
39 #include <stdlib.h>
40 #include <stdio.h>
41 #include <sys/file.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <sys/param.h>
45 #include <fcntl.h>
46 #include <unistd.h>
47 #include <errno.h>
48 #include <string.h>
49 #include <assert.h>
50 #include <sys/scsi/scsi.h>
51 #include <dirent.h> /* for DIR */
52 #include <sys/vtoc.h>
53 #include <sys/dkio.h>
54 #include <nl_types.h>
55 #include <strings.h>
56 #include <sys/ddi.h> /* for max */
57 #include <l_common.h>
58 #include <stgcom.h>
59 #include <l_error.h>
60 #include <rom.h>
61 #include <exec.h>
62 #include <a_state.h>
63 #include <a5k.h>
64
65
66 /* Defines */
67 #define PLNDEF "SUNW,pln" /* check if box name starts with 'c' */
68 #define DOWNLOAD_RETRIES 60*5 /* 5 minutes */
69 #define IBFIRMWARE_FILE "/usr/lib/locale/C/LC_MESSAGES/ibfirmware"
70
71 /* Global variables */
72 extern uchar_t g_switch_to_alpa[];
73 extern uchar_t g_sf_alpa_to_switch[];
74
75 /* Forward declarations */
76 static int pwr_up_down(char *, L_state *, int, int, int, int);
77 static int load_flds_if_enc_disk(char *, struct path_struct **);
78 static int copy_config_page(struct l_state_struct *, uchar_t *);
79 static void copy_page_7(struct l_state_struct *, uchar_t *);
80 static int l_get_node_status(char *, struct l_disk_state_struct *,
81 int *, WWN_list *, int);
82 static int check_file(int, int, uchar_t **, int);
83 static int check_dpm_file(int);
84 static int ib_download_code_cmd(int, int, int, uchar_t *, int, int);
85 static int dak_download_code_cmd(int, uchar_t *, int);
86 static void free_mp_dev_map(struct gfc_map_mp **);
87 static int get_mp_dev_map(char *, struct gfc_map_mp **, int);
88
89 /*
90 * l_get_mode_pg() - Read all mode pages.
91 *
92 * RETURNS:
93 * 0 O.K.
94 * non-zero otherwise
95 *
96 * INPUTS:
97 * path pointer to device path
98 * pg_buf ptr to mode pages
99 *
100 */
101 /*ARGSUSED*/
102 int
l_get_mode_pg(char * path,uchar_t ** pg_buf,int verbose)103 l_get_mode_pg(char *path, uchar_t **pg_buf, int verbose)
104 {
105 Mode_header_10 *mode_header_ptr;
106 int status, size, fd;
107
108 P_DPRINTF(" l_get_mode_pg: Reading Mode Sense pages.\n");
109
110 /* do not do mode sense if this is a tape device */
111 /* mode sense will rewind the tape */
112 if (strstr(path, SLSH_DRV_NAME_ST)) {
113 return (-1);
114 }
115
116 /* open controller */
117 if ((fd = g_object_open(path, O_NDELAY | O_RDWR)) == -1)
118 return (L_OPEN_PATH_FAIL);
119
120 /*
121 * Read the first part of the page to get the page size
122 */
123 size = 20;
124 if ((*pg_buf = (uchar_t *)g_zalloc(size)) == NULL) {
125 (void) close(fd);
126 return (L_MALLOC_FAILED);
127 }
128 /* read page */
129 if (status = g_scsi_mode_sense_cmd(fd, *pg_buf, size,
130 0, MODEPAGE_ALLPAGES)) {
131 (void) close(fd);
132 (void) g_destroy_data((char *)*pg_buf);
133 return (status);
134 }
135 /* Now get the size for all pages */
136 mode_header_ptr = (struct mode_header_10_struct *)(void *)*pg_buf;
137 size = mode_header_ptr->length + sizeof (mode_header_ptr->length);
138 (void) g_destroy_data((char *)*pg_buf);
139 if ((*pg_buf = (uchar_t *)g_zalloc(size)) == NULL) {
140 (void) close(fd);
141 return (L_MALLOC_FAILED);
142 }
143 /* read all pages */
144 if (status = g_scsi_mode_sense_cmd(fd, *pg_buf, size,
145 0, MODEPAGE_ALLPAGES)) {
146 (void) close(fd);
147 (void) g_destroy_data((char *)*pg_buf);
148 return (status);
149 }
150 (void) close(fd);
151 return (0);
152 }
153
154
155
156 /*
157 * Format QLA21xx status
158 *
159 * INPUTS: message buffer
160 * Count
161 * status
162 *
163 * OUTPUT: Message of this format in message buffer
164 * "status type: 0xstatus count"
165 */
166 int
l_format_ifp_status_msg(char * status_msg_buf,int count,int status)167 l_format_ifp_status_msg(char *status_msg_buf, int count, int status)
168 {
169 if (status_msg_buf == NULL) {
170 return (0);
171 }
172
173 switch (status) {
174 case IFP_CMD_CMPLT:
175 (void) sprintf(status_msg_buf,
176 MSGSTR(9000, "O.K. 0x%-2x"
177 " %d"), status, count);
178 break;
179 case IFP_CMD_INCOMPLETE:
180 (void) sprintf(status_msg_buf,
181 MSGSTR(9001, "Cmd incomplete 0x%-2x"
182 " %d"), status, count);
183 break;
184 case IFP_CMD_DMA_DERR:
185 (void) sprintf(status_msg_buf,
186 MSGSTR(9002, "DMA direction error 0x%-2x"
187 " %d"), status, count);
188 break;
189 case IFP_CMD_TRAN_ERR:
190 (void) sprintf(status_msg_buf,
191 MSGSTR(9003, "Unspecified transport error 0x%-2x"
192 " %d"), status, count);
193 break;
194 case IFP_CMD_RESET:
195 (void) sprintf(status_msg_buf,
196 MSGSTR(9004, "Reset aborted transport 0x%-2x"
197 " %d"), status, count);
198 break;
199 case IFP_CMD_ABORTED:
200 (void) sprintf(status_msg_buf,
201 MSGSTR(9005, "Cmd aborted 0x%-2x"
202 " %d"), status, count);
203 break;
204 case IFP_CMD_TIMEOUT:
205 (void) sprintf(status_msg_buf,
206 MSGSTR(9006, "Cmd Timeout 0x%-2x"
207 " %d"), status, count);
208 break;
209 case IFP_CMD_DATA_OVR:
210 (void) sprintf(status_msg_buf,
211 MSGSTR(9007, "Data Overrun 0x%-2x"
212 " %d"), status, count);
213 break;
214 case IFP_CMD_ABORT_REJECTED:
215 (void) sprintf(status_msg_buf,
216 MSGSTR(9008, "Target rejected abort msg 0x%-2x"
217 " %d"), status, count);
218 break;
219 case IFP_CMD_RESET_REJECTED:
220 (void) sprintf(status_msg_buf,
221 MSGSTR(9009, "Target rejected reset msg 0x%-2x"
222 " %d"), status, count);
223 break;
224 case IFP_CMD_DATA_UNDER:
225 (void) sprintf(status_msg_buf,
226 MSGSTR(9010, "Data underrun 0x%-2x"
227 " %d"), status, count);
228 break;
229 case IFP_CMD_QUEUE_FULL:
230 (void) sprintf(status_msg_buf,
231 MSGSTR(9011, "Queue full SCSI status 0x%-2x"
232 " %d"), status, count);
233 break;
234 case IFP_CMD_PORT_UNAVAIL:
235 (void) sprintf(status_msg_buf,
236 MSGSTR(9012, "Port unavailable 0x%-2x"
237 " %d"), status, count);
238 break;
239 case IFP_CMD_PORT_LOGGED_OUT:
240 (void) sprintf(status_msg_buf,
241 MSGSTR(9013, "Port loged out 0x%-2x"
242 " %d"), status, count);
243 break;
244 case IFP_CMD_PORT_CONFIG_CHANGED:
245 /* Not enough packets for given request */
246 (void) sprintf(status_msg_buf,
247 MSGSTR(9014, "Port name changed 0x%-2x"
248 " %d"), status, count);
249 break;
250 default:
251 (void) sprintf(status_msg_buf,
252 "%s 0x%-2x"
253 " %d", MSGSTR(4, "Unknown status"),
254 status, count);
255
256 } /* End of switch() */
257
258 return (0);
259
260 }
261
262
263
264 /*
265 * Format Fibre Channel status
266 *
267 * INPUTS: message buffer
268 * Count
269 * status
270 *
271 * OUTPUT: Message of this format in message buffer
272 * "status type: 0xstatus count"
273 */
274 int
l_format_fc_status_msg(char * status_msg_buf,int count,int status)275 l_format_fc_status_msg(char *status_msg_buf, int count, int status)
276 {
277 if (status_msg_buf == NULL) {
278 return (0);
279 }
280
281 switch (status) {
282 case FCAL_STATUS_OK:
283 (void) sprintf(status_msg_buf,
284 MSGSTR(9015, "O.K. 0x%-2x"
285 " %d"), status, count);
286 break;
287 case FCAL_STATUS_P_RJT:
288 (void) sprintf(status_msg_buf,
289 MSGSTR(9016, "P_RJT (Frame Rejected) 0x%-2x"
290 " %d"), status, count);
291 break;
292 case FCAL_STATUS_F_RJT:
293 (void) sprintf(status_msg_buf,
294 MSGSTR(9017, "F_RJT (Frame Rejected) 0x%-2x"
295 " %d"), status, count);
296 break;
297 case FCAL_STATUS_P_BSY:
298 (void) sprintf(status_msg_buf,
299 MSGSTR(9018, "P_BSY (Port Busy) 0x%-2x"
300 " %d"), status, count);
301 break;
302 case FCAL_STATUS_F_BSY:
303 (void) sprintf(status_msg_buf,
304 MSGSTR(9019, "F_BSY (Port Busy) 0x%-2x"
305 " %d"), status, count);
306 break;
307 case FCAL_STATUS_OLDPORT_ONLINE:
308 /* Should not happen. */
309 (void) sprintf(status_msg_buf,
310 MSGSTR(9020, "Old port Online 0x%-2x"
311 " %d"), status, count);
312 break;
313 case FCAL_STATUS_ERR_OFFLINE:
314 (void) sprintf(status_msg_buf,
315 MSGSTR(9021, "Link Offline 0x%-2x"
316 " %d"), status, count);
317 break;
318 case FCAL_STATUS_TIMEOUT:
319 /* Should not happen. */
320 (void) sprintf(status_msg_buf,
321 MSGSTR(9022, "Sequence Timeout 0x%-2x"
322 " %d"), status, count);
323 break;
324 case FCAL_STATUS_ERR_OVERRUN:
325 (void) sprintf(status_msg_buf,
326 MSGSTR(9023, "Sequence Payload Overrun 0x%-2x"
327 " %d"), status, count);
328 break;
329 case FCAL_STATUS_LOOP_ONLINE:
330 (void) sprintf(status_msg_buf,
331 MSGSTR(9060, "Loop Online 0x%-2x"
332 " %d"), status, count);
333 break;
334 case FCAL_STATUS_OLD_PORT:
335 (void) sprintf(status_msg_buf,
336 MSGSTR(9061, "Old port 0x%-2x"
337 " %d"), status, count);
338 break;
339 case FCAL_STATUS_AL_PORT:
340 (void) sprintf(status_msg_buf,
341 MSGSTR(9062, "AL port 0x%-2x"
342 " %d"), status, count);
343 break;
344 case FCAL_STATUS_UNKNOWN_CQ_TYPE:
345 (void) sprintf(status_msg_buf,
346 MSGSTR(9024, "Unknown request type 0x%-2x"
347 " %d"), status, count);
348 break;
349 case FCAL_STATUS_BAD_SEG_CNT:
350 (void) sprintf(status_msg_buf,
351 MSGSTR(9025, "Bad segment count 0x%-2x"
352 " %d"), status, count);
353 break;
354 case FCAL_STATUS_MAX_XCHG_EXCEEDED:
355 (void) sprintf(status_msg_buf,
356 MSGSTR(9026, "Maximum exchanges exceeded 0x%-2x"
357 " %d"), status, count);
358 break;
359 case FCAL_STATUS_BAD_XID:
360 (void) sprintf(status_msg_buf,
361 MSGSTR(9027, "Bad exchange identifier 0x%-2x"
362 " %d"), status, count);
363 break;
364 case FCAL_STATUS_XCHG_BUSY:
365 (void) sprintf(status_msg_buf,
366 MSGSTR(9028, "Duplicate exchange request 0x%-2x"
367 " %d"), status, count);
368 break;
369 case FCAL_STATUS_BAD_POOL_ID:
370 (void) sprintf(status_msg_buf,
371 MSGSTR(9029, "Bad memory pool ID 0x%-2x"
372 " %d"), status, count);
373 break;
374 case FCAL_STATUS_INSUFFICIENT_CQES:
375 /* Not enough packets for given request */
376 (void) sprintf(status_msg_buf,
377 MSGSTR(9030, "Invalid # of segments for req 0x%-2x"
378 " %d"), status, count);
379 break;
380 case FCAL_STATUS_ALLOC_FAIL:
381 (void) sprintf(status_msg_buf,
382 MSGSTR(9031, "Resource allocation failure 0x%-2x"
383 " %d"), status, count);
384 break;
385 case FCAL_STATUS_BAD_SID:
386 (void) sprintf(status_msg_buf,
387 MSGSTR(9032, "Bad Source Identifier(S_ID) 0x%-2x"
388 " %d"), status, count);
389 break;
390 case FCAL_STATUS_NO_SEQ_INIT:
391 (void) sprintf(status_msg_buf,
392 MSGSTR(9033, "No sequence initiative 0x%-2x"
393 " %d"), status, count);
394 break;
395 case FCAL_STATUS_BAD_DID:
396 (void) sprintf(status_msg_buf,
397 MSGSTR(9034, "Bad Destination ID(D_ID) 0x%-2x"
398 " %d"), status, count);
399 break;
400 case FCAL_STATUS_ABORTED:
401 (void) sprintf(status_msg_buf,
402 MSGSTR(9035, "Received BA_ACC from abort 0x%-2x"
403 " %d"), status, count);
404 break;
405 case FCAL_STATUS_ABORT_FAILED:
406 (void) sprintf(status_msg_buf,
407 MSGSTR(9036, "Received BA_RJT from abort 0x%-2x"
408 " %d"), status, count);
409 break;
410 case FCAL_STATUS_DIAG_BUSY:
411 (void) sprintf(status_msg_buf,
412 MSGSTR(9037, "Diagnostics currently busy 0x%-2x"
413 " %d"), status, count);
414 break;
415 case FCAL_STATUS_DIAG_INVALID:
416 (void) sprintf(status_msg_buf,
417 MSGSTR(9038, "Diagnostics illegal request 0x%-2x"
418 " %d"), status, count);
419 break;
420 case FCAL_STATUS_INCOMPLETE_DMA_ERR:
421 (void) sprintf(status_msg_buf,
422 MSGSTR(9039, "SBus DMA did not complete 0x%-2x"
423 " %d"), status, count);
424 break;
425 case FCAL_STATUS_CRC_ERR:
426 (void) sprintf(status_msg_buf,
427 MSGSTR(9040, "CRC error detected 0x%-2x"
428 " %d"), status, count);
429 break;
430 case FCAL_STATUS_OPEN_FAIL:
431 (void) sprintf(status_msg_buf,
432 MSGSTR(9063, "Open failure 0x%-2x"
433 " %d"), status, count);
434 break;
435 case FCAL_STATUS_ERROR:
436 (void) sprintf(status_msg_buf,
437 MSGSTR(9041, "Invalid status error 0x%-2x"
438 " %d"), status, count);
439 break;
440 case FCAL_STATUS_ONLINE_TIMEOUT:
441 (void) sprintf(status_msg_buf,
442 MSGSTR(9042, "Timed out before ONLINE 0x%-2x"
443 " %d"), status, count);
444 break;
445 default:
446 (void) sprintf(status_msg_buf,
447 "%s 0x%-2x"
448 " %d", MSGSTR(4, "Unknown status"),
449 status, count);
450
451 } /* End of switch() */
452
453 return (0);
454
455 }
456
457
458
459 /*
460 * Get the indexes to the disk device elements in page 2,
461 * based on the locations found in page 1.
462 *
463 * RETURNS:
464 * 0 O.K.
465 * non-zero otherwise
466 */
467 int
l_get_disk_element_index(struct l_state_struct * l_state,int * front_index,int * rear_index)468 l_get_disk_element_index(struct l_state_struct *l_state, int *front_index,
469 int *rear_index)
470 {
471 int index = 0, front_flag = 0, local_front = 0, local_rear = 0;
472 int i, rear_flag = 0;
473
474 if ((l_state == NULL) || (front_index == NULL) ||
475 (rear_index == NULL)) {
476 return (L_INVALID_PATH_FORMAT);
477 }
478
479 *front_index = *rear_index = 0;
480 /* Get the indexes to the disk device elements */
481 for (i = 0; i < (int)l_state->ib_tbl.config.enc_num_elem; i++) {
482 if (l_state->ib_tbl.config.type_hdr[i].type == ELM_TYP_DD) {
483 if (front_flag) {
484 local_rear = index;
485 rear_flag = 1;
486 break;
487 } else {
488 local_front = index;
489 front_flag = 1;
490 }
491 }
492 index += l_state->ib_tbl.config.type_hdr[i].num;
493 index++; /* for global element */
494 }
495
496 D_DPRINTF(" l_get_disk_element_index:"
497 " Index to front disk elements 0x%x\n"
498 " l_get_disk_element_index:"
499 " Index to rear disk elements 0x%x\n",
500 local_front, local_rear);
501
502 if (!front_flag && !rear_flag) { /* neither is found */
503 return (L_RD_NO_DISK_ELEM);
504 }
505 *front_index = local_front;
506 *rear_index = local_rear;
507 return (0);
508 }
509
510
511
512 /*
513 * l_led() manage the device led's
514 *
515 * RETURNS:
516 * 0 O.K.
517 * non-zero otherwise
518 */
519 int
l_led(struct path_struct * path_struct,int led_action,struct device_element * status,int verbose)520 l_led(struct path_struct *path_struct, int led_action,
521 struct device_element *status,
522 int verbose)
523 {
524 gfc_map_t map;
525 char ses_path[MAXPATHLEN];
526 uchar_t *page_buf;
527 int err, write, fd, front_index, rear_index, offset;
528 unsigned short page_len;
529 struct device_element *elem;
530 L_state *l_state;
531 int enc_type;
532
533 if ((path_struct == NULL) || (status == NULL)) {
534 return (L_INVALID_PATH_FORMAT);
535 }
536
537 /*
538 * Need to get a valid location, front/rear & slot.
539 *
540 * The path_struct will return a valid slot
541 * and the IB path or a disk path.
542 */
543
544 map.dev_addr = (gfc_port_dev_info_t *)NULL;
545 if (!path_struct->ib_path_flag) {
546 if ((err = g_get_dev_map(path_struct->p_physical_path,
547 &map, verbose)) != 0)
548 return (err);
549 if ((err = l_get_ses_path(path_struct->p_physical_path,
550 ses_path, &map, verbose)) != 0) {
551 free((void *)map.dev_addr);
552 return (err);
553 }
554 } else {
555 (void) strcpy(ses_path, path_struct->p_physical_path);
556 }
557
558 if ((l_state = (L_state *)calloc(1, sizeof (L_state))) == NULL) {
559 free((void *)map.dev_addr);
560 return (L_MALLOC_FAILED);
561 }
562
563 if (!path_struct->slot_valid) {
564 if ((map.dev_addr != NULL) &&
565 (err = g_get_dev_map(path_struct->p_physical_path,
566 &map, verbose)) != 0) {
567 (void) l_free_lstate(&l_state);
568 return (err);
569 }
570 if ((err = l_get_ses_path(path_struct->p_physical_path,
571 ses_path, &map, verbose)) != 0) {
572 (void) l_free_lstate(&l_state);
573 free((void *)map.dev_addr);
574 return (err);
575 }
576 if ((err = l_get_status(ses_path, l_state, verbose)) != 0) {
577 (void) l_free_lstate(&l_state);
578 free((void *)map.dev_addr);
579 return (err);
580 }
581
582 /* We are passing the disks path */
583 if (err = l_get_slot(path_struct, l_state, verbose)) {
584 (void) l_free_lstate(&l_state);
585 free((void *)map.dev_addr);
586 return (err);
587 }
588 }
589 if (map.dev_addr != NULL)
590 free((void *)map.dev_addr); /* Not used anymore */
591
592 if ((page_buf = (uchar_t *)calloc(1,
593 MAX_REC_DIAG_LENGTH)) == NULL) {
594 (void) l_free_lstate(&l_state);
595 return (L_MALLOC_FAILED);
596 }
597
598 if ((fd = g_object_open(ses_path, O_NDELAY | O_RDWR)) == -1) {
599 (void) l_free_lstate(&l_state);
600 (void) g_destroy_data(page_buf);
601 return (L_OPEN_PATH_FAIL);
602 }
603
604 if (err = l_get_envsen_page(fd, page_buf, MAX_REC_DIAG_LENGTH,
605 L_PAGE_2, verbose)) {
606 (void) l_free_lstate(&l_state);
607 (void) close(fd);
608 (void) g_destroy_data(page_buf);
609 return (err);
610 }
611
612 page_len = (page_buf[2] << 8 | page_buf[3]) + HEADER_LEN;
613
614 /* Get index to the disk we are interested in */
615 if (err = l_get_status(ses_path, l_state, verbose)) {
616 (void) l_free_lstate(&l_state);
617 (void) close(fd);
618 (void) g_destroy_data(page_buf);
619 return (err);
620 }
621
622 /* find enclosure type */
623 if ((strncmp((char *)l_state->ib_tbl.config.prod_id, DAK_OFF_NAME,
624 strlen(DAK_OFF_NAME)) == 0) ||
625 (strncmp((char *)l_state->ib_tbl.config.prod_id, DAK_PROD_STR,
626 strlen(DAK_PROD_STR)) == 0)) {
627 enc_type = DAK_ENC_TYPE;
628 } else {
629 enc_type = SENA_ENC_TYPE;
630 }
631
632 /* Double check slot. */
633 if (path_struct->slot >= l_state->total_num_drv/2) {
634 (void) l_free_lstate(&l_state);
635 return (L_INVALID_SLOT);
636 }
637
638 if (err = l_get_disk_element_index(l_state, &front_index,
639 &rear_index)) {
640 (void) l_free_lstate(&l_state);
641 return (err);
642 }
643
644 /* Skip global element */
645 front_index++;
646 if (enc_type == DAK_ENC_TYPE) {
647 rear_index += l_state->total_num_drv/2 + 1;
648 } else {
649 rear_index++;
650 }
651
652 if (path_struct->f_flag) {
653 offset = (8 + (front_index + path_struct->slot)*4);
654 } else {
655 offset = (8 + (rear_index + path_struct->slot)*4);
656 }
657
658 elem = (struct device_element *)(page_buf + offset);
659 /*
660 * now do requested action.
661 */
662 bcopy((const void *)elem, (void *)status,
663 sizeof (struct device_element)); /* save status */
664 bzero(elem, sizeof (struct device_element));
665 elem->select = 1;
666 elem->dev_off = status->dev_off;
667 elem->en_bypass_a = status->en_bypass_a;
668 elem->en_bypass_b = status->en_bypass_b;
669 write = 1;
670
671 switch (led_action) {
672 case L_LED_STATUS:
673 write = 0;
674 break;
675 case L_LED_RQST_IDENTIFY:
676 elem->ident = 1;
677 if (verbose) {
678 if (enc_type == DAK_ENC_TYPE) {
679 (void) fprintf(stdout,
680 MSGSTR(9043, " Blinking LED for slot %d in enclosure"
681 " %s\n"), path_struct->f_flag ? path_struct->slot :
682 path_struct->slot + (MAX_DRIVES_DAK/2),
683 l_state->ib_tbl.enclosure_name);
684 } else {
685 (void) fprintf(stdout,
686 MSGSTR(9043, " Blinking LED for slot %d in enclosure"
687 " %s\n"), path_struct->slot,
688 l_state->ib_tbl.enclosure_name);
689 }
690 }
691 break;
692 case L_LED_OFF:
693 if (verbose) {
694 if (enc_type == DAK_ENC_TYPE) {
695 (void) fprintf(stdout,
696 MSGSTR(9044,
697 " Turning off LED for slot %d in enclosure"
698 " %s\n"), path_struct->f_flag ? path_struct->slot
699 : path_struct->slot + (MAX_DRIVES_DAK/2),
700 l_state->ib_tbl.enclosure_name);
701 } else {
702 (void) fprintf(stdout,
703 MSGSTR(9044,
704 " Turning off LED for slot %d in enclosure"
705 " %s\n"), path_struct->slot,
706 l_state->ib_tbl.enclosure_name);
707 }
708 }
709 break;
710 default:
711 (void) l_free_lstate(&l_state);
712 return (L_INVALID_LED_RQST);
713 } /* End of switch */
714
715 if (write) {
716 if (getenv("_LUX_D_DEBUG") != NULL) {
717 g_dump(" l_led: Updating led state: "
718 "Device Status Element ",
719 (uchar_t *)elem, sizeof (struct device_element),
720 HEX_ONLY);
721 }
722 if (err = g_scsi_send_diag_cmd(fd,
723 (uchar_t *)page_buf, page_len)) {
724 (void) close(fd);
725 (void) g_destroy_data(page_buf);
726 (void) l_free_lstate(&l_state);
727 return (err);
728 }
729
730 bzero(page_buf, MAX_REC_DIAG_LENGTH);
731 if (err = l_get_envsen_page(fd, page_buf, MAX_REC_DIAG_LENGTH,
732 L_PAGE_2, verbose)) {
733 (void) g_destroy_data(page_buf);
734 (void) close(fd);
735 (void) l_free_lstate(&l_state);
736 return (err);
737 }
738 elem = (struct device_element *)(page_buf + offset);
739 bcopy((const void *)elem, (void *)status,
740 sizeof (struct device_element));
741 }
742 if (getenv("_LUX_D_DEBUG") != NULL) {
743 g_dump(" l_led: Device Status Element ",
744 (uchar_t *)status, sizeof (struct device_element),
745 HEX_ONLY);
746 }
747
748 (void) l_free_lstate(&l_state);
749 (void) close(fd);
750 (void) g_destroy_data(page_buf);
751 return (0);
752 }
753
754
755 /*
756 * frees the previously alloced l_state
757 * structure.
758 *
759 * RETURNS:
760 * 0 O.K.
761 * non-zero otherwise
762 */
763 int
l_free_lstate(L_state ** l_state)764 l_free_lstate(L_state **l_state)
765 {
766 int i;
767
768 if ((l_state == NULL) || (*l_state == NULL))
769 return (0);
770
771 for (i = 0; i < (int)(*l_state)->total_num_drv/2; i++) {
772 if ((*l_state)->drv_front[i].g_disk_state.multipath_list != NULL)
773 (void) g_free_multipath(
774 (*l_state)->drv_front[i].g_disk_state.multipath_list);
775 if ((*l_state)->drv_rear[i].g_disk_state.multipath_list != NULL)
776 (void) g_free_multipath(
777 (*l_state)->drv_rear[i].g_disk_state.multipath_list);
778 }
779 (void) g_destroy_data (*l_state);
780 l_state = NULL;
781
782 return (0);
783 }
784
785
786
787 /*
788 * Set the state of an individual disk
789 * in the Photon enclosure the powered
790 * up/down mode. The path must point to
791 * a disk or the ib_path_flag must be set.
792 *
793 * RETURNS:
794 * 0 O.K.
795 * non-zero otherwise
796 */
797 int
l_dev_pwr_up_down(char * path_phys,struct path_struct * path_struct,int power_off_flag,int verbose,int force_flag)798 l_dev_pwr_up_down(char *path_phys, struct path_struct *path_struct,
799 int power_off_flag, int verbose, int force_flag)
800 /*ARGSUSED*/
801 {
802 gfc_map_t map;
803 char ses_path[MAXPATHLEN], dev_path[MAXPATHLEN];
804 int slot, err = 0;
805 L_state *l_state = NULL;
806 struct l_disk_state_struct *drive;
807 struct dlist *dl, *dl1;
808 devctl_hdl_t devhdl;
809 WWN_list *wwn_list = NULL;
810 L_inquiry inq;
811
812 if (path_struct == NULL) {
813 return (L_INVALID_PATH_FORMAT);
814 }
815
816 dl = (struct dlist *)NULL;
817 map.dev_addr = (gfc_port_dev_info_t *)NULL;
818
819 if (err = g_get_dev_map(path_struct->p_physical_path,
820 &map, verbose))
821 return (err);
822
823 if (err = l_get_ses_path(path_struct->p_physical_path,
824 ses_path, &map, verbose)) {
825 free((void *)map.dev_addr);
826 return (err);
827 }
828 free((void *)map.dev_addr); /* Not used anymore */
829
830 /*
831 * Check to see if we have a photon, and if not, don't allow
832 * this operation
833 */
834 if (err = g_get_inquiry(ses_path, &inq)) {
835 return (err);
836 }
837 if (l_get_enc_type(inq) != SENA_ENC_TYPE) {
838 return (L_ENCL_INVALID_PATH);
839 }
840 /*
841 * OK, so we have a photon... we can continue
842 */
843
844
845 if ((l_state = (L_state *)calloc(1, sizeof (L_state))) == NULL) {
846 return (L_MALLOC_FAILED);
847 }
848
849 if (err = l_get_status(ses_path, l_state, verbose)) {
850 (void) l_free_lstate(&l_state);
851 return (err);
852 }
853
854 if (!path_struct->slot_valid) {
855 /* We are passing the disks path */
856 if (err = l_get_slot(path_struct, l_state, verbose)) {
857 (void) l_free_lstate(&l_state);
858 return (err);
859 }
860 }
861
862 slot = path_struct->slot;
863 (void) strcpy(dev_path, path_struct->p_physical_path);
864
865 /*
866 * Either front or rear drive
867 */
868 if (path_struct->f_flag) {
869 drive = &l_state->drv_front[slot];
870 } else {
871 drive = &l_state->drv_rear[slot];
872 }
873
874 /*
875 * Check for drive presence always
876 */
877 if (drive->ib_status.code == S_NOT_INSTALLED) {
878 (void) l_free_lstate(&l_state);
879 return (L_SLOT_EMPTY);
880 }
881
882 /*
883 * Check disk state
884 * before the power off.
885 *
886 */
887 if (power_off_flag && !force_flag) {
888 goto pre_pwr_dwn;
889 } else {
890 goto pwr_up_dwn;
891 }
892
893 pre_pwr_dwn:
894
895 /*
896 * Check whether disk
897 * is reserved by another
898 * host
899 */
900 if ((drive->g_disk_state.d_state_flags[PORT_A] & L_RESERVED) ||
901 (drive->g_disk_state.d_state_flags[PORT_B] &
902 L_RESERVED)) {
903 (void) l_free_lstate(&l_state);
904 return (L_DEVICE_RESERVED);
905 }
906
907
908 if ((dl = (struct dlist *)g_zalloc(sizeof (struct dlist))) == NULL) {
909 (void) l_free_lstate(&l_state);
910 return (L_MALLOC_FAILED);
911 }
912
913 /*
914 * NOTE: It is not necessary to get the multipath list here as ------
915 * we alread have it after getting the status earlier.
916 * - REWRITE -
917 */
918
919 /*
920 * Get path to all the FC disk and tape devices.
921 *
922 * I get this now and pass down for performance
923 * reasons.
924 * If for some reason the list can become invalid,
925 * i.e. device being offlined, then the list
926 * must be re-gotten.
927 */
928 if (err = g_get_wwn_list(&wwn_list, verbose)) {
929 (void) g_destroy_data(dl);
930 (void) l_free_lstate(&l_state);
931 return (err); /* Failure */
932 }
933
934 dl->dev_path = dev_path;
935 if ((err = g_get_multipath(dev_path,
936 &(dl->multipath), wwn_list, verbose)) != 0) {
937 (void) g_destroy_data(dl);
938 (void) g_free_wwn_list(&wwn_list);
939 (void) l_free_lstate(&l_state);
940 return (err);
941 }
942
943 for (dl1 = dl->multipath; dl1 != NULL; dl1 = dl1->next) {
944 if ((devhdl = devctl_device_acquire(dl1->dev_path,
945 DC_EXCL)) == NULL) {
946 if (errno != EBUSY) {
947 ER_DPRINTF("%s could not acquire"
948 " the device: %s\n\n",
949 strerror(errno), dl1->dev_path);
950 continue;
951 }
952 }
953 if (devctl_device_offline(devhdl) != 0) {
954 (void) devctl_release(devhdl);
955 (void) g_free_multipath(dl->multipath);
956 (void) g_destroy_data(dl);
957 (void) g_free_wwn_list(&wwn_list);
958 (void) l_free_lstate(&l_state);
959 return (L_POWER_OFF_FAIL_BUSY);
960 }
961 (void) devctl_release(devhdl);
962 }
963
964 pwr_up_dwn:
965 err = pwr_up_down(ses_path, l_state, path_struct->f_flag,
966 path_struct->slot, power_off_flag, verbose);
967
968 if (dl != NULL) {
969 (void) g_free_multipath(dl->multipath);
970 (void) g_destroy_data(dl);
971 }
972 (void) g_free_wwn_list(&wwn_list);
973 (void) l_free_lstate(&l_state);
974 if (err) {
975 return (err);
976 }
977 return (0);
978 }
979
980
981
982 /*
983 * l_pho_pwr_up_down() Set the state of the Photon enclosure
984 * the powered up/down mode.
985 * The path must point to an IB.
986 *
987 * RETURNS:
988 * 0 O.K.
989 * non-zero otherwise
990 */
991 int
l_pho_pwr_up_down(char * dev_name,char * path_phys,int power_off_flag,int verbose,int force_flag)992 l_pho_pwr_up_down(char *dev_name, char *path_phys, int power_off_flag,
993 int verbose, int force_flag)
994 {
995 L_state *l_state = NULL;
996 int i, err = 0;
997 struct dlist *dl, *dl1;
998 char dev_path[MAXPATHLEN];
999 devctl_hdl_t devhdl;
1000 WWN_list *wwn_list = NULL;
1001
1002 if (path_phys == NULL) {
1003 return (L_INVALID_PATH_FORMAT);
1004 }
1005
1006 dl = (struct dlist *)NULL;
1007 if ((l_state = (L_state *)calloc(1, sizeof (L_state))) == NULL) {
1008 return (L_MALLOC_FAILED);
1009 }
1010 if (err = l_get_status(path_phys, l_state, verbose)) {
1011 (void) l_free_lstate(&l_state);
1012 return (err);
1013 }
1014 if (power_off_flag && !force_flag) {
1015 goto pre_pwr_dwn;
1016 } else {
1017 goto pwr_up_dwn;
1018 }
1019
1020 pre_pwr_dwn:
1021
1022 /*
1023 * Check if any disk in this enclosure
1024 * is reserved by another host before
1025 * the power off.
1026 */
1027 for (i = 0; i < l_state->total_num_drv/2; i++) {
1028 if ((l_state->drv_front[i].g_disk_state.d_state_flags[PORT_A] &
1029 L_RESERVED) ||
1030 (l_state->drv_front[i].g_disk_state.d_state_flags[PORT_B] &
1031 L_RESERVED) ||
1032 (l_state->drv_rear[i].g_disk_state.d_state_flags[PORT_A] &
1033 L_RESERVED) ||
1034 (l_state->drv_rear[i].g_disk_state.d_state_flags[PORT_B] &
1035 L_RESERVED)) {
1036 return (L_DISKS_RESERVED);
1037 }
1038 }
1039
1040 /*
1041 * Check if any disk in this enclosure
1042 * Get path to all the FC disk and tape devices.
1043 *
1044 * I get this now and pass down for performance
1045 * reasons.
1046 * If for some reason the list can become invalid,
1047 * i.e. device being offlined, then the list
1048 * must be re-gotten.
1049 */
1050 if (err = g_get_wwn_list(&wwn_list, verbose)) {
1051 (void) l_free_lstate(&l_state);
1052 return (err); /* Failure */
1053 }
1054 for (i = 0; i < l_state->total_num_drv/2; i++) {
1055 if (*l_state->drv_front[i].g_disk_state.physical_path) {
1056 (void) memset(dev_path, 0, MAXPATHLEN);
1057 (void) strcpy(dev_path,
1058 (char *)&l_state->drv_front[i].g_disk_state.physical_path);
1059
1060 if ((dl = (struct dlist *)
1061 g_zalloc(sizeof (struct dlist))) == NULL) {
1062 (void) g_free_wwn_list(&wwn_list);
1063 (void) l_free_lstate(&l_state);
1064 return (L_MALLOC_FAILED);
1065 }
1066 dl->dev_path = dev_path;
1067 if (g_get_multipath(dev_path, &(dl->multipath),
1068 wwn_list, verbose) != 0) {
1069 (void) g_destroy_data(dl);
1070 continue;
1071 }
1072
1073 for (dl1 = dl->multipath;
1074 dl1 != NULL;
1075 dl1 = dl1->next) {
1076
1077 /* attempt to acquire the device */
1078 if ((devhdl = devctl_device_acquire(
1079 dl1->dev_path, DC_EXCL)) == NULL) {
1080 if (errno != EBUSY) {
1081 ER_DPRINTF("%s: Could not "
1082 "acquire the device: %s\n\n",
1083 strerror(errno),
1084 dl1->dev_path);
1085 continue;
1086 }
1087 }
1088
1089 /* attempt to offline the device */
1090 if (devctl_device_offline(devhdl) != 0) {
1091 (void) devctl_release(devhdl);
1092 (void) g_free_multipath(
1093 dl->multipath);
1094 (void) g_destroy_data(dl);
1095 (void) g_free_wwn_list(&wwn_list);
1096 (void) l_free_lstate(&l_state);
1097 return (L_POWER_OFF_FAIL_BUSY);
1098 }
1099
1100 /* release handle acquired above */
1101 (void) devctl_release(devhdl);
1102 }
1103 (void) g_free_multipath(dl->multipath);
1104 (void) g_destroy_data(dl);
1105
1106 }
1107 if (*l_state->drv_rear[i].g_disk_state.physical_path) {
1108 (void) memset(dev_path, 0, MAXPATHLEN);
1109 (void) strcpy(dev_path,
1110 (char *)&l_state->drv_rear[i].g_disk_state.physical_path);
1111
1112 if ((dl = (struct dlist *)
1113 g_zalloc(sizeof (struct dlist))) == NULL) {
1114 (void) g_free_wwn_list(&wwn_list);
1115 (void) l_free_lstate(&l_state);
1116 return (L_MALLOC_FAILED);
1117 }
1118 dl->dev_path = dev_path;
1119 if (g_get_multipath(dev_path, &(dl->multipath),
1120 wwn_list, verbose) != 0) {
1121 (void) g_destroy_data(dl);
1122 continue;
1123 }
1124
1125
1126 for (dl1 = dl->multipath;
1127 dl1 != NULL;
1128 dl1 = dl1->next) {
1129
1130 /* attempt to acquire the device */
1131 if ((devhdl = devctl_device_acquire(
1132 dl1->dev_path, DC_EXCL)) == NULL) {
1133 if (errno != EBUSY) {
1134 ER_DPRINTF("%s: Could not "
1135 "acquire the device: %s\n\n",
1136 strerror(errno),
1137 dl1->dev_path);
1138 continue;
1139 }
1140 }
1141 /* attempt to offline the device */
1142 if (devctl_device_offline(devhdl) != 0) {
1143 (void) devctl_release(devhdl);
1144 (void) g_free_multipath(
1145 dl->multipath);
1146 (void) g_destroy_data(dl);
1147 (void) g_free_wwn_list(&wwn_list);
1148 (void) l_free_lstate(&l_state);
1149 return (L_POWER_OFF_FAIL_BUSY);
1150 }
1151
1152 /* release handle acquired above */
1153 (void) devctl_release(devhdl);
1154 }
1155 (void) g_free_multipath(dl->multipath);
1156 (void) g_destroy_data(dl);
1157
1158 }
1159 }
1160
1161 pwr_up_dwn:
1162
1163 (void) g_free_wwn_list(&wwn_list);
1164 if ((err = pwr_up_down(path_phys, l_state, 0, -1,
1165 power_off_flag, verbose)) != 0) {
1166 (void) l_free_lstate(&l_state);
1167 return (err);
1168 }
1169 (void) l_free_lstate(&l_state);
1170 return (0);
1171 }
1172
1173
1174 /*
1175 * Set the state of the Photon enclosure or disk
1176 * powered up/down mode.
1177 * The path must point to an IB.
1178 * slot == -1 implies entire enclosure.
1179 *
1180 * RETURNS:
1181 * 0 O.K.
1182 * non-zero otherwise
1183 */
1184 static int
pwr_up_down(char * path_phys,L_state * l_state,int front,int slot,int power_off_flag,int verbose)1185 pwr_up_down(char *path_phys, L_state *l_state, int front, int slot,
1186 int power_off_flag, int verbose)
1187 {
1188 L_inquiry inq;
1189 int fd, status, err;
1190 uchar_t *page_buf;
1191 int front_index, rear_index, front_offset, rear_offset;
1192 unsigned short page_len;
1193 struct device_element *front_elem, *rear_elem;
1194
1195 (void) memset(&inq, 0, sizeof (inq));
1196 if ((fd = g_object_open(path_phys, O_NDELAY | O_RDONLY)) == -1) {
1197 return (L_OPEN_PATH_FAIL);
1198 }
1199 /* Verify it is a Photon */
1200 if (status = g_scsi_inquiry_cmd(fd,
1201 (uchar_t *)&inq, sizeof (struct l_inquiry_struct))) {
1202 (void) close(fd);
1203 return (status);
1204 }
1205 if ((strstr((char *)inq.inq_pid, ENCLOSURE_PROD_ID) == 0) &&
1206 (!(strncmp((char *)inq.inq_vid, "SUN ",
1207 sizeof (inq.inq_vid)) &&
1208 ((inq.inq_dtype & DTYPE_MASK) == DTYPE_ESI)))) {
1209 (void) close(fd);
1210 return (L_ENCL_INVALID_PATH);
1211 }
1212
1213 /*
1214 * To power up/down a Photon we use the Driver Off
1215 * bit in the global device control element.
1216 */
1217 if ((page_buf = (uchar_t *)malloc(MAX_REC_DIAG_LENGTH)) == NULL) {
1218 return (L_MALLOC_FAILED);
1219 }
1220 if (err = l_get_envsen_page(fd, page_buf, MAX_REC_DIAG_LENGTH,
1221 L_PAGE_2, verbose)) {
1222 (void) close(fd);
1223 (void) g_destroy_data(page_buf);
1224 return (err);
1225 }
1226
1227 page_len = (page_buf[2] << 8 | page_buf[3]) + HEADER_LEN;
1228
1229 /* Double check slot as convert_name only does gross check */
1230 if (slot >= l_state->total_num_drv/2) {
1231 (void) close(fd);
1232 (void) g_destroy_data(page_buf);
1233 return (L_INVALID_SLOT);
1234 }
1235
1236 if (err = l_get_disk_element_index(l_state, &front_index,
1237 &rear_index)) {
1238 (void) close(fd);
1239 (void) g_destroy_data(page_buf);
1240 return (err);
1241 }
1242 /* Skip global element */
1243 front_index++;
1244 rear_index++;
1245
1246 front_offset = (8 + (front_index + slot)*4);
1247 rear_offset = (8 + (rear_index + slot)*4);
1248
1249 front_elem = (struct device_element *)(page_buf + front_offset);
1250 rear_elem = (struct device_element *)(page_buf + rear_offset);
1251
1252 if (front || slot == -1) {
1253 /*
1254 * now do requested action.
1255 */
1256 bzero(front_elem, sizeof (struct device_element));
1257 /* Set/reset power off bit */
1258 front_elem->dev_off = power_off_flag;
1259 front_elem->select = 1;
1260 }
1261 if (!front || slot == -1) {
1262 /* Now do rear */
1263 bzero(rear_elem, sizeof (struct device_element));
1264 /* Set/reset power off bit */
1265 rear_elem->dev_off = power_off_flag;
1266 rear_elem->select = 1;
1267 }
1268
1269 if (getenv("_LUX_D_DEBUG") != NULL) {
1270 if (front || slot == -1) {
1271 g_dump(" pwr_up_down: "
1272 "Front Device Status Element ",
1273 (uchar_t *)front_elem,
1274 sizeof (struct device_element),
1275 HEX_ONLY);
1276 }
1277 if (!front || slot == -1) {
1278 g_dump(" pwr_up_down: "
1279 "Rear Device Status Element ",
1280 (uchar_t *)rear_elem,
1281 sizeof (struct device_element),
1282 HEX_ONLY);
1283 }
1284 }
1285 if (err = g_scsi_send_diag_cmd(fd,
1286 (uchar_t *)page_buf, page_len)) {
1287 (void) close(fd);
1288 (void) g_destroy_data(page_buf);
1289 return (err);
1290 }
1291 (void) close(fd);
1292 (void) g_destroy_data(page_buf);
1293 return (0);
1294 }
1295
1296 /*
1297 * Set the password of the FPM by sending the password
1298 * in page 4 of the Send Diagnostic command.
1299 *
1300 * The path must point to an IB.
1301 *
1302 * The size of the password string must be <= 8 bytes.
1303 * The string can also be NULL. This is the way the user
1304 * chooses to not have a password.
1305 *
1306 * I then tell the photon by giving him 4 NULL bytes.
1307 *
1308 * RETURNS:
1309 * 0 O.K.
1310 * non-zero otherwise
1311 */
1312 int
l_new_password(char * path_phys,char * password)1313 l_new_password(char *path_phys, char *password)
1314 {
1315 Page4_name page4;
1316 L_inquiry inq;
1317 int fd, status;
1318
1319 (void) memset(&inq, 0, sizeof (inq));
1320 (void) memset(&page4, 0, sizeof (page4));
1321
1322 if ((fd = g_object_open(path_phys, O_NDELAY | O_RDONLY)) == -1) {
1323 return (L_OPEN_PATH_FAIL);
1324 }
1325 /* Verify it is a Photon */
1326 if (status = g_scsi_inquiry_cmd(fd,
1327 (uchar_t *)&inq, sizeof (struct l_inquiry_struct))) {
1328 (void) close(fd);
1329 return (status);
1330 }
1331 if ((strstr((char *)inq.inq_pid, ENCLOSURE_PROD_ID) == 0) &&
1332 (!(strncmp((char *)inq.inq_vid, "SUN ",
1333 sizeof (inq.inq_vid)) &&
1334 ((inq.inq_dtype & DTYPE_MASK) == DTYPE_ESI)))) {
1335 (void) close(fd);
1336 return (L_ENCL_INVALID_PATH);
1337 }
1338
1339 page4.page_code = L_PAGE_4;
1340 page4.page_len = (ushort_t)max((strlen(password) + 4), 8);
1341 /* Double check */
1342 if (strlen(password) > 8) {
1343 return (L_INVALID_PASSWORD_LEN);
1344 }
1345 page4.string_code = L_PASSWORD;
1346 page4.enable = 1;
1347 (void) strcpy((char *)page4.name, password);
1348
1349 if (status = g_scsi_send_diag_cmd(fd, (uchar_t *)&page4,
1350 page4.page_len + HEADER_LEN)) {
1351 (void) close(fd);
1352 return (status);
1353 }
1354
1355 (void) close(fd);
1356 return (0);
1357 }
1358
1359
1360
1361 /*
1362 * Set the name of the enclosure by sending the name
1363 * in page 4 of the Send Diagnostic command.
1364 *
1365 * The path must point to an IB.
1366 *
1367 * RETURNS:
1368 * 0 O.K.
1369 * non-zero otherwise
1370 */
1371 int
l_new_name(char * path_phys,char * name)1372 l_new_name(char *path_phys, char *name)
1373 {
1374 Page4_name page4;
1375 L_inquiry inq;
1376 int fd, status;
1377
1378 if ((path_phys == NULL) || (name == NULL)) {
1379 return (L_INVALID_PATH_FORMAT);
1380 }
1381
1382 (void) memset(&inq, 0, sizeof (inq));
1383 (void) memset(&page4, 0, sizeof (page4));
1384
1385 if ((fd = g_object_open(path_phys, O_NDELAY | O_RDONLY)) == -1) {
1386 return (L_OPEN_PATH_FAIL);
1387 }
1388 /* Verify it is a Photon */
1389 if (status = g_scsi_inquiry_cmd(fd,
1390 (uchar_t *)&inq, sizeof (struct l_inquiry_struct))) {
1391 (void) close(fd);
1392 return (status);
1393 }
1394 if ((strstr((char *)inq.inq_pid, ENCLOSURE_PROD_ID) == 0) &&
1395 (!(strncmp((char *)inq.inq_vid, "SUN ",
1396 sizeof (inq.inq_vid)) &&
1397 ((inq.inq_dtype & DTYPE_MASK) == DTYPE_ESI)))) {
1398 (void) close(fd);
1399 return (L_ENCL_INVALID_PATH);
1400 }
1401
1402 page4.page_code = L_PAGE_4;
1403 page4.page_len = (ushort_t)((sizeof (struct page4_name) - 4));
1404 page4.string_code = L_ENCL_NAME;
1405 page4.enable = 1;
1406 strncpy((char *)page4.name, name, sizeof (page4.name));
1407
1408 if (status = g_scsi_send_diag_cmd(fd, (uchar_t *)&page4,
1409 sizeof (page4))) {
1410 (void) close(fd);
1411 return (status);
1412 }
1413
1414 /*
1415 * Check the name really changed.
1416 */
1417 if (status = g_scsi_inquiry_cmd(fd,
1418 (uchar_t *)&inq, sizeof (struct l_inquiry_struct))) {
1419 (void) close(fd);
1420 return (status);
1421 }
1422 if (strncmp((char *)inq.inq_box_name, name, sizeof (page4.name)) != 0) {
1423 char name_buf[MAXNAMELEN];
1424 (void) close(fd);
1425 strncpy((char *)name_buf, (char *)inq.inq_box_name,
1426 sizeof (inq.inq_box_name));
1427 return (L_ENCL_NAME_CHANGE_FAIL);
1428 }
1429
1430 (void) close(fd);
1431 return (0);
1432 }
1433
1434
1435
1436 /*
1437 * Issue a Loop Port enable Primitive sequence
1438 * to the device specified by the pathname.
1439 */
1440 int
l_enable(char * path,int verbose)1441 l_enable(char *path, int verbose)
1442 /*ARGSUSED*/
1443 {
1444
1445 return (0);
1446 }
1447
1448 /*
1449 * Issue a Loop Port Bypass Primitive sequence
1450 * to the device specified by the pathname. This requests the
1451 * device to set its L_Port into the bypass mode.
1452 */
1453 int
l_bypass(char * path,int verbose)1454 l_bypass(char *path, int verbose)
1455 /*ARGSUSED*/
1456 {
1457
1458 return (0);
1459 }
1460
1461
1462
1463 /*
1464 * Create a linked list of all the Photon enclosures that
1465 * are attached to this host.
1466 *
1467 * RETURN VALUES: 0 O.K.
1468 *
1469 * box_list pointer:
1470 * NULL: No enclosures found.
1471 * !NULL: Enclosures found
1472 * box_list points to a linked list of boxes.
1473 */
1474 int
l_get_box_list(struct box_list_struct ** box_list_ptr,int verbose)1475 l_get_box_list(struct box_list_struct **box_list_ptr, int verbose)
1476 {
1477 char *dev_name;
1478 DIR *dirp;
1479 struct dirent *entp;
1480 char namebuf[MAXPATHLEN];
1481 struct stat sb;
1482 char *result = NULL;
1483 int fd, status;
1484 L_inquiry inq;
1485 Box_list *box_list, *l1, *l2;
1486 IB_page_config page1;
1487 uchar_t node_wwn[WWN_SIZE], port_wwn[WWN_SIZE];
1488 int al_pa;
1489
1490 if (box_list_ptr == NULL) {
1491 return (L_INVALID_PATH_FORMAT);
1492 }
1493
1494 box_list = *box_list_ptr = NULL;
1495 if ((dev_name = (char *)g_zalloc(sizeof ("/dev/es"))) == NULL) {
1496 return (L_MALLOC_FAILED);
1497 }
1498 (void) sprintf((char *)dev_name, "/dev/es");
1499
1500 if (verbose) {
1501 (void) fprintf(stdout,
1502 MSGSTR(9045,
1503 " Searching directory %s for links to enclosures\n"),
1504 dev_name);
1505 }
1506
1507 if ((dirp = opendir(dev_name)) == NULL) {
1508 (void) g_destroy_data(dev_name);
1509 /* No Photons found */
1510 B_DPRINTF(" l_get_box_list: No Photons found\n");
1511 return (0);
1512 }
1513
1514
1515 while ((entp = readdir(dirp)) != NULL) {
1516 if (strcmp(entp->d_name, ".") == 0 ||
1517 strcmp(entp->d_name, "..") == 0)
1518 continue;
1519
1520 (void) sprintf(namebuf, "%s/%s", dev_name, entp->d_name);
1521
1522 if ((lstat(namebuf, &sb)) < 0) {
1523 ER_DPRINTF("Warning: Cannot stat %s\n",
1524 namebuf);
1525 continue;
1526 }
1527
1528 if (!S_ISLNK(sb.st_mode)) {
1529 ER_DPRINTF("Warning: %s is not a symbolic link\n",
1530 namebuf);
1531 continue;
1532 }
1533 if ((result = g_get_physical_name_from_link(namebuf)) == NULL) {
1534 ER_DPRINTF(" Warning: Get physical name from"
1535 " link failed. Link=%s\n", namebuf);
1536 continue;
1537 }
1538
1539 /* Found a SES card. */
1540 B_DPRINTF(" l_get_box_list: Link to SES Card found: %s/%s\n",
1541 dev_name, entp->d_name);
1542 if ((fd = g_object_open(result, O_NDELAY | O_RDONLY)) == -1) {
1543 g_destroy_data(result);
1544 continue; /* Ignore errors */
1545 }
1546 /* Get the box name */
1547 if (status = g_scsi_inquiry_cmd(fd,
1548 (uchar_t *)&inq, sizeof (struct l_inquiry_struct))) {
1549 (void) close(fd);
1550 g_destroy_data(result);
1551 continue; /* Ignore errors */
1552 }
1553
1554 if ((strstr((char *)inq.inq_pid, ENCLOSURE_PROD_ID) != NULL) ||
1555 (((inq.inq_dtype & DTYPE_MASK) == DTYPE_ESI) &&
1556 (l_get_enc_type(inq) == DAK_ENC_TYPE))) {
1557 /*
1558 * Found Photon/Daktari
1559 */
1560
1561 /* Get the port WWN from the IB, page 1 */
1562 if ((status = l_get_envsen_page(fd, (uchar_t *)&page1,
1563 sizeof (page1), 1, 0)) != NULL) {
1564 (void) close(fd);
1565 g_destroy_data(result);
1566 (void) g_destroy_data(dev_name);
1567 closedir(dirp);
1568 return (status);
1569 }
1570
1571 /*
1572 * Build list of names.
1573 */
1574 if ((l2 = (struct box_list_struct *)
1575 g_zalloc(sizeof (struct box_list_struct)))
1576 == NULL) {
1577 (void) close(fd);
1578 g_destroy_data(result);
1579 g_destroy_data(dev_name);
1580 closedir(dirp);
1581 return (L_MALLOC_FAILED);
1582 }
1583
1584 /* Fill in structure */
1585 (void) strcpy((char *)l2->b_physical_path,
1586 (char *)result);
1587 (void) strcpy((char *)l2->logical_path,
1588 (char *)namebuf);
1589 bcopy((void *)page1.enc_node_wwn,
1590 (void *)l2->b_node_wwn, WWN_SIZE);
1591 (void) sprintf(l2->b_node_wwn_s,
1592 "%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x",
1593 page1.enc_node_wwn[0],
1594 page1.enc_node_wwn[1],
1595 page1.enc_node_wwn[2],
1596 page1.enc_node_wwn[3],
1597 page1.enc_node_wwn[4],
1598 page1.enc_node_wwn[5],
1599 page1.enc_node_wwn[6],
1600 page1.enc_node_wwn[7]);
1601 strncpy((char *)l2->prod_id_s,
1602 (char *)inq.inq_pid,
1603 sizeof (inq.inq_pid));
1604 strncpy((char *)l2->b_name,
1605 (char *)inq.inq_box_name,
1606 sizeof (inq.inq_box_name));
1607 /* make sure null terminated */
1608 l2->b_name[sizeof (l2->b_name) - 1] = NULL;
1609
1610 /*
1611 * Now get the port WWN for the port
1612 * we are connected to.
1613 */
1614 status = g_get_wwn(result, port_wwn, node_wwn,
1615 &al_pa, verbose);
1616 if (status == 0) {
1617 (void) sprintf(l2->b_port_wwn_s,
1618 "%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x",
1619 port_wwn[0], port_wwn[1], port_wwn[2],
1620 port_wwn[3], port_wwn[4], port_wwn[5],
1621 port_wwn[6], port_wwn[7]);
1622 bcopy((void *)port_wwn,
1623 (void *)l2->b_port_wwn, WWN_SIZE);
1624
1625 B_DPRINTF(" l_get_box_list:"
1626 " Found enclosure named:%s\n", l2->b_name);
1627
1628 if (box_list == NULL) {
1629 l1 = box_list = l2;
1630 } else {
1631 l2->box_prev = l1;
1632 l1 = l1->box_next = l2;
1633 }
1634 } else {
1635 (void) close(fd);
1636 g_destroy_data(result);
1637 (void) g_destroy_data(dev_name);
1638 (void) g_destroy_data(l2);
1639 closedir(dirp);
1640 return (status);
1641 }
1642
1643 }
1644 g_destroy_data(result);
1645 (void) close(fd);
1646 *box_list_ptr = box_list; /* pass back ptr to list */
1647 }
1648 (void) g_destroy_data(dev_name);
1649 closedir(dirp);
1650 return (0);
1651 }
1652
1653 void
l_free_box_list(struct box_list_struct ** box_list)1654 l_free_box_list(struct box_list_struct **box_list)
1655 {
1656 Box_list *next = NULL;
1657
1658 if (box_list == NULL) {
1659 return;
1660 }
1661
1662 for (; *box_list != NULL; *box_list = next) {
1663 next = (*box_list)->box_next;
1664 (void) g_destroy_data(*box_list);
1665 }
1666
1667 *box_list = NULL;
1668 }
1669
1670
1671
1672 /*
1673 * Finds out if there are any other boxes
1674 * with the same name as "name".
1675 *
1676 * RETURNS:
1677 * 0 There are no other boxes with the same name.
1678 * >0 if duplicate names found
1679 */
1680 /*ARGSUSED*/
1681 int
l_duplicate_names(Box_list * b_list,char wwn[],char * name,int verbose)1682 l_duplicate_names(Box_list *b_list, char wwn[], char *name, int verbose)
1683 {
1684 int dup_flag = 0;
1685 Box_list *box_list_ptr = NULL;
1686
1687 if ((name == NULL) || (wwn == NULL))
1688 return (0);
1689
1690 box_list_ptr = b_list;
1691 while (box_list_ptr != NULL) {
1692 if ((strcmp(name, (const char *)box_list_ptr->b_name) == 0) &&
1693 (strcmp(box_list_ptr->b_node_wwn_s, wwn) != 0)) {
1694 dup_flag++;
1695 break;
1696 }
1697 box_list_ptr = box_list_ptr->box_next;
1698 }
1699 return (dup_flag);
1700 }
1701
1702
1703
1704 /*
1705 * Checks for a name conflict with an SSA cN type name.
1706 */
1707 int
l_get_conflict(char * name,char ** result,int verbose)1708 l_get_conflict(char *name, char **result, int verbose)
1709 {
1710 char s[MAXPATHLEN];
1711 char *p = NULL;
1712 char *pp = NULL;
1713 Box_list *box_list = NULL;
1714 int found_box = 0, err = 0;
1715
1716 (void) strcpy(s, name);
1717 if ((*result = g_get_physical_name(s)) == NULL) {
1718 return (0);
1719 }
1720 if ((strstr((const char *)*result, PLNDEF)) == NULL) {
1721 (void) g_destroy_data(*result);
1722 *result = NULL;
1723 return (0);
1724 }
1725 P_DPRINTF(" l_get_conflict: Found "
1726 "SSA path using %s\n", s);
1727 /* Find path to IB */
1728 if ((err = l_get_box_list(&box_list, verbose)) != 0) {
1729 return (err); /* Failure */
1730 }
1731 /*
1732 * Valid cN type name found.
1733 */
1734 while (box_list != NULL) {
1735 if ((strcmp((char *)s,
1736 (char *)box_list->b_name)) == 0) {
1737 found_box = 1;
1738 if (p == NULL) {
1739 if ((p = g_zalloc(strlen(
1740 box_list->b_physical_path)
1741 + 2)) == NULL) {
1742 (void) l_free_box_list(&box_list);
1743 return (errno);
1744 }
1745 } else {
1746 if ((pp = g_zalloc(strlen(
1747 box_list->b_physical_path)
1748 + strlen(p)
1749 + 2)) == NULL) {
1750 (void) l_free_box_list(&box_list);
1751 return (errno);
1752 }
1753 (void) strcpy(pp, p);
1754 (void) g_destroy_data(p);
1755 p = pp;
1756 }
1757 (void) strcat(p, box_list->b_physical_path);
1758 (void) strcat(p, "\n");
1759 }
1760 box_list = box_list->box_next;
1761 }
1762 if (found_box) {
1763 D_DPRINTF("There is a conflict between the "
1764 "enclosure\nwith this name, %s, "
1765 "and a SSA name of the same form.\n"
1766 "Please use one of the following physical "
1767 "pathnames:\n%s\n%s\n",
1768 s, *result, p);
1769
1770 (void) l_free_box_list(&box_list);
1771 (void) g_destroy_data(p);
1772 return (L_SSA_CONFLICT); /* failure */
1773 }
1774 (void) l_free_box_list(&box_list);
1775 return (0);
1776 }
1777
1778 /*
1779 * This function sets the "slot", "slot_valid" and "f_flag" fields of the
1780 * path_struct that is passed in IFF the device path passed in ("phys_path")
1781 * is a disk in an A5K or a Daktari. This is achieved by calling l_get_slot().
1782 *
1783 * INPUT :
1784 * phys_path - physical path to a device
1785 * path_sturct - Pointer to pointer to a path_struct data structure
1786 *
1787 * OUTPUT :
1788 * if phys_path is that of an A5K/Daktari disk
1789 * path_struct->slot is set to the slot position in enclosure
1790 * path_struct->slot_valid is set to 1
1791 * path_struct->f_flag is set to 1 if in the front of an A5k
1792 * or if among the first 6 disks on a Daktari
1793 * else
1794 * they are left as they were
1795 * RETURNS:
1796 * 0 on SUCCESS
1797 * non-zero otherwise
1798 */
1799 static int
load_flds_if_enc_disk(char * phys_path,struct path_struct ** path_struct)1800 load_flds_if_enc_disk(char *phys_path, struct path_struct **path_struct)
1801 {
1802 int err = 0, verbose = 0;
1803 char ses_path[MAXPATHLEN];
1804 gfc_map_t map;
1805 L_inquiry inq;
1806 L_state *l_state = NULL;
1807
1808 if ((path_struct == NULL) || (*path_struct == NULL) ||
1809 (phys_path == NULL) || (*phys_path == NULL)) {
1810 return (L_INVALID_PATH_FORMAT);
1811 }
1812
1813 if ((strstr(phys_path, SLSH_DRV_NAME_SSD) == NULL) ||
1814 (g_get_path_type(phys_path) == 0)) {
1815 /*
1816 * Don't proceed when not a disk device or if it is not a
1817 * valid FC device on which g_get_dev_map() can be done
1818 * (for example, g_get_dev_map() will fail on SSAs).
1819 *
1820 * Just return success
1821 */
1822 return (0);
1823 }
1824
1825 if ((*path_struct)->ib_path_flag) {
1826 /*
1827 * If this flag is set, l_get_slot() should not be called
1828 * So, no point in proceeding. Just return success.
1829 */
1830 return (0);
1831 }
1832
1833 if ((err = g_get_dev_map(phys_path, &map, verbose)) != 0) {
1834 return (err);
1835 }
1836
1837 if ((err = l_get_ses_path(phys_path, ses_path, &map, verbose)) != 0) {
1838 (void) free(map.dev_addr);
1839 if (err == L_NO_SES_PATH) {
1840 /*
1841 * This is not an error since this could be a device
1842 * which does not have SES nodes
1843 */
1844 return (0);
1845 }
1846 return (err);
1847 }
1848
1849 /*
1850 * There is a SES path on the same FCA as the given disk. But if the
1851 * SES node is not of a photon/Daktari, we dont proceed
1852 */
1853 if ((err = g_get_inquiry(ses_path, &inq)) != 0) {
1854 (void) free(map.dev_addr);
1855 return (err);
1856 }
1857
1858 /*
1859 * only want to continue if this is a photon or a Daktari
1860 *
1861 * if product ID is not SENA or VID is not "SUN" (checks for photon)
1862 * and if enclosure type is not a Daktari, then I return
1863 */
1864 if (((strstr((char *)inq.inq_pid, ENCLOSURE_PROD_ID) == 0) ||
1865 (strncmp((char *)inq.inq_vid, "SUN ",
1866 sizeof (inq.inq_vid)) != 0)) &&
1867 ((l_get_enc_type(inq) != DAK_ENC_TYPE))) {
1868 /* Not a photon/Daktari */
1869 (void) free(map.dev_addr);
1870 return (0);
1871 }
1872
1873 /* Now, set some fields that l_get_slot() uses and then call it */
1874 if ((l_state = (L_state *)g_zalloc(sizeof (L_state))) == NULL) {
1875 (void) free(map.dev_addr);
1876 return (L_MALLOC_FAILED);
1877 }
1878
1879 if ((err = l_get_ib_status(ses_path, l_state, verbose)) != 0) {
1880 (void) free(map.dev_addr);
1881 (void) l_free_lstate(&l_state);
1882 return (err);
1883 }
1884
1885 if ((err = l_get_slot(*path_struct, l_state, verbose)) != 0) {
1886 (void) free(map.dev_addr);
1887 (void) l_free_lstate(&l_state);
1888 return (err);
1889 }
1890
1891 (void) free(map.dev_addr);
1892 (void) l_free_lstate(&l_state);
1893 return (0);
1894 }
1895
1896 /*
1897 * convert box name or WWN or logical path to physical path.
1898 *
1899 * OUTPUT:
1900 * path_struct:
1901 * - This structure is used to return more detailed
1902 * information about the path.
1903 * - *p_physical_path
1904 * Normally this is the requested physical path.
1905 * If the requested path is not found then iff the
1906 * ib_path_flag is set this is the IB path.
1907 * - *argv
1908 * This is the argument variable input. e.g. Bob,f1
1909 * - slot_valid
1910 * - slot
1911 * This is the slot number that was entered when using
1912 * the box,[fr]slot format. It is only valid if the
1913 * slot_valid flag is set.
1914 * - f_flag
1915 * Front flag - If set, the requested device is located in the
1916 * front of the enclosure.
1917 * - ib_path_flag
1918 * If this flag is set it means a devices path was requested
1919 * but could not be found but an IB's path was found and
1920 * the p_physical_path points to that path.
1921 * - **phys_path
1922 * physical path to the device.
1923 * RETURNS:
1924 * - 0 if O.K.
1925 * - error otherwise.
1926 */
1927 int
l_convert_name(char * name,char ** phys_path,struct path_struct ** path_struct,int verbose)1928 l_convert_name(char *name, char **phys_path,
1929 struct path_struct **path_struct, int verbose)
1930 {
1931 char tmp_name[MAXPATHLEN], ses_path[MAXPATHLEN];
1932 char *char_ptr, *ptr = NULL;
1933 char *result = NULL;
1934 char *env = NULL;
1935 char save_frd; /* which designator was it? */
1936 int slot = 0, slot_flag = 0, found_box = 0, found_comma = 0;
1937 int err = 0, enc_type = 0;
1938 hrtime_t start_time, end_time;
1939 Box_list *box_list = NULL, *box_list_ptr = NULL;
1940 L_inquiry inq;
1941 L_state *l_state = NULL;
1942 Path_struct *path_ptr = NULL;
1943 WWN_list *wwn_list, *wwn_list_ptr;
1944
1945 if ((name == NULL) || (phys_path == NULL) ||
1946 (path_struct == NULL)) {
1947 return (L_INVALID_PATH_FORMAT);
1948 }
1949
1950 if ((env = getenv("_LUX_T_DEBUG")) != NULL) {
1951 start_time = gethrtime();
1952 }
1953
1954 if ((*path_struct = path_ptr = (struct path_struct *)
1955 g_zalloc(sizeof (struct path_struct))) == NULL) {
1956 return (L_MALLOC_FAILED);
1957 }
1958
1959 *phys_path = NULL;
1960 /*
1961 * If the path contains a "/" then assume
1962 * it is a logical or physical path as the
1963 * box name or wwn can not contain "/"s.
1964 */
1965 if (strchr(name, '/') != NULL) {
1966 if ((result = g_get_physical_name(name)) == NULL) {
1967 return (L_NO_PHYS_PATH);
1968 }
1969
1970 path_ptr->p_physical_path = result;
1971 /*
1972 * Make sure it's a disk or tape path
1973 */
1974 if (strstr(name, DEV_RDIR) || strstr(name, SLSH_DRV_NAME_SSD) ||
1975 strstr(name, DEV_TAPE_DIR) ||
1976 strstr(name, SLSH_DRV_NAME_ST)) {
1977 if ((err = g_get_inquiry(result, &inq)) != 0) {
1978 (void) free(result);
1979 return (L_SCSI_ERROR);
1980 }
1981 /*
1982 * Check to see if it is not a
1983 * A5K/v880/v890 disk
1984 *
1985 */
1986 if (!g_enclDiskChk((char *)inq.inq_vid,
1987 (char *)inq.inq_pid)) {
1988 path_ptr->argv = name;
1989 *phys_path = result;
1990 return (0);
1991 }
1992 }
1993
1994 if (err = load_flds_if_enc_disk(result, path_struct)) {
1995 (void) free(result);
1996 return (err);
1997 }
1998 goto done;
1999 }
2000
2001 (void) strcpy(tmp_name, name);
2002 if ((tmp_name[0] == 'c') &&
2003 ((int)strlen(tmp_name) > 1) && ((int)strlen(tmp_name) < 5)) {
2004 if ((err = l_get_conflict(tmp_name, &result, verbose)) != 0) {
2005 if (result != NULL) {
2006 (void) g_destroy_data(result);
2007 }
2008 return (err);
2009 }
2010 if (result != NULL) {
2011 path_ptr->p_physical_path = result;
2012 if ((err = g_get_inquiry(result, &inq)) != 0) {
2013 (void) free(result);
2014 return (L_SCSI_ERROR);
2015 }
2016 /*
2017 * Check to see if it is a supported
2018 * A5K/v880/v890 storage subsystem disk
2019 */
2020 if (g_enclDiskChk((char *)inq.inq_vid,
2021 (char *)inq.inq_pid)) {
2022 if (err = load_flds_if_enc_disk(
2023 result, path_struct)) {
2024 (void) free(result);
2025 return (err);
2026 }
2027 }
2028 goto done;
2029 }
2030 }
2031
2032 /*
2033 * Check to see if we have a box or WWN name.
2034 *
2035 * If it contains a , then the format must be
2036 * box_name,f1 where f is front and 1 is the slot number
2037 * or it is a format like
2038 * ssd@w2200002037049adf,0:h,raw
2039 * or
2040 * SUNW,pln@a0000000,77791d:ctlr
2041 */
2042 if (((char_ptr = strstr(tmp_name, ",")) != NULL) &&
2043 ((*(char_ptr + 1) == 'f') || (*(char_ptr + 1) == 'r') ||
2044 (*(char_ptr + 1) == 's'))) {
2045 char_ptr++; /* point to f/r */
2046 if ((*char_ptr == 'f') || (*char_ptr == 's')) {
2047 path_ptr->f_flag = 1;
2048 } else if (*char_ptr != 'r') {
2049 return (L_INVALID_PATH_FORMAT);
2050 }
2051 save_frd = (char)*char_ptr; /* save it */
2052 char_ptr++;
2053 slot = strtol(char_ptr, &ptr, 10);
2054 /*
2055 * NOTE: Need to double check the slot when we get
2056 * the number of the devices actually in the box.
2057 */
2058 if ((slot < 0) || (ptr == char_ptr) ||
2059 ((save_frd == 's' && slot >= MAX_DRIVES_DAK) ||
2060 ((save_frd != 's' && slot >= (MAX_DRIVES_PER_BOX/2))))) {
2061 return (L_INVALID_SLOT);
2062 }
2063 /* Say slot valid. */
2064 slot_flag = path_ptr->slot_valid = 1;
2065 if (save_frd == 's' && slot >= (MAX_DRIVES_DAK/2)) {
2066 path_ptr->slot = slot = slot % (MAX_DRIVES_DAK/2);
2067 path_ptr->f_flag = 0;
2068 } else
2069 path_ptr->slot = slot;
2070 }
2071
2072 if (((char_ptr = strstr(tmp_name, ",")) != NULL) &&
2073 ((*(char_ptr + 1) == 'f') || (*(char_ptr + 1) == 'r') ||
2074 (*(char_ptr + 1) == 's'))) {
2075 *char_ptr = NULL; /* make just box name */
2076 found_comma = 1;
2077 }
2078 /* Find path to IB */
2079 if ((err = l_get_box_list(&box_list, verbose)) != 0) {
2080 (void) l_free_box_list(&box_list);
2081 return (err);
2082 }
2083 box_list_ptr = box_list;
2084 /* Look for box name. */
2085 while (box_list != NULL) {
2086 if ((strcmp((char *)tmp_name, (char *)box_list->b_name)) == 0) {
2087 result =
2088 g_alloc_string(box_list->b_physical_path);
2089 L_DPRINTF(" l_convert_name:"
2090 " Found subsystem: name %s WWN %s\n",
2091 box_list->b_name, box_list->b_node_wwn_s);
2092 /*
2093 * Check for another box with this name.
2094 */
2095 if (l_duplicate_names(box_list_ptr,
2096 box_list->b_node_wwn_s,
2097 (char *)box_list->b_name,
2098 verbose)) {
2099 (void) l_free_box_list(&box_list_ptr);
2100 (void) g_destroy_data(result);
2101 return (L_DUPLICATE_ENCLOSURES);
2102 }
2103 found_box = 1;
2104 break;
2105 }
2106 box_list = box_list->box_next;
2107 }
2108 /*
2109 * Check to see if we must get individual disks path.
2110 */
2111
2112 if (found_box && slot_flag) {
2113 if ((l_state = (L_state *)g_zalloc(sizeof (L_state))) == NULL) {
2114 (void) g_destroy_data(result);
2115 (void) l_free_box_list(&box_list_ptr);
2116 return (L_MALLOC_FAILED);
2117 }
2118 (void) strcpy(ses_path, result);
2119 if ((err = l_get_status(ses_path, l_state,
2120 verbose)) != 0) {
2121 (void) g_destroy_data(result);
2122 (void) g_destroy_data(l_state);
2123 (void) l_free_box_list(&box_list_ptr);
2124 return (err);
2125 }
2126 /*
2127 * Now double check the slot number.
2128 */
2129 if (slot >= l_state->total_num_drv/2) {
2130 path_ptr->slot_valid = 0;
2131 (void) g_destroy_data(result);
2132 (void) l_free_box_list(&box_list_ptr);
2133 (void) l_free_lstate(&l_state);
2134 return (L_INVALID_SLOT);
2135 }
2136
2137 /* Only allow the single slot version for Daktari */
2138 if (g_get_inquiry(ses_path, &inq)) {
2139 return (L_SCSI_ERROR);
2140 }
2141 enc_type = l_get_enc_type(inq);
2142 if (((enc_type == DAK_ENC_TYPE) && (save_frd != 's')) ||
2143 ((enc_type != DAK_ENC_TYPE) && (save_frd == 's'))) {
2144 path_ptr->slot_valid = 0;
2145 (void) g_destroy_data(result);
2146 (void) l_free_box_list(&box_list_ptr);
2147 (void) l_free_lstate(&l_state);
2148 return (L_INVALID_SLOT);
2149 }
2150
2151 if (path_ptr->f_flag) {
2152 if (*l_state->drv_front[slot].g_disk_state.physical_path) {
2153 result =
2154 g_alloc_string(l_state->drv_front[slot].g_disk_state.physical_path);
2155 } else {
2156 /* Result is the IB path */
2157 path_ptr->ib_path_flag = 1;
2158 path_ptr->p_physical_path =
2159 g_alloc_string(result);
2160 (void) g_destroy_data(result);
2161 result = NULL;
2162 }
2163 } else {
2164 if (*l_state->drv_rear[slot].g_disk_state.physical_path) {
2165 result =
2166 g_alloc_string(l_state->drv_rear[slot].g_disk_state.physical_path);
2167 } else {
2168 /* Result is the IB path */
2169 path_ptr->ib_path_flag = 1;
2170 path_ptr->p_physical_path =
2171 g_alloc_string(result);
2172 (void) g_destroy_data(result);
2173 result = NULL;
2174 }
2175 }
2176 (void) l_free_lstate(&l_state);
2177 goto done;
2178 }
2179 if (found_box || found_comma) {
2180 goto done;
2181 }
2182 /*
2183 * No luck with the box name.
2184 *
2185 * Try WWN's
2186 */
2187 /* Look for the SES's WWN */
2188 box_list = box_list_ptr;
2189 while (box_list != NULL) {
2190 if (((strcasecmp((char *)tmp_name,
2191 (char *)box_list->b_port_wwn_s)) == 0) ||
2192 ((strcasecmp((char *)tmp_name,
2193 (char *)box_list->b_node_wwn_s)) == 0)) {
2194 result =
2195 g_alloc_string(box_list->b_physical_path);
2196 L_DPRINTF(" l_convert_name:"
2197 " Found subsystem using the WWN"
2198 ": name %s WWN %s\n",
2199 box_list->b_name, box_list->b_node_wwn_s);
2200 goto done;
2201 }
2202 box_list = box_list->box_next;
2203 }
2204 /* Look for a device's WWN */
2205 if (strlen(tmp_name) <= L_WWN_LENGTH) {
2206 if ((err = g_get_wwn_list(&wwn_list, verbose)) != 0) {
2207 (void) l_free_box_list(&box_list_ptr);
2208 return (err);
2209 }
2210 for (wwn_list_ptr = wwn_list; wwn_list_ptr != NULL;
2211 wwn_list_ptr = wwn_list_ptr->wwn_next) {
2212 if (((strcasecmp((char *)tmp_name,
2213 (char *)wwn_list_ptr->node_wwn_s)) == 0) ||
2214 ((strcasecmp((char *)tmp_name,
2215 (char *)wwn_list_ptr->port_wwn_s)) == 0)) {
2216 /*
2217 * Found the device's WWN in the global WWN list.
2218 * It MAY be in a photon/Daktari. If it is, we'll set
2219 * additional fields in path_struct.
2220 */
2221 result = g_alloc_string(wwn_list_ptr->physical_path);
2222 L_DPRINTF(" l_convert_name:"
2223 " Found device: WWN %s Path %s\n",
2224 tmp_name, wwn_list_ptr->logical_path);
2225
2226 (void) g_free_wwn_list(&wwn_list);
2227
2228 /*
2229 * Now check if it is a disk in an A5K and set
2230 * path_struct fields
2231 */
2232 path_ptr->p_physical_path = result;
2233 if ((err = g_get_inquiry(result, &inq)) != 0) {
2234 (void) free(result);
2235 return (L_SCSI_ERROR);
2236 }
2237 /*
2238 * Check to see if it is a supported
2239 * A5K/v880/v890 storage subsystem disk
2240 */
2241 if (g_enclDiskChk((char *)inq.inq_vid,
2242 (char *)inq.inq_pid)) {
2243 if (err = load_flds_if_enc_disk(
2244 result, path_struct)) {
2245 (void) free(result);
2246 return (err);
2247 }
2248 }
2249 goto done;
2250 }
2251 }
2252 }
2253
2254 /*
2255 * Try again in case we were in the /dev
2256 * or /devices directory.
2257 */
2258 result = g_get_physical_name(name);
2259
2260 done:
2261 (void) l_free_box_list(&box_list_ptr);
2262 path_ptr->argv = name;
2263 if (result == NULL) {
2264 if (!path_ptr->ib_path_flag)
2265 return (-1);
2266 } else {
2267 path_ptr->p_physical_path = result;
2268 }
2269
2270 L_DPRINTF(" l_convert_name: path_struct:\n\tphysical_path:\n\t %s\n"
2271 "\targv:\t\t%s"
2272 "\n\tslot_valid\t%d"
2273 "\n\tslot\t\t%d"
2274 "\n\tf_flag\t\t%d"
2275 "\n\tib_path_flag\t%d\n",
2276 path_ptr->p_physical_path,
2277 path_ptr->argv,
2278 path_ptr->slot_valid,
2279 path_ptr->slot,
2280 path_ptr->f_flag,
2281 path_ptr->ib_path_flag);
2282 if (env != NULL) {
2283 end_time = gethrtime();
2284 (void) fprintf(stdout, " l_convert_name: "
2285 "Time = %lld millisec\n",
2286 (end_time - start_time)/1000000);
2287 }
2288
2289 if (path_ptr->ib_path_flag)
2290 return (-1);
2291 *phys_path = result;
2292 return (0);
2293 }
2294
2295
2296 /*
2297 * Gets envsen information of an enclosure from IB
2298 *
2299 * RETURNS:
2300 * 0 O.K.
2301 * non-zero otherwise
2302 */
2303 int
l_get_envsen_page(int fd,uchar_t * buf,int buf_size,uchar_t page_code,int verbose)2304 l_get_envsen_page(int fd, uchar_t *buf, int buf_size, uchar_t page_code,
2305 int verbose)
2306 {
2307 Rec_diag_hdr hdr;
2308 uchar_t *pg;
2309 int size, new_size, status;
2310
2311 if (buf == NULL) {
2312 return (L_INVALID_BUF_LEN);
2313 }
2314
2315 if (verbose) {
2316 (void) fprintf(stdout,
2317 MSGSTR(9046, " Reading SES page %x\n"), page_code);
2318 }
2319
2320 (void) memset(&hdr, 0, sizeof (struct rec_diag_hdr));
2321 if (status = g_scsi_rec_diag_cmd(fd, (uchar_t *)&hdr,
2322 sizeof (struct rec_diag_hdr), page_code)) {
2323 return (status);
2324 }
2325
2326 /* Check */
2327 if ((hdr.page_code != page_code) || (hdr.page_len == 0)) {
2328 return (L_RD_PG_INVLD_CODE);
2329 }
2330 size = HEADER_LEN + hdr.page_len;
2331 /*
2332 * Because of a hardware restriction in the soc+ chip
2333 * the transfers must be word aligned.
2334 */
2335 while (size & 0x03) {
2336 size++;
2337 if (size > buf_size) {
2338 return (L_RD_PG_MIN_BUFF);
2339 }
2340 P_DPRINTF(" l_get_envsen_page: Adjusting size of the "
2341 "g_scsi_rec_diag_cmd buffer.\n");
2342 }
2343
2344 if ((pg = (uchar_t *)g_zalloc(size)) == NULL) {
2345 return (L_MALLOC_FAILED);
2346 }
2347
2348 P_DPRINTF(" l_get_envsen_page: Reading page %x of size 0x%x\n",
2349 page_code, size);
2350 if (status = g_scsi_rec_diag_cmd(fd, pg, size, page_code)) {
2351 (void) g_destroy_data((char *)pg);
2352 return (status);
2353 }
2354
2355 new_size = MIN(size, buf_size);
2356 bcopy((const void *)pg, (void *)buf, (size_t)new_size);
2357
2358 (void) g_destroy_data(pg);
2359 return (0);
2360 }
2361
2362
2363
2364 /*
2365 * Get consolidated copy of all environmental information
2366 * into buf structure.
2367 *
2368 * RETURNS:
2369 * 0 O.K.
2370 * non-zero otherwise
2371 */
2372
2373 int
l_get_envsen(char * path_phys,uchar_t * buf,int size,int verbose)2374 l_get_envsen(char *path_phys, uchar_t *buf, int size, int verbose)
2375 {
2376 int fd, rval;
2377 uchar_t *page_list_ptr, page_code, *local_buf_ptr = buf;
2378 Rec_diag_hdr *hdr = (struct rec_diag_hdr *)(void *)buf;
2379 ushort_t num_pages;
2380
2381 if ((path_phys == NULL) || (buf == NULL)) {
2382 return (L_INVALID_PATH_FORMAT);
2383 }
2384
2385 page_code = L_PAGE_PAGE_LIST;
2386
2387 /* open IB */
2388 if ((fd = g_object_open(path_phys, O_NDELAY | O_RDONLY)) == -1)
2389 return (L_OPEN_PATH_FAIL);
2390
2391 P_DPRINTF(" l_get_envsen: Getting list of supported"
2392 " pages from IB\n");
2393 if (verbose) {
2394 (void) fprintf(stdout,
2395 MSGSTR(9047, " Getting list of supported pages from IB\n"));
2396 }
2397
2398 /* Get page 0 */
2399 if ((rval = l_get_envsen_page(fd, local_buf_ptr,
2400 size, page_code, verbose)) != NULL) {
2401 (void) close(fd);
2402 return (rval);
2403 }
2404
2405 page_list_ptr = buf + HEADER_LEN + 1; /* +1 to skip page 0 */
2406
2407 num_pages = hdr->page_len - 1;
2408
2409 /*
2410 * check whether the number of pages received
2411 * from IB are valid. SENA enclosure
2412 * supports only 8 pages of sense information.
2413 * According to SES specification dpANS X3.xxx-1997
2414 * X3T10/Project 1212-D/Rev 8a, the enclosure supported
2415 * pages can go upto L_MAX_POSSIBLE_PAGES (0xFF).
2416 * Return an error if no. of pages exceeds L_MAX_POSSIBLE_PAGES.
2417 * See if (num_pages >= L_MAX_POSSIBLE_PAGES) since 1 page (page 0)
2418 * was already subtracted from the total number of pages before.
2419 */
2420 if (num_pages < 1 || num_pages >= L_MAX_POSSIBLE_PAGES) {
2421 return (L_INVALID_NO_OF_ENVSEN_PAGES);
2422 }
2423 /*
2424 * Buffer size of MAX_REC_DIAG_LENGTH can be small if the
2425 * number of pages exceed more than L_MAX_SENAIB_PAGES
2426 * but less than L_MAX_POSSIBLE_PAGES.
2427 */
2428 if (size == MAX_REC_DIAG_LENGTH &&
2429 num_pages >= L_MAX_SENAIB_PAGES) {
2430 return (L_INVALID_BUF_LEN);
2431 }
2432 /* Align buffer */
2433 while (hdr->page_len & 0x03) {
2434 hdr->page_len++;
2435 }
2436 local_buf_ptr += HEADER_LEN + hdr->page_len;
2437
2438 /*
2439 * Getting all pages and appending to buf
2440 */
2441 for (; num_pages--; page_list_ptr++) {
2442 /*
2443 * The fifth byte of page 0 is the start
2444 * of the list of pages not including page 0.
2445 */
2446 page_code = *page_list_ptr;
2447
2448 if ((rval = l_get_envsen_page(fd, local_buf_ptr,
2449 size, page_code, verbose)) != NULL) {
2450 (void) close(fd);
2451 return (rval);
2452 }
2453 hdr = (struct rec_diag_hdr *)(void *)local_buf_ptr;
2454 local_buf_ptr += HEADER_LEN + hdr->page_len;
2455 }
2456
2457 (void) close(fd);
2458 return (0);
2459 }
2460
2461
2462
2463 /*
2464 * Get the individual disk status.
2465 * Path must be physical and point to a disk.
2466 *
2467 * This function updates the d_state_flags, port WWN's
2468 * and num_blocks for all accessiable ports
2469 * in l_disk_state->g_disk_state structure.
2470 *
2471 * RETURNS:
2472 * 0 O.K.
2473 * non-zero otherwise
2474 */
2475 int
l_get_disk_status(char * path,struct l_disk_state_struct * l_disk_state,WWN_list * wwn_list,int verbose)2476 l_get_disk_status(char *path, struct l_disk_state_struct *l_disk_state,
2477 WWN_list *wwn_list, int verbose)
2478 {
2479 struct dlist *ml;
2480 char path_a[MAXPATHLEN], path_b[MAXPATHLEN], ses_path[MAXPATHLEN];
2481 gfc_map_t map;
2482 int path_a_found = 0, path_b_found = 0, local_port_a_flag;
2483 uchar_t node_wwn[WWN_SIZE], port_wwn[WWN_SIZE];
2484 int al_pa, err, pathcnt = 1;
2485 int i = 0;
2486 char temppath[MAXPATHLEN];
2487 mp_pathlist_t pathlist;
2488 char pwwn[WWN_S_LEN];
2489 struct stat sbuf;
2490
2491 if ((path == NULL) || (l_disk_state == NULL)) {
2492 return (L_INVALID_PATH_FORMAT);
2493 }
2494
2495 /* Check device name */
2496 if (stat(path, &sbuf) || (sbuf.st_rdev == NODEV)) {
2497 G_DPRINTF(" l_get_disk_status: invalid device %s\n", path);
2498 return (L_INVALID_PATH);
2499 }
2500
2501 /* Initialize */
2502 *path_a = *path_b = NULL;
2503 l_disk_state->g_disk_state.num_blocks = 0;
2504
2505 /* Get paths. */
2506 g_get_multipath(path,
2507 &(l_disk_state->g_disk_state.multipath_list),
2508 wwn_list, verbose);
2509 ml = l_disk_state->g_disk_state.multipath_list;
2510 if (ml == NULL) {
2511 l_disk_state->l_state_flag = L_NO_PATH_FOUND;
2512 G_DPRINTF(" l_get_disk_status: Error finding a "
2513 "multipath to the disk.\n");
2514 return (0);
2515 }
2516
2517 if (strstr(path, SCSI_VHCI) != NULL) {
2518 /*
2519 * It is an MPXIO Path
2520 */
2521 (void) strcpy(temppath, path);
2522 if (g_get_pathlist(temppath, &pathlist)) {
2523 return (0);
2524 }
2525 pathcnt = pathlist.path_count;
2526 for (i = 0; i < pathcnt; i++) {
2527 /*
2528 * Skip inactive paths.
2529 * A path that is not in either
2530 * MDI_PATHINFO_STATE_ONLINE or
2531 * MDI_PATHINFO_STATE_STANDBY state is not
2532 * an active path.
2533 *
2534 * When a disk port is bypassed and mpxio is
2535 * enabled, the path_state for that path goes to the
2536 * offline state
2537 */
2538 if (pathlist.path_info[i].path_state !=
2539 MDI_PATHINFO_STATE_ONLINE &&
2540 pathlist.path_info[i].path_state !=
2541 MDI_PATHINFO_STATE_STANDBY) {
2542 continue;
2543 }
2544 (void) strncpy(pwwn, pathlist.path_info[i].path_addr,
2545 L_WWN_LENGTH);
2546 pwwn[L_WWN_LENGTH] = '\0';
2547 if (!(path_a_found || path_b_found)) {
2548 if (pwwn[1] == '1') {
2549 local_port_a_flag = 1;
2550 } else {
2551 local_port_a_flag = 0;
2552 }
2553 } else if (path_a_found &&
2554 (strstr(l_disk_state->g_disk_state.port_a_wwn_s,
2555 pwwn) == NULL)) {
2556 /* do port b */
2557 local_port_a_flag = 0;
2558 } else if (path_b_found &&
2559 (strstr(l_disk_state->g_disk_state.port_b_wwn_s,
2560 pwwn) == NULL)) {
2561 /* do port a */
2562 local_port_a_flag = 1;
2563 }
2564
2565 if (err = l_get_disk_port_status(path,
2566 l_disk_state, local_port_a_flag, verbose)) {
2567 return (err);
2568 }
2569
2570 if (local_port_a_flag && (!path_a_found)) {
2571 (void) strcpy(l_disk_state->
2572 g_disk_state.port_a_wwn_s, pwwn);
2573 l_disk_state->g_disk_state.port_a_valid++;
2574 path_a_found++;
2575 }
2576
2577 if ((!local_port_a_flag) && (!path_b_found)) {
2578 (void) strcpy(l_disk_state->
2579 g_disk_state.port_b_wwn_s, pwwn);
2580 l_disk_state->g_disk_state.port_b_valid++;
2581 path_b_found++;
2582 }
2583 }
2584 free(pathlist.path_info);
2585 return (0);
2586 }
2587
2588 while (ml && (!(path_a_found && path_b_found))) {
2589 if (err = g_get_dev_map(ml->dev_path, &map, verbose)) {
2590 (void) g_free_multipath(ml);
2591 return (err);
2592 }
2593 if ((err = l_get_ses_path(ml->dev_path, ses_path,
2594 &map, verbose)) != 0) {
2595 (void) g_free_multipath(ml);
2596 free((void *)map.dev_addr);
2597 return (err);
2598 }
2599 free((void *)map.dev_addr); /* Not used anymore */
2600
2601 /*
2602 * Get the port, A or B, of the disk,
2603 * by passing the IB path.
2604 */
2605 if (err = l_get_port(ses_path, &local_port_a_flag, verbose)) {
2606 (void) g_free_multipath(ml);
2607 return (err);
2608 }
2609 if (local_port_a_flag && (!path_a_found)) {
2610 G_DPRINTF(" l_get_disk_status: Path to Port A "
2611 "found: %s\n", ml->dev_path);
2612 if (err = l_get_disk_port_status(ml->dev_path,
2613 l_disk_state, local_port_a_flag, verbose)) {
2614 (void) g_free_multipath(ml);
2615 return (err);
2616 }
2617 if (err = g_get_wwn(ml->dev_path,
2618 port_wwn, node_wwn,
2619 &al_pa, verbose)) {
2620 (void) g_free_multipath(ml);
2621 return (err);
2622 }
2623 (void) sprintf(l_disk_state->g_disk_state.port_a_wwn_s,
2624 "%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x",
2625 port_wwn[0], port_wwn[1], port_wwn[2], port_wwn[3],
2626 port_wwn[4], port_wwn[5], port_wwn[6], port_wwn[7]);
2627
2628 l_disk_state->g_disk_state.port_a_valid++;
2629 path_a_found++;
2630 }
2631 if ((!local_port_a_flag) && (!path_b_found)) {
2632 G_DPRINTF(" l_get_disk_status: Path to Port B "
2633 "found: %s\n", ml->dev_path);
2634 if (err = l_get_disk_port_status(ml->dev_path,
2635 l_disk_state, local_port_a_flag, verbose)) {
2636 return (err);
2637 }
2638 if (err = g_get_wwn(ml->dev_path,
2639 port_wwn, node_wwn,
2640 &al_pa, verbose)) {
2641 (void) g_free_multipath(ml);
2642 return (err);
2643 }
2644 (void) sprintf(l_disk_state->g_disk_state.port_b_wwn_s,
2645 "%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x",
2646 port_wwn[0], port_wwn[1], port_wwn[2], port_wwn[3],
2647 port_wwn[4], port_wwn[5], port_wwn[6], port_wwn[7]);
2648
2649 l_disk_state->g_disk_state.port_b_valid++;
2650 path_b_found++;
2651 }
2652 ml = ml->next;
2653 }
2654 return (0);
2655
2656
2657 }
2658
2659
2660
2661 /*
2662 * Check for Persistent Reservations.
2663 */
2664 int
l_persistent_check(int fd,struct l_disk_state_struct * l_disk_state,int verbose)2665 l_persistent_check(int fd, struct l_disk_state_struct *l_disk_state,
2666 int verbose)
2667 {
2668 int status;
2669 Read_keys read_key_buf;
2670 Read_reserv read_reserv_buf;
2671
2672 (void) memset(&read_key_buf, 0, sizeof (struct read_keys_struct));
2673 if ((status = g_scsi_persistent_reserve_in_cmd(fd,
2674 (uchar_t *)&read_key_buf, sizeof (struct read_keys_struct),
2675 ACTION_READ_KEYS))) {
2676 return (status);
2677 }
2678 /* This means persistent reservations are supported by the disk. */
2679 l_disk_state->g_disk_state.persistent_reserv_flag = 1;
2680
2681 if (read_key_buf.rk_length) {
2682 l_disk_state->g_disk_state.persistent_registered = 1;
2683 }
2684
2685 (void) memset(&read_reserv_buf, 0,
2686 sizeof (struct read_reserv_struct));
2687 if ((status = g_scsi_persistent_reserve_in_cmd(fd,
2688 (uchar_t *)&read_reserv_buf,
2689 sizeof (struct read_reserv_struct),
2690 ACTION_READ_RESERV))) {
2691 return (status);
2692 }
2693 if (read_reserv_buf.rr_length) {
2694 l_disk_state->g_disk_state.persistent_active = 1;
2695 }
2696 if (verbose) {
2697 (void) fprintf(stdout,
2698 MSGSTR(9048, " Checking for Persistent "
2699 "Reservations:"));
2700 if (l_disk_state->g_disk_state.persistent_reserv_flag) {
2701 if (l_disk_state->g_disk_state.persistent_active != NULL) {
2702 (void) fprintf(stdout, MSGSTR(39, "Active"));
2703 } else {
2704 (void) fprintf(stdout, MSGSTR(9049, "Registered"));
2705 }
2706 } else {
2707 (void) fprintf(stdout,
2708 MSGSTR(87,
2709 "Not being used"));
2710 }
2711 (void) fprintf(stdout, "\n");
2712 }
2713 return (0);
2714 }
2715
2716
2717
2718 /*
2719 * Gets the disk status and
2720 * updates the l_disk_state_struct structure.
2721 * Checks for open fail, Reservation Conflicts,
2722 * Not Ready and so on.
2723 *
2724 * RETURNS:
2725 * 0 O.K.
2726 * non-zero otherwise
2727 */
2728 int
l_get_disk_port_status(char * path,struct l_disk_state_struct * l_disk_state,int port_a_flag,int verbose)2729 l_get_disk_port_status(char *path, struct l_disk_state_struct *l_disk_state,
2730 int port_a_flag, int verbose)
2731 {
2732 int fd, status = 0, local_state = 0;
2733 Read_capacity_data capacity; /* local read capacity buffer */
2734 struct vtoc vtoc;
2735
2736 if ((path == NULL) || (l_disk_state == NULL)) {
2737 return (L_INVALID_PATH_FORMAT);
2738 }
2739
2740 /*
2741 * Try to open drive.
2742 */
2743 if ((fd = g_object_open(path, O_RDONLY)) == -1) {
2744 if ((fd = g_object_open(path,
2745 O_RDONLY | O_NDELAY)) == -1) {
2746 G_DPRINTF(" l_get_disk_port_status: Error "
2747 "opening drive %s\n", path);
2748 local_state = L_OPEN_FAIL;
2749 } else {
2750 /* See if drive ready */
2751 if (status = g_scsi_tur(fd)) {
2752 if ((status & L_SCSI_ERROR) &&
2753 ((status & ~L_SCSI_ERROR) == STATUS_CHECK)) {
2754 /*
2755 * TBD
2756 * This is where I should figure out
2757 * if the device is Not Ready or whatever.
2758 */
2759 local_state = L_NOT_READY;
2760 } else if ((status & L_SCSI_ERROR) &&
2761 ((status & ~L_SCSI_ERROR) ==
2762 STATUS_RESERVATION_CONFLICT)) {
2763 /* mark reserved */
2764 local_state = L_RESERVED;
2765 } else {
2766 local_state = L_SCSI_ERR;
2767 }
2768
2769 /*
2770 * There may not be a label on the drive - check
2771 */
2772 } else if (ioctl(fd, DKIOCGVTOC, &vtoc) == 0) {
2773 /*
2774 * Sanity-check the vtoc
2775 */
2776 if (vtoc.v_sanity != VTOC_SANE ||
2777 vtoc.v_sectorsz != DEV_BSIZE) {
2778 local_state = L_NO_LABEL;
2779 G_DPRINTF(" l_get_disk_port_status: "
2780 "Checking vtoc - No Label found.\n");
2781 }
2782 } else if (errno != ENOTSUP) {
2783 I_DPRINTF("\t- DKIOCGVTOC ioctl failed: "
2784 " invalid geometry\n");
2785 local_state = L_NO_LABEL;
2786 }
2787 }
2788 }
2789 /*
2790 * Need an extra check for tape devices
2791 * read capacity should not be run on tape devices.
2792 * It will always return Not Readable
2793 */
2794 if (((local_state == 0) || (local_state == L_NO_LABEL)) &&
2795 ! (strstr(path, SLSH_DRV_NAME_ST))) {
2796
2797 if (status = g_scsi_read_capacity_cmd(fd, (uchar_t *)&capacity,
2798 sizeof (capacity))) {
2799 G_DPRINTF(" l_get_disk_port_status: "
2800 "Read Capacity failed.\n");
2801 if (status & L_SCSI_ERROR) {
2802 if ((status & ~L_SCSI_ERROR) ==
2803 STATUS_RESERVATION_CONFLICT) {
2804 /* mark reserved */
2805 local_state |= L_RESERVED;
2806 } else
2807 /* mark bad */
2808 local_state |= L_NOT_READABLE;
2809 } else {
2810 /*
2811 * TBD
2812 * Need a more complete state definition here.
2813 */
2814 l_disk_state->g_disk_state.d_state_flags[port_a_flag] =
2815 L_SCSI_ERR;
2816 (void) close(fd);
2817 return (0);
2818 }
2819 } else {
2820 /* save capacity */
2821 l_disk_state->g_disk_state.num_blocks =
2822 capacity.last_block_addr + 1;
2823 }
2824
2825 }
2826 (void) close(fd);
2827
2828 l_disk_state->g_disk_state.d_state_flags[port_a_flag] = local_state;
2829 G_DPRINTF(" l_get_disk_port_status: Individual Disk"
2830 " Status: 0x%x for"
2831 " port %s for path:"
2832 " %s\n", local_state,
2833 port_a_flag ? "A" : "B", path);
2834
2835 return (0);
2836 }
2837
2838
2839
2840 /*
2841 * Copy and format page 1 from big buffer to state structure.
2842 *
2843 * RETURNS:
2844 * 0 O.K.
2845 * non-zero otherwise
2846 */
2847
2848 static int
copy_config_page(struct l_state_struct * l_state,uchar_t * from_ptr)2849 copy_config_page(struct l_state_struct *l_state, uchar_t *from_ptr)
2850 {
2851 IB_page_config *encl_ptr;
2852 int size, i;
2853
2854
2855 encl_ptr = (struct ib_page_config *)(void *)from_ptr;
2856
2857 /* Sanity check. */
2858 if ((encl_ptr->enc_len > MAX_VEND_SPECIFIC_ENC) ||
2859 (encl_ptr->enc_len == 0)) {
2860 return (L_REC_DIAG_PG1);
2861 }
2862 if ((encl_ptr->enc_num_elem > MAX_IB_ELEMENTS) ||
2863 (encl_ptr->enc_num_elem == 0)) {
2864 return (L_REC_DIAG_PG1);
2865 }
2866
2867 size = HEADER_LEN + 4 + HEADER_LEN + encl_ptr->enc_len;
2868 bcopy((void *)(from_ptr),
2869 (void *)&l_state->ib_tbl.config, (size_t)size);
2870 /*
2871 * Copy Type Descriptors seperately to get aligned.
2872 */
2873 from_ptr += size;
2874 size = (sizeof (struct type_desc_hdr))*encl_ptr->enc_num_elem;
2875 bcopy((void *)(from_ptr),
2876 (void *)&l_state->ib_tbl.config.type_hdr, (size_t)size);
2877
2878 /*
2879 * Copy Text Descriptors seperately to get aligned.
2880 *
2881 * Must use the text size from the Type Descriptors.
2882 */
2883 from_ptr += size;
2884 for (i = 0; i < (int)l_state->ib_tbl.config.enc_num_elem; i++) {
2885 size = l_state->ib_tbl.config.type_hdr[i].text_len;
2886 bcopy((void *)(from_ptr),
2887 (void *)&l_state->ib_tbl.config.text[i], (size_t)size);
2888 from_ptr += size;
2889 }
2890 return (0);
2891 }
2892
2893
2894
2895 /*
2896 * Copy page 7 (Element Descriptor page) to state structure.
2897 * Copy header then copy each element descriptor
2898 * seperately.
2899 *
2900 * RETURNS:
2901 * 0 O.K.
2902 * non-zero otherwise
2903 */
2904 static void
copy_page_7(struct l_state_struct * l_state,uchar_t * from_ptr)2905 copy_page_7(struct l_state_struct *l_state, uchar_t *from_ptr)
2906 {
2907 uchar_t *my_from_ptr;
2908 int size, j, k, p7_index;
2909
2910 size = HEADER_LEN +
2911 sizeof (l_state->ib_tbl.p7_s.gen_code);
2912 bcopy((void *)(from_ptr),
2913 (void *)&l_state->ib_tbl.p7_s, (size_t)size);
2914 my_from_ptr = from_ptr + size;
2915 if (getenv("_LUX_D_DEBUG") != NULL) {
2916 g_dump(" copy_page_7: Page 7 header: ",
2917 (uchar_t *)&l_state->ib_tbl.p7_s, size,
2918 HEX_ASCII);
2919 (void) fprintf(stdout,
2920 " copy_page_7: Elements being stored "
2921 "in state table\n"
2922 " ");
2923 }
2924 /* I am assuming page 1 has been read. */
2925 for (j = 0, p7_index = 0;
2926 j < (int)l_state->ib_tbl.config.enc_num_elem; j++) {
2927 /* Copy global element */
2928 size = HEADER_LEN +
2929 ((*(my_from_ptr + 2) << 8) | *(my_from_ptr + 3));
2930 bcopy((void *)(my_from_ptr),
2931 (void *)&l_state->ib_tbl.p7_s.element_desc[p7_index++],
2932 (size_t)size);
2933 my_from_ptr += size;
2934 for (k = 0; k < (int)l_state->ib_tbl.config.type_hdr[j].num;
2935 k++) {
2936 /* Copy individual elements */
2937 size = HEADER_LEN +
2938 ((*(my_from_ptr + 2) << 8) |
2939 *(my_from_ptr + 3));
2940 bcopy((void *)(my_from_ptr),
2941 (void *)&l_state->ib_tbl.p7_s.element_desc[p7_index++],
2942 (size_t)size);
2943 my_from_ptr += size;
2944 D_DPRINTF(".");
2945 }
2946 }
2947 D_DPRINTF("\n");
2948 }
2949
2950
2951 /*
2952 * Gets IB diagnostic pages on a given pathname from l_get_envsen().
2953 * It also fills up the individual device element of l_state_struct using
2954 * diagnostics pages.
2955 * Gets IB diagnostic pages on a given pathname from l_get_envsen().
2956 * It also fills up the individual device element of l_state_struct using
2957 * diagnostics pages.
2958 *
2959 * The path must be of the ses driver.
2960 * e.g.
2961 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@e,0:0
2962 * or
2963 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@WWN,0:0
2964 *
2965 *
2966 * RETURNS:
2967 * 0 O.K.
2968 * non-zero otherwise
2969 */
2970 int
l_get_ib_status(char * path,struct l_state_struct * l_state,int verbose)2971 l_get_ib_status(char *path, struct l_state_struct *l_state,
2972 int verbose)
2973 {
2974 L_inquiry inq;
2975 uchar_t *ib_buf, *from_ptr;
2976 int num_pages, i, size, err;
2977 IB_page_2 *encl_ptr;
2978 int front_index, rear_index;
2979 int enc_type = 0;
2980
2981 if ((path == NULL) || (l_state == NULL)) {
2982 return (L_INVALID_PATH_FORMAT);
2983 }
2984
2985 /*
2986 * get big buffer
2987 */
2988 if ((ib_buf = (uchar_t *)calloc(1,
2989 MAX_REC_DIAG_LENGTH)) == NULL) {
2990 return (L_MALLOC_FAILED);
2991 }
2992
2993 /*
2994 * Get IB information
2995 * Even if there are 2 IB's in this box on this loop don't bother
2996 * talking to the other one as both IB's in a box
2997 * are supposed to report the same information.
2998 */
2999 if (err = l_get_envsen(path, ib_buf, MAX_REC_DIAG_LENGTH,
3000 verbose)) {
3001 (void) g_destroy_data(ib_buf);
3002 return (err);
3003 }
3004
3005 /*
3006 * Set up state structure
3007 */
3008 bcopy((void *)ib_buf, (void *)&l_state->ib_tbl.p0,
3009 (size_t)sizeof (struct ib_page_0));
3010
3011 num_pages = l_state->ib_tbl.p0.page_len;
3012 from_ptr = ib_buf + HEADER_LEN + l_state->ib_tbl.p0.page_len;
3013
3014 for (i = 1; i < num_pages; i++) {
3015 if (l_state->ib_tbl.p0.sup_page_codes[i] == L_PAGE_1) {
3016 if (err = copy_config_page(l_state, from_ptr)) {
3017 return (err);
3018 }
3019 } else if (l_state->ib_tbl.p0.sup_page_codes[i] ==
3020 L_PAGE_2) {
3021 encl_ptr = (struct ib_page_2 *)(void *)from_ptr;
3022 size = HEADER_LEN + encl_ptr->page_len;
3023 bcopy((void *)(from_ptr),
3024 (void *)&l_state->ib_tbl.p2_s, (size_t)size);
3025 if (getenv("_LUX_D_DEBUG") != NULL) {
3026 g_dump(" l_get_ib_status: Page 2: ",
3027 (uchar_t *)&l_state->ib_tbl.p2_s, size,
3028 HEX_ONLY);
3029 }
3030
3031 } else if (l_state->ib_tbl.p0.sup_page_codes[i] ==
3032 L_PAGE_7) {
3033 (void) copy_page_7(l_state, from_ptr);
3034 }
3035 from_ptr += ((*(from_ptr + 2) << 8) | *(from_ptr + 3));
3036 from_ptr += HEADER_LEN;
3037 }
3038 (void) g_destroy_data(ib_buf);
3039 G_DPRINTF(" l_get_ib_status: Read %d Receive Diagnostic pages "
3040 "from the IB.\n", num_pages);
3041
3042 if (err = g_get_inquiry(path, &inq)) {
3043 return (err);
3044 }
3045 enc_type = l_get_enc_type(inq);
3046 /*
3047 * Get the total number of drives per box.
3048 * This assumes front & rear are the same.
3049 */
3050 l_state->total_num_drv = 0; /* default to use as a flag */
3051 for (i = 0; i < (int)l_state->ib_tbl.config.enc_num_elem; i++) {
3052 if (l_state->ib_tbl.config.type_hdr[i].type == ELM_TYP_DD) {
3053 if (l_state->total_num_drv) {
3054 if (l_state->total_num_drv !=
3055 (l_state->ib_tbl.config.type_hdr[i].num * 2)) {
3056 return (L_INVALID_NUM_DISKS_ENCL);
3057 }
3058 } else {
3059 if (enc_type == DAK_ENC_TYPE) {
3060 l_state->total_num_drv =
3061 l_state->ib_tbl.config.type_hdr[i].num;
3062 } else {
3063 l_state->total_num_drv =
3064 l_state->ib_tbl.config.type_hdr[i].num * 2;
3065 }
3066 }
3067 }
3068 }
3069
3070 /*
3071 * transfer the individual drive Device Element information
3072 * from IB state to drive state.
3073 */
3074 if (err = l_get_disk_element_index(l_state, &front_index,
3075 &rear_index)) {
3076 return (err);
3077 }
3078 /* Skip global element */
3079 front_index++;
3080 if (enc_type == DAK_ENC_TYPE) {
3081 rear_index += l_state->total_num_drv/2 + 1;
3082 } else {
3083 rear_index++;
3084 }
3085
3086 for (i = 0; i < l_state->total_num_drv/2; i++) {
3087 bcopy((void *)&l_state->ib_tbl.p2_s.element[front_index + i],
3088 (void *)&l_state->drv_front[i].ib_status,
3089 (size_t)sizeof (struct device_element));
3090 bcopy((void *)&l_state->ib_tbl.p2_s.element[rear_index + i],
3091 (void *)&l_state->drv_rear[i].ib_status,
3092 (size_t)sizeof (struct device_element));
3093 }
3094 if (getenv("_LUX_G_DEBUG") != NULL) {
3095 g_dump(" l_get_ib_status: disk elements: ",
3096 (uchar_t *)&l_state->ib_tbl.p2_s.element[front_index],
3097 ((sizeof (struct device_element)) * (l_state->total_num_drv)),
3098 HEX_ONLY);
3099 }
3100
3101 return (0);
3102 }
3103
3104
3105
3106 /*
3107 * Given an IB path get the port, A or B.
3108 *
3109 * OUTPUT:
3110 * port_a: sets to 1 for port A
3111 * and 0 for port B.
3112 * RETURNS:
3113 * err: 0 O.k.
3114 * non-zero otherwise
3115 */
3116 int
l_get_port(char * ses_path,int * port_a,int verbose)3117 l_get_port(char *ses_path, int *port_a, int verbose)
3118 {
3119 L_state *ib_state = NULL;
3120 Ctlr_elem_st ctlr;
3121 int i, err, elem_index = 0;
3122
3123 if ((ses_path == NULL) || (port_a == NULL)) {
3124 return (L_NO_SES_PATH);
3125 }
3126
3127 if ((ib_state = (L_state *)calloc(1, sizeof (L_state))) == NULL) {
3128 return (L_MALLOC_FAILED);
3129 }
3130
3131 bzero(&ctlr, sizeof (ctlr));
3132 if (err = l_get_ib_status(ses_path, ib_state, verbose)) {
3133 (void) l_free_lstate(&ib_state);
3134 return (err);
3135 }
3136
3137 for (i = 0; i < (int)ib_state->ib_tbl.config.enc_num_elem; i++) {
3138 elem_index++; /* skip global */
3139 if (ib_state->ib_tbl.config.type_hdr[i].type == ELM_TYP_IB) {
3140 bcopy((const void *)
3141 &ib_state->ib_tbl.p2_s.element[elem_index],
3142 (void *)&ctlr, sizeof (ctlr));
3143 break;
3144 }
3145 elem_index += ib_state->ib_tbl.config.type_hdr[i].num;
3146 }
3147 *port_a = ctlr.report;
3148 G_DPRINTF(" l_get_port: Found ses is the %s card.\n",
3149 ctlr.report ? "A" : "B");
3150 (void) l_free_lstate(&ib_state);
3151 return (0);
3152 }
3153
3154 /*
3155 * This function expects a pointer to a device path ending in the form
3156 * .../ses@w<NODEWWN>,<something> or .../ssd@w<NODEWWN>,<something>
3157 *
3158 * No validity checking of the path is done by the function.
3159 *
3160 * It gets the wwn (node wwn) out of the passed string, searches the passed
3161 * map for a match, gets the corresponding phys addr (port id) for that entry
3162 * and stores in the pointer the caller has passed as an argument (pid)
3163 *
3164 * This function is to be called only for public/fabric topologies
3165 *
3166 * If this interface is going to get exported, one point to be
3167 * considered is if a call to g_get_path_type() has to be made.
3168 *
3169 * INPUT:
3170 * path - pointer to the enclosure/disk device path
3171 * map - pointer to the map
3172 *
3173 * OUTPUT:
3174 * pid - the physical address associated for the node WWN that was found
3175 * in the map
3176 *
3177 * RETURNS:
3178 * 0 - on success
3179 * non-zero - otherwise
3180 */
3181 int
l_get_pid_from_path(const char * path,const gfc_map_t * map,int * pid)3182 l_get_pid_from_path(const char *path, const gfc_map_t *map, int *pid)
3183 {
3184 int i;
3185 unsigned long long ll_wwn;
3186 char *char_ptr, wwn_str[WWN_SIZE * 2 + 1];
3187 char *byte_ptr, *temp_ptr;
3188 gfc_port_dev_info_t *dev_addr_ptr;
3189 mp_pathlist_t pathlist;
3190 char path0[MAXPATHLEN], pwwn0[WWN_S_LEN];
3191
3192 /* if mpxio device */
3193 if (strstr(path, SCSI_VHCI) != NULL) {
3194 (void) strcpy(path0, path);
3195 if (g_get_pathlist(path0, &pathlist)) {
3196 return (L_INVALID_PATH);
3197 } else {
3198 (void) strncpy(pwwn0, pathlist.path_info[0].
3199 path_addr, L_WWN_LENGTH);
3200 pwwn0[L_WWN_LENGTH] = '\0';
3201 free(pathlist.path_info);
3202 char_ptr = pwwn0;
3203 }
3204 } else {
3205 /* First a quick check on the path */
3206 if (((char_ptr = strrchr(path, '@')) == NULL) ||
3207 (*++char_ptr != 'w')) {
3208 return (L_INVALID_PATH);
3209 } else {
3210 char_ptr++;
3211 }
3212 }
3213
3214 if (strlen(char_ptr) < (WWN_SIZE * 2)) {
3215 return (L_INVALID_PATH);
3216 }
3217 (void) strncpy(wwn_str, char_ptr, WWN_SIZE * 2);
3218 wwn_str[WWN_SIZE * 2] = '\0';
3219 errno = 0; /* For error checking */
3220 ll_wwn = strtoull(wwn_str, &temp_ptr, L_WWN_LENGTH);
3221
3222 if (errno || (temp_ptr != (wwn_str + (WWN_SIZE * 2)))) {
3223 return (L_INVALID_PATH);
3224 }
3225
3226 byte_ptr = (char *)&ll_wwn;
3227
3228 /*
3229 * Search for the ses's node wwn in map to get the area and
3230 * domain ids from the corresponding port id (phys address).
3231 */
3232 for (dev_addr_ptr = map->dev_addr, i = 0; i < map->count;
3233 dev_addr_ptr++, i++) {
3234 if (bcmp((char *)dev_addr_ptr->gfc_port_dev.
3235 pub_port.dev_nwwn.raw_wwn, byte_ptr, WWN_SIZE) == 0)
3236 break;
3237 }
3238 if (i >= map->count)
3239 return (L_INVALID_PATH);
3240 *pid = dev_addr_ptr->gfc_port_dev.pub_port.dev_did.port_id;
3241 return (0);
3242 }
3243
3244
3245 /*
3246 * Finds the disk's node wwn string, and
3247 * port A and B's WWNs and their port status.
3248 *
3249 * INPUT:
3250 * path - pointer to a ses path
3251 * wwn_list - pointer to the wwn_list
3252 *
3253 * OUTPUT:
3254 * state - node_wwn and wwn of ports A & B of disk, etc are inited
3255 * - by l_get_disk_status()
3256 * found_flag - incremented after each examined element in the map
3257 *
3258 * RETURNS:
3259 * 0 O.K.
3260 * non-zero otherwise.
3261 */
3262 static int
l_get_node_status(char * path,struct l_disk_state_struct * state,int * found_flag,WWN_list * wwn_list,int verbose)3263 l_get_node_status(char *path, struct l_disk_state_struct *state,
3264 int *found_flag, WWN_list *wwn_list, int verbose)
3265 {
3266 int j, select_id, err;
3267 int path_pid;
3268 char temp_path[MAXPATHLEN];
3269 char sbuf[MAXPATHLEN], *char_ptr;
3270 gfc_map_mp_t *map_mp, *map_ptr;
3271 struct stat stat_buf;
3272 WWN_list *wwnlp;
3273 char wwnp[WWN_S_LEN];
3274
3275 /*
3276 * Get a new map.
3277 */
3278 map_mp = NULL;
3279 if (err = get_mp_dev_map(path, &map_mp, verbose))
3280 return (err);
3281
3282 for (map_ptr = map_mp; map_ptr != NULL; map_ptr = map_ptr->map_next) {
3283 switch (map_ptr->map.hba_addr.port_topology) {
3284 case FC_TOP_PRIVATE_LOOP:
3285 for (j = 0; j < map_ptr->map.count; j++) {
3286 /*
3287 * Get a generic path to a device
3288 *
3289 * This assumes the path looks something like this
3290 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/...
3291 * ...ses@x,0:0
3292 * then creates a path that looks like
3293 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ssd@
3294 */
3295 (void) strcpy(temp_path, path);
3296 if ((char_ptr = strrchr(temp_path, '/')) == NULL) {
3297 free_mp_dev_map(&map_mp);
3298 return (L_INVALID_PATH);
3299 }
3300 *char_ptr = '\0'; /* Terminate sting */
3301 (void) strcat(temp_path, SLSH_DRV_NAME_SSD);
3302 /*
3303 * Create complete path.
3304 *
3305 * Build entry ssd@xx,0:c,raw
3306 * where xx is the WWN.
3307 */
3308 select_id = g_sf_alpa_to_switch[map_ptr->map.
3309 dev_addr[j].gfc_port_dev.priv_port.sf_al_pa];
3310 G_DPRINTF(" l_get_node_status: Searching loop map "
3311 "to find disk: ID:0x%x"
3312 " AL_PA:0x%x\n", select_id,
3313 state->ib_status.sel_id);
3314
3315 if (strstr(path, SCSI_VHCI) == NULL) {
3316
3317 (void) sprintf(sbuf,
3318 "w%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x,0:c,raw",
3319 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3320 sf_port_wwn[0],
3321 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3322 sf_port_wwn[1],
3323 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3324 sf_port_wwn[2],
3325 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3326 sf_port_wwn[3],
3327 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3328 sf_port_wwn[4],
3329 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3330 sf_port_wwn[5],
3331 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3332 sf_port_wwn[6],
3333 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3334 sf_port_wwn[7]);
3335 (void) strcat(temp_path, sbuf);
3336
3337 }
3338 /*
3339 * If we find a device on this loop in this box
3340 * update its status.
3341 */
3342 if (state->ib_status.sel_id == select_id) {
3343 /*
3344 * Found a device on this loop in this box.
3345 *
3346 * Update state.
3347 */
3348 (void) sprintf(state->g_disk_state.node_wwn_s,
3349 "%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x",
3350 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3351 sf_node_wwn[0],
3352 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3353 sf_node_wwn[1],
3354 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3355 sf_node_wwn[2],
3356 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3357 sf_node_wwn[3],
3358 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3359 sf_node_wwn[4],
3360 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3361 sf_node_wwn[5],
3362 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3363 sf_node_wwn[6],
3364 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3365 sf_node_wwn[7]);
3366
3367 if (strstr(path, SCSI_VHCI) != NULL) {
3368 (void) g_ll_to_str(map_ptr->map.dev_addr[j].gfc_port_dev.
3369 priv_port.sf_node_wwn, wwnp);
3370 for (wwnlp = wwn_list; wwnlp != NULL;
3371 wwnlp = wwnlp->wwn_next) {
3372 if (strcmp(wwnlp->node_wwn_s, wwnp) == 0) {
3373 (void) strcpy(temp_path, wwnlp->physical_path);
3374 break;
3375 }
3376 }
3377 if (wwnlp == NULL) {
3378 (void) sprintf(sbuf,
3379 "g%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x:c,raw",
3380 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3381 sf_node_wwn[0],
3382 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3383 sf_node_wwn[1],
3384 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3385 sf_node_wwn[2],
3386 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3387 sf_node_wwn[3],
3388 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3389 sf_node_wwn[4],
3390 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3391 sf_node_wwn[5],
3392 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3393 sf_node_wwn[6],
3394 map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3395 sf_node_wwn[7]);
3396 (void) strcat(temp_path, sbuf);
3397 /*
3398 * check to make sure this is a valid path.
3399 * Paths may not always be created on the
3400 * host. So, we make a quick check.
3401 */
3402 if (stat(temp_path, &stat_buf) == -1) {
3403 free_mp_dev_map(&map_mp);
3404 return (errno);
3405 }
3406
3407 }
3408 }
3409 (void) strcpy(state->g_disk_state.physical_path,
3410 temp_path);
3411
3412
3413 /* Bad if WWN is all zeros. */
3414 if (is_null_wwn(map_ptr->map.dev_addr[j].
3415 gfc_port_dev.priv_port.
3416 sf_node_wwn)) {
3417 state->l_state_flag = L_INVALID_WWN;
3418 G_DPRINTF(" l_get_node_status: "
3419 "Disk state was "
3420 " Invalid WWN.\n");
3421 (*found_flag)++;
3422 free_mp_dev_map(&map_mp);
3423 return (0);
3424 }
3425
3426 /* get device status */
3427 if (err = l_get_disk_status(temp_path, state,
3428 wwn_list, verbose)) {
3429 free_mp_dev_map(&map_mp);
3430 return (err);
3431 }
3432 /*
3433 * found device in map. Don't need to look
3434 * any further
3435 */
3436 (*found_flag)++;
3437 free_mp_dev_map(&map_mp);
3438 return (0);
3439 }
3440 } /* for loop */
3441 break;
3442 case FC_TOP_PUBLIC_LOOP:
3443 case FC_TOP_FABRIC:
3444 /*
3445 * Get a generic path to a device
3446 * This assumes the path looks something like this
3447 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@wWWN,0:0
3448 * then creates a path that looks like
3449 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ssd@
3450 */
3451 (void) strcpy(temp_path, path);
3452 if ((char_ptr = strrchr(temp_path, '/')) == NULL) {
3453 free_mp_dev_map(&map_mp);
3454 return (L_INVALID_PATH);
3455 }
3456 *char_ptr = '\0'; /* Terminate sting */
3457
3458 if (err = l_get_pid_from_path(path, &map_ptr->map, &path_pid)) {
3459 free_mp_dev_map(&map_mp);
3460 return (err);
3461 }
3462
3463 /* Now append the ssd string */
3464 (void) strcat(temp_path, SLSH_DRV_NAME_SSD);
3465
3466 /*
3467 * Create complete path.
3468 *
3469 * Build entry ssd@WWN,0:c,raw
3470 *
3471 * First, search the map for a device with the area code and
3472 * domain as in 'path_pid'.
3473 */
3474 for (j = 0; j < map_ptr->map.count; j++) {
3475 if (map_ptr->map.dev_addr[j].gfc_port_dev.pub_port.
3476 dev_dtype != DTYPE_ESI) {
3477 select_id = g_sf_alpa_to_switch[map_ptr->map.
3478 dev_addr[j].gfc_port_dev.pub_port.dev_did.
3479 port_id & 0xFF];
3480
3481 if (((map_ptr->map.dev_addr[j].gfc_port_dev.
3482 pub_port.dev_did.port_id &
3483 AREA_DOMAIN_ID) ==
3484 (path_pid & AREA_DOMAIN_ID)) &&
3485 (state->ib_status.sel_id == select_id)) {
3486 /*
3487 * Found the device. Update state.
3488 */
3489 if (strstr(temp_path, SCSI_VHCI) == NULL) {
3490 (void) sprintf(sbuf,
3491 "w%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x,0:c,raw",
3492 map_ptr->map.dev_addr[j].gfc_port_dev.
3493 pub_port.dev_pwwn.raw_wwn[0],
3494 map_ptr->map.dev_addr[j].gfc_port_dev.
3495 pub_port.dev_pwwn.raw_wwn[1],
3496 map_ptr->map.dev_addr[j].gfc_port_dev.
3497 pub_port.dev_pwwn.raw_wwn[2],
3498 map_ptr->map.dev_addr[j].gfc_port_dev.
3499 pub_port.dev_pwwn.raw_wwn[3],
3500 map_ptr->map.dev_addr[j].gfc_port_dev.
3501 pub_port.dev_pwwn.raw_wwn[4],
3502 map_ptr->map.dev_addr[j].gfc_port_dev.
3503 pub_port.dev_pwwn.raw_wwn[5],
3504 map_ptr->map.dev_addr[j].gfc_port_dev.
3505 pub_port.dev_pwwn.raw_wwn[6],
3506 map_ptr->map.dev_addr[j].gfc_port_dev.
3507 pub_port.dev_pwwn.raw_wwn[7]);
3508 (void) strcat(temp_path, sbuf);
3509
3510 /*
3511 * Paths for fabric cases may not always
3512 * be created on the host. So, we make a
3513 * quick check.
3514 */
3515 if (stat(temp_path, &stat_buf) == -1) {
3516 free_mp_dev_map(&map_mp);
3517 return (errno);
3518 }
3519
3520 (void) sprintf(state->
3521 g_disk_state.node_wwn_s,
3522 "%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x",
3523 map_ptr->map.dev_addr[j].gfc_port_dev.
3524 pub_port.dev_nwwn.raw_wwn[0],
3525 map_ptr->map.dev_addr[j].gfc_port_dev.
3526 pub_port.dev_nwwn.raw_wwn[1],
3527 map_ptr->map.dev_addr[j].gfc_port_dev.
3528 pub_port.dev_nwwn.raw_wwn[2],
3529 map_ptr->map.dev_addr[j].gfc_port_dev.
3530 pub_port.dev_nwwn.raw_wwn[3],
3531 map_ptr->map.dev_addr[j].gfc_port_dev.
3532 pub_port.dev_nwwn.raw_wwn[4],
3533 map_ptr->map.dev_addr[j].gfc_port_dev.
3534 pub_port.dev_nwwn.raw_wwn[5],
3535 map_ptr->map.dev_addr[j].gfc_port_dev.
3536 pub_port.dev_nwwn.raw_wwn[6],
3537 map_ptr->map.dev_addr[j].gfc_port_dev.
3538 pub_port.dev_nwwn.raw_wwn[7]);
3539
3540 } else {
3541 (void) g_ll_to_str(map_ptr->map.dev_addr[j].gfc_port_dev.
3542 priv_port.sf_node_wwn, wwnp);
3543 for (wwnlp = wwn_list; wwnlp != NULL;
3544 wwnlp = wwnlp->wwn_next) {
3545 if (strcmp(wwnlp->node_wwn_s, wwnp) == 0) {
3546 (void) strcpy(temp_path, wwnlp->physical_path);
3547 break;
3548 }
3549 }
3550 if (wwnlp == NULL) {
3551 (void) sprintf(sbuf,
3552 "w%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x,0:c,raw",
3553 map_ptr->map.dev_addr[j].gfc_port_dev.pub_port.
3554 dev_nwwn.raw_wwn[0],
3555 map_ptr->map.dev_addr[j].gfc_port_dev.pub_port.
3556 dev_nwwn.raw_wwn[1],
3557 map_ptr->map.dev_addr[j].gfc_port_dev.pub_port.
3558 dev_nwwn.raw_wwn[2],
3559 map_ptr->map.dev_addr[j].gfc_port_dev.pub_port.
3560 dev_nwwn.raw_wwn[3],
3561 map_ptr->map.dev_addr[j].gfc_port_dev.pub_port.
3562 dev_nwwn.raw_wwn[4],
3563 map_ptr->map.dev_addr[j].gfc_port_dev.pub_port.
3564 dev_nwwn.raw_wwn[5],
3565 map_ptr->map.dev_addr[j].gfc_port_dev.pub_port.
3566 dev_nwwn.raw_wwn[6],
3567 map_ptr->map.dev_addr[j].gfc_port_dev.pub_port.
3568 dev_nwwn.raw_wwn[7]);
3569 (void) strcat(temp_path, sbuf);
3570 }
3571 }
3572 (void) strcpy(state->g_disk_state.physical_path,
3573 temp_path);
3574
3575 /* Bad if WWN is all zeros. */
3576 if (is_null_wwn(map_ptr->map.
3577 dev_addr[j].gfc_port_dev.
3578 pub_port.dev_nwwn.
3579 raw_wwn)) {
3580 state->l_state_flag =
3581 L_INVALID_WWN;
3582 G_DPRINTF(
3583 " l_get_node_status: "
3584 "Disk state was "
3585 " Invalid WWN.\n");
3586 (*found_flag)++;
3587 free_mp_dev_map(&map_mp);
3588 return (0);
3589 }
3590
3591 /* get device status */
3592 if (err = l_get_disk_status(temp_path,
3593 state, wwn_list, verbose)) {
3594 free_mp_dev_map(&map_mp);
3595 return (err);
3596 }
3597
3598 (*found_flag)++;
3599 free_mp_dev_map(&map_mp);
3600 return (0);
3601 } /* if select_id match */
3602 } /* if !DTYPE_ESI */
3603 } /* for loop */
3604 break;
3605 case FC_TOP_PT_PT:
3606 free_mp_dev_map(&map_mp);
3607 return (L_PT_PT_FC_TOP_NOT_SUPPORTED);
3608 default:
3609 free_mp_dev_map(&map_mp);
3610 return (L_UNEXPECTED_FC_TOPOLOGY);
3611 } /* End of switch on port_topology */
3612
3613 }
3614 free_mp_dev_map(&map_mp);
3615 return (0);
3616 }
3617
3618
3619 /*
3620 * Get the individual drives status for the device specified by the index.
3621 * device at the path where the path is of the IB and updates the
3622 * g_disk_state_struct structure.
3623 *
3624 * If the disk's port is bypassed, it gets the
3625 * drive status such as node WWN from the second port.
3626 *
3627 * RETURNS:
3628 * 0 O.K.
3629 * non-zero otherwise
3630 */
3631 int
l_get_individual_state(char * path,struct l_disk_state_struct * state,Ib_state * ib_state,int front_flag,struct box_list_struct * box_list,struct wwn_list_struct * wwn_list,int verbose)3632 l_get_individual_state(char *path,
3633 struct l_disk_state_struct *state, Ib_state *ib_state,
3634 int front_flag, struct box_list_struct *box_list,
3635 struct wwn_list_struct *wwn_list, int verbose)
3636 {
3637 int found_flag = 0, elem_index = 0;
3638 int port_a_flag, err, j;
3639 struct dlist *seslist = NULL;
3640 Bp_elem_st bpf, bpr;
3641 hrtime_t start_time, end_time;
3642
3643 if ((path == NULL) || (state == NULL) ||
3644 (ib_state == NULL) || (box_list == NULL)) {
3645 return (L_INVALID_PATH_FORMAT);
3646 }
3647
3648 start_time = gethrtime();
3649
3650
3651 if ((state->ib_status.code != S_NOT_INSTALLED) &&
3652 (state->ib_status.code != S_NOT_AVAILABLE)) {
3653
3654 /*
3655 * Disk could have been bypassed on this loop.
3656 * Check the port state before l_state_flag
3657 * is set to L_INVALID_MAP.
3658 */
3659 for (j = 0;
3660 j < (int)ib_state->config.enc_num_elem;
3661 j++) {
3662 elem_index++;
3663 if (ib_state->config.type_hdr[j].type ==
3664 ELM_TYP_BP)
3665 break;
3666 elem_index +=
3667 ib_state->config.type_hdr[j].num;
3668 }
3669
3670 /*
3671 * check if port A & B of backplane are bypassed.
3672 * If so, do not bother.
3673 */
3674 if (front_flag) {
3675 bcopy((const void *)
3676 &(ib_state->p2_s.element[elem_index]),
3677 (void *)&bpf, sizeof (bpf));
3678
3679 if ((bpf.byp_a_enabled || bpf.en_bypass_a) &&
3680 (bpf.byp_b_enabled || bpf.en_bypass_b))
3681 return (0);
3682 } else {
3683 /* if disk is in rear slot */
3684 bcopy((const void *)
3685 &(ib_state->p2_s.element[elem_index+1]),
3686 (void *)&bpr, sizeof (bpr));
3687
3688 if ((bpr.byp_b_enabled || bpr.en_bypass_b) &&
3689 (bpr.byp_a_enabled || bpr.en_bypass_a))
3690 return (0);
3691 }
3692
3693 if ((err = l_get_node_status(path, state,
3694 &found_flag, wwn_list, verbose)) != 0)
3695 return (err);
3696
3697 if (!found_flag) {
3698 if ((err = l_get_allses(path, box_list,
3699 &seslist, 0)) != 0) {
3700 return (err);
3701 }
3702
3703 if (err = l_get_port(path, &port_a_flag, verbose))
3704 goto done;
3705
3706 if (port_a_flag) {
3707 if ((state->ib_status.bypass_a_en &&
3708 !(state->ib_status.bypass_b_en)) ||
3709 !(state->ib_status.bypass_b_en)) {
3710 while (seslist != NULL && !found_flag) {
3711 if (err = l_get_port(
3712 seslist->dev_path,
3713 &port_a_flag, verbose)) {
3714 goto done;
3715 }
3716 if ((strcmp(seslist->dev_path,
3717 path) != 0) &&
3718 !port_a_flag) {
3719 *path = NULL;
3720 (void) strcpy(path,
3721 seslist->dev_path);
3722 if (err =
3723 l_get_node_status(path,
3724 state, &found_flag,
3725 wwn_list, verbose)) {
3726 goto done;
3727 }
3728 }
3729 seslist = seslist->next;
3730 }
3731 }
3732 } else {
3733 if ((state->ib_status.bypass_b_en &&
3734 !(state->ib_status.bypass_a_en)) ||
3735 !(state->ib_status.bypass_a_en)) {
3736 while (seslist != NULL && !found_flag) {
3737 if (err = l_get_port(
3738 seslist->dev_path,
3739 &port_a_flag, verbose)) {
3740 goto done;
3741 }
3742 if ((strcmp(seslist->dev_path,
3743 path) != 0) && port_a_flag) {
3744 *path = NULL;
3745 (void) strcpy(path,
3746 seslist->dev_path);
3747 if (err =
3748 l_get_node_status(path,
3749 state, &found_flag,
3750 wwn_list, verbose)) {
3751 goto done;
3752 }
3753 }
3754 seslist = seslist->next;
3755 }
3756 }
3757 }
3758 if (!found_flag) {
3759 state->l_state_flag = L_INVALID_MAP;
3760 G_DPRINTF(" l_get_individual_state: "
3761 "Disk state was "
3762 "Not in map.\n");
3763 } else {
3764 G_DPRINTF(" l_get_individual_state: "
3765 "Disk was found in the map.\n");
3766 }
3767
3768 if (seslist != NULL)
3769 (void) g_free_multipath(seslist);
3770
3771 }
3772
3773 } else {
3774 G_DPRINTF(" l_get_individual_state: Disk state was %s.\n",
3775 (state->ib_status.code == S_NOT_INSTALLED) ?
3776 "Not Installed" : "Not Available");
3777 }
3778
3779 if (getenv("_LUX_T_DEBUG") != NULL) {
3780 end_time = gethrtime();
3781 (void) fprintf(stdout, " l_get_individual_state:"
3782 "\tTime = %lld millisec\n",
3783 (end_time - start_time)/1000000);
3784 }
3785
3786 return (0);
3787 done:
3788 (void) g_free_multipath(seslist);
3789 return (err);
3790 }
3791
3792
3793
3794 /*
3795 * Get the global state of the photon.
3796 *
3797 * INPUT:
3798 * path and verbose flag
3799 *
3800 * "path" must be of the ses driver.
3801 * e.g.
3802 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@e,0:0
3803 * or
3804 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@WWN,0:0
3805 *
3806 * OUTPUT:
3807 * The struct l_state (which was passed in) has the status info
3808 *
3809 * RETURNS:
3810 * 0 O.K.
3811 * non-zero otherwise
3812 */
3813 int
l_get_status(char * path,struct l_state_struct * l_state,int verbose)3814 l_get_status(char *path, struct l_state_struct *l_state, int verbose)
3815 {
3816 int err = 0, i, count;
3817 L_inquiry inq;
3818 uchar_t node_wwn[WWN_SIZE], port_wwn[WWN_SIZE];
3819 int al_pa, found_front, found_rear, front_flag, enc_type;
3820 char ses_path_front[MAXPATHLEN];
3821 char ses_path_rear[MAXPATHLEN];
3822 Box_list *b_list = NULL;
3823 Box_list *o_list = NULL;
3824 char node_wwn_s[(WWN_SIZE*2)+1];
3825 uint_t select_id;
3826 hrtime_t start_time, end_time;
3827 WWN_list *wwn_list = NULL;
3828
3829 if ((path == NULL) || (l_state == NULL)) {
3830 return (L_INVALID_PATH_FORMAT);
3831 }
3832
3833 start_time = gethrtime();
3834
3835 G_DPRINTF(" l_get_status: Get Status for enclosure at: "
3836 " %s\n", path);
3837
3838 /* initialization */
3839 (void) memset(l_state, 0, sizeof (struct l_state_struct));
3840
3841 if (err = g_get_inquiry(path, &inq)) {
3842 return (err);
3843 }
3844 if ((strstr((char *)inq.inq_pid, ENCLOSURE_PROD_ID) == 0) &&
3845 (!(strncmp((char *)inq.inq_vid, "SUN ",
3846 sizeof (inq.inq_vid)) &&
3847 ((inq.inq_dtype & DTYPE_MASK) == DTYPE_ESI)))) {
3848 return (L_ENCL_INVALID_PATH);
3849 }
3850
3851 (void) strncpy((char *)l_state->ib_tbl.enclosure_name,
3852 (char *)inq.inq_box_name, sizeof (inq.inq_box_name));
3853
3854 /*
3855 * Get all of the IB Receive Diagnostic pages.
3856 */
3857 if (err = l_get_ib_status(path, l_state, verbose)) {
3858 return (err);
3859 }
3860
3861 /*
3862 * Now get the individual devices information from
3863 * the device itself.
3864 *
3865 * May need to use multiple paths to get to the
3866 * front and rear drives in the box.
3867 * If the loop is split some drives may not even be available
3868 * from this host.
3869 *
3870 * The way this works is in the select ID the front disks
3871 * are accessed via the IB with the bit 4 = 0
3872 * and the rear disks by the IB with bit 4 = 1.
3873 *
3874 * First get device map from fc nexus driver for this loop.
3875 */
3876 /*
3877 * Get the boxes node WWN & al_pa for this path.
3878 */
3879 if (err = g_get_wwn(path, port_wwn, node_wwn, &al_pa, verbose)) {
3880 return (err);
3881 }
3882 if (err = l_get_box_list(&o_list, verbose)) {
3883 (void) l_free_box_list(&o_list);
3884 return (err); /* Failure */
3885 }
3886
3887 found_front = found_rear = 0;
3888 for (i = 0; i < WWN_SIZE; i++) {
3889 (void) sprintf(&node_wwn_s[i << 1], "%02x", node_wwn[i]);
3890 }
3891
3892 /*
3893 * The al_pa (or pa) can be 24 bits in size for fabric loops.
3894 * But we will take only the low order byte to get the select_id.
3895 * Private loops have al_pa which is only a byte in size.
3896 */
3897 select_id = g_sf_alpa_to_switch[al_pa & 0xFF];
3898 l_state->ib_tbl.box_id = (select_id & BOX_ID_MASK) >> 5;
3899
3900 G_DPRINTF(" l_get_status: Using this select_id 0x%x "
3901 "and node WWN %s\n",
3902 select_id, node_wwn_s);
3903
3904 if (strstr(path, SCSI_VHCI) != NULL) {
3905 /* there is no way to obtain all the al_pa with */
3906 /* current implementation. assume both front */
3907 /* and rear. need changes later on. */
3908 found_rear = 1;
3909 found_front = 1;
3910 (void) strcpy(ses_path_rear, path);
3911 (void) strcpy(ses_path_front, path);
3912 } else {
3913
3914 if (select_id & ALT_BOX_ID) {
3915 found_rear = 1;
3916 (void) strcpy(ses_path_rear, path);
3917 b_list = o_list;
3918 while (b_list) {
3919 if (strcmp(b_list->b_node_wwn_s, node_wwn_s) == 0) {
3920 if (err = g_get_wwn(b_list->b_physical_path,
3921 port_wwn, node_wwn,
3922 &al_pa, verbose)) {
3923 (void) l_free_box_list(&o_list);
3924 return (err);
3925 }
3926
3927 /* Take the low order byte of al_pa */
3928 select_id = g_sf_alpa_to_switch[al_pa & 0xFF];
3929 if (!(select_id & ALT_BOX_ID)) {
3930 (void) strcpy(ses_path_front,
3931 b_list->b_physical_path);
3932 found_front = 1;
3933 break;
3934 }
3935 }
3936 b_list = b_list->box_next;
3937 }
3938 } else {
3939 (void) strcpy(ses_path_front, path);
3940 found_front = 1;
3941 b_list = o_list;
3942 while (b_list) {
3943 if (strcmp(b_list->b_node_wwn_s, node_wwn_s) == 0) {
3944 if (err = g_get_wwn(b_list->b_physical_path,
3945 port_wwn, node_wwn,
3946 &al_pa, verbose)) {
3947 (void) l_free_box_list(&o_list);
3948 return (err);
3949 }
3950 select_id = g_sf_alpa_to_switch[al_pa & 0xFF];
3951 if (select_id & ALT_BOX_ID) {
3952 (void) strcpy(ses_path_rear,
3953 b_list->b_physical_path);
3954 found_rear = 1;
3955 break;
3956 }
3957 }
3958 b_list = b_list->box_next;
3959 }
3960 }
3961 }
3962
3963 if (getenv("_LUX_G_DEBUG") != NULL) {
3964 if (!found_front) {
3965 (void) printf("l_get_status: Loop to front disks not found.\n");
3966 }
3967 if (!found_rear) {
3968 (void) printf("l_get_status: Loop to rear disks not found.\n");
3969 }
3970 }
3971
3972 /*
3973 * Get path to all the FC disk and tape devices.
3974 *
3975 * I get this now and pass down for performance
3976 * reasons.
3977 * If for some reason the list can become invalid,
3978 * i.e. device being offlined, then the list
3979 * must be re-gotten.
3980 */
3981 if (err = g_get_wwn_list(&wwn_list, verbose)) {
3982 return (err); /* Failure */
3983 }
3984
3985 enc_type = l_get_enc_type(inq);
3986 if (found_front) {
3987 front_flag = 1;
3988 for (i = 0, count = 0; i < l_state->total_num_drv/2;
3989 count++, i++) {
3990 if (enc_type == DAK_ENC_TYPE) {
3991 G_DPRINTF(" l_get_status: Getting individual"
3992 " State for disk in slot %d\n", count);
3993 } else {
3994 G_DPRINTF(" l_get_status: Getting individual"
3995 " State for front disk in slot %d\n", i);
3996 }
3997 if (err = l_get_individual_state(ses_path_front,
3998 (struct l_disk_state_struct *)&l_state->drv_front[i],
3999 &l_state->ib_tbl, front_flag, o_list,
4000 wwn_list, verbose)) {
4001 (void) l_free_box_list(&o_list);
4002 (void) g_free_wwn_list(&wwn_list);
4003 return (err);
4004 }
4005 }
4006 } else {
4007 /* Set to loop not accessable. */
4008 for (i = 0; i < l_state->total_num_drv/2; i++) {
4009 l_state->drv_front[i].l_state_flag = L_NO_LOOP;
4010 }
4011 }
4012 /*
4013 * For Daktari's, disk 0-5 information are located in the
4014 * l_state->drv_front array
4015 * For Daktari's, disk 6-11 information are located in the
4016 * l_state->drv_rear array
4017 *
4018 * For this reason, on daktari's, I ignore the found_front and
4019 * found_rear flags and check both the drv_front and drv_rear
4020 */
4021
4022 if (enc_type == DAK_ENC_TYPE && found_front) {
4023 front_flag = 1;
4024 for (i = 0; i < l_state->total_num_drv/2; i++, count++) {
4025 G_DPRINTF(" l_get_status: Getting individual"
4026 " State for disk in slot %d\n", count);
4027 if (err = l_get_individual_state(ses_path_front,
4028 (struct l_disk_state_struct *)&l_state->drv_rear[i],
4029 &l_state->ib_tbl, front_flag, o_list,
4030 wwn_list, verbose)) {
4031 (void) l_free_box_list(&o_list);
4032 (void) g_free_wwn_list(&wwn_list);
4033 return (err);
4034 }
4035 }
4036 } else if (enc_type != DAK_ENC_TYPE && found_rear) {
4037 for (i = 0; i < l_state->total_num_drv/2; i++, count++) {
4038 G_DPRINTF(" l_get_status: Getting individual"
4039 " State for rear disk in slot %d\n", i);
4040 if (err = l_get_individual_state(ses_path_rear,
4041 (struct l_disk_state_struct *)&l_state->drv_rear[i],
4042 &l_state->ib_tbl, front_flag, o_list,
4043 wwn_list, verbose)) {
4044 (void) l_free_box_list(&o_list);
4045 (void) g_free_wwn_list(&wwn_list);
4046 return (err);
4047 }
4048 }
4049 } else if (enc_type != DAK_ENC_TYPE) {
4050 /* Set to loop not accessable. */
4051 for (i = 0; i < l_state->total_num_drv/2; i++) {
4052 l_state->drv_rear[i].l_state_flag = L_NO_LOOP;
4053 }
4054 }
4055
4056 (void) l_free_box_list(&o_list);
4057 (void) g_free_wwn_list(&wwn_list);
4058 if (getenv("_LUX_T_DEBUG") != NULL) {
4059 end_time = gethrtime();
4060 (void) fprintf(stdout, " l_get_status: "
4061 "Time = %lld millisec\n",
4062 (end_time - start_time)/1000000);
4063 }
4064
4065 return (0);
4066 }
4067
4068
4069
4070 /*
4071 * Check the SENA file for validity:
4072 * - verify the size is that of 3 proms worth of text.
4073 * - verify PROM_MAGIC.
4074 * - verify (and print) the date.
4075 * - verify the checksum.
4076 * - verify the WWN == 0.
4077 * Since this requires reading the entire file, do it now and pass a pointer
4078 * to the allocated buffer back to the calling routine (which is responsible
4079 * for freeing it). If the buffer is not allocated it will be NULL.
4080 *
4081 * RETURNS:
4082 * 0 O.K.
4083 * non-zero otherwise
4084 */
4085
4086 static int
check_file(int fd,int verbose,uchar_t ** buf_ptr,int dl_info_offset)4087 check_file(int fd, int verbose, uchar_t **buf_ptr, int dl_info_offset)
4088 {
4089 struct exec the_exec;
4090 int temp, i, j, *p, size, *start;
4091 uchar_t *buf;
4092 char *date_str;
4093 struct dl_info *dl_info;
4094
4095 *buf_ptr = NULL;
4096
4097 /* read exec header */
4098 if (lseek(fd, 0, SEEK_SET) == -1)
4099 return (errno);
4100 if ((temp = read(fd, (char *)&the_exec, sizeof (the_exec))) == -1) {
4101 return (L_DWNLD_READ_HEADER_FAIL);
4102 }
4103 if (temp != sizeof (the_exec)) {
4104 return (L_DWNLD_READ_INCORRECT_BYTES);
4105 }
4106
4107 if (the_exec.a_text != PROMSIZE) {
4108 return (L_DWNLD_INVALID_TEXT_SIZE);
4109 }
4110
4111 if (!(buf = (uchar_t *)g_zalloc(PROMSIZE)))
4112 return (L_MALLOC_FAILED);
4113
4114 if ((temp = read(fd, buf, PROMSIZE)) == -1) {
4115 return (L_DWNLD_READ_ERROR);
4116 }
4117
4118 if (temp != PROMSIZE) {
4119 return (L_DWNLD_READ_INCORRECT_BYTES);
4120 }
4121
4122
4123
4124 /* check the IB firmware MAGIC */
4125 dl_info = (struct dl_info *)(unsigned long)(buf + dl_info_offset);
4126 if (dl_info->magic != PROM_MAGIC) {
4127 return (L_DWNLD_BAD_FRMWARE);
4128 }
4129
4130 /*
4131 * Get the date
4132 */
4133
4134 date_str = ctime(&dl_info->datecode);
4135
4136 if (verbose) {
4137 (void) fprintf(stdout,
4138 MSGSTR(9050, " IB Prom Date: %s"),
4139 date_str);
4140 }
4141
4142 /*
4143 * verify checksum
4144 */
4145
4146 if (dl_info_offset == FPM_DL_INFO) {
4147 start = (int *)(long)(buf + FPM_OFFSET);
4148 size = FPM_SZ;
4149 } else {
4150 start = (int *)(long)buf;
4151 size = TEXT_SZ + IDATA_SZ;
4152 }
4153
4154 for (j = 0, p = start, i = 0; i < (size/ 4); i++, j ^= *p++);
4155
4156 if (j != 0) {
4157 return (L_DWNLD_CHKSUM_FAILED);
4158 }
4159
4160 /* file verified */
4161 *buf_ptr = buf;
4162
4163 return (0);
4164 }
4165
4166 /*
4167 * Check the DPM file for validity:
4168 *
4169 * RETURNS:
4170 * 0 O.K.
4171 * non-zero otherwise
4172 */
4173 #define dakstring "64616B74617269"
4174 #define dakoffs "BFC00000"
4175
4176 static int
check_dpm_file(int fd)4177 check_dpm_file(int fd)
4178 {
4179 struct s3hdr {
4180 char rtype[2];
4181 char rlen[2];
4182 char data[255];
4183 } theRec;
4184 int nread;
4185 int reclen;
4186
4187 if (fd < 0) {
4188 return (L_DWNLD_READ_ERROR);
4189 }
4190 lseek(fd, 0, SEEK_SET);
4191
4192 /* First record */
4193 memset((void*)&theRec, 0, sizeof (struct s3hdr));
4194 nread = read(fd, (void *)&theRec, 4);
4195 if (nread != 4) {
4196 /* error reading first record/length */
4197 return (L_DWNLD_READ_ERROR);
4198 }
4199 if (strncmp((char *)&theRec.rtype[0], "S0", 2) != 0) {
4200 /* error in first record type */
4201 return (L_DWNLD_READ_HEADER_FAIL);
4202 }
4203 reclen = strtol(&theRec.rlen[0], (char **)NULL, 16);
4204 if (reclen == 0) {
4205 /* error in length == 0 */
4206 return (L_DWNLD_READ_HEADER_FAIL);
4207 }
4208 nread = read(fd, (void *)&theRec.data[0], ((reclen*2) +1));
4209 if (nread != ((reclen*2) +1)) {
4210 /* error in trying to read data */
4211 return (L_DWNLD_READ_HEADER_FAIL);
4212 }
4213 if (strncmp(&theRec.data[4], dakstring, 14) != 0) {
4214 /* error in compiled file name */
4215 return (L_DWNLD_READ_HEADER_FAIL);
4216 }
4217
4218 /* Second record */
4219 memset((void*)&theRec, 0, sizeof (struct s3hdr));
4220 nread = read(fd, (void *)&theRec, 4);
4221 if (nread != 4) {
4222 /* error reading second record/length */
4223 return (L_DWNLD_READ_ERROR);
4224 }
4225 if (strncmp((char *)&theRec.rtype[0], "S3", 2) != 0) {
4226 /* error in second record type */
4227 return (L_DWNLD_READ_HEADER_FAIL);
4228 }
4229 reclen = strtol(&theRec.rlen[0], (char **)NULL, 16);
4230 if (reclen == 0) {
4231 /* error in length == 0 */
4232 return (L_DWNLD_READ_HEADER_FAIL);
4233 }
4234 nread = read(fd, (void *)&theRec.data[0], ((reclen*2) +1));
4235 if (nread != ((reclen*2) +1)) {
4236 /* error in trying to read data */
4237 return (L_DWNLD_READ_HEADER_FAIL);
4238 }
4239 if (strncmp(&theRec.data[0], dakoffs, 8) != 0) {
4240 /* error in SSC100 offset pointer */
4241 return (L_DWNLD_READ_HEADER_FAIL);
4242 }
4243 lseek(fd, 0, SEEK_SET);
4244 return (0);
4245 }
4246
4247
4248
4249 int
l_check_file(char * file,int verbose)4250 l_check_file(char *file, int verbose)
4251 {
4252 int file_fd;
4253 int err;
4254 uchar_t *buf;
4255
4256 if ((file_fd = g_object_open(file, O_RDONLY)) == -1) {
4257 return (L_OPEN_PATH_FAIL);
4258 }
4259 err = check_file(file_fd, verbose, &buf, FW_DL_INFO);
4260 if (buf)
4261 (void) g_destroy_data((char *)buf);
4262 return (err);
4263 }
4264
4265
4266
4267 /*
4268 * Write buffer command set up to download
4269 * firmware to the Photon IB.
4270 *
4271 * RETURNS:
4272 * status
4273 */
4274 static int
ib_download_code_cmd(int fd,int promid,int off,uchar_t * buf_ptr,int buf_len,int sp)4275 ib_download_code_cmd(int fd, int promid, int off, uchar_t *buf_ptr,
4276 int buf_len, int sp)
4277 {
4278 int status, sz;
4279
4280 while (buf_len) {
4281 sz = MIN(256, buf_len);
4282 buf_len -= sz;
4283 status = g_scsi_writebuffer_cmd(fd, off, buf_ptr, sz,
4284 (sp) ? 3 : 2, promid);
4285 if (status)
4286 return (status);
4287 buf_ptr += sz;
4288 off += sz;
4289 }
4290
4291 return (status);
4292 }
4293
4294 /*
4295 *
4296 * Downloads the code to the DAKTARI/DPM with the hdr set correctly
4297 *
4298 *
4299 * Inputs:
4300 * fd - int for the file descriptor
4301 * buf_ptr - uchar_t pointer to the firmware itself
4302 * buf_len - int for the length of the data
4303 *
4304 * Returns:
4305 * status: 0 indicates success, != 0 failure, returned from writebuffer
4306 *
4307 */
4308
4309 static int
dak_download_code_cmd(int fd,uchar_t * buf_ptr,int buf_len)4310 dak_download_code_cmd(int fd, uchar_t *buf_ptr, int buf_len)
4311 {
4312 int status = 0;
4313 int sz = 0;
4314 int offs = 0;
4315
4316 while (buf_len > 0) {
4317 sz = MIN(256, buf_len);
4318 buf_len -= sz;
4319 status = g_scsi_writebuffer_cmd(fd, offs, buf_ptr, sz, 0x07, 0);
4320 if (status != 0) {
4321 return (status);
4322 }
4323 buf_ptr += sz;
4324 offs += sz;
4325 }
4326 return (status);
4327 }
4328
4329
4330
4331
4332 /*
4333 * Downloads the new prom image to IB.
4334 *
4335 * INPUTS:
4336 * path - physical path of Photon SES card
4337 * file - input file for new code (may be NULL)
4338 * ps - whether the "save" bit should be set
4339 * verbose - to be verbose or not
4340 *
4341 * RETURNS:
4342 * 0 O.K.
4343 * non-zero otherwise
4344 */
4345 int
l_download(char * path_phys,char * file,int ps,int verbose)4346 l_download(char *path_phys, char *file, int ps, int verbose)
4347 {
4348 int file_fd, controller_fd;
4349 int err, status;
4350 uchar_t *buf_ptr;
4351 char printbuf[MAXPATHLEN];
4352 int retry;
4353 char file_path[MAXPATHLEN];
4354 struct stat statbuf;
4355 int enc_type;
4356 L_inquiry inq;
4357
4358 if (path_phys == NULL) {
4359 return (L_INVALID_PATH_FORMAT);
4360 }
4361
4362 if (!file) {
4363 (void) strcpy(file_path, IBFIRMWARE_FILE);
4364 } else {
4365 (void) strncpy(file_path, file, sizeof (file_path));
4366 }
4367 if (verbose)
4368 (void) fprintf(stdout, "%s\n",
4369 MSGSTR(9051, " Opening the IB for I/O."));
4370
4371 if ((controller_fd = g_object_open(path_phys, O_NDELAY | O_RDWR)) == -1)
4372 return (L_OPEN_PATH_FAIL);
4373
4374 (void) sprintf(printbuf, MSGSTR(9052, " Doing download to:"
4375 "\n\t%s.\n From file: %s."), path_phys, file_path);
4376
4377 if (verbose)
4378 (void) fprintf(stdout, "%s\n", printbuf);
4379 P_DPRINTF(" Doing download to:"
4380 "\n\t%s\n From file: %s\n", path_phys, file_path);
4381
4382 if ((file_fd = g_object_open(file_path, O_NDELAY | O_RDONLY)) == -1) {
4383 /*
4384 * Return a different error code here to differentiate between
4385 * this failure in g_object_open() and the one above.
4386 */
4387 return (L_INVALID_PATH);
4388 }
4389
4390 if (g_scsi_inquiry_cmd(controller_fd, (uchar_t *)&inq, sizeof (inq))) {
4391 return (L_SCSI_ERROR);
4392 }
4393 enc_type = l_get_enc_type(inq);
4394 switch (enc_type) {
4395 case DAK_ENC_TYPE:
4396 /*
4397 * We don't have a default daktari file location, so
4398 * the user must specify the firmware file on the command line
4399 */
4400 if (!file) {
4401 return (L_REQUIRE_FILE);
4402 }
4403 /* Validate the file */
4404 if ((err = check_dpm_file(file_fd))) {
4405 return (err);
4406 }
4407 /* Now go ahead and load up the data */
4408 if (fstat(file_fd, &statbuf) == -1) {
4409 err = errno;
4410 (void) fprintf(stdout, "%s %s\n",
4411 MSGSTR(9101, " Stat'ing the F/W file:"), strerror(err));
4412 return (L_OPEN_PATH_FAIL);
4413 }
4414 buf_ptr = (uchar_t *)g_zalloc(statbuf.st_size);
4415 if (buf_ptr == NULL) {
4416 err = errno;
4417 (void) fprintf(stdout, "%s %s\n",
4418 MSGSTR(9102, " Cannot alloc mem to read F/W file:"),
4419 strerror(err));
4420 return (L_MALLOC_FAILED);
4421 }
4422 if (read(file_fd, buf_ptr, statbuf.st_size) == -1) {
4423 err = errno;
4424 (void) fprintf(stdout, "%s %s\n",
4425 MSGSTR(9103, " Reading F/W file:"), strerror(err));
4426 g_destroy_data((char *)buf_ptr);
4427 return (L_DWNLD_READ_ERROR);
4428 }
4429 break;
4430 default:
4431 if (err = check_file(file_fd, verbose, &buf_ptr, FW_DL_INFO)) {
4432 if (buf_ptr) {
4433 (void) g_destroy_data((char *)buf_ptr);
4434 return (err);
4435 }
4436 }
4437 break;
4438 }
4439
4440 if (verbose) {
4441 (void) fprintf(stdout, " ");
4442 (void) fprintf(stdout, MSGSTR(127, "Checkfile O.K."));
4443 (void) fprintf(stdout, "\n");
4444 }
4445 P_DPRINTF(" Checkfile OK.\n");
4446 (void) close(file_fd);
4447
4448 if (verbose) {
4449 (void) fprintf(stdout, MSGSTR(9053,
4450 " Verifying the IB is available.\n"));
4451 }
4452
4453 retry = DOWNLOAD_RETRIES;
4454 while (retry) {
4455 if ((status = g_scsi_tur(controller_fd)) == 0) {
4456 break;
4457 } else {
4458 if ((retry % 30) == 0) {
4459 ER_DPRINTF(" Waiting for the IB to be"
4460 " available.\n");
4461 }
4462 (void) sleep(1);
4463 }
4464 }
4465 if (!retry) {
4466 if (buf_ptr)
4467 (void) g_destroy_data((char *)buf_ptr);
4468 (void) close(controller_fd);
4469 return (status);
4470 }
4471
4472 if (verbose)
4473 (void) fprintf(stdout, "%s\n",
4474 MSGSTR(9054, " Writing new text image to IB."));
4475 P_DPRINTF(" Writing new image to IB\n");
4476 switch (enc_type) {
4477 case DAK_ENC_TYPE:
4478 status = dak_download_code_cmd(controller_fd, buf_ptr,
4479 statbuf.st_size);
4480 if (status != 0) {
4481 if (buf_ptr != NULL) {
4482 g_destroy_data((char *)buf_ptr);
4483 }
4484 (void) close(controller_fd);
4485 return (status);
4486 }
4487 break;
4488 default:
4489 status = ib_download_code_cmd(controller_fd, IBEEPROM, TEXT_OFFSET,
4490 (uchar_t *)(buf_ptr + TEXT_OFFSET), TEXT_SZ, ps);
4491 if (status) {
4492 (void) close(controller_fd);
4493 (void) g_destroy_data((char *)buf_ptr);
4494 return (status);
4495 }
4496 if (verbose) {
4497 (void) fprintf(stdout, "%s\n",
4498 MSGSTR(9055, " Writing new data image to IB."));
4499 }
4500 status = ib_download_code_cmd(controller_fd, IBEEPROM, IDATA_OFFSET,
4501 (uchar_t *)(buf_ptr + IDATA_OFFSET), IDATA_SZ, ps);
4502 if (status) {
4503 (void) close(controller_fd);
4504 (void) g_destroy_data((char *)buf_ptr);
4505 return (status);
4506 }
4507 break;
4508 }
4509
4510
4511 if (verbose) {
4512 (void) fprintf(stdout, MSGSTR(9056,
4513 " Re-verifying the IB is available.\n"));
4514 }
4515
4516 retry = DOWNLOAD_RETRIES;
4517 while (retry) {
4518 if ((status = g_scsi_tur(controller_fd)) == 0) {
4519 break;
4520 } else {
4521 if ((retry % 30) == 0) {
4522 ER_DPRINTF(" Waiting for the IB to be"
4523 " available.\n");
4524 }
4525 (void) sleep(1);
4526 }
4527 retry--;
4528 }
4529 if (!retry) {
4530 (void) close(controller_fd);
4531 (void) g_destroy_data((char *)buf_ptr);
4532 return (L_DWNLD_TIMED_OUT);
4533 }
4534
4535 switch (enc_type) {
4536 case DAK_ENC_TYPE:
4537 break;
4538 default:
4539 if (verbose) {
4540 (void) fprintf(stdout, "%s\n",
4541 MSGSTR(9057, " Writing new image to FPM."));
4542 }
4543 status = ib_download_code_cmd(controller_fd, MBEEPROM, FPM_OFFSET,
4544 (uchar_t *)(buf_ptr + FPM_OFFSET), FPM_SZ, ps);
4545 break;
4546 }
4547
4548 if ((!status) && ps) {
4549 /*
4550 * Reset the IB
4551 */
4552 status = g_scsi_reset(controller_fd);
4553 }
4554
4555 (void) close(controller_fd);
4556 return (status);
4557 }
4558
4559 /*
4560 * Set the World Wide Name
4561 * in page 4 of the Send Diagnostic command.
4562 *
4563 * Is it allowed to change the wwn ???
4564 * The path must point to an IB.
4565 *
4566 */
4567 int
l_set_wwn(char * path_phys,char * wwn)4568 l_set_wwn(char *path_phys, char *wwn)
4569 {
4570 Page4_name page4;
4571 L_inquiry inq;
4572 int fd, status;
4573 char wwnp[WWN_SIZE];
4574
4575 (void) memset(&inq, 0, sizeof (inq));
4576 (void) memset(&page4, 0, sizeof (page4));
4577
4578 if ((fd = g_object_open(path_phys, O_NDELAY | O_RDONLY)) == -1) {
4579 return (L_OPEN_PATH_FAIL);
4580 }
4581 /* Verify it is a Photon */
4582 if (status = g_scsi_inquiry_cmd(fd,
4583 (uchar_t *)&inq, sizeof (struct l_inquiry_struct))) {
4584 (void) close(fd);
4585 return (status);
4586 }
4587 if ((strstr((char *)inq.inq_pid, ENCLOSURE_PROD_ID) == 0) &&
4588 (!(strncmp((char *)inq.inq_vid, "SUN ",
4589 sizeof (inq.inq_vid)) &&
4590 ((inq.inq_dtype & DTYPE_MASK) == DTYPE_ESI)))) {
4591 (void) close(fd);
4592 return (L_ENCL_INVALID_PATH);
4593 }
4594
4595 page4.page_code = L_PAGE_4;
4596 page4.page_len = (ushort_t)((sizeof (struct page4_name) - 4));
4597 page4.string_code = L_WWN;
4598 page4.enable = 1;
4599 if (g_string_to_wwn((uchar_t *)wwn, (uchar_t *)&page4.name)) {
4600 close(fd);
4601 return (EINVAL);
4602 }
4603 bcopy((void *)wwnp, (void *)page4.name, (size_t)WWN_SIZE);
4604
4605 if (status = g_scsi_send_diag_cmd(fd, (uchar_t *)&page4,
4606 sizeof (page4))) {
4607 (void) close(fd);
4608 return (status);
4609 }
4610
4611 /*
4612 * Check the wwn really changed.
4613 */
4614 bzero((char *)page4.name, 32);
4615 if (status = g_scsi_rec_diag_cmd(fd, (uchar_t *)&page4,
4616 sizeof (page4), L_PAGE_4)) {
4617 (void) close(fd);
4618 return (status);
4619 }
4620 if (bcmp((char *)page4.name, wwnp, WWN_SIZE)) {
4621 (void) close(fd);
4622 return (L_WARNING);
4623 }
4624
4625 (void) close(fd);
4626 return (0);
4627 }
4628
4629
4630
4631 /*
4632 * Use a physical path to a disk in a Photon box
4633 * as the base to genererate a path to a SES
4634 * card in this box.
4635 *
4636 * path_phys: Physical path to a Photon disk.
4637 * ses_path: This must be a pointer to an already allocated path string.
4638 *
4639 * RETURNS:
4640 * 0 O.K.
4641 * non-zero otherwise
4642 */
4643 int
l_get_ses_path(char * path_phys,char * ses_path,gfc_map_t * map,int verbose)4644 l_get_ses_path(char *path_phys, char *ses_path, gfc_map_t *map,
4645 int verbose)
4646 {
4647 char *char_ptr, id_buf[MAXPATHLEN], wwn[20];
4648 uchar_t t_wwn[20], *ses_wwn, *ses_wwn1, *ses_nwwn;
4649 int j, al_pa, al_pa1, box_id, fd, disk_flag = 0;
4650 int err, found = 0;
4651 gfc_port_dev_info_t *dev_addr_ptr;
4652
4653 if ((path_phys == NULL) || (ses_path == NULL) || (map == NULL)) {
4654 return (L_NO_SES_PATH);
4655 }
4656
4657 (void) strcpy(ses_path, path_phys);
4658 if ((char_ptr = strrchr(ses_path, '/')) == NULL) {
4659 return (L_INVLD_PATH_NO_SLASH_FND);
4660 }
4661 disk_flag++;
4662 *char_ptr = '\0'; /* Terminate sting */
4663 (void) strcat(ses_path, SLSH_SES_NAME);
4664
4665 /*
4666 * Figure out and create the boxes pathname.
4667 *
4668 * NOTE: This uses the fact that the disks's
4669 * AL_PA and the boxes AL_PA must match
4670 * the assigned hard address in the current
4671 * implementations. This may not be true in the
4672 * future.
4673 */
4674 if ((char_ptr = strrchr(path_phys, '@')) == NULL) {
4675 return (L_INVLD_PATH_NO_ATSIGN_FND);
4676 }
4677 char_ptr++; /* point to the loop identifier */
4678
4679 if ((err = g_get_wwn(path_phys, t_wwn, t_wwn,
4680 &al_pa, verbose)) != 0) {
4681 return (err);
4682 }
4683 box_id = g_sf_alpa_to_switch[al_pa & 0xFF] & BOX_ID_MASK;
4684
4685 switch (map->hba_addr.port_topology) {
4686 case FC_TOP_PRIVATE_LOOP:
4687 for (j = 0, dev_addr_ptr = map->dev_addr;
4688 j < map->count; j++, dev_addr_ptr++) {
4689 if (dev_addr_ptr->gfc_port_dev.priv_port.
4690 sf_inq_dtype == DTYPE_ESI) {
4691 al_pa1 = dev_addr_ptr->gfc_port_dev.
4692 priv_port.sf_al_pa;
4693 if (box_id == (g_sf_alpa_to_switch[al_pa1] &
4694 BOX_ID_MASK)) {
4695 if (!found) {
4696 ses_wwn = dev_addr_ptr->
4697 gfc_port_dev.priv_port.sf_port_wwn;
4698 ses_nwwn = dev_addr_ptr->
4699 gfc_port_dev.priv_port.sf_node_wwn;
4700 if (getenv("_LUX_P_DEBUG")) {
4701 (void) g_ll_to_str(ses_wwn,
4702 (char *)t_wwn);
4703 (void) printf(
4704 " l_get_ses_path: "
4705 "Found ses wwn = %s "
4706 "al_pa 0x%x\n", t_wwn, al_pa1);
4707 }
4708 } else {
4709 ses_wwn1 = dev_addr_ptr->
4710 gfc_port_dev.priv_port.sf_port_wwn;
4711 if (getenv("_LUX_P_DEBUG")) {
4712 (void) g_ll_to_str(ses_wwn1,
4713 (char *)t_wwn);
4714 (void) printf(
4715 " l_get_ses_path: "
4716 "Found second ses " "wwn = %s "
4717 "al_pa 0x%x\n", t_wwn, al_pa1);
4718 }
4719 }
4720 found++;
4721 }
4722 }
4723 }
4724 break;
4725 case FC_TOP_FABRIC:
4726 case FC_TOP_PUBLIC_LOOP:
4727 for (j = 0, dev_addr_ptr = map->dev_addr;
4728 j < map->count; j++, dev_addr_ptr++) {
4729 if (dev_addr_ptr->gfc_port_dev.pub_port.dev_dtype ==
4730 DTYPE_ESI) {
4731 /*
4732 * We found an enclosure, lets match the
4733 * area and domain codes for this enclosure with
4734 * that of the ses path since there may be
4735 * multiple enclosures with same box id on a
4736 * fabric
4737 */
4738 al_pa1 = dev_addr_ptr->gfc_port_dev.
4739 pub_port.dev_did.port_id;
4740 if ((al_pa & AREA_DOMAIN_ID) ==
4741 (al_pa1 & AREA_DOMAIN_ID)) {
4742 /*
4743 * The area and domain matched. Now, we
4744 * match the box id of the disk with
4745 * this enclosure
4746 */
4747 if (box_id ==
4748 (g_sf_alpa_to_switch[al_pa1 &
4749 0xFF] & BOX_ID_MASK)) {
4750 if (!found) {
4751 ses_wwn = dev_addr_ptr->
4752 gfc_port_dev.pub_port.
4753 dev_pwwn.raw_wwn;
4754 ses_nwwn = dev_addr_ptr->
4755 gfc_port_dev.pub_port.
4756 dev_nwwn.raw_wwn;
4757 if (getenv("_LUX_P_DEBUG")) {
4758 (void) g_ll_to_str(ses_wwn,
4759 (char *)t_wwn);
4760 (void) printf(
4761 " l_get_ses_path: "
4762 "Found ses wwn = %s "
4763 "al_pa 0x%x\n", t_wwn,
4764 al_pa1);
4765 }
4766 } else {
4767 ses_wwn1 = dev_addr_ptr->
4768 gfc_port_dev.pub_port.
4769 dev_pwwn.raw_wwn;
4770 if (getenv("_LUX_P_DEBUG")) {
4771 (void) g_ll_to_str(ses_wwn1,
4772 (char *)t_wwn);
4773 (void) printf(
4774 " l_get_ses_path: "
4775 "Found second ses "
4776 "wwn = %s "
4777 "al_pa 0x%x\n", t_wwn,
4778 al_pa1);
4779 }
4780 }
4781 found++;
4782 }
4783 }
4784 }
4785 }
4786 break;
4787 case FC_TOP_PT_PT:
4788 return (L_PT_PT_FC_TOP_NOT_SUPPORTED);
4789 default:
4790 return (L_UNEXPECTED_FC_TOPOLOGY);
4791 } /* End of switch on port_topology */
4792
4793 if (!found) {
4794 return (L_NO_SES_PATH);
4795 }
4796
4797 if (strstr(path_phys, SCSI_VHCI) != NULL) {
4798 (void) g_ll_to_str(ses_nwwn, wwn);
4799 (void) sprintf(id_buf, "g%s:0", wwn);
4800 } else {
4801 (void) g_ll_to_str(ses_wwn, wwn);
4802 (void) sprintf(id_buf, "w%s,0:0", wwn);
4803 }
4804 (void) strcat(ses_path, id_buf);
4805 if (verbose) {
4806 (void) fprintf(stdout,
4807 MSGSTR(9058, " Creating enclosure path:\n %s\n"),
4808 ses_path);
4809 }
4810
4811 /*
4812 * see if these paths exist.
4813 */
4814 if ((fd = g_object_open(ses_path, O_NDELAY | O_RDONLY)) == -1) {
4815
4816 if (strstr(path_phys, SCSI_VHCI) != NULL) {
4817 return (L_INVALID_PATH);
4818 }
4819
4820 char_ptr = strrchr(ses_path, '/');
4821 *char_ptr = '\0';
4822 (void) strcat(ses_path, SLSH_SES_NAME);
4823 if (found > 1) {
4824 (void) g_ll_to_str(ses_wwn1, wwn);
4825 P_DPRINTF(" l_get_ses_path: "
4826 "Using second path, ses wwn1 = %s\n",
4827 wwn);
4828 (void) sprintf(id_buf, "w%s,0:0", wwn);
4829 strcat(ses_path, id_buf);
4830 return (0);
4831 } else {
4832 return (L_NO_SES_PATH);
4833 }
4834 }
4835 close(fd);
4836 return (0);
4837 }
4838
4839
4840
4841 /*
4842 * Get a valid location, front/rear & slot.
4843 *
4844 * path_struct->p_physical_path must be of a disk.
4845 *
4846 * OUTPUT: path_struct->slot_valid
4847 * path_struct->slot
4848 * path_struct->f_flag
4849 *
4850 * RETURN:
4851 * 0 O.K.
4852 * non-zero otherwise
4853 */
4854 int
l_get_slot(struct path_struct * path_struct,L_state * l_state,int verbose)4855 l_get_slot(struct path_struct *path_struct, L_state *l_state, int verbose)
4856 {
4857 int err, al_pa, slot, found = 0;
4858 uchar_t node_wwn[WWN_SIZE], port_wwn[WWN_SIZE];
4859 uint_t select_id;
4860
4861 if ((path_struct == NULL) || (l_state == NULL)) {
4862 return (L_INVALID_PATH_FORMAT);
4863 }
4864
4865 /* Double check to see if we need to calculate. */
4866 if (path_struct->slot_valid)
4867 return (0);
4868
4869 /* Programming error if this occures */
4870 assert(path_struct->ib_path_flag == 0);
4871
4872 if (strstr(path_struct->p_physical_path, "ssd") == NULL) {
4873 return (L_INVLD_PHYS_PATH_TO_DISK);
4874 }
4875 if (err = g_get_wwn(path_struct->p_physical_path, port_wwn, node_wwn,
4876 &al_pa, verbose)) {
4877 return (err);
4878 }
4879
4880 /*
4881 * Find the slot by searching for the matching hard address.
4882 * Take only the low order byte ignoring area and domain code in
4883 * fabric devices' 24 bit al_pa
4884 */
4885 select_id = g_sf_alpa_to_switch[al_pa & 0xFF];
4886 P_DPRINTF(" l_get_slot: Searching Receive Diagnostic page 2, "
4887 "to find the slot number with this ID:0x%x\n",
4888 select_id);
4889
4890 for (slot = 0; slot < l_state->total_num_drv/2; slot++) {
4891 if (l_state->drv_front[slot].ib_status.sel_id ==
4892 select_id) {
4893 path_struct->f_flag = 1;
4894 found = 1;
4895 break;
4896 } else if (l_state->drv_rear[slot].ib_status.sel_id ==
4897 select_id) {
4898 path_struct->f_flag = 0;
4899 found = 1;
4900 break;
4901 }
4902 }
4903 if (!found) {
4904 return (L_INVALID_SLOT); /* Failure */
4905 }
4906 if ((strncmp((char *)l_state->ib_tbl.config.prod_id, DAK_OFF_NAME,
4907 strlen(DAK_OFF_NAME)) == 0) ||
4908 (strncmp((char *)l_state->ib_tbl.config.prod_id, DAK_PROD_STR,
4909 strlen(DAK_OFF_NAME)) == 0)) {
4910 P_DPRINTF(" l_get_slot: Found slot %d.\n",
4911 path_struct->f_flag ? slot : slot + (MAX_DRIVES_DAK/2));
4912 } else {
4913 P_DPRINTF(" l_get_slot: Found slot %d %s.\n", slot,
4914 path_struct->f_flag ? "Front" : "Rear");
4915 }
4916 path_struct->slot = slot;
4917 path_struct->slot_valid = 1;
4918 return (0);
4919 }
4920
4921
4922 void
l_element_msg_string(uchar_t code,char * es)4923 l_element_msg_string(uchar_t code, char *es)
4924 {
4925 if (code == S_OK) {
4926 (void) sprintf(es, MSGSTR(29, "O.K."));
4927 } else if (code == S_NOT_AVAILABLE) {
4928 (void) sprintf(es, MSGSTR(34, "Disabled"));
4929 } else if (code == S_NOT_INSTALLED) {
4930 (void) sprintf(es, MSGSTR(30, "Not Installed"));
4931 } else if (code == S_NONCRITICAL) {
4932 (void) sprintf(es, MSGSTR(9059, "Noncritical failure"));
4933 } else if (code == S_CRITICAL) {
4934 (void) sprintf(es, MSGSTR(122, "Critical failure"));
4935 } else {
4936 (void) sprintf(es, MSGSTR(4, "Unknown status"));
4937 }
4938 }
4939
4940
4941 /*
4942 * Get all ses paths paths to a given box.
4943 * The arg should be the physical path to one of the box's IB.
4944 * NOTE: The caller must free the allocated lists.
4945 *
4946 * OUTPUT:
4947 * a pointer to a list of ses paths if found
4948 * NULL on error.
4949 *
4950 * RETURNS:
4951 * 0 if O.K.
4952 * non-zero otherwise
4953 */
4954 int
l_get_allses(char * path,struct box_list_struct * box_list,struct dlist ** ses_list,int verbose)4955 l_get_allses(char *path, struct box_list_struct *box_list,
4956 struct dlist **ses_list, int verbose)
4957 {
4958 struct box_list_struct *box_list_ptr;
4959 char node_wwn_s[WWN_S_LEN];
4960 struct dlist *dlt, *dl;
4961
4962 if ((path == NULL) || (box_list == NULL) || (ses_list == NULL)) {
4963 return (L_INVALID_PATH_FORMAT);
4964 }
4965
4966 /* Initialize lists/arrays */
4967 *ses_list = dlt = dl = (struct dlist *)NULL;
4968 node_wwn_s[0] = '\0';
4969
4970 H_DPRINTF(" l_get_allses: Looking for all ses paths for"
4971 " box at path: %s\n", path);
4972
4973 for (box_list_ptr = box_list; box_list_ptr != NULL;
4974 box_list_ptr = box_list_ptr->box_next) {
4975 H_DPRINTF(" l_get_allses: physical_path= %s\n",
4976 box_list_ptr->b_physical_path);
4977 if (strcmp(path, box_list_ptr->b_physical_path) == 0) {
4978 (void) strcpy(node_wwn_s, box_list_ptr->b_node_wwn_s);
4979 break;
4980 }
4981 }
4982 if (node_wwn_s[0] == '\0') {
4983 H_DPRINTF("node_wwn_s is NULL!\n");
4984 return (L_NO_NODE_WWN_IN_BOXLIST);
4985 }
4986 H_DPRINTF(" l_get_allses: node_wwn=%s\n", node_wwn_s);
4987 for (box_list_ptr = box_list; box_list_ptr != NULL;
4988 box_list_ptr = box_list_ptr->box_next) {
4989 if (strcmp(node_wwn_s, box_list_ptr->b_node_wwn_s) == 0) {
4990 if ((dl = (struct dlist *)
4991 g_zalloc(sizeof (struct dlist))) == NULL) {
4992 while (*ses_list != NULL) {
4993 dl = dlt->next;
4994 (void) g_destroy_data(dlt);
4995 dlt = dl;
4996 }
4997 return (L_MALLOC_FAILED);
4998 }
4999 H_DPRINTF(" l_get_allses: Found ses=%s\n",
5000 box_list_ptr->b_physical_path);
5001 dl->dev_path = strdup(box_list_ptr->b_physical_path);
5002 dl->logical_path = strdup(box_list_ptr->logical_path);
5003 if (*ses_list == NULL) {
5004 *ses_list = dlt = dl;
5005 } else {
5006 dlt->next = dl;
5007 dl->prev = dlt;
5008 dlt = dl;
5009 }
5010 }
5011 }
5012
5013 return (0);
5014 }
5015
5016 /*
5017 * Routine to return the enclosure type pointed to by the path.
5018 * Inputs: The inquiry data for the device in question
5019 *
5020 * Return: >= 0 is the type:
5021 *
5022 * Types are defined in storage/libg_fc/common/hdrs/g_state.h:
5023 *
5024 * 0 -> default (SENA)
5025 * 1 -> Daktari
5026 * 2 -> Other Enclosures
5027 *
5028 */
5029 int
l_get_enc_type(L_inquiry inq)5030 l_get_enc_type(L_inquiry inq)
5031 {
5032 if (strncmp((char *)&inq.inq_pid[0], ENCLOSURE_PROD_ID,
5033 strlen(ENCLOSURE_PROD_ID)) == 0) {
5034 return (SENA_ENC_TYPE);
5035 }
5036 if (strncmp((char *)&inq.inq_pid[0], DAK_OFF_NAME,
5037 strlen(DAK_OFF_NAME)) == 0) {
5038 return (DAK_ENC_TYPE);
5039 }
5040 if (strncmp((char *)&inq.inq_pid[0], DAK_PROD_STR,
5041 strlen(DAK_PROD_STR)) == 0) {
5042 return (DAK_ENC_TYPE);
5043 }
5044 /*
5045 * ADD OTHERS here if ever needed/wanted, and add to def's
5046 * as noted above
5047 */
5048 return (UNDEF_ENC_TYPE);
5049 }
5050
5051 void
free_mp_dev_map(gfc_map_mp_t ** map_mp_ptr)5052 free_mp_dev_map(gfc_map_mp_t **map_mp_ptr) {
5053 gfc_map_mp_t *next = NULL;
5054
5055 for (; *map_mp_ptr != NULL; *map_mp_ptr = next) {
5056 next = (*map_mp_ptr)->map_next;
5057 (void) g_destroy_data((*map_mp_ptr)->map.dev_addr);
5058 (void) g_destroy_data(*map_mp_ptr);
5059 }
5060 *map_mp_ptr = NULL;
5061 }
5062 /*
5063 * This function will return a linked list of device maps
5064 * An example of when this will be used is when we want to return the device
5065 * map of a vhci path.
5066 */
5067
5068 int
get_mp_dev_map(char * path,gfc_map_mp_t ** map_mp_ptr,int verbose)5069 get_mp_dev_map(char *path, gfc_map_mp_t **map_mp_ptr, int verbose) {
5070
5071 int pathcnt, i, err;
5072 mp_pathlist_t pathlist;
5073 gfc_map_mp_t *new_map_mp_ptr;
5074 char drvr_path[MAXPATHLEN];
5075 if (strstr(path, SCSI_VHCI)) {
5076 if (g_get_pathlist(path, &pathlist)) {
5077 return (L_INVALID_PATH);
5078 }
5079 pathcnt = pathlist.path_count;
5080 for (i = 0; i < pathcnt; i++) {
5081 if (pathlist.path_info[i].path_state < MAXPATHSTATE) {
5082 /*
5083 * only pay attention to paths that are either
5084 * ONLINE or STANDBY
5085 */
5086 if ((pathlist.path_info[i].path_state ==
5087 MDI_PATHINFO_STATE_ONLINE) ||
5088 (pathlist.path_info[i].path_state ==
5089 MDI_PATHINFO_STATE_STANDBY)) {
5090 if ((new_map_mp_ptr = (gfc_map_mp_t *)
5091 g_zalloc(sizeof (gfc_map_mp_t)))
5092 == NULL) {
5093 free(pathlist.path_info);
5094 free_mp_dev_map(map_mp_ptr);
5095 return (L_MALLOC_FAILED);
5096 }
5097 (void) strcpy(drvr_path,
5098 pathlist.path_info[i].path_hba);
5099 (void) strcat(drvr_path, FC_CTLR);
5100 if (err = g_get_dev_map(drvr_path,
5101 &(new_map_mp_ptr->map),
5102 verbose)) {
5103 free(pathlist.path_info);
5104 free_mp_dev_map(map_mp_ptr);
5105 return (err);
5106 }
5107 /* add newly created map onto list */
5108 if (*map_mp_ptr == NULL) {
5109 new_map_mp_ptr->map_next = NULL;
5110 *map_mp_ptr = new_map_mp_ptr;
5111 } else {
5112 new_map_mp_ptr->map_next =
5113 *map_mp_ptr;
5114 *map_mp_ptr = new_map_mp_ptr;
5115 }
5116 }
5117 }
5118 }
5119 free(pathlist.path_info);
5120 } else {
5121 if ((new_map_mp_ptr = (gfc_map_mp_t *)g_zalloc
5122 (sizeof (gfc_map_mp_t))) == NULL) {
5123 return (L_MALLOC_FAILED);
5124 }
5125 g_get_dev_map(path, &(new_map_mp_ptr->map), verbose);
5126 *map_mp_ptr = new_map_mp_ptr;
5127 }
5128 return (0);
5129 }
5130