Home | History | Annotate | Download | only in scsi_vhci
      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
     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
    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
    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 	pkt->pkt_cdbp[0] = SCMD_INQUIRY;
    263 	pkt->pkt_cdbp[4] = sizeof (inq);
    264 	pkt->pkt_time = 60;
    265 
    266 	retval = vhci_do_scsi_cmd(pkt);
    267 	scsi_destroy_pkt(pkt);
    268 	if (retval == 0) {
    269 		VHCI_DEBUG(1, (CE_WARN, NULL, "!vhci_tpgs_inquiry: Failure"
    270 		    " returned from vhci_do_scsi_cmd"));
    271 		return (1);
    272 	}
    273 
    274 	if (inq.inq_tpgs == TPGS_FAILOVER_NONE) {
    275 		VHCI_DEBUG(1, (CE_WARN, NULL,
    276 		    "!vhci_tpgs_inquiry: zero tpgs_bits"));
    277 		return (1);
    278 	}
    279 	retval = 0;
    280 	if (inq.inq_tpgs == TPGS_FAILOVER_IMPLICIT) {
    281 		*mode = SCSI_IMPLICIT_FAILOVER;
    282 	} else if (inq.inq_tpgs == TPGS_FAILOVER_EXPLICIT) {
    283 		*mode = SCSI_EXPLICIT_FAILOVER;
    284 	} else if (inq.inq_tpgs == TPGS_FAILOVER_BOTH) {
    285 		*mode = SCSI_BOTH_FAILOVER;
    286 	} else {
    287 		VHCI_DEBUG(1, (CE_WARN, NULL,
    288 		    "!vhci_tpgs_inquiry: Illegal mode returned: %x mode: %x",
    289 		    inq.inq_tpgs, *mode));
    290 		retval = 1;
    291 	}
    292 
    293 	return (retval);
    294 }
    295 
    296 static int
    297 vhci_tpgs_page83(struct scsi_address *ap, struct buf *bp,
    298 	int *rel_tgt_port, int *tgt_port, int *lu)
    299 {
    300 	char			*ptr, *end;
    301 	struct scsi_pkt		*pkt;
    302 	char			*bufp;
    303 	unsigned int		buf_len, rx_bsize;
    304 
    305 	/*
    306 	 * lets start the buf size with 512 bytes. If this
    307 	 * if found to be insufficient, we can allocate
    308 	 * appropriate size in the next iteration.
    309 	 */
    310 	buf_len = 512;
    311 
    312 once_again:
    313 	bufp = kmem_zalloc(buf_len, KM_NOSLEEP);
    314 	if (bufp == NULL) {
    315 		VHCI_DEBUG(1, (CE_WARN, NULL, "!vhci_tpgs_page83: "
    316 		    "request packet allocation for %d failed....",
    317 		    buf_len));
    318 		return (1);
    319 	}
    320 
    321 
    322 	bp->b_un.b_addr = bufp;
    323 	bp->b_flags = B_READ;
    324 	bp->b_bcount = buf_len;
    325 	bp->b_resid = 0;
    326 
    327 	pkt = scsi_init_pkt(ap, NULL, bp, CDB_GROUP0,
    328 	    sizeof (struct scsi_arq_status), 0, 0, NULL, NULL);
    329 	if (pkt == NULL) {
    330 		VHCI_DEBUG(1, (CE_WARN, NULL,
    331 		    "!vhci_tpgs_page83: Failure returned from scsi_init_pkt"));
    332 		kmem_free((void *)bufp, buf_len);
    333 		return (1);
    334 	}
    335 
    336 	pkt->pkt_cdbp[0] = SCMD_INQUIRY;
    337 	pkt->pkt_cdbp[1] = 0x1;
    338 	pkt->pkt_cdbp[2] = 0x83;
    339 	pkt->pkt_cdbp[3] = (unsigned char)((buf_len >> 8) & 0xff);
    340 	pkt->pkt_cdbp[4] = (unsigned char)(buf_len & 0xff);
    341 	pkt->pkt_time = 90;
    342 
    343 	if (vhci_do_scsi_cmd(pkt) == 0) {
    344 		VHCI_DEBUG(1, (CE_NOTE, NULL,
    345 		    "!vhci_tpgs_page83: vhci_do_scsi_cmd failed\n"));
    346 		kmem_free((void *)bufp, buf_len);
    347 		scsi_destroy_pkt(pkt);
    348 		return (1);
    349 	}
    350 
    351 	/*
    352 	 * Now lets check if the size that was provided was
    353 	 * sufficient. If not, allocate the appropriate size
    354 	 * and retry the command again.
    355 	 */
    356 	rx_bsize = (((bufp[2] & 0xff) << 8) | (bufp[3] & 0xff));
    357 	rx_bsize += 4;
    358 	if (rx_bsize > buf_len) {
    359 		/*
    360 		 * Need to allocate more buf and retry again
    361 		 */
    362 		VHCI_DEBUG(1, (CE_NOTE, NULL, "!vhci_tpgs_page83: "
    363 		    "bufsize: %d greater than allocated buf: %d\n",
    364 		    rx_bsize, buf_len));
    365 		VHCI_DEBUG(1, (CE_NOTE, NULL, "Retrying for size %d\n",
    366 		    rx_bsize));
    367 		kmem_free((void *)bufp, buf_len);
    368 		buf_len = (unsigned int)(rx_bsize);
    369 		goto once_again;
    370 	}
    371 
    372 	ptr = bufp;
    373 	ptr += 4; /* identification descriptor 0 */
    374 	end = bufp + rx_bsize;
    375 	while (ptr < end) {
    376 		VHCI_DEBUG(1, (CE_NOTE, NULL, "vhci_tpgs_page83: "
    377 		    "desc[1/4/5/6/7]:%x %x %x %x %x\n",
    378 		    ptr[1], ptr[4], ptr[5], ptr[6], ptr[7]));
    379 		if ((ptr[1] & 0x0f) == 0x04) {
    380 			*rel_tgt_port = 0;
    381 			*rel_tgt_port |= ((ptr[6] & 0xff) << 8);
    382 			*rel_tgt_port |= (ptr[7] & 0xff);
    383 			VHCI_DEBUG(1, (CE_NOTE, NULL,
    384 			    "!vhci_tpgs_page83: relative target port: %x\n",
    385 			    *rel_tgt_port));
    386 		} else if ((ptr[1] & 0x0f) == 0x05) {
    387 			*tgt_port = 0;
    388 			*tgt_port = ((ptr[6] & 0xff) << 8);
    389 			*tgt_port |= (ptr[7] & 0xff);
    390 			VHCI_DEBUG(1, (CE_NOTE, NULL,
    391 			    "!vhci_tpgs_page83: target port: %x\n", *tgt_port));
    392 		} else if ((ptr[1] & 0x0f) == 0x06) {
    393 			*lu = 0;
    394 			*lu |= ((ptr[6] & 0xff)<< 8);
    395 			*lu |= (ptr[7] & 0xff);
    396 			VHCI_DEBUG(1, (CE_NOTE, NULL,
    397 			    "!vhci_tpgs_page83: logical unit: %x\n", *lu));
    398 		}
    399 		ptr += ptr[3] + 4;  /* next identification descriptor */
    400 	}
    401 	kmem_free((void *)bufp, buf_len);
    402 	scsi_destroy_pkt(pkt);
    403 	return (0);
    404 }
    405 
    406 #ifdef DEBUG
    407 static void
    408 print_buf(char *buf, int buf_size)
    409 {
    410 	int		i = 0, j;
    411 	int		loop, left;
    412 
    413 	loop = buf_size / 8;
    414 	left = buf_size % 8;
    415 
    416 	VHCI_DEBUG(4, (CE_NOTE, NULL, "!buf_size: %x loop: %x left: %x",
    417 	    buf_size, loop, left));
    418 
    419 	for (j = 0; j < loop; j++) {
    420 		VHCI_DEBUG(4, (CE_NOTE, NULL,
    421 		    "!buf[%d-%d]: %x %x %x %x %x %x %x %x",
    422 		    i, i + 7, buf[i], buf[i+1], buf[i+2], buf[i+3],
    423 		    buf[i+4], buf[i+5], buf[i+6], buf[i+7]));
    424 		i += 8;
    425 	}
    426 
    427 	if (left) {
    428 		VHCI_DEBUG(4, (CE_CONT, NULL,
    429 		    "NOTICE: buf[%d-%d]:", i, i + left));
    430 		for (j = 0; j < left; j++) {
    431 			VHCI_DEBUG(4, (CE_CONT, NULL, " %x", buf[i + j]));
    432 		}
    433 		VHCI_DEBUG(4, (CE_CONT, NULL, "\n"));
    434 	}
    435 }
    436 #endif
    437 
    438 static int
    439 vhci_tpgs_report_target_groups(struct scsi_address *ap, struct buf *bp,
    440 	int rel_tgt_port, int tgt_port, int *pstate, int *preferred)
    441 {
    442 	struct scsi_pkt		*pkt;
    443 	char			*ptr, *end, *bufp, *mpapi_ptr;
    444 	unsigned int		rtpg_len = 0;
    445 	unsigned int		l_tgt_port = 0, tpgs_state = 0;
    446 	unsigned int		tgt_port_cnt = 0, lr_tgt_port = 0;
    447 	int			i, len;
    448 
    449 	/*
    450 	 * Start with buffer size of 512.
    451 	 * If this is found to be insufficient, required size
    452 	 * will be allocated and the command will be retried.
    453 	 */
    454 	len = 512;
    455 
    456 try_again:
    457 	bufp = kmem_zalloc(len, KM_NOSLEEP);
    458 	if (bufp == NULL) {
    459 		VHCI_DEBUG(1, (CE_WARN, NULL, "!vhci_tpgs_report_target_groups:"
    460 		    " request packet allocation for %d failed....", len));
    461 		return (1);
    462 	}
    463 
    464 	bp->b_un.b_addr = bufp;
    465 	bp->b_flags = B_READ;
    466 	bp->b_bcount = len;
    467 	bp->b_resid = 0;
    468 
    469 	pkt = scsi_init_pkt(ap, NULL, bp, CDB_GROUP5,
    470 	    sizeof (struct scsi_arq_status), 0, 0, NULL, NULL);
    471 
    472 	if (pkt == NULL) {
    473 		VHCI_DEBUG(1, (CE_NOTE, NULL,
    474 		    "!vhci_tpgs_report_target_groups: scsi_init_pkt error\n"));
    475 		kmem_free((void *)bufp, len);
    476 		return (1);
    477 	}
    478 
    479 	pkt->pkt_cdbp[0] = SCMD_MAINTENANCE_IN;
    480 	pkt->pkt_cdbp[1] = SSVC_ACTION_GET_TARGET_PORT_GROUPS;
    481 	pkt->pkt_cdbp[6] = ((len >>  24) & 0xff);
    482 	pkt->pkt_cdbp[7] = ((len >> 16) & 0xff);
    483 	pkt->pkt_cdbp[8] = ((len >> 8) & 0xff);
    484 	pkt->pkt_cdbp[9] = len & 0xff;
    485 	pkt->pkt_time = 90;
    486 
    487 	VHCI_DEBUG(6, (CE_NOTE, NULL,
    488 	    "!vhci_tpgs_report_target_groups: sending target port group:"
    489 	    " cdb[6/7/8/9]: %x/%x/%x/%x\n", pkt->pkt_cdbp[6],
    490 	    pkt->pkt_cdbp[7], pkt->pkt_cdbp[8], pkt->pkt_cdbp[9]));
    491 	if (vhci_do_scsi_cmd(pkt) == 0) {
    492 		VHCI_DEBUG(4, (CE_NOTE, NULL, "!vhci_tpgs_report_target_groups:"
    493 		    " vhci_do_scsi_cmd failed\n"));
    494 		kmem_free((void *)bufp, len);
    495 		scsi_destroy_pkt(pkt);
    496 		return (1);
    497 	}
    498 	ptr = bufp;
    499 	VHCI_DEBUG(6, (CE_NOTE, NULL, "!vhci_tpgs_report_target_groups:"
    500 	    " returned from target"
    501 	    " port group: buf[0/1/2/3]: %x/%x/%x/%x\n",
    502 	    ptr[0], ptr[1], ptr[2], ptr[3]));
    503 	rtpg_len = (unsigned int)((0xff & ptr[0]) << 24);
    504 	rtpg_len |= (unsigned int)((0xff & ptr[1]) << 16);
    505 	rtpg_len |= (unsigned int)((0xff & ptr[2]) << 8);
    506 	rtpg_len |= (unsigned int)(0xff & ptr[3]);
    507 	rtpg_len += 4;
    508 	if (rtpg_len > len) {
    509 		VHCI_DEBUG(4, (CE_NOTE, NULL, "!vhci_tpgs_report_target_groups:"
    510 		    " bufsize: %d greater than allocated buf: %d\n",
    511 		    rtpg_len, len));
    512 		VHCI_DEBUG(4, (CE_NOTE, NULL, "Retrying for size %d\n",
    513 		    rtpg_len));
    514 		kmem_free((void *)bufp, len);
    515 		len = (unsigned int)(rtpg_len + 1);
    516 		goto try_again;
    517 	}
    518 #ifdef DEBUG
    519 	print_buf(bufp, rtpg_len);
    520 #endif
    521 	end = ptr + rtpg_len;
    522 	ptr += 4;
    523 	while (ptr < end) {
    524 		mpapi_ptr = ptr;
    525 		l_tgt_port = ((ptr[2] & 0xff) << 8) + (ptr[3] & 0xff);
    526 		tpgs_state = ptr[0] & 0x0f;
    527 		tgt_port_cnt = (ptr[7] & 0xff);
    528 		VHCI_DEBUG(4, (CE_NOTE, NULL, "!vhci_tpgs_report_tgt_groups:"
    529 		    " tpgs state: %x"
    530 		    " tgt_group: %x count: %x\n", tpgs_state,
    531 		    l_tgt_port, tgt_port_cnt));
    532 		ptr += 8;
    533 		for (i = 0; i < tgt_port_cnt; i++) {
    534 			lr_tgt_port = 0;
    535 			lr_tgt_port |= ((ptr[2] & 0Xff) << 8);
    536 			lr_tgt_port |= (ptr[3] & 0xff);
    537 
    538 			if ((lr_tgt_port == rel_tgt_port) &&
    539 			    (l_tgt_port == tgt_port)) {
    540 				VHCI_DEBUG(4, (CE_NOTE, NULL,
    541 				    "!vhci_tpgs_report_tgt_groups:"
    542 				    " found tgt_port: %x rel_tgt_port:%x"
    543 				    " tpgs_state: %x\n", tgt_port, rel_tgt_port,
    544 				    tpgs_state));
    545 				/*
    546 				 * once we have the preferred flag
    547 				 * and a non-optimized state flag
    548 				 * we will get preferred flag  from the
    549 				 * report target groups
    550 				 */
    551 				if (tpgs_state == STD_ACTIVE_OPTIMIZED) {
    552 					*pstate = STD_ACTIVE_OPTIMIZED;
    553 					*preferred = PCLASS_PREFERRED;
    554 				} else if (tpgs_state ==
    555 				    STD_ACTIVE_NONOPTIMIZED) {
    556 					*pstate = STD_ACTIVE_NONOPTIMIZED;
    557 					*preferred = PCLASS_NONPREFERRED;
    558 				} else if (tpgs_state == STD_STANDBY) {
    559 					*pstate = STD_STANDBY;
    560 					*preferred = PCLASS_NONPREFERRED;
    561 				} else {
    562 					*pstate = STD_UNAVAILABLE;
    563 					*preferred = PCLASS_NONPREFERRED;
    564 				}
    565 				vhci_mpapi_update_tpg_data(ap, mpapi_ptr,
    566 				    rel_tgt_port);
    567 				kmem_free((void *)bufp, len);
    568 				scsi_destroy_pkt(pkt);
    569 				return (0);
    570 			}
    571 			VHCI_DEBUG(4, (CE_NOTE, NULL,
    572 			    "!vhci_tpgs_report_tgt_groups:"
    573 			    " tgt_port: %x rel_tgt_port:%x\n", tgt_port,
    574 			    rel_tgt_port));
    575 			ptr += 4;
    576 		}
    577 	}
    578 	*pstate = SCSI_PATH_INACTIVE;
    579 	*preferred = PCLASS_NONPREFERRED;
    580 	VHCI_DEBUG(1, (CE_NOTE, NULL, "!vhci_tpgs_report_tgt_groups: "
    581 	    "NO rel_TGTPRT MATCH!!! Assigning Default: state: %x "
    582 	    "preferred: %d\n", *pstate, *preferred));
    583 	kmem_free((void *)bufp, len);
    584 	scsi_destroy_pkt(pkt);
    585 	return (1);
    586 }
    587