xref: /illumos-gate/usr/src/lib/storage/liba5k/common/diag.c (revision b30d193948be5a7794d7ae3ba0ed9c2f72c88e0f)
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
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
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
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
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
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
721 d_p_bypass(char *path, int verbose)
722 /*ARGSUSED*/
723 {
724 
725 	return (0);
726 }
727