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