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: 8000 - 8499
37 * Shared common messages: 1 - 1999
38 */
39
40 /* Includes */
41 #include <stdlib.h>
42 #include <stdio.h>
43 #include <sys/file.h>
44 #include <sys/types.h>
45 #include <sys/param.h>
46 #include <fcntl.h>
47 #include <unistd.h>
48 #include <errno.h>
49 #include <string.h>
50 #include <sys/scsi/scsi.h>
51 #include <nl_types.h>
52 #include <strings.h>
53 #include <sys/ddi.h> /* for max */
54 #include <l_common.h>
55 #include <stgcom.h>
56 #include <l_error.h>
57 #include <a_state.h>
58 #include <a5k.h>
59
60
61
62 /* Defines */
63 #define VERBPRINT if (verbose) (void) printf
64
65
66 /*
67 * take all paths supplied by dl offline.
68 *
69 * RETURNS:
70 * 0 = No error.
71 * *bsy_res_flag_p: 1 = The device is "busy".
72 *
73 * In pre-2.6 we just return success
74 */
75 static int
d_offline_drive(struct dlist * dl,int * bsy_res_flag_p,int verbose)76 d_offline_drive(struct dlist *dl, int *bsy_res_flag_p, int verbose)
77 {
78 char dev_path1[MAXPATHLEN];
79 devctl_hdl_t devhdl;
80
81
82 /* for each path attempt to take it offline */
83 for (; dl != NULL; dl = dl->next) {
84
85 /* save a copy of the pathname */
86 (void) strcpy(dev_path1, dl->dev_path);
87
88 /* attempt to acquire the device */
89 if ((devhdl = devctl_device_acquire(dev_path1,
90 DC_EXCL)) == NULL) {
91 if (errno != EBUSY) {
92 return (L_ACQUIRE_FAIL);
93 }
94 }
95
96 /* attempt to offline the drive */
97 if (devctl_device_offline(devhdl) != 0) {
98 *bsy_res_flag_p = 1;
99 (void) devctl_release(devhdl);
100 return (0);
101 }
102
103 E_DPRINTF(" d_offline_drive: Offline succeeded:/n "
104 "%s\n", dev_path1);
105 /* offline succeeded -- release handle acquired above */
106 (void) devctl_release(devhdl);
107 }
108 return (0);
109 }
110
111
112
113
114 /*
115 * Check to see if any of the disks that are attached
116 * to the selected port on this backplane are reserved or busy.
117 *
118 * INPUTS:
119 * RETURNS:
120 * 0 = No error.
121 * *bsy_res_flag_p: 1 = The device is "busy".
122 */
123
124 int
l_check_busy_reserv_bp(char * ses_path,int front_flag,int port_a_flag,int * bsy_res_flag_p,int verbose)125 l_check_busy_reserv_bp(char *ses_path, int front_flag,
126 int port_a_flag, int *bsy_res_flag_p, int verbose)
127 {
128 int err, i;
129 L_state *l_state = NULL;
130 struct dlist *p_list;
131
132 if ((l_state = (L_state *)calloc(1, sizeof (L_state))) == NULL) {
133 return (L_MALLOC_FAILED);
134 }
135
136 if (err = l_get_status(ses_path, l_state, verbose)) {
137 (void) l_free_lstate(&l_state);
138 return (err);
139 }
140 for (i = 0; i < (int)l_state->total_num_drv/2; i++) {
141 if ((front_flag &&
142 (l_state->drv_front[i].g_disk_state.d_state_flags[port_a_flag] &
143 L_RESERVED)) || (!front_flag &&
144 (l_state->drv_rear[i].g_disk_state.d_state_flags[port_a_flag] &
145 L_RESERVED))) {
146 *bsy_res_flag_p = 1;
147 (void) l_free_lstate(&l_state);
148 return (0);
149 }
150 }
151
152 for (i = 0; i < (int)l_state->total_num_drv/2; i++) {
153 /* Get list of all paths to the requested port. */
154 if (front_flag) {
155 if (port_a_flag) {
156 if ((err = g_get_port_multipath(
157 l_state->drv_front[i].g_disk_state.port_a_wwn_s,
158 &p_list, verbose)) != 0) {
159 (void) l_free_lstate(&l_state);
160 return (err);
161 }
162 } else {
163 if ((err = g_get_port_multipath(
164 l_state->drv_front[i].g_disk_state.port_b_wwn_s,
165 &p_list, verbose)) != 0) {
166 (void) l_free_lstate(&l_state);
167 return (err);
168 }
169 }
170 } else {
171 if (port_a_flag) {
172 if ((err = g_get_port_multipath(
173 l_state->drv_rear[i].g_disk_state.port_a_wwn_s,
174 &p_list, verbose)) != 0) {
175 (void) l_free_lstate(&l_state);
176 return (err);
177 }
178 } else {
179 if ((err = g_get_port_multipath(
180 l_state->drv_rear[i].g_disk_state.port_b_wwn_s,
181 &p_list, verbose)) != 0) {
182 (void) l_free_lstate(&l_state);
183 return (err);
184 }
185 }
186 }
187 if (err = d_offline_drive(p_list,
188 bsy_res_flag_p, verbose)) {
189 (void) g_free_multipath(p_list);
190 (void) l_free_lstate(&l_state);
191 return (err);
192 }
193 (void) g_free_multipath(p_list);
194 }
195 (void) l_free_lstate(&l_state);
196 return (0);
197 }
198
199
200
201 /*
202 * Request the enclosure services controller (IB)
203 * to set the LRC (Loop Redundancy Circuit) to the
204 * bypassed/enabled state for the backplane specified by
205 * the a and f flag and the enclosure or pathname.
206 */
207 int
l_bp_bypass_enable(char * ses_path,int bypass_flag,int port_a_flag,int front_flag,int force_flag,int verbose)208 l_bp_bypass_enable(char *ses_path, int bypass_flag, int port_a_flag,
209 int front_flag, int force_flag, int verbose)
210 {
211
212 int fd, i;
213 int nobj = 0;
214 ses_objarg obj;
215 ses_object *all_objp = NULL, *all_objp_save = NULL;
216 int found = 0;
217 Bp_elem_st *bp;
218 char msg[MAXPATHLEN];
219 int bsy_res_flag = 0;
220 int err;
221
222 if (ses_path == NULL) {
223 return (L_NO_SES_PATH);
224 }
225
226 /*
227 * Check for reservation and busy for all disks on this
228 * backplane.
229 */
230
231 if (!force_flag && bypass_flag) {
232 if (err = l_check_busy_reserv_bp(ses_path,
233 front_flag, port_a_flag, &bsy_res_flag, verbose)) {
234 return (err);
235 }
236 if (bsy_res_flag) {
237 return (L_BP_BUSY_RESERVED);
238 }
239 }
240
241
242 if ((fd = g_object_open(ses_path, O_NDELAY | O_RDWR)) == -1) {
243 return (errno);
244 }
245
246 if (ioctl(fd, SESIOC_GETNOBJ, (caddr_t)&nobj) < 0) {
247 (void) close(fd);
248 return (errno);
249 }
250 if (nobj == 0) {
251 (void) close(fd);
252 return (L_IB_NO_ELEM_FOUND);
253 }
254
255 E_DPRINTF(" l_ib_bypass_bp: Number of SES objects: 0x%x\n",
256 nobj);
257
258 /* alloc some memory for the objmap */
259 if ((all_objp = g_zalloc((nobj + 1) * sizeof (ses_object))) == NULL) {
260 (void) close(fd);
261 return (errno);
262 }
263
264 all_objp_save = all_objp;
265
266 if (ioctl(fd, SESIOC_GETOBJMAP, (caddr_t)all_objp) < 0) {
267 (void) close(fd);
268 (void) g_destroy_data(all_objp_save);
269 return (errno);
270 }
271
272 for (i = 0; i < nobj; i++, all_objp++) {
273 E_DPRINTF(" ID 0x%x\t Element type 0x%x\n",
274 all_objp->obj_id, all_objp->elem_type);
275 if (all_objp->elem_type == ELM_TYP_BP) {
276 found++;
277 break;
278 }
279 }
280
281 if (found == 0) {
282 (void) close(fd);
283 (void) g_destroy_data(all_objp_save);
284 return (L_NO_BP_ELEM_FOUND);
285 }
286
287 /*
288 * We found the backplane element.
289 */
290
291
292 if (verbose) {
293 /* Get the status for backplane #0 */
294 obj.obj_id = all_objp->obj_id;
295 if (ioctl(fd, SESIOC_GETOBJSTAT, (caddr_t)&obj) < 0) {
296 (void) close(fd);
297 (void) g_destroy_data(all_objp_save);
298 return (errno);
299 }
300 (void) fprintf(stdout, MSGSTR(8000,
301 " Front backplane status: "));
302 bp = (struct bp_element_status *)&obj.cstat[0];
303 l_element_msg_string(bp->code, msg);
304 (void) fprintf(stdout, "%s\n", msg);
305 if (bp->byp_a_enabled || bp->en_bypass_a) {
306 (void) fprintf(stdout, " ");
307 (void) fprintf(stdout,
308 MSGSTR(130, "Bypass A enabled"));
309 (void) fprintf(stdout, ".\n");
310 }
311 if (bp->byp_b_enabled || bp->en_bypass_b) {
312 (void) fprintf(stdout, " ");
313 (void) fprintf(stdout,
314 MSGSTR(129, "Bypass B enabled"));
315 (void) fprintf(stdout, ".\n");
316 }
317
318 all_objp++;
319 obj.obj_id = all_objp->obj_id;
320 all_objp--;
321 if (ioctl(fd, SESIOC_GETOBJSTAT, (caddr_t)&obj) < 0) {
322 (void) close(fd);
323 (void) g_destroy_data(all_objp_save);
324 return (errno);
325 }
326 (void) fprintf(stdout, MSGSTR(8001,
327 " Rear backplane status: "));
328 bp = (struct bp_element_status *)&obj.cstat[0];
329 l_element_msg_string(bp->code, msg);
330 (void) fprintf(stdout, "%s\n", msg);
331 if (bp->byp_a_enabled || bp->en_bypass_a) {
332 (void) fprintf(stdout, " ");
333 (void) fprintf(stdout,
334 MSGSTR(130, "Bypass A enabled"));
335 (void) fprintf(stdout, ".\n");
336 }
337 if (bp->byp_b_enabled || bp->en_bypass_b) {
338 (void) fprintf(stdout, " ");
339 (void) fprintf(stdout,
340 MSGSTR(129, "Bypass B enabled"));
341 (void) fprintf(stdout, ".\n");
342 }
343 }
344
345 /* Get the current status */
346 if (!front_flag) {
347 all_objp++;
348 }
349 obj.obj_id = all_objp->obj_id;
350 if (ioctl(fd, SESIOC_GETOBJSTAT, (caddr_t)&obj) < 0) {
351 (void) close(fd);
352 (void) g_destroy_data(all_objp_save);
353 return (errno);
354 }
355 /* Do the requested action. */
356 bp = (struct bp_element_status *)&obj.cstat[0];
357 bp->select = 1;
358 bp->code = 0;
359 if (port_a_flag) {
360 bp->en_bypass_a = bypass_flag;
361 } else {
362 bp->en_bypass_b = bypass_flag;
363 }
364 if (getenv("_LUX_E_DEBUG") != NULL) {
365 (void) printf(" Sending this structure to ID 0x%x"
366 " of type 0x%x\n",
367 obj.obj_id, all_objp->elem_type);
368 for (i = 0; i < 4; i++) {
369 (void) printf(" Byte %d 0x%x\n", i,
370 obj.cstat[i]);
371 }
372 }
373
374 if (ioctl(fd, SESIOC_SETOBJSTAT, (caddr_t)&obj) < 0) {
375 (void) close(fd);
376 (void) g_destroy_data(all_objp_save);
377 return (errno);
378 }
379
380 (void) g_destroy_data(all_objp_save);
381 (void) close(fd);
382
383 return (0);
384 }
385
386
387
388
389 /*
390 * This function will request the enclosure services
391 * controller (IB) to set the LRC (Loop Redundancy Circuit) to the
392 * bypassed/enabled state for the device specified by the
393 * enclosure,dev or pathname and the port specified by the a
394 * flag.
395 */
396
397 int
l_dev_bypass_enable(struct path_struct * path_struct,int bypass_flag,int force_flag,int port_a_flag,int verbose)398 l_dev_bypass_enable(struct path_struct *path_struct, int bypass_flag,
399 int force_flag, int port_a_flag, int verbose)
400 {
401 gfc_map_t map;
402 char ses_path[MAXPATHLEN];
403 uchar_t *page_buf;
404 int err, fd, front_index, rear_index, offset;
405 int pathcnt = 1;
406 unsigned short page_len;
407 struct device_element *elem;
408 L_state *l_state = NULL;
409 struct device_element status;
410 int bsy_flag = 0, i, f_flag;
411 struct dlist *p_list;
412 char temppath[MAXPATHLEN];
413 mp_pathlist_t pathlist;
414 int p_pw = 0, p_on = 0, p_st = 0;
415 L_inquiry inq;
416
417 if (path_struct == NULL) {
418 return (L_INVALID_PATH_FORMAT);
419 }
420
421 if ((l_state = (L_state *)calloc(1, sizeof (L_state))) == NULL) {
422 return (L_MALLOC_FAILED);
423 }
424 map.dev_addr = (gfc_port_dev_info_t *)NULL;
425 (void) strcpy(temppath, path_struct->p_physical_path);
426 if ((strstr(path_struct->p_physical_path, SCSI_VHCI) != NULL) &&
427 (!g_get_pathlist(temppath, &pathlist))) {
428 pathcnt = pathlist.path_count;
429 p_pw = p_on = p_st = 0;
430 for (i = 0; i < pathcnt; i++) {
431 if (pathlist.path_info[i].path_state <
432 MAXPATHSTATE) {
433 if (strstr(pathlist.path_info[i].
434 path_addr,
435 path_struct->argv) != NULL) {
436 p_pw = i;
437 break;
438 }
439 if (pathlist.path_info[i].path_state ==
440 MDI_PATHINFO_STATE_ONLINE) {
441 p_on = i;
442 }
443 if (pathlist.path_info[i].path_state ==
444 MDI_PATHINFO_STATE_STANDBY) {
445 p_st = i;
446 }
447 }
448 }
449 if (strstr(pathlist.path_info[p_pw].path_addr,
450 path_struct->argv) != NULL) {
451 /* matching input pwwn */
452 (void) strcpy(temppath,
453 pathlist.path_info[p_pw].path_hba);
454 } else if (pathlist.path_info[p_on].path_state ==
455 MDI_PATHINFO_STATE_ONLINE) {
456 /* on_line path */
457 (void) strcpy(temppath,
458 pathlist.path_info[p_on].path_hba);
459 } else {
460 /* standby or path0 */
461 (void) strcpy(temppath,
462 pathlist.path_info[p_st].path_hba);
463 }
464 free(pathlist.path_info);
465 (void) strcat(temppath, FC_CTLR);
466 }
467
468 /*
469 * Need to get a valid location, front/rear & slot.
470 *
471 * The path_struct will return a valid slot
472 * and the IB path or a disk path.
473 */
474
475 if (!path_struct->ib_path_flag) {
476 if (err = g_get_dev_map(temppath, &map, verbose)) {
477 (void) l_free_lstate(&l_state);
478 return (err);
479 }
480 if (err = l_get_ses_path(path_struct->p_physical_path,
481 ses_path, &map, verbose)) {
482 (void) l_free_lstate(&l_state);
483 free((void *)map.dev_addr);
484 return (err);
485 }
486 } else {
487 (void) strcpy(ses_path, path_struct->p_physical_path);
488 }
489 if (!path_struct->slot_valid) {
490 if ((map.dev_addr == (gfc_port_dev_info_t *)NULL) &&
491 ((err = g_get_dev_map(temppath,
492 &map, verbose)) != 0)) {
493 (void) l_free_lstate(&l_state);
494 return (err);
495 }
496 if ((err = l_get_ses_path(path_struct->p_physical_path,
497 ses_path, &map, verbose)) != 0) {
498 (void) l_free_lstate(&l_state);
499 free((void *)map.dev_addr);
500 return (err);
501 }
502 if ((err = l_get_status(ses_path, l_state, verbose)) != 0) {
503 (void) l_free_lstate(&l_state);
504 free((void *)map.dev_addr);
505 return (err);
506 }
507
508 /* We are passing the disks path */
509 if ((err = l_get_slot(path_struct, l_state, verbose)) != 0) {
510 (void) l_free_lstate(&l_state);
511 free((void *)map.dev_addr);
512 return (err);
513 }
514 }
515
516 if (map.dev_addr != (gfc_port_dev_info_t *)NULL) {
517 free((void *)map.dev_addr);
518 }
519
520 if ((page_buf = (uchar_t *)malloc(MAX_REC_DIAG_LENGTH)) == NULL) {
521 (void) l_free_lstate(&l_state);
522 return (errno);
523 }
524
525 if ((fd = g_object_open(ses_path, O_NDELAY | O_RDWR)) == -1) {
526 (void) g_destroy_data(page_buf);
527 (void) l_free_lstate(&l_state);
528 return (errno);
529 }
530
531 if (err = l_get_envsen_page(fd, page_buf, MAX_REC_DIAG_LENGTH,
532 L_PAGE_2, verbose)) {
533 (void) close(fd);
534 (void) g_destroy_data(page_buf);
535 (void) l_free_lstate(&l_state);
536 return (err);
537 }
538
539 page_len = (page_buf[2] << 8 | page_buf[3]) + HEADER_LEN;
540
541 /* Get index to the disk we are interested in */
542 if (err = l_get_status(ses_path, l_state, verbose)) {
543 (void) close(fd);
544 (void) g_destroy_data(page_buf);
545 (void) l_free_lstate(&l_state);
546 return (err);
547 }
548 /*
549 * Now that we have the status check to see if
550 * busy or reserved, if bypassing.
551 */
552 if ((!(force_flag | path_struct->ib_path_flag)) &&
553 bypass_flag) {
554 i = path_struct->slot;
555 f_flag = path_struct->f_flag;
556
557 /*
558 * Check for reservation and busy
559 */
560 if ((f_flag &&
561 (l_state->drv_front[i].g_disk_state.d_state_flags[port_a_flag] &
562 L_RESERVED)) || (!f_flag &&
563 (l_state->drv_rear[i].g_disk_state.d_state_flags[port_a_flag] &
564 L_RESERVED))) {
565 (void) close(fd);
566 (void) g_destroy_data(page_buf);
567 (void) l_free_lstate(&l_state);
568 return (L_BP_RESERVED);
569 }
570 if (f_flag) {
571 if (port_a_flag) {
572 if ((err = g_get_port_multipath(
573 l_state->drv_front[i].g_disk_state.port_a_wwn_s,
574 &p_list, verbose)) != 0) {
575 (void) close(fd);
576 (void) g_destroy_data(page_buf);
577 (void) l_free_lstate(&l_state);
578 return (err);
579 }
580 } else {
581 if ((err = g_get_port_multipath(
582 l_state->drv_front[i].g_disk_state.port_b_wwn_s,
583 &p_list, verbose)) != 0) {
584 (void) close(fd);
585 (void) g_destroy_data(page_buf);
586 (void) l_free_lstate(&l_state);
587 return (err);
588 }
589 }
590 } else {
591 if (port_a_flag) {
592 if ((err = g_get_port_multipath(
593 l_state->drv_rear[i].g_disk_state.port_a_wwn_s,
594 &p_list, verbose)) != 0) {
595 (void) close(fd);
596 (void) g_destroy_data(page_buf);
597 (void) l_free_lstate(&l_state);
598 return (err);
599 }
600 } else {
601 if ((err = g_get_port_multipath(
602 l_state->drv_rear[i].g_disk_state.port_b_wwn_s,
603 &p_list, verbose)) != 0) {
604 (void) close(fd);
605 (void) g_destroy_data(page_buf);
606 (void) l_free_lstate(&l_state);
607 return (err);
608 }
609 }
610 }
611 if (err = d_offline_drive(p_list,
612 &bsy_flag, verbose)) {
613 (void) g_free_multipath(p_list);
614 (void) close(fd);
615 (void) g_destroy_data(page_buf);
616 (void) l_free_lstate(&l_state);
617 return (err);
618 }
619 (void) g_free_multipath(p_list);
620 if (bsy_flag) {
621 (void) close(fd);
622 (void) g_destroy_data(page_buf);
623 (void) l_free_lstate(&l_state);
624 return (L_BP_BUSY);
625 }
626 }
627
628 if (err = l_get_disk_element_index(l_state, &front_index,
629 &rear_index)) {
630 (void) close(fd);
631 (void) g_destroy_data(page_buf);
632 (void) l_free_lstate(&l_state);
633 return (err);
634 }
635
636 if (g_get_inquiry(ses_path, &inq)) {
637 return (L_SCSI_ERROR);
638 }
639
640 /* Skip global element */
641 front_index++;
642 if ((strncmp((char *)&inq.inq_pid[0], DAK_OFF_NAME,
643 strlen(DAK_OFF_NAME)) == 0) ||
644 (strncmp((char *)&inq.inq_pid[0], DAK_PROD_STR,
645 strlen(DAK_PROD_STR)) == 0)) {
646 rear_index += (MAX_DRIVES_DAK/2) + 1;
647 } else {
648 rear_index++;
649 }
650
651 if (path_struct->f_flag) {
652 offset = (8 + (front_index + path_struct->slot)*4);
653 } else {
654 offset = (8 + (rear_index + path_struct->slot)*4);
655 }
656
657 elem = (struct device_element *)(page_buf + offset);
658 /*
659 * now do requested action.
660 */
661 bcopy((const void *)elem, (void *)&status,
662 sizeof (struct device_element)); /* save status */
663 bzero(elem, sizeof (struct device_element));
664 elem->select = 1;
665 elem->dev_off = status.dev_off;
666 elem->en_bypass_a = status.en_bypass_a;
667 elem->en_bypass_b = status.en_bypass_b;
668
669 /* Do requested action */
670 if (port_a_flag) {
671 elem->en_bypass_a = bypass_flag;
672 } else {
673 elem->en_bypass_b = bypass_flag;
674 }
675
676 if (getenv("_LUX_E_DEBUG") != NULL) {
677 g_dump(" l_dev_bypass_enable: Updating LRC circuit state:\n"
678 " Device Status Element ",
679 (uchar_t *)elem, sizeof (struct device_element),
680 HEX_ONLY);
681 (void) fprintf(stdout, " for device at location:"
682 " enclosure:%s slot:%d %s\n",
683 l_state->ib_tbl.enclosure_name,
684 path_struct->slot,
685 path_struct->f_flag ? "front" : "rear");
686 }
687 if (err = g_scsi_send_diag_cmd(fd,
688 (uchar_t *)page_buf, page_len)) {
689 (void) close(fd);
690 (void) g_destroy_data(page_buf);
691 (void) l_free_lstate(&l_state);
692 return (err);
693 }
694
695 (void) close(fd);
696 (void) g_destroy_data(page_buf);
697 (void) l_free_lstate(&l_state);
698 return (0);
699 }
700
701
702
703 /*
704 * Issue a Loop Port enable Primitive sequence
705 * to the device specified by the pathname.
706 */
707 int
d_p_enable(char * path,int verbose)708 d_p_enable(char *path, int verbose)
709 /*ARGSUSED*/
710 {
711
712 return (0);
713 }
714
715 /*
716 * Issue a Loop Port Bypass Primitive sequence
717 * to the device specified by the pathname. This requests the
718 * device to set its L_Port into the bypass mode.
719 */
720 int
d_p_bypass(char * path,int verbose)721 d_p_bypass(char *path, int verbose)
722 /*ARGSUSED*/
723 {
724
725 return (0);
726 }
727