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