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 = NULL;
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 = NULL;
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,
401 int f_flag, int slot, int verbose_flag)
402 {
403 uchar_t *page_buf;
404 int fd, front_index, rear_index, offset, err;
405 unsigned short page_len;
406 struct device_element *elem;
407
408 if ((ses_path == NULL) || (l_state == NULL)) {
409 return (L_INVALID_PATH_FORMAT);
410 }
411
412 if ((page_buf = (uchar_t *)g_zalloc(MAX_REC_DIAG_LENGTH)) == NULL) {
413 return (L_MALLOC_FAILED);
414 }
415
416 if ((fd = g_object_open(ses_path, O_NDELAY | O_RDWR)) == -1) {
417 (void) g_destroy_data(page_buf);
418 return (L_OPEN_PATH_FAIL);
419 }
420
421 if ((err = l_get_envsen_page(fd, page_buf, MAX_REC_DIAG_LENGTH,
422 L_PAGE_2, verbose_flag)) != 0) {
423 (void) g_destroy_data(page_buf);
424 (void) close(fd);
425 return (err);
426 }
427
428 page_len = (page_buf[2] << 8 | page_buf[3]) + HEADER_LEN;
429
430 if ((err = l_get_disk_element_index(l_state, &front_index,
431 &rear_index)) != 0) {
432 (void) g_destroy_data(page_buf);
433 (void) close(fd);
434 return (err);
435 }
436 /* Skip global element */
437 front_index++;
438 if ((strncmp((char *)l_state->ib_tbl.config.prod_id, DAK_OFF_NAME,
439 strlen(DAK_OFF_NAME)) == 0) ||
440 (strncmp((char *)l_state->ib_tbl.config.prod_id, DAK_PROD_STR,
441 strlen(DAK_OFF_NAME)) == 0)) {
442 rear_index += l_state->total_num_drv/2 + 1;
443 } else
444 rear_index++;
445
446 if (f_flag) {
447 offset = (8 + (front_index + slot)*4);
448 } else {
449 offset = (8 + (rear_index + slot)*4);
450 }
451
452 elem = (struct device_element *)(page_buf + offset);
453
454 switch (func) {
455 case OVERALL_STATUS:
456 if (code == NULL) {
457 return (L_INVALID_ARG);
458 }
459 switch (todo) {
460 case INSERT_DEVICE:
461 *code = (elem->code != S_OK) ? elem->code : 0;
462 (void) g_destroy_data(page_buf);
463 (void) close(fd);
464 return (0);
465 case REMOVE_DEVICE:
466 *code = (elem->code != S_NOT_INSTALLED) ?
467 elem->code : 0;
468 (void) g_destroy_data(page_buf);
469 (void) close(fd);
470 return (0);
471 }
472 /* NOTREACHED */
473 case SET_RQST_INSRT:
474 bzero(elem, sizeof (struct device_element));
475 elem->select = 1;
476 elem->rdy_to_ins = 1;
477 break;
478 case SET_RQST_RMV:
479 bzero(elem, sizeof (struct device_element));
480 elem->select = 1;
481 elem->rmv = 1;
482 elem->dev_off = 1;
483 elem->en_bypass_a = 1;
484 elem->en_bypass_b = 1;
485 break;
486 case SET_FAULT:
487 bzero(elem, sizeof (struct device_element));
488 elem->select = 1;
489 elem->fault_req = 1;
490 elem->dev_off = 1;
491 elem->en_bypass_a = 1;
492 elem->en_bypass_b = 1;
493 break;
494 case SET_DRV_ON:
495 bzero(elem, sizeof (struct device_element));
496 elem->select = 1;
497 break;
498 }
499
500 err = g_scsi_send_diag_cmd(fd, (uchar_t *)page_buf, page_len);
501 (void) g_destroy_data(page_buf);
502 (void) close(fd);
503 return (err);
504 }
505
506
507
508 /*
509 * Finds whether device id (tid) exists in the
510 * Arbitrated loop map or not.
511 *
512 * INPUT:
513 * ses_path - pointer to a ses path
514 * tid - the target id of the device we want to check on
515 * - only the low order 8 bits has the tid
516 * map - pointer to a map of the system
517 * verbose_flag - self explanatory
518 *
519 * OUTPUT:
520 * dev_path - the device path of the device with "tid".
521 * Caller is responsible for freeing it
522 *
523 * RETURNS:
524 * 1 if device present
525 * 0 otherwise
526 */
527 int
l_device_present(char * ses_path,int tid,gfc_map_t * map,int verbose_flag,char ** dev_path)528 l_device_present(char *ses_path, int tid, gfc_map_t *map,
529 int verbose_flag, char **dev_path)
530 {
531 char sf_path[MAXPATHLEN];
532 uchar_t wwn[40], c;
533 int len, i, j, k, fnib, snib, this_pid;
534 int fd, ses_pid, al_pa, err;
535 char ssd[30];
536 gfc_port_dev_info_t *dev_addr_ptr;
537 WWN_list *wwnlp, *wwn_list;
538
539
540 if (dev_path == NULL)
541 return (0);
542
543 if ((ses_path == NULL) || (map == NULL)) {
544 return (L_NO_SES_PATH);
545 }
546
547 *dev_path = NULL;
548
549 switch (map->hba_addr.port_topology) {
550 case FC_TOP_PRIVATE_LOOP:
551 for (i = 0, dev_addr_ptr = map->dev_addr; i < map->count;
552 i++, dev_addr_ptr++) {
553 if (dev_addr_ptr->gfc_port_dev.
554 priv_port.sf_inq_dtype != DTYPE_ESI) {
555 al_pa = dev_addr_ptr->gfc_port_dev.
556 priv_port.sf_al_pa;
557 if (tid == g_sf_alpa_to_switch[al_pa]) {
558 break;
559 }
560 }
561 }
562 if (i >= map->count)
563 return (0);
564 /*
565 * Make sure that the port WWN is valid
566 */
567 if (is_null_wwn(dev_addr_ptr->gfc_port_dev.
568 priv_port.sf_port_wwn)) {
569 return (0);
570 }
571 for (j = 0, k = 0; j < WWN_SIZE; j++) {
572 c = dev_addr_ptr->gfc_port_dev.priv_port.sf_port_wwn[j];
573 fnib = (((int)(c & 0xf0)) >> 4);
574 snib = (c & 0x0f);
575 if (fnib >= 0 && fnib <= 9)
576 wwn[k++] = '0' + fnib;
577 else if (fnib >= 10 && fnib <= 15)
578 wwn[k++] = 'a' + fnib - 10;
579 if (snib >= 0 && snib <= 9)
580 wwn[k++] = '0' + snib;
581 else if (snib >= 10 && snib <= 15)
582 wwn[k++] = 'a' + snib - 10;
583 }
584 wwn[k] = '\0';
585 break;
586 case FC_TOP_PUBLIC_LOOP:
587 case FC_TOP_FABRIC:
588 /*
589 * Get the phys address (port id) of this ses device
590 */
591 if (err = l_get_pid_from_path(ses_path, map, &ses_pid))
592 return (err);
593
594 for (i = 0, dev_addr_ptr = map->dev_addr; i < map->count;
595 i++, dev_addr_ptr++) {
596 if (dev_addr_ptr->gfc_port_dev.pub_port.dev_dtype !=
597 DTYPE_ESI) {
598 /*
599 * We have a device. First match the area and
600 * domain ids and if they match, then see if
601 * the 8bit tid matches the last 8 bits of
602 * 'this_pid'
603 */
604 this_pid = dev_addr_ptr->gfc_port_dev.
605 pub_port.dev_did.port_id;
606 if ((this_pid & AREA_DOMAIN_ID) ==
607 (ses_pid & AREA_DOMAIN_ID)) {
608 if (tid == g_sf_alpa_to_switch[
609 this_pid & 0xFF])
610 break;
611 }
612 }
613 }
614
615 if (i >= map->count)
616 return (0);
617 /*
618 * Make sure that the port WWN is valid
619 */
620 if (is_null_wwn(dev_addr_ptr->gfc_port_dev.
621 pub_port.dev_pwwn.raw_wwn)) {
622 return (0);
623 }
624 for (j = 0, k = 0; j < WWN_SIZE; j++) {
625 c = dev_addr_ptr->gfc_port_dev.pub_port.
626 dev_pwwn.raw_wwn[j];
627 fnib = (((int)(c & 0xf0)) >> 4);
628 snib = (c & 0x0f);
629 if (fnib >= 0 && fnib <= 9)
630 wwn[k++] = '0' + fnib;
631 else if (fnib >= 10 && fnib <= 15)
632 wwn[k++] = 'a' + fnib - 10;
633 if (snib >= 0 && snib <= 9)
634 wwn[k++] = '0' + snib;
635 else if (snib >= 10 && snib <= 15)
636 wwn[k++] = 'a' + snib - 10;
637 }
638 wwn[k] = '\0';
639 break;
640 case FC_TOP_PT_PT:
641 return (L_PT_PT_FC_TOP_NOT_SUPPORTED);
642 default:
643 return (L_UNEXPECTED_FC_TOPOLOGY);
644 } /* End of switch on port_topology */
645
646 if (strstr(ses_path, SCSI_VHCI) != NULL) {
647 if (err = g_get_wwn_list(&wwn_list, 0)) {
648 return (err);
649 }
650 for (wwnlp = wwn_list; wwnlp != NULL;
651 wwnlp = wwnlp->wwn_next) {
652 if (memcmp(wwnlp->port_wwn_s, wwn, WWN_S_LEN) == 0) {
653 break;
654 }
655 }
656 if (wwnlp != NULL) {
657 if ((*dev_path = g_zalloc(MAXPATHLEN)) == NULL) {
658 g_free_wwn_list(&wwn_list);
659 return (L_MALLOC_FAILED);
660 }
661 (void) strcpy(*dev_path, wwnlp->physical_path);
662 } else {
663 g_free_wwn_list(&wwn_list);
664 return (0);
665 }
666 } else {
667
668 len = strlen(ses_path) - strlen(strrchr(ses_path, '/'));
669
670 (void) sprintf(ssd, "ssd@w%s,0", wwn);
671
672 (void) strncpy(sf_path, ses_path, len);
673 sf_path[len] = '\0';
674 P_DPRINTF(" l_device_present: wwn=%s, sf_path=%s\n",
675 wwn, sf_path);
676
677 if ((*dev_path = g_zalloc(MAXPATHLEN)) == NULL) {
678 return (L_MALLOC_FAILED);
679 }
680 (void) sprintf(*dev_path, "%s/%s", sf_path, ssd);
681 P_DPRINTF(" l_device_present: dev_path=%s\n", *dev_path);
682
683 (void) strcat(*dev_path, ":c");
684 }
685 if ((fd = open(*dev_path, O_RDONLY)) == -1) {
686 free(*dev_path);
687 *dev_path = NULL;
688 return (0);
689 }
690 (void) close(fd);
691 return (1);
692 }
693
694
695
696 /*
697 * onlines the given list of devices
698 * and free up the allocated memory.
699 *
700 * RETURNS:
701 * N/A
702 */
703 static void
online_dev(struct dlist * dl_head,int force_flag)704 online_dev(struct dlist *dl_head, int force_flag)
705 {
706 struct dlist *dl, *dl1;
707
708 for (dl = dl_head; dl != NULL; ) {
709 (void) g_online_drive(dl->multipath, force_flag);
710 (void) g_free_multipath(dl->multipath);
711 dl1 = dl;
712 dl = dl->next;
713 (void) g_destroy_data(dl1);
714 }
715 }
716
717
718
719 /*
720 * offlines all the disks in a
721 * SENA enclosure.
722 *
723 * RETURNS:
724 * 0 if O.K.
725 * non-zero otherwise
726 */
727 int
l_offline_photon(struct hotplug_disk_list * hotplug_sena,struct wwn_list_struct * wwn_list,int force_flag,int verbose_flag)728 l_offline_photon(struct hotplug_disk_list *hotplug_sena,
729 struct wwn_list_struct *wwn_list,
730 int force_flag, int verbose_flag)
731 {
732 int i, err;
733 struct dlist *dl_head, *dl_tail, *dl, *dl_ses;
734 char *dev_path, ses_path[MAXPATHLEN];
735 L_state *l_state = NULL;
736
737 if (hotplug_sena == NULL) {
738 return (L_INVALID_PATH_FORMAT);
739 }
740
741 dl_head = dl_tail = NULL;
742 if ((l_state = (L_state *)calloc(1, sizeof (L_state))) == NULL) {
743 return (L_MALLOC_FAILED);
744 }
745
746 /* Get global status for this Photon */
747 dl_ses = hotplug_sena->seslist;
748 while (dl_ses) {
749 (void) strcpy(ses_path, dl_ses->dev_path);
750 if (l_get_status(ses_path, l_state, verbose_flag) == 0)
751 break;
752 dl_ses = dl_ses->next;
753 }
754
755 if (dl_ses == NULL) {
756 (void) l_free_lstate(&l_state);
757 return (L_ENCL_INVALID_PATH);
758 }
759
760 for (i = 0; i < l_state->total_num_drv/2; i++) {
761 if (*l_state->drv_front[i].g_disk_state.physical_path) {
762 if ((dev_path = g_zalloc(MAXPATHLEN)) == NULL) {
763 (void) online_dev(dl_head, force_flag);
764 (void) l_free_lstate(&l_state);
765 return (L_MALLOC_FAILED);
766 }
767 (void) strcpy(dev_path,
768 (char *)&l_state->drv_front[i].g_disk_state.physical_path);
769 if ((dl = g_zalloc(sizeof (struct dlist))) == NULL) {
770 (void) g_destroy_data(dev_path);
771 (void) online_dev(dl_head, force_flag);
772 (void) l_free_lstate(&l_state);
773 return (L_MALLOC_FAILED);
774 }
775 dl->dev_path = dev_path;
776 if ((err = g_get_multipath(dev_path,
777 &(dl->multipath), wwn_list, 0)) != 0) {
778 (void) g_destroy_data(dev_path);
779 if (dl->multipath != NULL) {
780 (void) g_free_multipath(dl->multipath);
781 }
782 (void) g_destroy_data(dl);
783 (void) online_dev(dl_head, force_flag);
784 (void) l_free_lstate(&l_state);
785 return (err);
786 }
787 if ((err = g_offline_drive(dl->multipath,
788 force_flag)) != 0) {
789 (void) g_destroy_data(dev_path);
790 (void) g_free_multipath(dl->multipath);
791 (void) g_destroy_data(dl);
792 (void) online_dev(dl_head, force_flag);
793 (void) l_free_lstate(&l_state);
794 return (err);
795 }
796 if (dl_head == NULL) {
797 dl_head = dl_tail = dl;
798 } else {
799 dl_tail->next = dl;
800 dl->prev = dl_tail;
801 dl_tail = dl;
802 }
803 (void) g_destroy_data(dev_path);
804 }
805 if (*l_state->drv_rear[i].g_disk_state.physical_path) {
806 if ((dev_path = g_zalloc(MAXPATHLEN)) == NULL) {
807 (void) online_dev(dl_head, force_flag);
808 (void) l_free_lstate(&l_state);
809 return (L_MALLOC_FAILED);
810 }
811 (void) strcpy(dev_path,
812 (char *)&l_state->drv_rear[i].g_disk_state.physical_path);
813 if ((dl = g_zalloc(sizeof (struct dlist))) == NULL) {
814 (void) g_destroy_data(dev_path);
815 (void) online_dev(dl_head, force_flag);
816 (void) l_free_lstate(&l_state);
817 return (L_MALLOC_FAILED);
818 }
819 dl->dev_path = dev_path;
820 if ((err = g_get_multipath(dev_path,
821 &(dl->multipath), wwn_list, 0)) != 0) {
822 (void) g_destroy_data(dev_path);
823 if (dl->multipath != NULL) {
824 (void) g_free_multipath(dl->multipath);
825 }
826 (void) g_destroy_data(dl);
827 (void) online_dev(dl_head, force_flag);
828 (void) l_free_lstate(&l_state);
829 return (err);
830 }
831 if ((err = g_offline_drive(dl->multipath,
832 force_flag)) != 0) {
833 (void) g_destroy_data(dev_path);
834 (void) g_free_multipath(dl->multipath);
835 (void) g_destroy_data(dl);
836 (void) online_dev(dl_head, force_flag);
837 (void) l_free_lstate(&l_state);
838 return (err);
839 }
840 if (dl_head == NULL) {
841 dl_head = dl_tail = dl;
842 } else {
843 dl_tail->next = dl;
844 dl->prev = dl_tail;
845 dl_tail = dl;
846 }
847 (void) g_destroy_data(dev_path);
848 }
849 }
850 hotplug_sena->dlhead = dl_head;
851 (void) l_free_lstate(&l_state);
852 return (0);
853
854 }
855
856
857
858 /*
859 * prepares a char string
860 * containing the name of the
861 * device which will be hotplugged.
862 *
863 * RETURNS:
864 * N/A
865 */
866 void
l_get_drive_name(char * drive_name,int slot,int f_flag,char * box_name)867 l_get_drive_name(char *drive_name, int slot, int f_flag, char *box_name)
868 {
869 int enc_type = 0;
870 L_inquiry inq;
871 char *physpath;
872 Path_struct *p_pathstruct;
873
874 if ((drive_name == NULL) || (box_name == NULL)) {
875 return;
876 }
877
878 if (!l_convert_name(box_name, &physpath, &p_pathstruct, 0)) {
879 if (!g_get_inquiry(physpath, &inq)) {
880 enc_type = l_get_enc_type(inq);
881 }
882 }
883 /* If either of the above fail, we use the default value of 0 */
884 free(physpath);
885 free(p_pathstruct);
886 switch (enc_type) {
887 case DAK_ENC_TYPE:
888 if (f_flag != NULL) {
889 (void) sprintf(drive_name, MSGSTR(8502,
890 "Drive in \"%s\" slot %d"), box_name, slot);
891 } else {
892 (void) sprintf(drive_name, MSGSTR(8502,
893 "Drive in \"%s\" slot %d"), box_name,
894 slot + (MAX_DRIVES_DAK/2));
895 }
896 break;
897 default:
898 if (f_flag != NULL) {
899 (void) sprintf(drive_name, MSGSTR(8500,
900 "Drive in \"%s\" front slot %d"), box_name, slot);
901 } else {
902 (void) sprintf(drive_name, MSGSTR(8501,
903 "Drive in \"%s\" rear slot %d"), box_name, slot);
904 }
905 break;
906 }
907 }
908