1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26
27 /*LINTLIBRARY*/
28
29
30 /*
31 * This module is part of the photon library
32 */
33
34 /*
35 * I18N message number ranges
36 * This file: 8500 - 8999
37 * Shared common messages: 1 - 1999
38 */
39
40 /* #define _POSIX_SOURCE 1 */
41
42 /* Includes */
43 #include <stdlib.h>
44 #include <stdio.h>
45 #include <sys/file.h>
46 #include <sys/types.h>
47 #include <sys/stat.h>
48 #include <sys/param.h>
49 #include <fcntl.h>
50 #include <unistd.h>
51 #include <errno.h>
52 #include <string.h>
53 #include <time.h>
54 #include <sys/scsi/scsi.h>
55 #include <sys/vtoc.h>
56 #include <nl_types.h>
57 #include <strings.h>
58 #include <sys/ddi.h> /* for max */
59 #include <l_common.h>
60 #include <stgcom.h>
61 #include <l_error.h>
62 #include <rom.h>
63 #include <a_state.h>
64 #include <a5k.h>
65
66
67 /* Global variables */
68 extern uchar_t g_switch_to_alpa[];
69 extern uchar_t g_sf_alpa_to_switch[];
70
71
72 /*
73 * This function checks if the passed char pointer has WWN_SIZE nulls (zeroes).
74 *
75 * This is only a convenience function.
76 *
77 * INPUT:
78 * wwn_ptr - pointer to a character string of length WWN_SIZE
79 * It is expected to be holding the WWN
80 * Ex: A WWN like 508002000000ddc1 is expected to be stored as
81 * the following 8 bytes -
82 * 0x50, 0x80, 0x00, 0x20, ... etc
83 *
84 * RETURNS:
85 * 0 - if there is atleast one of WWN_SIZE bytes is != '\0'
86 * non-zero - if all WWN_SIZE bytes are '\0'
87 */
88 int
is_null_wwn(uchar_t * wwn_ptr)89 is_null_wwn(uchar_t *wwn_ptr)
90 {
91 int i;
92
93 for (i = 0; i < WWN_SIZE; i++) {
94 if (wwn_ptr[i] != '\0' || wwn_ptr[i] != '0')
95 return (0);
96 }
97 return (1);
98 }
99
100
101 /*
102 * This functions constructs a device path of the device/enclosure with the
103 * given tid and, for public/fabric cases, on the same area and domain as
104 * the given ses_path.
105 *
106 * INPUT:
107 * ses_path - pointer to the ses_path
108 * tid - tid of the device/enclosure whose path is to be constructed
109 * map - pointer to the map
110 * dtype - dtype of the device whose path is to be constructed
111 *
112 * OUTPUT:
113 * dev_path - pointer to the device path of type dtype and with tid
114 * - Caller has to free this after use
115 *
116 * RETURNS:
117 * 0 - on success
118 * non-zero - otherwise
119 */
120 int
l_make_node(char * ses_path,int tid,char * dev_path,gfc_map_t * map,int dtype)121 l_make_node(char *ses_path, int tid, char *dev_path,
122 gfc_map_t *map, int dtype)
123 {
124 int len, i, err;
125 int this_pid, ses_pid;
126 char ssd[40], wwn[20];
127 gfc_port_dev_info_t *dev_addr_ptr;
128 struct stat stat_buf;
129 WWN_list *wwnlp, *wwn_list;
130 int found = 0;
131
132 if ((ses_path == NULL) || (dev_path == NULL) || (map == NULL)) {
133 return (L_INVALID_PATH_FORMAT);
134 }
135
136 switch (map->hba_addr.port_topology) {
137 case FC_TOP_PRIVATE_LOOP:
138 for (i = 0, dev_addr_ptr = map->dev_addr;
139 i < map->count; i++, dev_addr_ptr++) {
140 if (dev_addr_ptr->gfc_port_dev.priv_port.
141 sf_al_pa == g_switch_to_alpa[tid])
142 break;
143 }
144 if (i >= map->count) {
145 *dev_path = '\0';
146 return (L_INVALID_LOOP_MAP);
147 }
148
149 /* Make sure that the port WWN is valid */
150 if (is_null_wwn(dev_addr_ptr->gfc_port_dev.
151 priv_port.sf_port_wwn)) {
152 *dev_path = '\0';
153 return (L_INVLD_WWN_FORMAT);
154 }
155
156 (void) g_ll_to_str(dev_addr_ptr->gfc_port_dev.
157 priv_port.sf_port_wwn, wwn);
158
159 if (strstr(ses_path, SCSI_VHCI) != NULL) {
160 if (err = g_get_wwn_list(&wwn_list, 0)) {
161 return (err);
162 }
163 for (wwnlp = wwn_list, found = 0;
164 wwnlp != NULL;
165 wwnlp = wwnlp->wwn_next) {
166 if (strcmp(wwnlp->port_wwn_s,
167 wwn) == 0) {
168 found = 1;
169 break;
170 }
171 }
172 if (found) {
173 (void) strcpy(dev_path,
174 wwnlp->physical_path);
175 } else {
176 return (L_INVALID_PATH);
177 }
178 } else {
179
180 len = strlen(ses_path) -
181 strlen(strrchr(ses_path, '/'));
182
183 if (dtype != DTYPE_ESI) {
184 (void) sprintf(ssd,
185 "/ssd@w%s,0:c", wwn);
186 } else {
187 (void) sprintf(ssd,
188 "/ses@w%s,0:c", wwn);
189 }
190
191 /* TBD: Must find path, not just use :c */
192 (void) strncpy(dev_path, ses_path, len);
193 dev_path[len] = '\0';
194 (void) strcat(dev_path, ssd);
195 }
196 break;
197 case FC_TOP_FABRIC:
198 case FC_TOP_PUBLIC_LOOP:
199 /* First lets get the PA from the ses path passed in */
200 if (err = l_get_pid_from_path(ses_path, map, &ses_pid)) {
201 return (err);
202 }
203
204 /*
205 * Now we go through every entry in the map and match the
206 * area and domain ids with the PA of the passed ses path.
207 * If we find a match, we then match the low order byte
208 */
209 for (i = 0, dev_addr_ptr = map->dev_addr; i < map->count;
210 i++, dev_addr_ptr++) {
211 this_pid = dev_addr_ptr->gfc_port_dev.pub_port.
212 dev_did.port_id;
213 if ((this_pid & AREA_DOMAIN_ID) ==
214 (ses_pid & AREA_DOMAIN_ID)) {
215 if ((uchar_t)(this_pid & 0xFF) ==
216 g_switch_to_alpa[tid])
217 break;
218 }
219 }
220 if (i >= map->count) {
221 *dev_path = '\0';
222 return (L_INVALID_LOOP_MAP);
223 }
224 /* Make sure that the port WWN is valid */
225 if (is_null_wwn(dev_addr_ptr->gfc_port_dev.pub_port.
226 dev_pwwn.raw_wwn)) {
227 *dev_path = '\0';
228 return (L_INVLD_WWN_FORMAT);
229 }
230 (void) g_ll_to_str(dev_addr_ptr->gfc_port_dev.
231 pub_port.dev_pwwn.raw_wwn, wwn);
232
233
234
235 if (strstr(ses_path, SCSI_VHCI) != NULL) {
236 if (err = g_get_wwn_list(&wwn_list, 0)) {
237 return (err);
238 }
239 for (wwnlp = wwn_list, found = 0; wwnlp != NULL;
240 wwnlp = wwnlp->wwn_next) {
241 if (strcmp(wwnlp->port_wwn_s,
242 wwn) == 0) {
243 found = 1;
244 }
245 }
246 if (found) {
247 (void) strcpy(dev_path,
248 wwnlp->physical_path);
249 } else {
250 return (L_INVALID_PATH);
251 }
252 } else {
253 len = strlen(ses_path) -
254 strlen(strrchr(ses_path, '/'));
255
256 if (dtype != DTYPE_ESI) {
257 (void) sprintf(ssd, "/ssd@w%s,0:c", wwn);
258 } else {
259 (void) sprintf(ssd, "/ses@w%s,0:c", wwn);
260 }
261
262 /* TBD: Must find path, not just use :c */
263 (void) strncpy(dev_path, ses_path, len);
264 dev_path[len] = '\0';
265 (void) strcat(dev_path, ssd);
266 }
267
268 if (stat(dev_path, &stat_buf) == -1) {
269 return (errno);
270 }
271
272 break;
273 case FC_TOP_PT_PT:
274 return (L_PT_PT_FC_TOP_NOT_SUPPORTED);
275 default:
276 return (L_UNEXPECTED_FC_TOPOLOGY);
277 } /* End of switch on port_topology */
278 return (0);
279 }
280
281
282
283 /*
284 * checks for null wwn to a disk.
285 * and returns -1 if found, 0
286 * otherwise.
287 *
288 * OUTPUT:
289 * char *ses_path
290 *
291 * RETURNS:
292 * 0 if OK
293 * non-zero otherwise
294 */
295 int
l_chk_null_wwn(Path_struct * path_struct,char * ses_path,L_state * l_state,int verbose)296 l_chk_null_wwn(Path_struct *path_struct, char *ses_path,
297 L_state *l_state, int verbose)
298 {
299 char *ptr, boxname[MAXPATHLEN];
300 char node_wwn_s[WWN_SIZE * 2 + 1];
301 Box_list *boxlist;
302
303
304 if ((path_struct == NULL) || (ses_path == NULL) ||
305 (l_state == NULL)) {
306 return (L_INVALID_PATH_FORMAT);
307 }
308
309 /*
310 * verify and continue only if the argv
311 * has a format like box,{f/r}<slot #>.
312 * Otherwise, return to the caller.
313 * The only way to address null wwn disk
314 * is using the box,{f/r}<slot#> format.
315 */
316 /* add support for new {f/r/s}<slot#> support for DPM */
317 (void) strcpy(boxname, path_struct->argv);
318 if (((ptr = strstr(boxname, ",")) != NULL) &&
319 ((*(ptr + 1) == 'f') || (*(ptr + 1) == 'r') ||
320 (*(ptr + 1) == 's'))) {
321 *ptr = '\0';
322 } else {
323 return (0);
324 }
325
326
327 /*
328 * Get the list of enclosures
329 * connected to the system.
330 */
331 if (l_get_box_list(&boxlist, verbose) != 0) {
332 return (L_NO_ENCL_LIST_FOUND);
333 }
334
335 *ses_path = '\0';
336
337 /*
338 * The following method is safer to get an ses path
339 * to the enclosure than calling l_get_ses_path(),
340 * with physical path to null WWN disk.
341 * Because, l_get_ses_path uses the disk's
342 * al_pa to get the box id and then ses path
343 * to the box. When a disk has null wwn, it may
344 * not have a valid al_pa, and hard address.
345 * There is a possibility that l_get_ses_path()
346 * not returning ses path to the correct enclosure.
347 */
348 while (boxlist != NULL) {
349 if ((strcmp(boxname, (char *)boxlist->b_name) == 0)) {
350 (void) strcpy(ses_path, boxlist->b_physical_path);
351 break;
352 }
353 boxlist = boxlist->box_next;
354 }
355
356 /* free the box list */
357 (void) l_free_box_list(&boxlist);
358
359 if ((ses_path != NULL) && (strstr(ses_path, "ses") != NULL)) {
360 if (l_get_status(ses_path, l_state,
361 verbose) != 0) {
362 return (L_GET_STATUS_FAILED);
363 }
364 if (path_struct->f_flag) {
365 (void) strcpy(node_wwn_s,
366 l_state->drv_front[path_struct->slot].g_disk_state.node_wwn_s);
367 } else {
368 (void) strcpy(node_wwn_s,
369 l_state->drv_rear[path_struct->slot].g_disk_state.node_wwn_s);
370 }
371
372 W_DPRINTF("Found ses path: %s\n"
373 "and Node WWN: %s\n", ses_path, node_wwn_s);
374
375 /* check for null WWN */
376 if (is_null_wwn((uchar_t *)node_wwn_s) == 0) {
377 return (0); /* Non-null wwn */
378 }
379 W_DPRINTF("Found NULL WWN: %s\n", node_wwn_s);
380 return (1);
381 }
382
383 return (0);
384
385 }
386
387
388
389 /*
390 * If OVERALL_STATUS is sent as the "func",
391 * the code pointer must be valid (non NULL).
392 * Otherwise NULL is a valid input for the code pointer.
393 *
394 * RETURNS:
395 * 0 if OK
396 * non-zero otherwise
397 */
398 int
l_encl_status_page_funcs(int func,char * code,int todo,char * ses_path,struct l_state_struct * l_state,int f_flag,int slot,int verbose_flag)399 l_encl_status_page_funcs(int func, char *code, int todo, char *ses_path,
400 struct l_state_struct *l_state, int f_flag, int slot, int verbose_flag)
401 {
402 uchar_t *page_buf;
403 int fd, front_index, rear_index, offset, err;
404 unsigned short page_len;
405 struct device_element *elem;
406
407 if ((ses_path == NULL) || (l_state == NULL)) {
408 return (L_INVALID_PATH_FORMAT);
409 }
410
411 if ((page_buf = (uchar_t *)g_zalloc(MAX_REC_DIAG_LENGTH)) == NULL) {
412 return (L_MALLOC_FAILED);
413 }
414
415 if ((fd = g_object_open(ses_path, O_NDELAY | O_RDWR)) == -1) {
416 (void) g_destroy_data(page_buf);
417 return (L_OPEN_PATH_FAIL);
418 }
419
420 if ((err = l_get_envsen_page(fd, page_buf, MAX_REC_DIAG_LENGTH,
421 L_PAGE_2, verbose_flag)) != 0) {
422 (void) g_destroy_data(page_buf);
423 (void) close(fd);
424 return (err);
425 }
426
427 page_len = (page_buf[2] << 8 | page_buf[3]) + HEADER_LEN;
428
429 if ((err = l_get_disk_element_index(l_state, &front_index,
430 &rear_index)) != 0) {
431 (void) g_destroy_data(page_buf);
432 (void) close(fd);
433 return (err);
434 }
435 /* Skip global element */
436 front_index++;
437 if ((strncmp((char *)l_state->ib_tbl.config.prod_id, DAK_OFF_NAME,
438 strlen(DAK_OFF_NAME)) == 0) ||
439 (strncmp((char *)l_state->ib_tbl.config.prod_id, DAK_PROD_STR,
440 strlen(DAK_OFF_NAME)) == 0)) {
441 rear_index += l_state->total_num_drv/2 + 1;
442 } else
443 rear_index++;
444
445 if (f_flag) {
446 offset = (8 + (front_index + slot)*4);
447 } else {
448 offset = (8 + (rear_index + slot)*4);
449 }
450
451 elem = (struct device_element *)(page_buf + offset);
452
453 switch (func) {
454 case OVERALL_STATUS:
455 if (code == NULL) {
456 return (L_INVALID_ARG);
457 }
458 switch (todo) {
459 case INSERT_DEVICE:
460 *code = (elem->code != S_OK) ? elem->code : 0;
461 (void) g_destroy_data(page_buf);
462 (void) close(fd);
463 return (0);
464 case REMOVE_DEVICE:
465 *code = (elem->code != S_NOT_INSTALLED) ?
466 elem->code : 0;
467 (void) g_destroy_data(page_buf);
468 (void) close(fd);
469 return (0);
470 }
471 /* NOTREACHED */
472 case SET_RQST_INSRT:
473 bzero(elem, sizeof (struct device_element));
474 elem->select = 1;
475 elem->rdy_to_ins = 1;
476 break;
477 case SET_RQST_RMV:
478 bzero(elem, sizeof (struct device_element));
479 elem->select = 1;
480 elem->rmv = 1;
481 elem->dev_off = 1;
482 elem->en_bypass_a = 1;
483 elem->en_bypass_b = 1;
484 break;
485 case SET_FAULT:
486 bzero(elem, sizeof (struct device_element));
487 elem->select = 1;
488 elem->fault_req = 1;
489 elem->dev_off = 1;
490 elem->en_bypass_a = 1;
491 elem->en_bypass_b = 1;
492 break;
493 case SET_DRV_ON:
494 bzero(elem, sizeof (struct device_element));
495 elem->select = 1;
496 break;
497 }
498
499 err = g_scsi_send_diag_cmd(fd, (uchar_t *)page_buf, page_len);
500 (void) g_destroy_data(page_buf);
501 (void) close(fd);
502 return (err);
503 }
504
505
506
507 /*
508 * Finds whether device id (tid) exists in the
509 * Arbitrated loop map or not.
510 *
511 * INPUT:
512 * ses_path - pointer to a ses path
513 * tid - the target id of the device we want to check on
514 * - only the low order 8 bits has the tid
515 * map - pointer to a map of the system
516 * verbose_flag - self explanatory
517 *
518 * OUTPUT:
519 * dev_path - the device path of the device with "tid".
520 * Caller is responsible for freeing it
521 *
522 * RETURNS:
523 * 1 if device present
524 * 0 otherwise
525 */
526 int
l_device_present(char * ses_path,int tid,gfc_map_t * map,int verbose_flag,char ** dev_path)527 l_device_present(char *ses_path, int tid, gfc_map_t *map,
528 int verbose_flag, char **dev_path)
529 {
530 char sf_path[MAXPATHLEN];
531 uchar_t wwn[40], c;
532 int len, i, j, k, fnib, snib, this_pid;
533 int fd, ses_pid, al_pa, err;
534 char ssd[30];
535 gfc_port_dev_info_t *dev_addr_ptr;
536 WWN_list *wwnlp, *wwn_list;
537
538
539 if (dev_path == NULL)
540 return (0);
541
542 if ((ses_path == NULL) || (map == NULL)) {
543 return (L_NO_SES_PATH);
544 }
545
546 *dev_path = NULL;
547
548 switch (map->hba_addr.port_topology) {
549 case FC_TOP_PRIVATE_LOOP:
550 for (i = 0, dev_addr_ptr = map->dev_addr; i < map->count;
551 i++, dev_addr_ptr++) {
552 if (dev_addr_ptr->gfc_port_dev.
553 priv_port.sf_inq_dtype != DTYPE_ESI) {
554 al_pa = dev_addr_ptr->gfc_port_dev.
555 priv_port.sf_al_pa;
556 if (tid == g_sf_alpa_to_switch[al_pa]) {
557 break;
558 }
559 }
560 }
561 if (i >= map->count)
562 return (0);
563 /*
564 * Make sure that the port WWN is valid
565 */
566 if (is_null_wwn(dev_addr_ptr->gfc_port_dev.
567 priv_port.sf_port_wwn)) {
568 return (0);
569 }
570 for (j = 0, k = 0; j < WWN_SIZE; j++) {
571 c = dev_addr_ptr->gfc_port_dev.priv_port.sf_port_wwn[j];
572 fnib = (((int)(c & 0xf0)) >> 4);
573 snib = (c & 0x0f);
574 if (fnib >= 0 && fnib <= 9)
575 wwn[k++] = '0' + fnib;
576 else if (fnib >= 10 && fnib <= 15)
577 wwn[k++] = 'a' + fnib - 10;
578 if (snib >= 0 && snib <= 9)
579 wwn[k++] = '0' + snib;
580 else if (snib >= 10 && snib <= 15)
581 wwn[k++] = 'a' + snib - 10;
582 }
583 wwn[k] = '\0';
584 break;
585 case FC_TOP_PUBLIC_LOOP:
586 case FC_TOP_FABRIC:
587 /*
588 * Get the phys address (port id) of this ses device
589 */
590 if (err = l_get_pid_from_path(ses_path, map, &ses_pid))
591 return (err);
592
593 for (i = 0, dev_addr_ptr = map->dev_addr; i < map->count;
594 i++, dev_addr_ptr++) {
595 if (dev_addr_ptr->gfc_port_dev.pub_port.dev_dtype !=
596 DTYPE_ESI) {
597 /*
598 * We have a device. First match the area and
599 * domain ids and if they match, then see if
600 * the 8bit tid matches the last 8 bits of
601 * 'this_pid'
602 */
603 this_pid = dev_addr_ptr->gfc_port_dev.
604 pub_port.dev_did.port_id;
605 if ((this_pid & AREA_DOMAIN_ID) ==
606 (ses_pid & AREA_DOMAIN_ID)) {
607 if (tid == g_sf_alpa_to_switch[
608 this_pid & 0xFF])
609 break;
610 }
611 }
612 }
613
614 if (i >= map->count)
615 return (0);
616 /*
617 * Make sure that the port WWN is valid
618 */
619 if (is_null_wwn(dev_addr_ptr->gfc_port_dev.
620 pub_port.dev_pwwn.raw_wwn)) {
621 return (0);
622 }
623 for (j = 0, k = 0; j < WWN_SIZE; j++) {
624 c = dev_addr_ptr->gfc_port_dev.pub_port.
625 dev_pwwn.raw_wwn[j];
626 fnib = (((int)(c & 0xf0)) >> 4);
627 snib = (c & 0x0f);
628 if (fnib >= 0 && fnib <= 9)
629 wwn[k++] = '0' + fnib;
630 else if (fnib >= 10 && fnib <= 15)
631 wwn[k++] = 'a' + fnib - 10;
632 if (snib >= 0 && snib <= 9)
633 wwn[k++] = '0' + snib;
634 else if (snib >= 10 && snib <= 15)
635 wwn[k++] = 'a' + snib - 10;
636 }
637 wwn[k] = '\0';
638 break;
639 case FC_TOP_PT_PT:
640 return (L_PT_PT_FC_TOP_NOT_SUPPORTED);
641 default:
642 return (L_UNEXPECTED_FC_TOPOLOGY);
643 } /* End of switch on port_topology */
644
645 if (strstr(ses_path, SCSI_VHCI) != NULL) {
646 if (err = g_get_wwn_list(&wwn_list, 0)) {
647 return (err);
648 }
649 for (wwnlp = wwn_list; wwnlp != NULL;
650 wwnlp = wwnlp->wwn_next) {
651 if (memcmp(wwnlp->port_wwn_s, wwn, WWN_S_LEN) == 0) {
652 break;
653 }
654 }
655 if (wwnlp != NULL) {
656 if ((*dev_path = g_zalloc(MAXPATHLEN)) == NULL) {
657 g_free_wwn_list(&wwn_list);
658 return (L_MALLOC_FAILED);
659 }
660 (void) strcpy(*dev_path, wwnlp->physical_path);
661 } else {
662 g_free_wwn_list(&wwn_list);
663 return (0);
664 }
665 } else {
666
667 len = strlen(ses_path) - strlen(strrchr(ses_path, '/'));
668
669 (void) sprintf(ssd, "ssd@w%s,0", wwn);
670
671 (void) strncpy(sf_path, ses_path, len);
672 sf_path[len] = '\0';
673 P_DPRINTF(" l_device_present: wwn=%s, sf_path=%s\n",
674 wwn, sf_path);
675
676 if ((*dev_path = g_zalloc(MAXPATHLEN)) == NULL) {
677 return (L_MALLOC_FAILED);
678 }
679 (void) sprintf(*dev_path, "%s/%s", sf_path, ssd);
680 P_DPRINTF(" l_device_present: dev_path=%s\n", *dev_path);
681
682 (void) strcat(*dev_path, ":c");
683 }
684 if ((fd = open(*dev_path, O_RDONLY)) == -1) {
685 free(*dev_path);
686 *dev_path = NULL;
687 return (0);
688 }
689 (void) close(fd);
690 return (1);
691 }
692
693
694
695 /*
696 * onlines the given list of devices
697 * and free up the allocated memory.
698 *
699 * RETURNS:
700 * N/A
701 */
702 static void
online_dev(struct dlist * dl_head,int force_flag)703 online_dev(struct dlist *dl_head, int force_flag)
704 {
705 struct dlist *dl, *dl1;
706
707 for (dl = dl_head; dl != NULL; ) {
708 (void) g_online_drive(dl->multipath, force_flag);
709 (void) g_free_multipath(dl->multipath);
710 dl1 = dl;
711 dl = dl->next;
712 (void) g_destroy_data(dl1);
713 }
714 }
715
716
717
718 /*
719 * offlines all the disks in a
720 * SENA enclosure.
721 *
722 * RETURNS:
723 * 0 if O.K.
724 * non-zero otherwise
725 */
726 int
l_offline_photon(struct hotplug_disk_list * hotplug_sena,struct wwn_list_struct * wwn_list,int force_flag,int verbose_flag)727 l_offline_photon(struct hotplug_disk_list *hotplug_sena,
728 struct wwn_list_struct *wwn_list,
729 int force_flag, int verbose_flag)
730 {
731 int i, err;
732 struct dlist *dl_head, *dl_tail, *dl, *dl_ses;
733 char *dev_path, ses_path[MAXPATHLEN];
734 L_state *l_state = NULL;
735
736 if (hotplug_sena == NULL) {
737 return (L_INVALID_PATH_FORMAT);
738 }
739
740 dl_head = dl_tail = NULL;
741 if ((l_state = (L_state *)calloc(1, sizeof (L_state))) == NULL) {
742 return (L_MALLOC_FAILED);
743 }
744
745 /* Get global status for this Photon */
746 dl_ses = hotplug_sena->seslist;
747 while (dl_ses) {
748 (void) strcpy(ses_path, dl_ses->dev_path);
749 if (l_get_status(ses_path, l_state, verbose_flag) == 0)
750 break;
751 dl_ses = dl_ses->next;
752 }
753
754 if (dl_ses == NULL) {
755 (void) l_free_lstate(&l_state);
756 return (L_ENCL_INVALID_PATH);
757 }
758
759 for (i = 0; i < l_state->total_num_drv/2; i++) {
760 if (*l_state->drv_front[i].g_disk_state.physical_path) {
761 if ((dev_path = g_zalloc(MAXPATHLEN)) == NULL) {
762 (void) online_dev(dl_head, force_flag);
763 (void) l_free_lstate(&l_state);
764 return (L_MALLOC_FAILED);
765 }
766 (void) strcpy(dev_path,
767 (char *)&l_state->drv_front[i].g_disk_state.physical_path);
768 if ((dl = g_zalloc(sizeof (struct dlist))) == NULL) {
769 (void) g_destroy_data(dev_path);
770 (void) online_dev(dl_head, force_flag);
771 (void) l_free_lstate(&l_state);
772 return (L_MALLOC_FAILED);
773 }
774 dl->dev_path = dev_path;
775 if ((err = g_get_multipath(dev_path,
776 &(dl->multipath), wwn_list, 0)) != 0) {
777 (void) g_destroy_data(dev_path);
778 if (dl->multipath != NULL) {
779 (void) g_free_multipath(dl->multipath);
780 }
781 (void) g_destroy_data(dl);
782 (void) online_dev(dl_head, force_flag);
783 (void) l_free_lstate(&l_state);
784 return (err);
785 }
786 if ((err = g_offline_drive(dl->multipath,
787 force_flag)) != 0) {
788 (void) g_destroy_data(dev_path);
789 (void) g_free_multipath(dl->multipath);
790 (void) g_destroy_data(dl);
791 (void) online_dev(dl_head, force_flag);
792 (void) l_free_lstate(&l_state);
793 return (err);
794 }
795 if (dl_head == NULL) {
796 dl_head = dl_tail = dl;
797 } else {
798 dl_tail->next = dl;
799 dl->prev = dl_tail;
800 dl_tail = dl;
801 }
802 (void) g_destroy_data(dev_path);
803 }
804 if (*l_state->drv_rear[i].g_disk_state.physical_path) {
805 if ((dev_path = g_zalloc(MAXPATHLEN)) == NULL) {
806 (void) online_dev(dl_head, force_flag);
807 (void) l_free_lstate(&l_state);
808 return (L_MALLOC_FAILED);
809 }
810 (void) strcpy(dev_path,
811 (char *)&l_state->drv_rear[i].g_disk_state.physical_path);
812 if ((dl = g_zalloc(sizeof (struct dlist))) == NULL) {
813 (void) g_destroy_data(dev_path);
814 (void) online_dev(dl_head, force_flag);
815 (void) l_free_lstate(&l_state);
816 return (L_MALLOC_FAILED);
817 }
818 dl->dev_path = dev_path;
819 if ((err = g_get_multipath(dev_path,
820 &(dl->multipath), wwn_list, 0)) != 0) {
821 (void) g_destroy_data(dev_path);
822 if (dl->multipath != NULL) {
823 (void) g_free_multipath(dl->multipath);
824 }
825 (void) g_destroy_data(dl);
826 (void) online_dev(dl_head, force_flag);
827 (void) l_free_lstate(&l_state);
828 return (err);
829 }
830 if ((err = g_offline_drive(dl->multipath,
831 force_flag)) != 0) {
832 (void) g_destroy_data(dev_path);
833 (void) g_free_multipath(dl->multipath);
834 (void) g_destroy_data(dl);
835 (void) online_dev(dl_head, force_flag);
836 (void) l_free_lstate(&l_state);
837 return (err);
838 }
839 if (dl_head == NULL) {
840 dl_head = dl_tail = dl;
841 } else {
842 dl_tail->next = dl;
843 dl->prev = dl_tail;
844 dl_tail = dl;
845 }
846 (void) g_destroy_data(dev_path);
847 }
848 }
849 hotplug_sena->dlhead = dl_head;
850 (void) l_free_lstate(&l_state);
851 return (0);
852
853 }
854
855
856
857 /*
858 * prepares a char string
859 * containing the name of the
860 * device which will be hotplugged.
861 *
862 * RETURNS:
863 * N/A
864 */
865 void
l_get_drive_name(char * drive_name,int slot,int f_flag,char * box_name)866 l_get_drive_name(char *drive_name, int slot, int f_flag, char *box_name)
867 {
868 int enc_type = 0;
869 L_inquiry inq;
870 char *physpath;
871 Path_struct *p_pathstruct;
872
873 if ((drive_name == NULL) || (box_name == NULL)) {
874 return;
875 }
876
877 if (!l_convert_name(box_name, &physpath, &p_pathstruct, 0)) {
878 if (!g_get_inquiry(physpath, &inq)) {
879 enc_type = l_get_enc_type(inq);
880 }
881 }
882 /* If either of the above fail, we use the default value of 0 */
883 free(physpath);
884 free(p_pathstruct);
885 switch (enc_type) {
886 case DAK_ENC_TYPE:
887 if (f_flag != 0) {
888 (void) sprintf(drive_name, MSGSTR(8502,
889 "Drive in \"%s\" slot %d"), box_name, slot);
890 } else {
891 (void) sprintf(drive_name, MSGSTR(8502,
892 "Drive in \"%s\" slot %d"), box_name,
893 slot + (MAX_DRIVES_DAK/2));
894 }
895 break;
896 default:
897 if (f_flag != 0) {
898 (void) sprintf(drive_name, MSGSTR(8500,
899 "Drive in \"%s\" front slot %d"), box_name, slot);
900 } else {
901 (void) sprintf(drive_name, MSGSTR(8501,
902 "Drive in \"%s\" rear slot %d"), box_name, slot);
903 }
904 break;
905 }
906 }
907