scsi_vhci_tpgs.c revision 6941:c5d83acec1bc
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#pragma ident	"%Z%%M%	%I%	%E% SMI"
26
27#include <sys/conf.h>
28#include <sys/file.h>
29#include <sys/ddi.h>
30#include <sys/sunddi.h>
31#include <sys/scsi/scsi.h>
32#include <sys/scsi/adapters/scsi_vhci.h>
33#include <sys/scsi/adapters/scsi_vhci_tpgs.h>
34
35/*
36 * External function definitions
37 */
38extern void vhci_mpapi_update_tpg_data(struct scsi_address *, char *);
39
40
41
42static int vhci_tpgs_inquiry(struct scsi_address *ap, struct buf *bp,
43    int *mode);
44static int vhci_tpgs_page83(struct scsi_address *ap, struct buf *bp,
45    int *rel_tgt_port, int *tgt_port, int *lu);
46static void print_buf(char *buf, int buf_size);
47static int vhci_tpgs_report_target_groups(struct scsi_address *ap,
48    struct buf *bp, int rel_tgt_port, int tgt_port, int *pstate,
49    int *preferred);
50
51int
52vhci_tpgs_set_target_groups(struct scsi_address *ap, int set_state,
53    int tpg_id)
54{
55	struct scsi_pkt			*pkt;
56	struct buf			*bp;
57	int				len, rval, ss = SCSI_SENSE_UNKNOWN;
58	char				*bufp;
59	struct scsi_extended_sense	*sns;
60
61	len = 8;
62
63	bp = getrbuf(KM_NOSLEEP);
64	if (bp == NULL) {
65		VHCI_DEBUG(1, (CE_WARN, NULL, "!vhci_tpgs_set_target_groups: "
66		    " failed getrbuf"));
67		return (1);
68	}
69
70	bufp = kmem_zalloc(len, KM_NOSLEEP);
71	if (bufp == NULL) {
72		VHCI_DEBUG(1, (CE_WARN, NULL, "!vhci_tpgs_set_target_groups: "
73		    "request packet allocation for %d failed....", len));
74		freerbuf(bp);
75		return (1);
76	}
77
78	bp->b_un.b_addr = bufp;
79	bp->b_flags = B_READ;
80	bp->b_bcount = len;
81	bp->b_resid = 0;
82
83	bufp[4] = (0x0f & set_state);
84	bufp[6] = (0xff00 & tpg_id) >> 8;
85	bufp[7] = (0x00ff & tpg_id);
86
87	pkt = scsi_init_pkt(ap, NULL, bp, CDB_GROUP5,
88	    sizeof (struct scsi_arq_status), 0, 0, NULL, NULL);
89
90	if (pkt == NULL) {
91		VHCI_DEBUG(1, (CE_NOTE, NULL,
92		    "!vhci_tpgs_set_target_groups: scsi_init_pkt error\n"));
93		freerbuf(bp);
94		kmem_free((void *)bufp, len);
95		return (1);
96	}
97
98	/*
99	 * Sends 1 TPG descriptor only. Hence Parameter list length pkt_cdbp[9]
100	 * is set to 8 bytes - Refer SPC3 for details.
101	 */
102	pkt->pkt_cdbp[0] = SCMD_MAINTENANCE_OUT;
103	pkt->pkt_cdbp[1] = SSVC_ACTION_SET_TARGET_PORT_GROUPS;
104	pkt->pkt_cdbp[9] = 8;
105	pkt->pkt_time = 90;
106
107	VHCI_DEBUG(1, (CE_NOTE, NULL,
108	    "!vhci_tpgs_set_target_groups: sending set target port group:"
109	    " cdb[0/1/6/7/8/9]: %x/%x/%x/%x/%x/%x\n", pkt->pkt_cdbp[0],
110	    pkt->pkt_cdbp[1], pkt->pkt_cdbp[6], pkt->pkt_cdbp[7],
111	    pkt->pkt_cdbp[8], pkt->pkt_cdbp[9]));
112
113#ifdef DEBUG
114	print_buf(bufp, len);
115#endif
116	rval = vhci_do_scsi_cmd(pkt);
117
118	if (rval == 0) {
119		VHCI_DEBUG(1, (CE_NOTE, NULL, "!vhci_tpgs_set_target_groups:"
120		    " vhci_do_scsi_cmd failed\n"));
121		freerbuf(bp);
122		kmem_free((void *)bufp, len);
123		scsi_destroy_pkt(pkt);
124		return (-1);
125	} else if ((pkt->pkt_reason == CMD_CMPLT) &&
126	    (SCBP_C(pkt) == STATUS_CHECK) &&
127	    (pkt->pkt_state & STATE_ARQ_DONE)) {
128		sns = &(((struct scsi_arq_status *)(uintptr_t)
129		    (pkt->pkt_scbp))->sts_sensedata);
130
131		if ((sns->es_key == KEY_UNIT_ATTENTION) &&
132		    (sns->es_add_code == STD_SCSI_ASC_STATE_CHG) &&
133		    (sns->es_qual_code == STD_SCSI_ASCQ_STATE_CHG_SUCC)) {
134			ss = SCSI_SENSE_STATE_CHANGED;
135			VHCI_DEBUG(4, (CE_NOTE, NULL,
136			    "!vhci_tpgs_set_target_groups:"
137			    " sense:%x, add_code: %x, qual_code:%x"
138			    " sense:%x\n", sns->es_key, sns->es_add_code,
139			    sns->es_qual_code, ss));
140		} else if ((sns->es_key == KEY_ILLEGAL_REQUEST) &&
141		    (sns->es_add_code == STD_SCSI_ASC_INVAL_PARAM_LIST)) {
142			ss = SCSI_SENSE_NOFAILOVER;
143			VHCI_DEBUG(1, (CE_NOTE, NULL,
144			    "!vhci_tpgs_set_target_groups:"
145			    " sense:%x, add_code: %x, qual_code:%x"
146			    " sense:%x\n", sns->es_key, sns->es_add_code,
147			    sns->es_qual_code, ss));
148		} else if ((sns->es_key == KEY_ILLEGAL_REQUEST) &&
149		    (sns->es_add_code == STD_SCSI_ASC_INVAL_CMD_OPCODE)) {
150			ss = SCSI_SENSE_NOFAILOVER;
151			VHCI_DEBUG(1, (CE_NOTE, NULL,
152			    "!vhci_tpgs_set_target_groups:"
153			    " sense_key:%x, add_code: %x, qual_code:%x"
154			    " sense:%x\n", sns->es_key, sns->es_add_code,
155			    sns->es_qual_code, rval));
156		} else {
157			/*
158			 * At this point sns data may be for power-on-reset
159			 * UNIT ATTN hardware errors, vendor unqiue sense etc.
160			 * For all these cases, sense is unknown.
161			 */
162			ss = SCSI_SENSE_NOFAILOVER;
163			VHCI_DEBUG(1, (CE_NOTE, NULL,
164			    "!vhci_tpgs_set_target_groups: "
165			    " sense UNKNOWN: sense key:%x, ASC:%x, ASCQ:%x\n",
166			    sns->es_key, sns->es_add_code, sns->es_qual_code));
167		}
168
169		if (ss == SCSI_SENSE_STATE_CHANGED) {
170			freerbuf(bp);
171			kmem_free((void *)bufp, len);
172			scsi_destroy_pkt(pkt);
173			return (0);
174		}
175	}
176
177	freerbuf(bp);
178	kmem_free((void *)bufp, len);
179	scsi_destroy_pkt(pkt);
180	return (1);
181}
182
183/*
184 * get the failover mode, ownership and if it has extended failover
185 * capability. The mode(bits5-4/byte5) is defined as implicit, explicit, or
186 * both.  The state is defined as online-optimized(0h),
187 * online-nonoptimized(1h), standby(2h), offline(3h),
188 * and transitioning(fh). Currently, there is online,
189 * standby, and offline(defined in sunmdi.h).
190 * Online-nonoptimized will be a mode of secondary
191 * and an ownership of online. Thought about using a different mode but
192 * it appears the states are really for the states for secondary mode.
193 * We currently have IS_ONLINING, IS_OFFLINING - should we have TRANSITIONING
194 * to mean from online-optimized to online-nonoptimized or does onlining
195 * cover this?
196 */
197/* ARGSUSED */
198int
199vhci_tpgs_get_target_fo_mode(struct scsi_device *sd, int *mode,
200    int *state, int *xlf_capable, int *preferred)
201{
202	int			retval = 0;
203	struct buf		*bp;
204	struct scsi_address	*ap;
205	int			lu = 0, rel_tgt_port = 0, tgt_port = 0x0;
206
207	VHCI_DEBUG(6, (CE_NOTE, NULL,
208	    "!vhci_tpgs_get_target_fo_mode: enter\n"));
209	*mode = *state = *xlf_capable = 0;
210	bp = getrbuf(KM_NOSLEEP);
211	if (bp == NULL) {
212		VHCI_DEBUG(1, (CE_NOTE, NULL, "!vhci_tpgs_get_target_fo_mode: "
213		    " failed getrbuf\n"));
214		return (1);
215	}
216
217	ap = &sd->sd_address;
218	if (vhci_tpgs_inquiry(ap, bp, mode)) {
219		VHCI_DEBUG(1, (CE_NOTE, NULL, "!vhci_tpgs_get_target_fo_mode: "
220		    " failed vhci_tpgs_inquiry\n"));
221		retval = 1;
222	} else if (vhci_tpgs_page83(ap, bp, &rel_tgt_port, &tgt_port, &lu)) {
223		VHCI_DEBUG(1, (CE_NOTE, NULL, "!vhci_tpgs_get_target_fo_mode: "
224		    " failed vhci_tpgs_page83\n"));
225		retval = 1;
226	} else if (vhci_tpgs_report_target_groups(ap, bp, rel_tgt_port,
227	    tgt_port, state, preferred)) {
228		VHCI_DEBUG(1, (CE_NOTE, NULL, "!vhci_tpgs_get_target_fo_mode: "
229		    " failed vhci_tpgs_report_target_groups\n"));
230		retval = 1;
231	}
232
233	freerbuf(bp);
234	if (retval == 0) {
235		VHCI_DEBUG(6, (CE_NOTE, NULL, "!vhci_tpgs_get_target_fo_mode: "
236		    "SUCCESS\n"));
237	}
238	return (retval);
239}
240
241static int
242vhci_tpgs_inquiry(struct scsi_address *ap, struct buf *bp, int *mode)
243{
244	struct scsi_pkt		*pkt;
245	struct scsi_inquiry	inq;
246	int			retval;
247
248	*mode = 0;
249	bp->b_un.b_addr = (caddr_t)&inq;
250	bp->b_flags = B_READ;
251	bp->b_bcount = sizeof (inq);
252	bp->b_resid = 0;
253
254	pkt = scsi_init_pkt(ap, NULL, bp, CDB_GROUP0,
255	    sizeof (struct scsi_arq_status), 0, 0, SLEEP_FUNC, NULL);
256	pkt->pkt_cdbp[0] = SCMD_INQUIRY;
257	pkt->pkt_cdbp[4] = sizeof (inq);
258	pkt->pkt_time = 60;
259
260	retval = vhci_do_scsi_cmd(pkt);
261	scsi_destroy_pkt(pkt);
262	if (retval == 0) {
263		VHCI_DEBUG(1, (CE_WARN, NULL, "!vhci_tpgs_inquiry: Failure"
264		    " returned from vhci_do_scsi_cmd"));
265		return (1);
266	}
267
268	if (inq.inq_tpgs == 0) {
269		VHCI_DEBUG(1, (CE_WARN, NULL,
270		    "!vhci_tpgs_inquiry: zero tpgs_bits"));
271		return (1);
272	}
273	retval = 0;
274	if (inq.inq_tpgs == SCSI_IMPLICIT_FAILOVER) {
275		*mode = SCSI_IMPLICIT_FAILOVER;
276	} else if (inq.inq_tpgs == SCSI_EXPLICIT_FAILOVER) {
277		*mode = SCSI_EXPLICIT_FAILOVER;
278	} else if (inq.inq_tpgs == SCSI_BOTH_FAILOVER) {
279		*mode = SCSI_BOTH_FAILOVER;
280	} else {
281		VHCI_DEBUG(1, (CE_WARN, NULL,
282		    "!vhci_tpgs_inquiry: Illegal mode returned: %x mode: %x",
283		    inq.inq_tpgs, *mode));
284		retval = 1;
285	}
286
287	return (retval);
288}
289
290static int
291vhci_tpgs_page83(struct scsi_address *ap, struct buf *bp,
292	int *rel_tgt_port, int *tgt_port, int *lu)
293{
294	char			*ptr, *end;
295	struct scsi_pkt		*pkt;
296	char			*bufp;
297	unsigned int		buf_len, rx_bsize;
298
299	/*
300	 * lets start the buf size with 512 bytes. If this
301	 * if found to be insufficient, we can allocate
302	 * appropriate size in the next iteration.
303	 */
304	buf_len = 512;
305
306once_again:
307	bufp = kmem_zalloc(buf_len, KM_NOSLEEP);
308	if (bufp == NULL) {
309		VHCI_DEBUG(1, (CE_WARN, NULL, "!vhci_tpgs_page83: "
310		    "request packet allocation for %d failed....",
311		    buf_len));
312		return (1);
313	}
314
315
316	bp->b_un.b_addr = bufp;
317	bp->b_flags = B_READ;
318	bp->b_bcount = buf_len;
319	bp->b_resid = 0;
320
321	pkt = scsi_init_pkt(ap, NULL, bp, CDB_GROUP0,
322	    sizeof (struct scsi_arq_status), 0, 0, NULL, NULL);
323	if (pkt == NULL) {
324		VHCI_DEBUG(1, (CE_WARN, NULL,
325		    "!vhci_tpgs_page83: Failure returned from scsi_init_pkt"));
326		kmem_free((void *)bufp, buf_len);
327		return (1);
328	}
329
330	pkt->pkt_cdbp[0] = SCMD_INQUIRY;
331	pkt->pkt_cdbp[1] = 0x1;
332	pkt->pkt_cdbp[2] = 0x83;
333	pkt->pkt_cdbp[3] = (unsigned char)((buf_len >> 8) & 0xff);
334	pkt->pkt_cdbp[4] = (unsigned char)(buf_len & 0xff);
335	pkt->pkt_time = 90;
336
337	if (vhci_do_scsi_cmd(pkt) == 0) {
338		VHCI_DEBUG(1, (CE_NOTE, NULL,
339		    "!vhci_tpgs_page83: vhci_do_scsi_cmd failed\n"));
340		kmem_free((void *)bufp, buf_len);
341		scsi_destroy_pkt(pkt);
342		return (1);
343	}
344
345	/*
346	 * Now lets check if the size that was provided was
347	 * sufficient. If not, allocate the appropriate size
348	 * and retry the command again.
349	 */
350	rx_bsize = (((bufp[2] & 0xff) << 8) | (bufp[3] & 0xff));
351	rx_bsize += 4;
352	if (rx_bsize > buf_len) {
353		/*
354		 * Need to allocate more buf and retry again
355		 */
356		VHCI_DEBUG(1, (CE_NOTE, NULL, "!vhci_tpgs_page83: "
357		    "bufsize: %d greater than allocated buf: %d\n",
358		    rx_bsize, buf_len));
359		VHCI_DEBUG(1, (CE_NOTE, NULL, "Retrying for size %d\n",
360		    rx_bsize));
361		kmem_free((void *)bufp, buf_len);
362		buf_len = (unsigned int)(rx_bsize);
363		goto once_again;
364	}
365
366	ptr = bufp;
367	ptr += 4; /* identification descriptor 0 */
368	end = bufp + rx_bsize;
369	while (ptr < end) {
370		VHCI_DEBUG(1, (CE_NOTE, NULL, "vhci_tpgs_page83: "
371		    "desc[1/4/5/6/7]:%x %x %x %x %x\n",
372		    ptr[1], ptr[4], ptr[5], ptr[6], ptr[7]));
373		if ((ptr[1] & 0x0f) == 0x04) {
374			*rel_tgt_port = 0;
375			*rel_tgt_port |= ((ptr[6] & 0xff) << 8);
376			*rel_tgt_port |= (ptr[7] & 0xff);
377			VHCI_DEBUG(1, (CE_NOTE, NULL,
378			    "!vhci_tpgs_page83: relative target port: %x\n",
379			    *rel_tgt_port));
380		} else if ((ptr[1] & 0x0f) == 0x05) {
381			*tgt_port = 0;
382			*tgt_port = ((ptr[6] & 0xff) << 8);
383			*tgt_port |= (ptr[7] & 0xff);
384			VHCI_DEBUG(1, (CE_NOTE, NULL,
385			    "!vhci_tpgs_page83: target port: %x\n", *tgt_port));
386		} else if ((ptr[1] & 0x0f) == 0x06) {
387			*lu = 0;
388			*lu |= ((ptr[6] & 0xff)<< 8);
389			*lu |= (ptr[7] & 0xff);
390			VHCI_DEBUG(1, (CE_NOTE, NULL,
391			    "!vhci_tpgs_page83: logical unit: %x\n", *lu));
392		}
393		ptr += ptr[3] + 4;  /* next identification descriptor */
394	}
395	kmem_free((void *)bufp, buf_len);
396	scsi_destroy_pkt(pkt);
397	return (0);
398}
399
400#ifdef DEBUG
401static void
402print_buf(char *buf, int buf_size)
403{
404	int		i = 0, j;
405	int		loop, left;
406
407	loop = buf_size / 8;
408	left = buf_size % 8;
409
410	VHCI_DEBUG(4, (CE_NOTE, NULL, "!buf_size: %x loop: %x left: %x",
411	    buf_size, loop, left));
412
413	for (j = 0; j < loop; j++) {
414		VHCI_DEBUG(4, (CE_NOTE, NULL,
415		    "!buf[%d-%d]: %x %x %x %x %x %x %x %x",
416		    i, i + 7, buf[i], buf[i+1], buf[i+2], buf[i+3],
417		    buf[i+4], buf[i+5], buf[i+6], buf[i+7]));
418		i += 8;
419	}
420
421	if (left) {
422		VHCI_DEBUG(4, (CE_CONT, NULL,
423		    "NOTICE: buf[%d-%d]:", i, i + left));
424		for (j = 0; j < left; j++) {
425			VHCI_DEBUG(4, (CE_CONT, NULL, " %x", buf[i + j]));
426		}
427		VHCI_DEBUG(4, (CE_CONT, NULL, "\n"));
428	}
429}
430#endif
431
432static int
433vhci_tpgs_report_target_groups(struct scsi_address *ap, struct buf *bp,
434	int rel_tgt_port, int tgt_port, int *pstate, int *preferred)
435{
436	struct scsi_pkt		*pkt;
437	char			*ptr, *end, *bufp, *mpapi_ptr;
438	unsigned int		rtpg_len = 0;
439	unsigned int		l_tgt_port = 0, tpgs_state = 0;
440	unsigned int		tgt_port_cnt = 0, lr_tgt_port = 0;
441	int			i, len;
442
443	/*
444	 * Start with buffer size of 512.
445	 * If this is found to be insufficient, required size
446	 * will be allocated and the command will be retried.
447	 */
448	len = 512;
449
450try_again:
451	bufp = kmem_zalloc(len, KM_NOSLEEP);
452	if (bufp == NULL) {
453		VHCI_DEBUG(1, (CE_WARN, NULL, "!vhci_tpgs_report_target_groups:"
454		    " request packet allocation for %d failed....", len));
455		return (1);
456	}
457
458	bp->b_un.b_addr = bufp;
459	bp->b_flags = B_READ;
460	bp->b_bcount = len;
461	bp->b_resid = 0;
462
463	pkt = scsi_init_pkt(ap, NULL, bp, CDB_GROUP5,
464	    sizeof (struct scsi_arq_status), 0, 0, NULL, NULL);
465
466	if (pkt == NULL) {
467		VHCI_DEBUG(1, (CE_NOTE, NULL,
468		    "!vhci_tpgs_report_target_groups: scsi_init_pkt error\n"));
469		kmem_free((void *)bufp, len);
470		return (1);
471	}
472
473	pkt->pkt_cdbp[0] = SCMD_MAINTENANCE_IN;
474	pkt->pkt_cdbp[1] = SSVC_ACTION_GET_TARGET_PORT_GROUPS;
475	pkt->pkt_cdbp[6] = ((len >>  24) & 0xff);
476	pkt->pkt_cdbp[7] = ((len >> 16) & 0xff);
477	pkt->pkt_cdbp[8] = ((len >> 8) & 0xff);
478	pkt->pkt_cdbp[9] = len & 0xff;
479	pkt->pkt_time = 90;
480
481	VHCI_DEBUG(6, (CE_NOTE, NULL,
482	    "!vhci_tpgs_report_target_groups: sending target port group:"
483	    " cdb[6/7/8/9]: %x/%x/%x/%x\n", pkt->pkt_cdbp[6],
484	    pkt->pkt_cdbp[7], pkt->pkt_cdbp[8], pkt->pkt_cdbp[9]));
485	if (vhci_do_scsi_cmd(pkt) == 0) {
486		VHCI_DEBUG(4, (CE_NOTE, NULL, "!vhci_tpgs_report_target_groups:"
487		    " vhci_do_scsi_cmd failed\n"));
488		kmem_free((void *)bufp, len);
489		scsi_destroy_pkt(pkt);
490		return (1);
491	}
492	ptr = bufp;
493	VHCI_DEBUG(6, (CE_NOTE, NULL, "!vhci_tpgs_report_target_groups:"
494	    " returned from target"
495	    " port group: buf[0/1/2/3]: %x/%x/%x/%x\n",
496	    ptr[0], ptr[1], ptr[2], ptr[3]));
497	rtpg_len = (unsigned int)((0xff & ptr[0]) << 24);
498	rtpg_len |= (unsigned int)((0xff & ptr[1]) << 16);
499	rtpg_len |= (unsigned int)((0xff & ptr[2]) << 8);
500	rtpg_len |= (unsigned int)(0xff & ptr[3]);
501	rtpg_len += 4;
502	if (rtpg_len > len) {
503		VHCI_DEBUG(4, (CE_NOTE, NULL, "!vhci_tpgs_report_target_groups:"
504		    " bufsize: %d greater than allocated buf: %d\n",
505		    rtpg_len, len));
506		VHCI_DEBUG(4, (CE_NOTE, NULL, "Retrying for size %d\n",
507		    rtpg_len));
508		kmem_free((void *)bufp, len);
509		len = (unsigned int)(rtpg_len + 1);
510		goto try_again;
511	}
512#ifdef DEBUG
513	print_buf(bufp, rtpg_len);
514#endif
515	end = ptr + rtpg_len;
516	ptr += 4;
517	while (ptr < end) {
518		mpapi_ptr = ptr;
519		l_tgt_port = ((ptr[2] & 0xff) << 8) + (ptr[3] & 0xff);
520		tpgs_state = ptr[0] & 0x0f;
521		tgt_port_cnt = (ptr[7] & 0xff);
522		VHCI_DEBUG(4, (CE_NOTE, NULL, "!vhci_tpgs_report_tgt_groups:"
523		    " tpgs state: %x"
524		    " tgt_group: %x count: %x\n", tpgs_state,
525		    l_tgt_port, tgt_port_cnt));
526		ptr += 8;
527		for (i = 0; i < tgt_port_cnt; i++) {
528			lr_tgt_port = 0;
529			lr_tgt_port |= ((ptr[2] & 0Xff) << 8);
530			lr_tgt_port |= (ptr[3] & 0xff);
531
532			if ((lr_tgt_port == rel_tgt_port) &&
533			    (l_tgt_port == tgt_port)) {
534				VHCI_DEBUG(4, (CE_NOTE, NULL,
535				    "!vhci_tpgs_report_tgt_groups:"
536				    " found tgt_port: %x rel_tgt_port:%x"
537				    " tpgs_state: %x\n", tgt_port, rel_tgt_port,
538				    tpgs_state));
539				/*
540				 * once we have the preferred flag
541				 * and a non-optimized state flag
542				 * we will get preferred flag  from the
543				 * report target groups
544				 */
545				if (tpgs_state == STD_ACTIVE_OPTIMIZED) {
546					*pstate = STD_ACTIVE_OPTIMIZED;
547					*preferred = PCLASS_PREFERRED;
548				} else if (tpgs_state ==
549				    STD_ACTIVE_NONOPTIMIZED) {
550					*pstate = STD_ACTIVE_NONOPTIMIZED;
551					*preferred = PCLASS_NONPREFERRED;
552				} else if (tpgs_state == STD_STANDBY) {
553					*pstate = STD_STANDBY;
554					*preferred = PCLASS_NONPREFERRED;
555				} else {
556					*pstate = STD_UNAVAILABLE;
557					*preferred = PCLASS_NONPREFERRED;
558				}
559				vhci_mpapi_update_tpg_data(ap, mpapi_ptr);
560				kmem_free((void *)bufp, len);
561				scsi_destroy_pkt(pkt);
562				return (0);
563			}
564			VHCI_DEBUG(4, (CE_NOTE, NULL,
565			    "!vhci_tpgs_report_tgt_groups:"
566			    " tgt_port: %x rel_tgt_port:%x\n", tgt_port,
567			    rel_tgt_port));
568			ptr += 4;
569		}
570	}
571	*pstate = SCSI_PATH_INACTIVE;
572	*preferred = PCLASS_NONPREFERRED;
573	VHCI_DEBUG(1, (CE_NOTE, NULL, "!vhci_tpgs_report_tgt_groups: "
574	    "NO rel_TGTPRT MATCH!!! Assigning Default: state: %x "
575	    "preferred: %d\n", *pstate, *preferred));
576	kmem_free((void *)bufp, len);
577	scsi_destroy_pkt(pkt);
578	return (1);
579}
580