xref: /onnv-gate/usr/src/uts/common/io/scsi/conf/scsi_confsubr.c (revision 13033:3ebd0e96f669)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51106Smrj  * Common Development and Distribution License (the "License").
61106Smrj  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
2212213SGavin.Maltby@Sun.COM  * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate 
250Sstevel@tonic-gate /*
260Sstevel@tonic-gate  * Utility SCSI configuration routines
270Sstevel@tonic-gate  */
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate  * Many routines in this file have built in parallel bus assumption
300Sstevel@tonic-gate  * which might need to change as other interconnect evolve.
310Sstevel@tonic-gate  */
320Sstevel@tonic-gate 
330Sstevel@tonic-gate #include <sys/scsi/scsi.h>
340Sstevel@tonic-gate #include <sys/modctl.h>
356640Scth #include <sys/bitmap.h>
3612213SGavin.Maltby@Sun.COM #include <sys/fm/protocol.h>
370Sstevel@tonic-gate 
380Sstevel@tonic-gate /*
390Sstevel@tonic-gate  * macro for filling in lun value for scsi-1 support
400Sstevel@tonic-gate  */
410Sstevel@tonic-gate 
4210696SDavid.Hollister@Sun.COM #define	FILL_SCSI1_LUN(sd, pkt) \
4310696SDavid.Hollister@Sun.COM 	if ((sd->sd_address.a_lun > 0) && \
4410696SDavid.Hollister@Sun.COM 	    (sd->sd_inq->inq_ansi == 0x1)) { \
450Sstevel@tonic-gate 		((union scsi_cdb *)(pkt)->pkt_cdbp)->scc_lun = \
4610696SDavid.Hollister@Sun.COM 		    sd->sd_address.a_lun; \
470Sstevel@tonic-gate 	}
480Sstevel@tonic-gate 
490Sstevel@tonic-gate extern struct mod_ops mod_miscops;
500Sstevel@tonic-gate 
510Sstevel@tonic-gate static struct modlmisc modlmisc = {
520Sstevel@tonic-gate 	&mod_miscops,	/* Type of module */
530Sstevel@tonic-gate 	"SCSI Bus Utility Routines"
540Sstevel@tonic-gate };
550Sstevel@tonic-gate 
560Sstevel@tonic-gate static struct modlinkage modlinkage = {
570Sstevel@tonic-gate 	MODREV_1, (void *)&modlmisc, NULL
580Sstevel@tonic-gate };
590Sstevel@tonic-gate 
6012213SGavin.Maltby@Sun.COM /*
6112213SGavin.Maltby@Sun.COM  * Contexts from which we call scsi_test
6212213SGavin.Maltby@Sun.COM  */
6312213SGavin.Maltby@Sun.COM enum scsi_test_ctxt {
6412213SGavin.Maltby@Sun.COM 	/*
6512213SGavin.Maltby@Sun.COM 	 * Those in scsi_hba_probe_pi()
6612213SGavin.Maltby@Sun.COM 	 */
6712213SGavin.Maltby@Sun.COM 	STC_PROBE_FIRST_INQ,
6812213SGavin.Maltby@Sun.COM 	STC_PROBE_FIRST_INQ_RETRY,
6912213SGavin.Maltby@Sun.COM 	STC_PROBE_PARTIAL_SUCCESS,
7012213SGavin.Maltby@Sun.COM 	STC_PROBE_RQSENSE1,
7112213SGavin.Maltby@Sun.COM 	STC_PROBE_CHK_CLEARED,
7212213SGavin.Maltby@Sun.COM 	STC_PROBE_RQSENSE2,
7312213SGavin.Maltby@Sun.COM 	STC_PROBE_INQ_FINAL,
7412213SGavin.Maltby@Sun.COM 	/*
7512213SGavin.Maltby@Sun.COM 	 * Those in check_vpd_page_support8083()
7612213SGavin.Maltby@Sun.COM 	 */
7712213SGavin.Maltby@Sun.COM 	STC_VPD_CHECK,
7812213SGavin.Maltby@Sun.COM 	/*
7912213SGavin.Maltby@Sun.COM 	 * Those in scsi_device_identity()
8012213SGavin.Maltby@Sun.COM 	 */
8112213SGavin.Maltby@Sun.COM 	STC_IDENTITY_PG80,
8212213SGavin.Maltby@Sun.COM 	STC_IDENTITY_PG83,
8312213SGavin.Maltby@Sun.COM };
8412213SGavin.Maltby@Sun.COM 
850Sstevel@tonic-gate static void create_inquiry_props(struct scsi_device *);
860Sstevel@tonic-gate 
870Sstevel@tonic-gate static int scsi_check_ss2_LUN_limit(struct scsi_device *);
880Sstevel@tonic-gate static void scsi_establish_LUN_limit(struct scsi_device *);
890Sstevel@tonic-gate static void scsi_update_parent_ss2_prop(dev_info_t *, int, int);
900Sstevel@tonic-gate 
9110696SDavid.Hollister@Sun.COM static int check_vpd_page_support8083(struct scsi_device *sd,
9210696SDavid.Hollister@Sun.COM 		int (*callback)(), int *, int *);
9310696SDavid.Hollister@Sun.COM static int send_scsi_INQUIRY(struct scsi_device *sd,
9410696SDavid.Hollister@Sun.COM 		int (*callback)(), uchar_t *bufaddr, size_t buflen,
9512213SGavin.Maltby@Sun.COM 		uchar_t evpd, uchar_t page_code, size_t *lenp,
9612213SGavin.Maltby@Sun.COM 		enum scsi_test_ctxt);
9710696SDavid.Hollister@Sun.COM 
980Sstevel@tonic-gate /*
990Sstevel@tonic-gate  * this int-array HBA-node property keeps track of strictly SCSI-2
1000Sstevel@tonic-gate  * target IDs
1010Sstevel@tonic-gate  */
1020Sstevel@tonic-gate #define	SS2_LUN0_TGT_LIST_PROP	"ss2-targets"
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate /*
1050Sstevel@tonic-gate  * for keeping track of nodes for which we do *NOT* want to probe above LUN 7
1060Sstevel@tonic-gate  * (i.e. strict SCSI-2 targets)
1070Sstevel@tonic-gate  *
1080Sstevel@tonic-gate  * note that we could also keep track of dtype (SCSI device type) and
1090Sstevel@tonic-gate  * ANSI (SCSI standard conformance level), but all currently-known cases of
1100Sstevel@tonic-gate  * this problem are on SCSI-2 PROCESSOR device types
1110Sstevel@tonic-gate  */
1120Sstevel@tonic-gate typedef struct ss2_lun0_info {
1130Sstevel@tonic-gate 	const char	*sli_vid;	/* SCSI inquiry VID */
1140Sstevel@tonic-gate 	const char	*sli_pid;	/* SCSI inquiry PID */
1150Sstevel@tonic-gate 	const char	*sli_rev;	/* SCSI inquiry REV */
1160Sstevel@tonic-gate } ss2_lun0_info_t;
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate /*
1190Sstevel@tonic-gate  * these two workarounds are for the SCSI-2 GEM2* chips used in the
1200Sstevel@tonic-gate  * D1000 and D240
1210Sstevel@tonic-gate  */
1220Sstevel@tonic-gate #define	SES_D1000_VID		"SYMBIOS"
1230Sstevel@tonic-gate #define	SES_D1000_PID		"D1000"		/* the D1000 */
1240Sstevel@tonic-gate #define	SES_D1000_REV		"2"
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate #define	SES_D240_VID		"SUN"
1270Sstevel@tonic-gate #define	SES_D240_PID		"D240"		/* the D240 */
1280Sstevel@tonic-gate #define	SES_D240_REV		"2"
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate /*
1310Sstevel@tonic-gate  * a static list of targets where we do *not* want to probe above LUN 7
1320Sstevel@tonic-gate  */
1330Sstevel@tonic-gate static const ss2_lun0_info_t	scsi_probe_strict_s2_list[] = {
1340Sstevel@tonic-gate 	{SES_D1000_VID, SES_D1000_PID, SES_D1000_REV},
1350Sstevel@tonic-gate 	{SES_D240_VID, SES_D240_PID, SES_D240_REV},
1360Sstevel@tonic-gate };
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate static const int		scsi_probe_strict_s2_size =
1390Sstevel@tonic-gate 	sizeof (scsi_probe_strict_s2_list) / sizeof (struct ss2_lun0_info);
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate #ifdef	DEBUG
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate int	scsi_probe_debug = 0;
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate #define	SCSI_PROBE_DEBUG0(l, s)		\
1470Sstevel@tonic-gate 		if (scsi_probe_debug >= (l)) printf(s)
1480Sstevel@tonic-gate #define	SCSI_PROBE_DEBUG1(l, s, a1)	\
1490Sstevel@tonic-gate 		if (scsi_probe_debug >= (l)) printf(s, a1)
1500Sstevel@tonic-gate #define	SCSI_PROBE_DEBUG2(l, s, a1, a2)	\
1510Sstevel@tonic-gate 		if (scsi_probe_debug >= (l)) printf(s, a1, a2)
1520Sstevel@tonic-gate #define	SCSI_PROBE_DEBUG3(l, s, a1, a2, a3)	\
1530Sstevel@tonic-gate 		if (scsi_probe_debug >= (l)) printf(s, a1, a2, a3)
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate #else	/* DEBUG */
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate #define	SCSI_PROBE_DEBUG0(l, s)
1580Sstevel@tonic-gate #define	SCSI_PROBE_DEBUG1(l, s, a1)
1590Sstevel@tonic-gate #define	SCSI_PROBE_DEBUG2(l, s, a1, a2)
1600Sstevel@tonic-gate #define	SCSI_PROBE_DEBUG3(l, s, a1, a2, a3)
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate #endif	/* DEBUG */
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate int	scsi_test_busy_timeout = SCSI_POLL_TIMEOUT;	/* in seconds */
1650Sstevel@tonic-gate int	scsi_test_busy_delay = 10000;			/* 10msec in usec */
1660Sstevel@tonic-gate 
16712213SGavin.Maltby@Sun.COM 
16812213SGavin.Maltby@Sun.COM /*
16912213SGavin.Maltby@Sun.COM  * Returns from scsi_test.
17012213SGavin.Maltby@Sun.COM  *
17112213SGavin.Maltby@Sun.COM  * SCSI_TEST_CMPLT_GOOD => TRAN_ACCEPT, CMD_CMPLT, STATUS_GOOD
17212213SGavin.Maltby@Sun.COM  *
17312213SGavin.Maltby@Sun.COM  * SCSI_TEST_CMPLT_BUSY => TRAN_ACCEPT, CMD_CMPLT, STATUS_BUSY
17412213SGavin.Maltby@Sun.COM  *
17512213SGavin.Maltby@Sun.COM  * SCSI_TEST_CMPLT_CHECK => TRAN_ACCEPT, CMD_CMPLT, STATUS_CHECK
17612213SGavin.Maltby@Sun.COM  *
17712213SGavin.Maltby@Sun.COM  * SCSI_TEST_CMPLT_OTHER => TRAN_ACCEPT, CMD_CMPLT, !STATUS_{GOOD,BUSY,CHECK}
17812213SGavin.Maltby@Sun.COM  *
17912213SGavin.Maltby@Sun.COM  * SCSI_TEST_CMD_INCOMPLETE => TRAN_ACCEPT, CMD_INCOMPLETE
18012213SGavin.Maltby@Sun.COM  *
18112213SGavin.Maltby@Sun.COM  * SCSI_TEST_NOTCMPLT => TRAN_ACCEPT, pkt_reason != CMD_{CMPLT,INCOMPLETE}
18212213SGavin.Maltby@Sun.COM  *
18312213SGavin.Maltby@Sun.COM  * SCSI_TEST_TRAN_BUSY => (Repeated) TRAN_BUSY from attempt scsi_transport
18412213SGavin.Maltby@Sun.COM  *
18512213SGavin.Maltby@Sun.COM  * SCSI_TEST_TRAN_REJECT => TRAN_BADPKT or TRAN_FATAL_ERROR
18612213SGavin.Maltby@Sun.COM  *
18712213SGavin.Maltby@Sun.COM  */
18812213SGavin.Maltby@Sun.COM #define	SCSI_TEST_CMPLT_GOOD		0x01U
18912213SGavin.Maltby@Sun.COM #define	SCSI_TEST_CMPLT_BUSY		0x02U
19012213SGavin.Maltby@Sun.COM #define	SCSI_TEST_CMPLT_CHECK		0x04U
19112213SGavin.Maltby@Sun.COM #define	SCSI_TEST_CMPLT_OTHER		0x08U
19212213SGavin.Maltby@Sun.COM 
19312213SGavin.Maltby@Sun.COM #define	SCSI_TEST_CMPLTMASK \
19412213SGavin.Maltby@Sun.COM 	(SCSI_TEST_CMPLT_GOOD | SCSI_TEST_CMPLT_BUSY | \
19512213SGavin.Maltby@Sun.COM 	SCSI_TEST_CMPLT_CHECK | SCSI_TEST_CMPLT_OTHER)
19612213SGavin.Maltby@Sun.COM 
19712213SGavin.Maltby@Sun.COM #define	SCSI_TEST_PARTCMPLTMASK \
19812213SGavin.Maltby@Sun.COM 	(SCSI_TEST_CMPLTMASK & ~SCSI_TEST_CMPLT_GOOD)
19912213SGavin.Maltby@Sun.COM 
20012213SGavin.Maltby@Sun.COM #define	SCSI_TEST_CMD_INCOMPLETE	0x10U
20112213SGavin.Maltby@Sun.COM #define	SCSI_TEST_NOTCMPLT		0x20U
20212213SGavin.Maltby@Sun.COM #define	SCSI_TEST_TRAN_BUSY		0x40U
20312213SGavin.Maltby@Sun.COM #define	SCSI_TEST_TRAN_REJECT		0x80U
20412213SGavin.Maltby@Sun.COM 
20512213SGavin.Maltby@Sun.COM #define	SCSI_TEST_FAILMASK \
20612213SGavin.Maltby@Sun.COM 	(SCSI_TEST_CMD_INCOMPLETE | SCSI_TEST_NOTCMPLT | \
20712213SGavin.Maltby@Sun.COM 	SCSI_TEST_TRAN_BUSY | SCSI_TEST_TRAN_REJECT)
20812213SGavin.Maltby@Sun.COM 
20912213SGavin.Maltby@Sun.COM #define	SCSI_TEST_FAILURE(x) (((x) & SCSI_TEST_FAILMASK) != 0)
21012213SGavin.Maltby@Sun.COM 
2111106Smrj /*
2121106Smrj  * architecture dependent allocation restrictions. For x86, we'll set
2131106Smrj  * dma_attr_addr_hi to scsi_max_phys_addr and dma_attr_sgllen to
2141106Smrj  * scsi_sgl_size during _init().
2151106Smrj  */
2161106Smrj #if defined(__sparc)
2171106Smrj ddi_dma_attr_t scsi_alloc_attr = {
2181106Smrj 	DMA_ATTR_V0,	/* version number */
2191106Smrj 	0x0,		/* lowest usable address */
2201106Smrj 	0xFFFFFFFFull,	/* high DMA address range */
2211106Smrj 	0xFFFFFFFFull,	/* DMA counter register */
2221106Smrj 	1,		/* DMA address alignment */
2231106Smrj 	1,		/* DMA burstsizes */
2241106Smrj 	1,		/* min effective DMA size */
2251106Smrj 	0xFFFFFFFFull,	/* max DMA xfer size */
2261106Smrj 	0xFFFFFFFFull,	/* segment boundary */
2271106Smrj 	1,		/* s/g list length */
2281106Smrj 	512,		/* granularity of device */
2291106Smrj 	0		/* DMA transfer flags */
2301106Smrj };
2311106Smrj #elif defined(__x86)
2321106Smrj ddi_dma_attr_t scsi_alloc_attr = {
2331106Smrj 	DMA_ATTR_V0,	/* version number */
2341106Smrj 	0x0,		/* lowest usable address */
2351106Smrj 	0x0,		/* high DMA address range [set in _init()] */
2361106Smrj 	0xFFFFull,	/* DMA counter register */
2371106Smrj 	1,		/* DMA address alignment */
2381106Smrj 	1,		/* DMA burstsizes */
2391106Smrj 	1,		/* min effective DMA size */
2401106Smrj 	0xFFFFFFFFull,	/* max DMA xfer size */
2411106Smrj 	0xFFFFFFFFull,  /* segment boundary */
2421106Smrj 	0,		/* s/g list length */
2431106Smrj 	512,		/* granularity of device [set in _init()] */
2441106Smrj 	0		/* DMA transfer flags */
2451106Smrj };
2461106Smrj uint64_t scsi_max_phys_addr = 0xFFFFFFFFull;
2471106Smrj int scsi_sgl_size = 0xFF;
2481106Smrj #endif
2491106Smrj 
2506640Scth ulong_t	*scsi_pkt_bad_alloc_bitmap;
2511106Smrj 
2520Sstevel@tonic-gate int
_init()2530Sstevel@tonic-gate _init()
2540Sstevel@tonic-gate {
2550Sstevel@tonic-gate 	scsi_initialize_hba_interface();
2560Sstevel@tonic-gate 	scsi_watch_init();
2571106Smrj 
2581106Smrj #if defined(__x86)
2591106Smrj 	/* set the max physical address for iob allocs on x86 */
2601106Smrj 	scsi_alloc_attr.dma_attr_addr_hi = scsi_max_phys_addr;
2611106Smrj 
2621106Smrj 	/*
2631106Smrj 	 * set the sgllen for iob allocs on x86. If this is set less than
2641106Smrj 	 * the number of pages the buffer will take (taking into account
2651106Smrj 	 * alignment), it would force the allocator to try and allocate
2661106Smrj 	 * contiguous pages.
2671106Smrj 	 */
2681106Smrj 	scsi_alloc_attr.dma_attr_sgllen = scsi_sgl_size;
2691106Smrj #endif
2701106Smrj 
2716640Scth 	/* bitmap to limit scsi_pkt allocation violation messages */
2726640Scth 	scsi_pkt_bad_alloc_bitmap = kmem_zalloc(BT_SIZEOFMAP(devcnt), KM_SLEEP);
2736640Scth 
2740Sstevel@tonic-gate 	return (mod_install(&modlinkage));
2750Sstevel@tonic-gate }
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate /*
2780Sstevel@tonic-gate  * there is no _fini() routine because this module is never unloaded
2790Sstevel@tonic-gate  */
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate int
_info(struct modinfo * modinfop)2820Sstevel@tonic-gate _info(struct modinfo *modinfop)
2830Sstevel@tonic-gate {
2840Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
2850Sstevel@tonic-gate }
2860Sstevel@tonic-gate 
28710696SDavid.Hollister@Sun.COM #define	ROUTE	(&sd->sd_address)
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate static int
scsi_slave_do_rqsense(struct scsi_device * sd,int (* callback)())29010696SDavid.Hollister@Sun.COM scsi_slave_do_rqsense(struct scsi_device *sd, int (*callback)())
2910Sstevel@tonic-gate {
2920Sstevel@tonic-gate 	struct scsi_pkt *rq_pkt = NULL;
2930Sstevel@tonic-gate 	struct buf *rq_bp = NULL;
2940Sstevel@tonic-gate 	int rval = SCSIPROBE_EXISTS;
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate 	/*
2970Sstevel@tonic-gate 	 * prepare rqsense packet
2980Sstevel@tonic-gate 	 */
2998335SChris.Horne@Sun.COM 	rq_bp = scsi_alloc_consistent_buf(ROUTE, (struct buf *)NULL,
3000Sstevel@tonic-gate 	    (uint_t)SENSE_LENGTH, B_READ, callback, NULL);
3010Sstevel@tonic-gate 	if (rq_bp == NULL) {
3024582Scth 		rval = SCSIPROBE_NOMEM;
3034582Scth 		goto out;
3040Sstevel@tonic-gate 	}
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate 	rq_pkt = scsi_init_pkt(ROUTE, (struct scsi_pkt *)NULL,
3070Sstevel@tonic-gate 	    rq_bp, CDB_GROUP0, 1, 0, PKT_CONSISTENT,
3080Sstevel@tonic-gate 	    callback, NULL);
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 	if (rq_pkt == NULL) {
3114582Scth 		if (rq_bp->b_error == 0)
3124582Scth 			rval = SCSIPROBE_NOMEM_CB;
3134582Scth 		else
3144582Scth 			rval = SCSIPROBE_NOMEM;
3154582Scth 		goto out;
3160Sstevel@tonic-gate 	}
3170Sstevel@tonic-gate 	ASSERT(rq_bp->b_error == 0);
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 	(void) scsi_setup_cdb((union scsi_cdb *)rq_pkt->
3200Sstevel@tonic-gate 	    pkt_cdbp, SCMD_REQUEST_SENSE, 0, SENSE_LENGTH, 0);
32110696SDavid.Hollister@Sun.COM 	FILL_SCSI1_LUN(sd, rq_pkt);
3220Sstevel@tonic-gate 	rq_pkt->pkt_flags = FLAG_NOINTR|FLAG_NOPARITY|FLAG_SENSING;
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate 	/*
3250Sstevel@tonic-gate 	 * The controller type is as yet unknown, so we
3260Sstevel@tonic-gate 	 * have to do a throwaway non-extended request sense,
3270Sstevel@tonic-gate 	 * and hope that that clears the check condition
3280Sstevel@tonic-gate 	 * for that unit until we can find out what kind
3290Sstevel@tonic-gate 	 * of drive it is. A non-extended request sense
3300Sstevel@tonic-gate 	 * is specified by stating that the sense block
3310Sstevel@tonic-gate 	 * has 0 length, which is taken to mean that it
3320Sstevel@tonic-gate 	 * is four bytes in length.
3330Sstevel@tonic-gate 	 */
3340Sstevel@tonic-gate 	if (scsi_poll(rq_pkt) < 0) {
3354582Scth 		rval = SCSIPROBE_FAILURE;
3360Sstevel@tonic-gate 	}
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate out:
3390Sstevel@tonic-gate 	if (rq_pkt) {
3404582Scth 		scsi_destroy_pkt(rq_pkt);
3410Sstevel@tonic-gate 	}
3420Sstevel@tonic-gate 	if (rq_bp) {
3434582Scth 		scsi_free_consistent_buf(rq_bp);
3440Sstevel@tonic-gate 	}
3450Sstevel@tonic-gate 
3460Sstevel@tonic-gate 	return (rval);
3470Sstevel@tonic-gate }
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate /*
3500Sstevel@tonic-gate  *
3510Sstevel@tonic-gate  * SCSI slave probe routine - provided as a service to target drivers
3520Sstevel@tonic-gate  *
35310696SDavid.Hollister@Sun.COM  * Mostly attempts to allocate and fill sd inquiry data..
3540Sstevel@tonic-gate  */
3550Sstevel@tonic-gate 
3560Sstevel@tonic-gate int
scsi_slave(struct scsi_device * sd,int (* callback)())35710696SDavid.Hollister@Sun.COM scsi_slave(struct scsi_device *sd, int (*callback)())
3580Sstevel@tonic-gate {
3590Sstevel@tonic-gate 	struct scsi_pkt	*pkt;
3600Sstevel@tonic-gate 	int		rval = SCSIPROBE_EXISTS;
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 	/*
3630Sstevel@tonic-gate 	 * the first test unit ready will tell us whether a target
3640Sstevel@tonic-gate 	 * responded and if there was one, it will clear the unit attention
3650Sstevel@tonic-gate 	 * condition
3660Sstevel@tonic-gate 	 */
3670Sstevel@tonic-gate 	pkt = scsi_init_pkt(ROUTE, (struct scsi_pkt *)NULL, NULL,
3680Sstevel@tonic-gate 	    CDB_GROUP0, sizeof (struct scsi_arq_status), 0, 0, callback, NULL);
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate 	if (pkt == NULL) {
3710Sstevel@tonic-gate 		return (SCSIPROBE_NOMEM_CB);
3720Sstevel@tonic-gate 	}
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate 	(void) scsi_setup_cdb((union scsi_cdb *)pkt->pkt_cdbp,
3750Sstevel@tonic-gate 	    SCMD_TEST_UNIT_READY, 0, 0, 0);
37610696SDavid.Hollister@Sun.COM 	FILL_SCSI1_LUN(sd, pkt);
3770Sstevel@tonic-gate 	pkt->pkt_flags = FLAG_NOINTR|FLAG_NOPARITY;
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate 	if (scsi_poll(pkt) < 0) {
3800Sstevel@tonic-gate 		if (pkt->pkt_reason == CMD_INCOMPLETE)
3810Sstevel@tonic-gate 			rval = SCSIPROBE_NORESP;
3820Sstevel@tonic-gate 		else
3830Sstevel@tonic-gate 			rval = SCSIPROBE_FAILURE;
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate 		if ((pkt->pkt_state & STATE_ARQ_DONE) == 0) {
3864582Scth 			if (((struct scsi_status *)pkt->pkt_scbp)->sts_chk)
3874582Scth 				/*
3884582Scth 				 * scanner and processor devices can return a
3894582Scth 				 * check condition here
3904582Scth 				 */
39110696SDavid.Hollister@Sun.COM 				rval = scsi_slave_do_rqsense(sd, callback);
3920Sstevel@tonic-gate 		}
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 		if (rval != SCSIPROBE_EXISTS) {
3950Sstevel@tonic-gate 			scsi_destroy_pkt(pkt);
3960Sstevel@tonic-gate 			return (rval);
3970Sstevel@tonic-gate 		}
3980Sstevel@tonic-gate 	}
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate 	/*
4010Sstevel@tonic-gate 	 * the second test unit ready, allows the host adapter to negotiate
4020Sstevel@tonic-gate 	 * synchronous transfer period and offset
4030Sstevel@tonic-gate 	 */
4040Sstevel@tonic-gate 	if (scsi_poll(pkt) < 0) {
4050Sstevel@tonic-gate 		if (pkt->pkt_reason == CMD_INCOMPLETE)
4060Sstevel@tonic-gate 			rval = SCSIPROBE_NORESP;
4070Sstevel@tonic-gate 		else
4080Sstevel@tonic-gate 			rval = SCSIPROBE_FAILURE;
4090Sstevel@tonic-gate 	}
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate 	/*
4120Sstevel@tonic-gate 	 * do a rqsense if there was a check condition and ARQ was not done
4130Sstevel@tonic-gate 	 */
4140Sstevel@tonic-gate 	if ((pkt->pkt_state & STATE_ARQ_DONE) == 0) {
4150Sstevel@tonic-gate 		if (((struct scsi_status *)pkt->pkt_scbp)->sts_chk) {
41610696SDavid.Hollister@Sun.COM 			rval = scsi_slave_do_rqsense(sd, callback);
4170Sstevel@tonic-gate 		}
4180Sstevel@tonic-gate 	}
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate 	/*
4210Sstevel@tonic-gate 	 * call scsi_probe to do the inquiry
42210696SDavid.Hollister@Sun.COM 	 *
42310696SDavid.Hollister@Sun.COM 	 * NOTE: there is minor difference with the old scsi_slave
42410696SDavid.Hollister@Sun.COM 	 * implementation: busy conditions are not handled in scsi_probe.
4250Sstevel@tonic-gate 	 */
4260Sstevel@tonic-gate 	scsi_destroy_pkt(pkt);
4270Sstevel@tonic-gate 	if (rval == SCSIPROBE_EXISTS) {
42810696SDavid.Hollister@Sun.COM 		return (scsi_probe(sd, callback));
4290Sstevel@tonic-gate 	} else {
4300Sstevel@tonic-gate 		return (rval);
4310Sstevel@tonic-gate 	}
4320Sstevel@tonic-gate }
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate /*
4350Sstevel@tonic-gate  * Undo scsi_slave - older interface, but still supported
4368017SChris.Horne@Sun.COM  *
4378017SChris.Horne@Sun.COM  * NOTE: The 'sd_inq' inquiry data is now freed by scsi_hba/scsi_vhci code
4388017SChris.Horne@Sun.COM  * as part of free of scsi_device(9S).
4390Sstevel@tonic-gate  */
4408017SChris.Horne@Sun.COM /*ARGSUSED*/
4410Sstevel@tonic-gate void
scsi_unslave(struct scsi_device * sd)44210696SDavid.Hollister@Sun.COM scsi_unslave(struct scsi_device *sd)
4430Sstevel@tonic-gate {
4440Sstevel@tonic-gate }
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate /*
4470Sstevel@tonic-gate  * Undo scsi_probe
4488017SChris.Horne@Sun.COM  *
4498017SChris.Horne@Sun.COM  * NOTE: The 'sd_inq' inquiry data is now freed by scsi_hba/scsi_vhci code
4508017SChris.Horne@Sun.COM  * as part of free of scsi_device(9S).
4510Sstevel@tonic-gate  */
4528017SChris.Horne@Sun.COM /*ARGSUSED*/
4530Sstevel@tonic-gate void
scsi_unprobe(struct scsi_device * sd)45410696SDavid.Hollister@Sun.COM scsi_unprobe(struct scsi_device *sd)
4550Sstevel@tonic-gate {
4560Sstevel@tonic-gate }
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate /*
45912213SGavin.Maltby@Sun.COM  * We log all scsi_test failures (as long as we are SE_HP etc).  The
46012213SGavin.Maltby@Sun.COM  * following table controls the "driver-assessment" payload item
46112213SGavin.Maltby@Sun.COM  * in the ereports we raise.  If a scsi_test return features in the
46212213SGavin.Maltby@Sun.COM  * retry mask then the calling context will retry; if it features in
46312213SGavin.Maltby@Sun.COM  * the fatal mask then the caller will not retry (although higher-level
46412213SGavin.Maltby@Sun.COM  * software might); if in neither (which shouldn't happen - you either
46512213SGavin.Maltby@Sun.COM  * retry or give up) default to 'retry'.
46612213SGavin.Maltby@Sun.COM  */
46712213SGavin.Maltby@Sun.COM static const struct scsi_test_profile {
46812213SGavin.Maltby@Sun.COM 	enum scsi_test_ctxt stp_ctxt;	/* Calling context */
46912213SGavin.Maltby@Sun.COM 	uint32_t stp_retrymask;		/* Returns caller will retry for */
47012213SGavin.Maltby@Sun.COM 	uint32_t stp_fatalmask;		/* Returns caller considers fatal */
47112213SGavin.Maltby@Sun.COM } scsi_test_profile[] = {
47212213SGavin.Maltby@Sun.COM 	/*
47312213SGavin.Maltby@Sun.COM 	 * This caller will retry on SCSI_TEST_FAILMASK as long as it was
47412213SGavin.Maltby@Sun.COM 	 * not SCSI_TEST_CMD_INCOMPLETE which is terminal.  A return from
47512213SGavin.Maltby@Sun.COM 	 * SCSI_TEST_PARTCMPLTMASK (command complete but status other than
47612213SGavin.Maltby@Sun.COM 	 * STATUS_GOOD) is not terminal and we'll move on to the context
47712213SGavin.Maltby@Sun.COM 	 * of STC_PROBE_PARTIAL_SUCCESS so that's a retry, too.
47812213SGavin.Maltby@Sun.COM 	 */
47912213SGavin.Maltby@Sun.COM 	{
48012213SGavin.Maltby@Sun.COM 		STC_PROBE_FIRST_INQ,
48112213SGavin.Maltby@Sun.COM 		SCSI_TEST_FAILMASK & ~SCSI_TEST_CMD_INCOMPLETE |
48212213SGavin.Maltby@Sun.COM 		    SCSI_TEST_PARTCMPLTMASK,
48312213SGavin.Maltby@Sun.COM 		SCSI_TEST_CMD_INCOMPLETE
48412213SGavin.Maltby@Sun.COM 	},
48512213SGavin.Maltby@Sun.COM 
48612213SGavin.Maltby@Sun.COM 	/*
48712213SGavin.Maltby@Sun.COM 	 * If the first inquiry fails outright we always retry just once
48812213SGavin.Maltby@Sun.COM 	 * (except for SCSI_TEST_CMD_INCOMPLETE as above).  A return in
48912213SGavin.Maltby@Sun.COM 	 * SCSI_TEST_FAILMASK is terminal; for SCSI_TEST_PARTCMPLTMASK
49012213SGavin.Maltby@Sun.COM 	 * we will retry at STC_PROBE_PARTIAL_SUCCESS.
49112213SGavin.Maltby@Sun.COM 	 */
49212213SGavin.Maltby@Sun.COM 	{
49312213SGavin.Maltby@Sun.COM 		STC_PROBE_FIRST_INQ_RETRY,
49412213SGavin.Maltby@Sun.COM 		SCSI_TEST_PARTCMPLTMASK,
49512213SGavin.Maltby@Sun.COM 		SCSI_TEST_FAILMASK
49612213SGavin.Maltby@Sun.COM 	},
49712213SGavin.Maltby@Sun.COM 
49812213SGavin.Maltby@Sun.COM 	/*
49912213SGavin.Maltby@Sun.COM 	 * If we've met with partial success we retry at caller context
50012213SGavin.Maltby@Sun.COM 	 * STC_PROBE_PARTIAL_SUCCESS.  Any SCSI_TEST_FAILMASK return
50112213SGavin.Maltby@Sun.COM 	 * here is terminal, as too is SCSI_TEST_CMPLT_BUSY.  A return in
50212213SGavin.Maltby@Sun.COM 	 * SCSI_TEST_PARTCMPLTMASK and we will continue with further
50312213SGavin.Maltby@Sun.COM 	 * inquiry attempts.
50412213SGavin.Maltby@Sun.COM 	 */
50512213SGavin.Maltby@Sun.COM 	{
50612213SGavin.Maltby@Sun.COM 		STC_PROBE_PARTIAL_SUCCESS,
50712213SGavin.Maltby@Sun.COM 		SCSI_TEST_PARTCMPLTMASK & ~SCSI_TEST_CMPLT_BUSY,
50812213SGavin.Maltby@Sun.COM 		SCSI_TEST_FAILMASK | SCSI_TEST_CMPLT_BUSY
50912213SGavin.Maltby@Sun.COM 	},
51012213SGavin.Maltby@Sun.COM 
51112213SGavin.Maltby@Sun.COM 	/*
51212213SGavin.Maltby@Sun.COM 	 * If we get past the above target busy case then we will
51312213SGavin.Maltby@Sun.COM 	 * perform a sense request if scsi_test indicates STATUS_CHECK
51412213SGavin.Maltby@Sun.COM 	 * and ARQ was not done.  We are not interested in logging telemetry
51512213SGavin.Maltby@Sun.COM 	 * for transports that do not perform ARQ automatically.
51612213SGavin.Maltby@Sun.COM 	 */
51712213SGavin.Maltby@Sun.COM 	{
51812213SGavin.Maltby@Sun.COM 		STC_PROBE_RQSENSE1,
51912213SGavin.Maltby@Sun.COM 		0,
52012213SGavin.Maltby@Sun.COM 		0
52112213SGavin.Maltby@Sun.COM 	},
52212213SGavin.Maltby@Sun.COM 
52312213SGavin.Maltby@Sun.COM 	/*
52412213SGavin.Maltby@Sun.COM 	 * If "something" responded to the probe but then the next inquiry
52512213SGavin.Maltby@Sun.COM 	 * sees a change of heart then we fail the probe on any of
52612213SGavin.Maltby@Sun.COM 	 * SCSI_TEST_FAILMASK or SCSI_TEST_CMPLT_BUSY.  For other values
52712213SGavin.Maltby@Sun.COM 	 * in SCSI_TEST_PARTCMPLTMASK we soldier on.
52812213SGavin.Maltby@Sun.COM 	 */
52912213SGavin.Maltby@Sun.COM 	{
53012213SGavin.Maltby@Sun.COM 		STC_PROBE_CHK_CLEARED,
53112213SGavin.Maltby@Sun.COM 		SCSI_TEST_PARTCMPLTMASK & ~SCSI_TEST_CMPLT_BUSY,
53212213SGavin.Maltby@Sun.COM 		SCSI_TEST_FAILMASK | SCSI_TEST_CMPLT_BUSY
53312213SGavin.Maltby@Sun.COM 	},
53412213SGavin.Maltby@Sun.COM 
53512213SGavin.Maltby@Sun.COM 	/*
53612213SGavin.Maltby@Sun.COM 	 * If after all that there we still have STATUS_CHECK from the
53712213SGavin.Maltby@Sun.COM 	 * inquiry status then we resend the sense request but the
53812213SGavin.Maltby@Sun.COM 	 * result is ignored (just clearing the condition).  Do not
53912213SGavin.Maltby@Sun.COM 	 * log.
54012213SGavin.Maltby@Sun.COM 	 */
54112213SGavin.Maltby@Sun.COM 	{
54212213SGavin.Maltby@Sun.COM 		STC_PROBE_RQSENSE2,
54312213SGavin.Maltby@Sun.COM 		0,
54412213SGavin.Maltby@Sun.COM 		0
54512213SGavin.Maltby@Sun.COM 	},
54612213SGavin.Maltby@Sun.COM 
54712213SGavin.Maltby@Sun.COM 	/*
54812213SGavin.Maltby@Sun.COM 	 * After the above sense request we once again send an inquiry.
54912213SGavin.Maltby@Sun.COM 	 * If it fails outright or STATUS_CHECK persists we give up.
55012213SGavin.Maltby@Sun.COM 	 * Any partial result is considered success.
55112213SGavin.Maltby@Sun.COM 	 */
55212213SGavin.Maltby@Sun.COM 	{
55312213SGavin.Maltby@Sun.COM 		STC_PROBE_INQ_FINAL,
55412213SGavin.Maltby@Sun.COM 		0,
55512213SGavin.Maltby@Sun.COM 		SCSI_TEST_FAILMASK | SCSI_TEST_CMPLT_CHECK
55612213SGavin.Maltby@Sun.COM 	},
55712213SGavin.Maltby@Sun.COM 
55812213SGavin.Maltby@Sun.COM 	/*
55912213SGavin.Maltby@Sun.COM 	 * check_vpd_page_support8083 called from scsi_device_identity
56012213SGavin.Maltby@Sun.COM 	 * performs an inquiry with EVPD set (and page necessarily 0)
56112213SGavin.Maltby@Sun.COM 	 * to see what pages are supported.
56212213SGavin.Maltby@Sun.COM 	 *
56312213SGavin.Maltby@Sun.COM 	 * Some devices do not support this command and therefore
56412213SGavin.Maltby@Sun.COM 	 * check_vpd_page_support8083 only returns an error of kmem_zalloc
56512213SGavin.Maltby@Sun.COM 	 * fails.  If the send_scsi_INQUIRY does not meet with complete
56612213SGavin.Maltby@Sun.COM 	 * success (SCSI_TEST_CMPLT_GOOD) it returns -1, othewise 0.
56712213SGavin.Maltby@Sun.COM 	 * So any scsi_test failure here will cause us to assume no page
56812213SGavin.Maltby@Sun.COM 	 * 80/83 support, and we will proceed without devid support.
56912213SGavin.Maltby@Sun.COM 	 * So -1 returns from send_scsi_INQUIRY are not terminal.
57012213SGavin.Maltby@Sun.COM 	 */
57112213SGavin.Maltby@Sun.COM 	{
57212213SGavin.Maltby@Sun.COM 		STC_VPD_CHECK,
57312213SGavin.Maltby@Sun.COM 		0,
57412213SGavin.Maltby@Sun.COM 		0
57512213SGavin.Maltby@Sun.COM 	},
57612213SGavin.Maltby@Sun.COM 
57712213SGavin.Maltby@Sun.COM 	/*
57812213SGavin.Maltby@Sun.COM 	 * If the above inquiry claims pg80 support then scsi_device_identity
57912213SGavin.Maltby@Sun.COM 	 * will perform a send_scsi_INQUIRY to retrieve that page.
58012213SGavin.Maltby@Sun.COM 	 * Anything other than SCSI_TEST_CMPLT_GOOD is a failure and will
58112213SGavin.Maltby@Sun.COM 	 * cause scsi_device_identity to return non-zero at which point the
58212213SGavin.Maltby@Sun.COM 	 * caller goes to SCSIPROBE_FAILURE.
58312213SGavin.Maltby@Sun.COM 	 */
58412213SGavin.Maltby@Sun.COM 	{
58512213SGavin.Maltby@Sun.COM 		STC_IDENTITY_PG80,
58612213SGavin.Maltby@Sun.COM 		0,
58712213SGavin.Maltby@Sun.COM 		SCSI_TEST_FAILMASK | SCSI_TEST_CMPLTMASK
58812213SGavin.Maltby@Sun.COM 	},
58912213SGavin.Maltby@Sun.COM 
59012213SGavin.Maltby@Sun.COM 	/*
59112213SGavin.Maltby@Sun.COM 	 * Similarly for pg83
59212213SGavin.Maltby@Sun.COM 	 */
59312213SGavin.Maltby@Sun.COM 	{
59412213SGavin.Maltby@Sun.COM 		STC_IDENTITY_PG83,
59512213SGavin.Maltby@Sun.COM 		0,
59612213SGavin.Maltby@Sun.COM 		SCSI_TEST_FAILMASK | SCSI_TEST_CMPLTMASK
59712213SGavin.Maltby@Sun.COM 	}
59812213SGavin.Maltby@Sun.COM };
59912213SGavin.Maltby@Sun.COM 
60012213SGavin.Maltby@Sun.COM int scsi_test_ereport_disable = 0;
60112213SGavin.Maltby@Sun.COM 
60212213SGavin.Maltby@Sun.COM extern int e_devid_cache_path_to_devid(char *, char *, char *, ddi_devid_t *);
60312213SGavin.Maltby@Sun.COM 
60412213SGavin.Maltby@Sun.COM static void
scsi_test_ereport_post(struct scsi_pkt * pkt,enum scsi_test_ctxt ctxt,uint32_t stresult)60512213SGavin.Maltby@Sun.COM scsi_test_ereport_post(struct scsi_pkt *pkt, enum scsi_test_ctxt ctxt,
60612213SGavin.Maltby@Sun.COM     uint32_t stresult)
60712213SGavin.Maltby@Sun.COM {
60812213SGavin.Maltby@Sun.COM 	char *nodename = NULL, *devidstr_buf = NULL, *devidstr = NULL;
60912213SGavin.Maltby@Sun.COM 	const struct scsi_test_profile *tp = &scsi_test_profile[ctxt];
61012213SGavin.Maltby@Sun.COM 	char ua[SCSI_MAXNAMELEN], nodenamebuf[SCSI_MAXNAMELEN];
61112213SGavin.Maltby@Sun.COM 	union scsi_cdb *cdbp = (union scsi_cdb *)pkt->pkt_cdbp;
61212213SGavin.Maltby@Sun.COM 	struct scsi_address *ap = &pkt->pkt_address;
61312213SGavin.Maltby@Sun.COM 	char *tgt_port, *tpl0 = NULL;
61412213SGavin.Maltby@Sun.COM 	ddi_devid_t devid = NULL;
61512213SGavin.Maltby@Sun.COM 	dev_info_t *probe, *hba;
61612213SGavin.Maltby@Sun.COM 	struct scsi_device *sd;
61712213SGavin.Maltby@Sun.COM 	scsi_lun64_t lun64;
61812213SGavin.Maltby@Sun.COM 	const char *d_ass;
61912213SGavin.Maltby@Sun.COM 	const char *class;
62012213SGavin.Maltby@Sun.COM 	char *pathbuf;
62112213SGavin.Maltby@Sun.COM 	nvlist_t *pl;
62212213SGavin.Maltby@Sun.COM 	uint64_t wwn;
62312213SGavin.Maltby@Sun.COM 	int err = 0;
62412213SGavin.Maltby@Sun.COM 	int dad = 0;
62512213SGavin.Maltby@Sun.COM 	size_t len;
62612213SGavin.Maltby@Sun.COM 	int lun;
62712213SGavin.Maltby@Sun.COM 
62812213SGavin.Maltby@Sun.COM 	if (scsi_test_ereport_disable)
62912213SGavin.Maltby@Sun.COM 		return;
63012213SGavin.Maltby@Sun.COM 
63112213SGavin.Maltby@Sun.COM 	ASSERT(tp->stp_ctxt == ctxt);
63212213SGavin.Maltby@Sun.COM 
63312213SGavin.Maltby@Sun.COM 	if ((sd = scsi_address_device(ap)) == NULL)
63412213SGavin.Maltby@Sun.COM 		return;		/* Not SCSI_HBA_ADDR_COMPLEX */
63512213SGavin.Maltby@Sun.COM 
63612213SGavin.Maltby@Sun.COM 	probe = sd->sd_dev;
63712213SGavin.Maltby@Sun.COM 	hba = ddi_get_parent(probe);
63812213SGavin.Maltby@Sun.COM 
63912213SGavin.Maltby@Sun.COM 	/*
64012213SGavin.Maltby@Sun.COM 	 * We only raise telemetry for SE_HP style enumeration
64112213SGavin.Maltby@Sun.COM 	 */
64212213SGavin.Maltby@Sun.COM 	if (!ndi_dev_is_hotplug_node(hba))
64312213SGavin.Maltby@Sun.COM 		return;
64412213SGavin.Maltby@Sun.COM 
64512213SGavin.Maltby@Sun.COM 	/*
64612213SGavin.Maltby@Sun.COM 	 * scsi_fm_ereport_post will use the hba for the fm-enabled devinfo
64712213SGavin.Maltby@Sun.COM 	 */
64812213SGavin.Maltby@Sun.COM 	if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(hba)))
64912213SGavin.Maltby@Sun.COM 		return;
65012213SGavin.Maltby@Sun.COM 
65112213SGavin.Maltby@Sun.COM 	/*
65212213SGavin.Maltby@Sun.COM 	 * Retrieve the unit address we were probing and the target
65312213SGavin.Maltby@Sun.COM 	 * port component thereof.
65412213SGavin.Maltby@Sun.COM 	 */
65512213SGavin.Maltby@Sun.COM 	if (!scsi_ua_get(sd, ua, sizeof (ua)) ||
65612213SGavin.Maltby@Sun.COM 	    scsi_device_prop_lookup_string(sd, SCSI_DEVICE_PROP_PATH,
65712213SGavin.Maltby@Sun.COM 	    SCSI_ADDR_PROP_TARGET_PORT, &tgt_port) != DDI_PROP_SUCCESS)
65812213SGavin.Maltby@Sun.COM 		return;
65912213SGavin.Maltby@Sun.COM 
66012213SGavin.Maltby@Sun.COM 	/*
66112213SGavin.Maltby@Sun.COM 	 * Determine whether unit address is location based or identity (wwn)
66212213SGavin.Maltby@Sun.COM 	 * based.  If we can't convert the target port address to a wwn then
66312213SGavin.Maltby@Sun.COM 	 * we're location based.
66412213SGavin.Maltby@Sun.COM 	 */
66512213SGavin.Maltby@Sun.COM 	if (scsi_wwnstr_to_wwn(tgt_port, &wwn) == DDI_FAILURE)
66612213SGavin.Maltby@Sun.COM 		return;
66712213SGavin.Maltby@Sun.COM 
66812213SGavin.Maltby@Sun.COM 	/*
66912213SGavin.Maltby@Sun.COM 	 * Get lun and lun64
67012213SGavin.Maltby@Sun.COM 	 */
67112213SGavin.Maltby@Sun.COM 	lun = scsi_device_prop_get_int(sd, SCSI_DEVICE_PROP_PATH,
67212213SGavin.Maltby@Sun.COM 	    SCSI_ADDR_PROP_LUN, 0);
67312213SGavin.Maltby@Sun.COM 	lun64 = scsi_device_prop_get_int64(sd, SCSI_DEVICE_PROP_PATH,
67412213SGavin.Maltby@Sun.COM 	    SCSI_ADDR_PROP_LUN64, lun);
67512213SGavin.Maltby@Sun.COM 
67612213SGavin.Maltby@Sun.COM 	/*
67712213SGavin.Maltby@Sun.COM 	 * We are guaranteed not to be in interrupt or any other
67812213SGavin.Maltby@Sun.COM 	 * problematic context.  So instead of repeated varargs
67912213SGavin.Maltby@Sun.COM 	 * style calls to scsi_fm_ereport_post for each flavour of
68012213SGavin.Maltby@Sun.COM 	 * ereport we have the luxury of being able to allocate
68112213SGavin.Maltby@Sun.COM 	 * and build an nvlist here.
68212213SGavin.Maltby@Sun.COM 	 *
68312213SGavin.Maltby@Sun.COM 	 * The ereports we raise here are all under the category
68412213SGavin.Maltby@Sun.COM 	 * ereport.io.scsi.cmd.disk category, namely
68512213SGavin.Maltby@Sun.COM 	 *
68612213SGavin.Maltby@Sun.COM 	 *	ereport.io.scsi.cmd.disk.
68712213SGavin.Maltby@Sun.COM 	 *			{dev.rqs.derr,dev.serr,tran}.
68812213SGavin.Maltby@Sun.COM 	 *
68912213SGavin.Maltby@Sun.COM 	 * For all ereports we also add the scsi_test specific payload.
69012213SGavin.Maltby@Sun.COM 	 * If we have it then we always include the devid in the payload
69112213SGavin.Maltby@Sun.COM 	 * (but only in the detector for device-as-detector ereports).
69212213SGavin.Maltby@Sun.COM 	 *
69312213SGavin.Maltby@Sun.COM 	 * Inherited From	Member Name
69412213SGavin.Maltby@Sun.COM 	 * -------------------- -------------------
69512213SGavin.Maltby@Sun.COM 	 *	.cmd		driver-assessment
69612213SGavin.Maltby@Sun.COM 	 *	.cmd		op-code
69712213SGavin.Maltby@Sun.COM 	 *	.cmd		cdb
69812213SGavin.Maltby@Sun.COM 	 *	.cmd		pkt-reason
69912213SGavin.Maltby@Sun.COM 	 *	.cmd		pkt-state
70012213SGavin.Maltby@Sun.COM 	 *	.cmd		pkt-stats
70112213SGavin.Maltby@Sun.COM 	 *	.cmd.disk	stat-code
70212213SGavin.Maltby@Sun.COM 	 *	-		scsi-test-return
70312213SGavin.Maltby@Sun.COM 	 *	-		scsi-test-context
70412213SGavin.Maltby@Sun.COM 	 */
70512213SGavin.Maltby@Sun.COM 
70612213SGavin.Maltby@Sun.COM 	if (nvlist_alloc(&pl, NV_UNIQUE_NAME, 0) != 0)
70712213SGavin.Maltby@Sun.COM 		return;
70812213SGavin.Maltby@Sun.COM 
70912213SGavin.Maltby@Sun.COM 	err |= nvlist_add_uint8(pl, "op-code", cdbp->scc_cmd);
71012213SGavin.Maltby@Sun.COM 	err |= nvlist_add_uint8_array(pl, "cdb", pkt->pkt_cdbp,
71112213SGavin.Maltby@Sun.COM 	    pkt->pkt_cdblen);
71212213SGavin.Maltby@Sun.COM 	err |= nvlist_add_uint8(pl, "pkt-reason", pkt->pkt_reason);
71312213SGavin.Maltby@Sun.COM 	err |= nvlist_add_uint32(pl, "pkt-state", pkt->pkt_state);
71412213SGavin.Maltby@Sun.COM 	err |= nvlist_add_uint32(pl, "pkt-stats", pkt->pkt_statistics);
71512213SGavin.Maltby@Sun.COM 	err |= nvlist_add_uint32(pl, "stat-code", *pkt->pkt_scbp);
71612213SGavin.Maltby@Sun.COM 	err |= nvlist_add_uint32(pl, "scsi-test-return", stresult);
71712213SGavin.Maltby@Sun.COM 	err |= nvlist_add_int32(pl, "scsi-test-context", ctxt);
71812213SGavin.Maltby@Sun.COM 
71912213SGavin.Maltby@Sun.COM 	switch (stresult) {
72012213SGavin.Maltby@Sun.COM 	case SCSI_TEST_CMPLT_BUSY:
72112213SGavin.Maltby@Sun.COM 		dad = 1;
72212213SGavin.Maltby@Sun.COM 		class = "cmd.disk.dev.serr";
72312213SGavin.Maltby@Sun.COM 		break;
72412213SGavin.Maltby@Sun.COM 
72512213SGavin.Maltby@Sun.COM 	case SCSI_TEST_CMPLT_CHECK:
72612213SGavin.Maltby@Sun.COM 		dad = 1;
72712213SGavin.Maltby@Sun.COM 
72812213SGavin.Maltby@Sun.COM 		if ((pkt->pkt_state & STATE_ARQ_DONE)) {
72912213SGavin.Maltby@Sun.COM 			struct scsi_arq_status *arqstat;
73012213SGavin.Maltby@Sun.COM 			uint8_t key, asc, ascq;
73112213SGavin.Maltby@Sun.COM 			uint8_t *sensep;
73212213SGavin.Maltby@Sun.COM 
73312213SGavin.Maltby@Sun.COM 			class = "cmd.disk.dev.rqs.derr";
73412213SGavin.Maltby@Sun.COM 			arqstat = (struct scsi_arq_status *)pkt->pkt_scbp;
73512213SGavin.Maltby@Sun.COM 			sensep = (uint8_t *)&arqstat->sts_sensedata;
73612213SGavin.Maltby@Sun.COM 			key = scsi_sense_key(sensep);
73712213SGavin.Maltby@Sun.COM 			asc = scsi_sense_asc(sensep);
73812213SGavin.Maltby@Sun.COM 			ascq = scsi_sense_ascq(sensep);
73912213SGavin.Maltby@Sun.COM 
74012213SGavin.Maltby@Sun.COM 			/*
74112213SGavin.Maltby@Sun.COM 			 * Add to payload.
74212213SGavin.Maltby@Sun.COM 			 */
74312213SGavin.Maltby@Sun.COM 			err |= nvlist_add_uint8(pl, "key", key);
74412213SGavin.Maltby@Sun.COM 			err |= nvlist_add_uint8(pl, "asc", asc);
74512213SGavin.Maltby@Sun.COM 			err |= nvlist_add_uint8(pl, "ascq", ascq);
74612213SGavin.Maltby@Sun.COM 			err |= nvlist_add_uint8_array(pl, "sense-data",
74712213SGavin.Maltby@Sun.COM 			    sensep, sizeof (arqstat->sts_sensedata));
74812213SGavin.Maltby@Sun.COM 		} else {
74912213SGavin.Maltby@Sun.COM 			class = "cmd.disk.dev.serr";
75012213SGavin.Maltby@Sun.COM 		}
75112213SGavin.Maltby@Sun.COM 
75212213SGavin.Maltby@Sun.COM 		break;
75312213SGavin.Maltby@Sun.COM 
75412213SGavin.Maltby@Sun.COM 	case SCSI_TEST_CMPLT_OTHER:
75512213SGavin.Maltby@Sun.COM 		dad = 1;
75612213SGavin.Maltby@Sun.COM 		class = "cmd.disk.dev.serr";
75712213SGavin.Maltby@Sun.COM 		break;
75812213SGavin.Maltby@Sun.COM 
75912213SGavin.Maltby@Sun.COM 	case SCSI_TEST_CMD_INCOMPLETE:
76012213SGavin.Maltby@Sun.COM 	case SCSI_TEST_NOTCMPLT:
76112213SGavin.Maltby@Sun.COM 	case SCSI_TEST_TRAN_BUSY:
76212213SGavin.Maltby@Sun.COM 	case SCSI_TEST_TRAN_REJECT:
76312213SGavin.Maltby@Sun.COM 		class = "cmd.disk.tran";
76412213SGavin.Maltby@Sun.COM 		break;
76512213SGavin.Maltby@Sun.COM 	}
76612213SGavin.Maltby@Sun.COM 
76712213SGavin.Maltby@Sun.COM 	/*
76812213SGavin.Maltby@Sun.COM 	 * Determine driver-assessment and add to payload.
76912213SGavin.Maltby@Sun.COM 	 */
77012213SGavin.Maltby@Sun.COM 	if (dad) {
77112213SGavin.Maltby@Sun.COM 		/*
77212213SGavin.Maltby@Sun.COM 		 * While higher level software can retry the enumeration
77312213SGavin.Maltby@Sun.COM 		 * the belief is that any device-as-detector style error
77412213SGavin.Maltby@Sun.COM 		 * will be persistent and will survive retries.  So we
77512213SGavin.Maltby@Sun.COM 		 * can make a local determination of driver assessment.
77612213SGavin.Maltby@Sun.COM 		 * Some day it may be more elegant to raise an ereport from
77712213SGavin.Maltby@Sun.COM 		 * scsi_tgtmap_scsi_deactivate to confirm retries failed,
77812213SGavin.Maltby@Sun.COM 		 * and correlate that ereport during diagnosis.
77912213SGavin.Maltby@Sun.COM 		 */
78012213SGavin.Maltby@Sun.COM 		if (stresult & tp->stp_fatalmask)
78112213SGavin.Maltby@Sun.COM 			d_ass = (const char *)"fatal";
78212213SGavin.Maltby@Sun.COM 		else if (stresult & tp->stp_retrymask)
78312213SGavin.Maltby@Sun.COM 			d_ass = (const char *)"retry";
78412213SGavin.Maltby@Sun.COM 		else
78512213SGavin.Maltby@Sun.COM 			d_ass = (const char *)"retry";
78612213SGavin.Maltby@Sun.COM 	} else {
78712213SGavin.Maltby@Sun.COM 		/* We do not diagnose transport errors (yet) */
78812213SGavin.Maltby@Sun.COM 			d_ass = (const char *)"retry";
78912213SGavin.Maltby@Sun.COM 	}
79012213SGavin.Maltby@Sun.COM 
79112213SGavin.Maltby@Sun.COM 	err |= nvlist_add_string(pl, "driver-assessment", d_ass);
79212213SGavin.Maltby@Sun.COM 
79312213SGavin.Maltby@Sun.COM 	/*
79412213SGavin.Maltby@Sun.COM 	 * If we're hoping for a device-as-detector style ereport then
79512213SGavin.Maltby@Sun.COM 	 * we're going to need a devid for the detector FMRI.  We
79612213SGavin.Maltby@Sun.COM 	 * don't have the devid because the target won't talk to us.
79712213SGavin.Maltby@Sun.COM 	 * But we do know which hba iport we were probing out of, and
79812213SGavin.Maltby@Sun.COM 	 * we know the unit address that was being probed (but not
79912213SGavin.Maltby@Sun.COM 	 * what type of device is or should be there).  So we
80012213SGavin.Maltby@Sun.COM 	 * search the devid cache for any cached devid matching
80112213SGavin.Maltby@Sun.COM 	 * path <iport-path>/<nodename>@<unit-address> with nodename
80212213SGavin.Maltby@Sun.COM 	 * wildcarded.  If a match is made we are returned not only the
80312213SGavin.Maltby@Sun.COM 	 * devid but also the nodename for the path that cached that
80412213SGavin.Maltby@Sun.COM 	 * entry.
80512213SGavin.Maltby@Sun.COM 	 *
80612213SGavin.Maltby@Sun.COM 	 * We also attempt to dig up a devid even for transport errors;
80712213SGavin.Maltby@Sun.COM 	 * we'll include that in the payload but not in the detector FMRI.
80812213SGavin.Maltby@Sun.COM 	 */
80912213SGavin.Maltby@Sun.COM 
81012213SGavin.Maltby@Sun.COM 	pathbuf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
81112213SGavin.Maltby@Sun.COM 	(void) ddi_pathname(hba, pathbuf);
81212213SGavin.Maltby@Sun.COM 
81312213SGavin.Maltby@Sun.COM 	if (e_devid_cache_path_to_devid(pathbuf, ua, nodenamebuf,
81412213SGavin.Maltby@Sun.COM 	    &devid) == DDI_SUCCESS) {
81512213SGavin.Maltby@Sun.COM 		nodename = nodenamebuf;
81612213SGavin.Maltby@Sun.COM 		devidstr = devidstr_buf = ddi_devid_str_encode(devid, NULL);
81712213SGavin.Maltby@Sun.COM 		kmem_free(devid, ddi_devid_sizeof(devid));
81812213SGavin.Maltby@Sun.COM 		err |= nvlist_add_string(pl, "devid", devidstr);
81912213SGavin.Maltby@Sun.COM 	}
82012213SGavin.Maltby@Sun.COM 
82112213SGavin.Maltby@Sun.COM 	/*
82212213SGavin.Maltby@Sun.COM 	 * If this is lun 0 we will include the target-port-l0id
82312213SGavin.Maltby@Sun.COM 	 * in the dev scheme detector for device-as-detector.
82412213SGavin.Maltby@Sun.COM 	 */
82512213SGavin.Maltby@Sun.COM 	if (dad && (lun == 0 || lun64 == 0))
82612213SGavin.Maltby@Sun.COM 		tpl0 = tgt_port;
82712213SGavin.Maltby@Sun.COM 
82812213SGavin.Maltby@Sun.COM 	/* Construct the devpath to use in the detector */
82912213SGavin.Maltby@Sun.COM 	(void) ddi_pathname(hba, pathbuf);
83012213SGavin.Maltby@Sun.COM 	len = strlen(pathbuf);
83112213SGavin.Maltby@Sun.COM 	(void) snprintf(pathbuf + len, MAXPATHLEN - len, "/%s@%s",
83212213SGavin.Maltby@Sun.COM 	    nodename ? nodename : "unknown", ua);
83312213SGavin.Maltby@Sun.COM 
83412213SGavin.Maltby@Sun.COM 	/*
83512213SGavin.Maltby@Sun.COM 	 * Let's review.
83612213SGavin.Maltby@Sun.COM 	 *
83712213SGavin.Maltby@Sun.COM 	 * Device-as-detector ereports for which the attempted lookup of
83812213SGavin.Maltby@Sun.COM 	 * devid and nodename succeeded:
83912213SGavin.Maltby@Sun.COM 	 *
84012213SGavin.Maltby@Sun.COM 	 *	- pathbuf has the full device path including nodename we
84112213SGavin.Maltby@Sun.COM 	 *	  dug up from the devid cache
84212213SGavin.Maltby@Sun.COM 	 *
84312213SGavin.Maltby@Sun.COM 	 *	- class is one of cmd.disk.{dev.rqs.derr,dev.serr}
84412213SGavin.Maltby@Sun.COM 	 *
84512213SGavin.Maltby@Sun.COM 	 *	- devidstr is non NULL and a valid devid string
84612213SGavin.Maltby@Sun.COM 	 *
84712213SGavin.Maltby@Sun.COM 	 * Would-be device-as-detector ereport for which the attempted lookup
84812213SGavin.Maltby@Sun.COM 	 * of devid failed:
84912213SGavin.Maltby@Sun.COM 	 *
85012213SGavin.Maltby@Sun.COM 	 *	- pathbuf has a device path with leaf nodename of "unknown"
85112213SGavin.Maltby@Sun.COM 	 *	  but still including the unit-address
85212213SGavin.Maltby@Sun.COM 	 *	- class is one of cmd.disk.{dev.rqs.derr,dev.serr}
85312213SGavin.Maltby@Sun.COM 	 *
85412213SGavin.Maltby@Sun.COM 	 * Transport errors:
85512213SGavin.Maltby@Sun.COM 	 *
85612213SGavin.Maltby@Sun.COM 	 *	class is cmd.disk.tran
85712213SGavin.Maltby@Sun.COM 	 *	devidstr is NULL
85812213SGavin.Maltby@Sun.COM 	 *
85912213SGavin.Maltby@Sun.COM 	 *	- we may have succeeded in looking up a devid and nodename -
86012213SGavin.Maltby@Sun.COM 	 *	  the devid we'll have added to the payload but we must not
86112213SGavin.Maltby@Sun.COM 	 *	  add to detector FMRI, and if we have have nodename then
86212213SGavin.Maltby@Sun.COM 	 *	  we have a full devpath otherwise one with "unknown" for
86312213SGavin.Maltby@Sun.COM 	 *	  nodename
86412213SGavin.Maltby@Sun.COM 	 */
86512213SGavin.Maltby@Sun.COM 
86612213SGavin.Maltby@Sun.COM 	if (err)
86712213SGavin.Maltby@Sun.COM 		(void) nvlist_add_boolean_value(pl, "payload-incomplete",
86812213SGavin.Maltby@Sun.COM 		    B_TRUE);
86912213SGavin.Maltby@Sun.COM 
87012213SGavin.Maltby@Sun.COM 	scsi_fm_ereport_post(
87112213SGavin.Maltby@Sun.COM 	    sd,
87212213SGavin.Maltby@Sun.COM 	    0,				/* path_instance - always 0 */
87312213SGavin.Maltby@Sun.COM 	    pathbuf,			/* devpath for detector */
87412213SGavin.Maltby@Sun.COM 	    class,			/* ereport class suffix */
87512213SGavin.Maltby@Sun.COM 	    0,				/* ENA - generate for us */
87612213SGavin.Maltby@Sun.COM 	    dad ? devidstr : NULL,	/* dtcr devid, dev-as-det only */
87712213SGavin.Maltby@Sun.COM 	    tpl0,			/* target-port-l0id */
87812213SGavin.Maltby@Sun.COM 	    DDI_SLEEP,
87912213SGavin.Maltby@Sun.COM 	    pl, /* preconstructed payload */
88012213SGavin.Maltby@Sun.COM 	    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0,
88112213SGavin.Maltby@Sun.COM 	    NULL);
88212213SGavin.Maltby@Sun.COM 
88312213SGavin.Maltby@Sun.COM 	nvlist_free(pl);
88412213SGavin.Maltby@Sun.COM 	if (devidstr_buf)
88512213SGavin.Maltby@Sun.COM 		ddi_devid_str_free(devidstr_buf);
88612213SGavin.Maltby@Sun.COM 	kmem_free(pathbuf, MAXPATHLEN);
88712213SGavin.Maltby@Sun.COM }
88812213SGavin.Maltby@Sun.COM 
88912213SGavin.Maltby@Sun.COM #ifdef	DEBUG
89012213SGavin.Maltby@Sun.COM /*
89112213SGavin.Maltby@Sun.COM  * Testing - fake scsi_test fails
89212213SGavin.Maltby@Sun.COM  */
89312213SGavin.Maltby@Sun.COM char scsi_test_fail_ua[SCSI_MAXNAMELEN];	/* unit address to object to */
89412213SGavin.Maltby@Sun.COM int scsi_test_fail_rc = TRAN_ACCEPT;		/* scsi_transport return */
89512213SGavin.Maltby@Sun.COM uchar_t scsi_test_fail_pkt_reason = CMD_CMPLT;	/* pkt_reason */
89612213SGavin.Maltby@Sun.COM uchar_t scsi_test_fail_status = STATUS_BUSY;	/* status */
89712213SGavin.Maltby@Sun.COM uint_t scsi_test_fail_repeat = (uint_t)-1;	/* number of times to fail ua */
89812213SGavin.Maltby@Sun.COM #endif
89912213SGavin.Maltby@Sun.COM 
90012213SGavin.Maltby@Sun.COM /*
9010Sstevel@tonic-gate  * This is like scsi_poll, but only does retry for TRAN_BUSY.
9020Sstevel@tonic-gate  */
90312213SGavin.Maltby@Sun.COM static uint32_t
scsi_test(struct scsi_pkt * pkt,enum scsi_test_ctxt ctxt)90412213SGavin.Maltby@Sun.COM scsi_test(struct scsi_pkt *pkt, enum scsi_test_ctxt ctxt)
9050Sstevel@tonic-gate {
90612213SGavin.Maltby@Sun.COM 	uint32_t	rval;
9070Sstevel@tonic-gate 	int		wait_usec;
9080Sstevel@tonic-gate 	int		rc;
9090Sstevel@tonic-gate 	extern int	do_polled_io;
9100Sstevel@tonic-gate 
9110Sstevel@tonic-gate 	pkt->pkt_flags |= FLAG_NOINTR;
9120Sstevel@tonic-gate 	pkt->pkt_time = SCSI_POLL_TIMEOUT;	/* in seconds */
9130Sstevel@tonic-gate 
9140Sstevel@tonic-gate 	if (scsi_ifgetcap(&pkt->pkt_address, "tagged-qing", 1) == 1) {
9150Sstevel@tonic-gate 		pkt->pkt_flags |= FLAG_STAG;
9160Sstevel@tonic-gate 	}
9170Sstevel@tonic-gate 
9180Sstevel@tonic-gate 	/*
9190Sstevel@tonic-gate 	 * Each TRAN_BUSY response waits scsi_test_busy_delay usec up to a
9200Sstevel@tonic-gate 	 * maximum of scsi_test_busy_timeout.
9210Sstevel@tonic-gate 	 */
9220Sstevel@tonic-gate 	for (wait_usec = 0; (wait_usec / 1000000) <= scsi_test_busy_timeout;
9230Sstevel@tonic-gate 	    wait_usec += scsi_test_busy_delay) {
9240Sstevel@tonic-gate 
9250Sstevel@tonic-gate 		/* Initialize pkt status variables */
9260Sstevel@tonic-gate 		*pkt->pkt_scbp = pkt->pkt_reason = pkt->pkt_state = 0;
9270Sstevel@tonic-gate 
9280Sstevel@tonic-gate 		rc = scsi_transport(pkt);
9290Sstevel@tonic-gate 		if ((rc != TRAN_BUSY) || (scsi_test_busy_delay == 0) ||
9300Sstevel@tonic-gate 		    (scsi_test_busy_timeout == 0))
9310Sstevel@tonic-gate 			break;
9320Sstevel@tonic-gate 
9330Sstevel@tonic-gate 		/* transport busy, wait */
9340Sstevel@tonic-gate 		if ((curthread->t_flag & T_INTR_THREAD) == 0 && !do_polled_io) {
9350Sstevel@tonic-gate 			delay(drv_usectohz(scsi_test_busy_delay));
9360Sstevel@tonic-gate 		} else {
9370Sstevel@tonic-gate 			/* we busy wait during cpr_dump or interrupt threads */
9380Sstevel@tonic-gate 			drv_usecwait(scsi_test_busy_delay);
9390Sstevel@tonic-gate 		}
9400Sstevel@tonic-gate 	}
9410Sstevel@tonic-gate 
94212213SGavin.Maltby@Sun.COM #ifdef	DEBUG
94312213SGavin.Maltby@Sun.COM 	if (scsi_test_fail_ua[0] != '\0' && scsi_test_fail_repeat > 0) {
94412213SGavin.Maltby@Sun.COM 		struct scsi_address *ap = &pkt->pkt_address;
94512213SGavin.Maltby@Sun.COM 		struct scsi_device *sd;
94612213SGavin.Maltby@Sun.COM 		dev_info_t *probe;
94712213SGavin.Maltby@Sun.COM 		char ua[SCSI_MAXNAMELEN];
94812213SGavin.Maltby@Sun.COM 
94912213SGavin.Maltby@Sun.COM 		if ((sd = scsi_address_device(ap)) != NULL) {
95012213SGavin.Maltby@Sun.COM 			probe = sd->sd_dev;
95112213SGavin.Maltby@Sun.COM 
95212213SGavin.Maltby@Sun.COM 			if (probe && scsi_ua_get(sd, ua, sizeof (ua)) &&
95312213SGavin.Maltby@Sun.COM 			    strncmp(ua, scsi_test_fail_ua, sizeof (ua)) == 0) {
95412213SGavin.Maltby@Sun.COM 				scsi_test_fail_repeat--;
95512213SGavin.Maltby@Sun.COM 				rc = scsi_test_fail_rc;
95612213SGavin.Maltby@Sun.COM 				if (rc == TRAN_ACCEPT)
95712213SGavin.Maltby@Sun.COM 					pkt->pkt_reason =
95812213SGavin.Maltby@Sun.COM 					    scsi_test_fail_pkt_reason;
95912213SGavin.Maltby@Sun.COM 				*pkt->pkt_scbp = scsi_test_fail_status;
96012213SGavin.Maltby@Sun.COM 				if (scsi_test_fail_status == STATUS_CHECK)
96112213SGavin.Maltby@Sun.COM 					pkt->pkt_state |= STATE_ARQ_DONE;
96212213SGavin.Maltby@Sun.COM 
96312213SGavin.Maltby@Sun.COM 			}
96412213SGavin.Maltby@Sun.COM 		}
96512213SGavin.Maltby@Sun.COM 	}
96612213SGavin.Maltby@Sun.COM #endif
96712213SGavin.Maltby@Sun.COM 
96812213SGavin.Maltby@Sun.COM 	switch (rc) {
96912213SGavin.Maltby@Sun.COM 	case TRAN_ACCEPT:
97012213SGavin.Maltby@Sun.COM 		switch (pkt->pkt_reason) {
97112213SGavin.Maltby@Sun.COM 		case CMD_CMPLT:
97212213SGavin.Maltby@Sun.COM 			switch ((*pkt->pkt_scbp) & STATUS_MASK) {
97312213SGavin.Maltby@Sun.COM 			case STATUS_GOOD:
97412213SGavin.Maltby@Sun.COM 				rval = SCSI_TEST_CMPLT_GOOD;
97512213SGavin.Maltby@Sun.COM 				break;
97612213SGavin.Maltby@Sun.COM 
97712213SGavin.Maltby@Sun.COM 			case STATUS_BUSY:
97812213SGavin.Maltby@Sun.COM 				rval = SCSI_TEST_CMPLT_BUSY;
97912213SGavin.Maltby@Sun.COM 				break;
98012213SGavin.Maltby@Sun.COM 
98112213SGavin.Maltby@Sun.COM 			case STATUS_CHECK:
98212213SGavin.Maltby@Sun.COM 				rval = SCSI_TEST_CMPLT_CHECK;
98312213SGavin.Maltby@Sun.COM 				break;
98412213SGavin.Maltby@Sun.COM 
98512213SGavin.Maltby@Sun.COM 			default:
98612213SGavin.Maltby@Sun.COM 				rval = SCSI_TEST_CMPLT_OTHER;
98712213SGavin.Maltby@Sun.COM 				break;
98812213SGavin.Maltby@Sun.COM 			}
98912213SGavin.Maltby@Sun.COM 			break;
99012213SGavin.Maltby@Sun.COM 
99112213SGavin.Maltby@Sun.COM 		case CMD_INCOMPLETE:
99212213SGavin.Maltby@Sun.COM 			rval = SCSI_TEST_CMD_INCOMPLETE;
99312213SGavin.Maltby@Sun.COM 			break;
99412213SGavin.Maltby@Sun.COM 
99512213SGavin.Maltby@Sun.COM 		default:
99612213SGavin.Maltby@Sun.COM 			rval = SCSI_TEST_NOTCMPLT;
99712213SGavin.Maltby@Sun.COM 			break;
99812213SGavin.Maltby@Sun.COM 		}
99912213SGavin.Maltby@Sun.COM 		break;
100012213SGavin.Maltby@Sun.COM 
100112213SGavin.Maltby@Sun.COM 	case TRAN_BUSY:
100212213SGavin.Maltby@Sun.COM 		rval = SCSI_TEST_TRAN_BUSY;
100312213SGavin.Maltby@Sun.COM 		break;
100412213SGavin.Maltby@Sun.COM 
100512213SGavin.Maltby@Sun.COM 	default:
100612213SGavin.Maltby@Sun.COM 		rval = SCSI_TEST_TRAN_REJECT;
100712213SGavin.Maltby@Sun.COM 		break;
10080Sstevel@tonic-gate 	}
10090Sstevel@tonic-gate 
101012213SGavin.Maltby@Sun.COM 	if (rval != SCSI_TEST_CMPLT_GOOD)
101112213SGavin.Maltby@Sun.COM 		scsi_test_ereport_post(pkt, ctxt, rval);
101212213SGavin.Maltby@Sun.COM 
10130Sstevel@tonic-gate 	return (rval);
10140Sstevel@tonic-gate }
10150Sstevel@tonic-gate 
10160Sstevel@tonic-gate /*
10170Sstevel@tonic-gate  * The implementation of scsi_probe now allows a particular
10180Sstevel@tonic-gate  * HBA to intercept the call, for any post- or pre-processing
10190Sstevel@tonic-gate  * it may need.  The default, if the HBA does not override it,
10200Sstevel@tonic-gate  * is to call scsi_hba_probe(), which retains the old functionality
10210Sstevel@tonic-gate  * intact.
10220Sstevel@tonic-gate  */
10230Sstevel@tonic-gate int
scsi_probe(struct scsi_device * sd,int (* callback)())102410696SDavid.Hollister@Sun.COM scsi_probe(struct scsi_device *sd, int (*callback)())
10250Sstevel@tonic-gate {
102612959Ssrikanth.suravajhala@oracle.com 	int			ret, retry = 0;
1027*13033Ssrikanth.suravajhala@oracle.com 	int			lr_cap, sr_ret;
102810696SDavid.Hollister@Sun.COM 	scsi_hba_tran_t		*tran = sd->sd_address.a_hba_tran;
10290Sstevel@tonic-gate 
103010696SDavid.Hollister@Sun.COM 	if (scsi_check_ss2_LUN_limit(sd) != 0) {
10310Sstevel@tonic-gate 		/*
10320Sstevel@tonic-gate 		 * caller is trying to probe a strictly-SCSI-2 device
10330Sstevel@tonic-gate 		 * with a LUN that is too large, so do not allow it
10340Sstevel@tonic-gate 		 */
10350Sstevel@tonic-gate 		return (SCSIPROBE_NORESP);	/* skip probing this one */
10360Sstevel@tonic-gate 	}
103712959Ssrikanth.suravajhala@oracle.com again:
1038*13033Ssrikanth.suravajhala@oracle.com 	ret = lr_cap = sr_ret = -1;
10398335SChris.Horne@Sun.COM 	if (tran->tran_tgt_probe != NULL) {
104010696SDavid.Hollister@Sun.COM 		ret = (*tran->tran_tgt_probe)(sd, callback);
10410Sstevel@tonic-gate 	} else {
104210696SDavid.Hollister@Sun.COM 		ret = scsi_hba_probe(sd, callback);
10430Sstevel@tonic-gate 	}
10440Sstevel@tonic-gate 
104512959Ssrikanth.suravajhala@oracle.com 	if ((ret != SCSIPROBE_EXISTS) && (retry == 0)) {
1046*13033Ssrikanth.suravajhala@oracle.com 		lr_cap = (*tran->tran_getcap)(&sd->sd_address, "lun-reset", 1);
1047*13033Ssrikanth.suravajhala@oracle.com 		sr_ret = scsi_reset(&sd->sd_address, RESET_LUN);
1048*13033Ssrikanth.suravajhala@oracle.com 		if ((sr_ret != 1) && (lr_cap == 1)) {
1049*13033Ssrikanth.suravajhala@oracle.com 			cmn_err(CE_WARN, "scsi_probe(%d): scsi_reset failed(%d)"
1050*13033Ssrikanth.suravajhala@oracle.com 			    " lun-reset cap(%d)", ret, sr_ret, lr_cap);
105112959Ssrikanth.suravajhala@oracle.com 		}
105212959Ssrikanth.suravajhala@oracle.com 		retry = 1;
105312959Ssrikanth.suravajhala@oracle.com 		goto again;
105412959Ssrikanth.suravajhala@oracle.com 	}
105512959Ssrikanth.suravajhala@oracle.com 
10560Sstevel@tonic-gate 	if (ret == SCSIPROBE_EXISTS) {
105710696SDavid.Hollister@Sun.COM 		create_inquiry_props(sd);
10580Sstevel@tonic-gate 		/* is this a strictly-SCSI-2 node ?? */
105910696SDavid.Hollister@Sun.COM 		scsi_establish_LUN_limit(sd);
10600Sstevel@tonic-gate 	}
10610Sstevel@tonic-gate 
10620Sstevel@tonic-gate 	return (ret);
10630Sstevel@tonic-gate }
106410696SDavid.Hollister@Sun.COM /*
106510696SDavid.Hollister@Sun.COM  * probe scsi device using any available path
106610696SDavid.Hollister@Sun.COM  *
106710696SDavid.Hollister@Sun.COM  */
106810696SDavid.Hollister@Sun.COM int
scsi_hba_probe(struct scsi_device * sd,int (* callback)())106910696SDavid.Hollister@Sun.COM scsi_hba_probe(struct scsi_device *sd, int (*callback)())
107010696SDavid.Hollister@Sun.COM {
107110696SDavid.Hollister@Sun.COM 	return (scsi_hba_probe_pi(sd, callback, 0));
107210696SDavid.Hollister@Sun.COM }
10730Sstevel@tonic-gate 
10740Sstevel@tonic-gate /*
107510696SDavid.Hollister@Sun.COM  * probe scsi device using specific path
107610696SDavid.Hollister@Sun.COM  *
107710696SDavid.Hollister@Sun.COM  * scsi_hba_probe_pi does not do any test unit ready's which access the medium
10780Sstevel@tonic-gate  * and could cause busy or not ready conditions.
107910696SDavid.Hollister@Sun.COM  * scsi_hba_probe_pi does 2 inquiries and a rqsense to clear unit attention
10800Sstevel@tonic-gate  * and to allow sync negotiation to take place
108110696SDavid.Hollister@Sun.COM  * finally, scsi_hba_probe_pi does one more inquiry which should
10820Sstevel@tonic-gate  * reliably tell us what kind of target we have.
10830Sstevel@tonic-gate  * A scsi-2 compliant target should be able to	return inquiry with 250ms
10840Sstevel@tonic-gate  * and we actually wait more than a second after reset.
10850Sstevel@tonic-gate  */
10860Sstevel@tonic-gate int
scsi_hba_probe_pi(struct scsi_device * sd,int (* callback)(),int pi)108710696SDavid.Hollister@Sun.COM scsi_hba_probe_pi(struct scsi_device *sd, int (*callback)(), int pi)
10880Sstevel@tonic-gate {
10890Sstevel@tonic-gate 	struct scsi_pkt		*inq_pkt = NULL;
10900Sstevel@tonic-gate 	struct scsi_pkt		*rq_pkt = NULL;
10910Sstevel@tonic-gate 	int			rval = SCSIPROBE_NOMEM;
10920Sstevel@tonic-gate 	struct buf		*inq_bp = NULL;
10930Sstevel@tonic-gate 	struct buf		*rq_bp = NULL;
10940Sstevel@tonic-gate 	int			(*cb_flag)();
10950Sstevel@tonic-gate 	int			pass = 1;
109612213SGavin.Maltby@Sun.COM 	uint32_t		str;
10970Sstevel@tonic-gate 
109810696SDavid.Hollister@Sun.COM 	if (sd->sd_inq == NULL) {
109910696SDavid.Hollister@Sun.COM 		sd->sd_inq = (struct scsi_inquiry *)
11004582Scth 		    kmem_alloc(SUN_INQSIZE, ((callback == SLEEP_FUNC) ?
11014582Scth 		    KM_SLEEP : KM_NOSLEEP));
110210696SDavid.Hollister@Sun.COM 		if (sd->sd_inq == NULL) {
11030Sstevel@tonic-gate 			goto out;
11040Sstevel@tonic-gate 		}
11050Sstevel@tonic-gate 	}
11060Sstevel@tonic-gate 
11070Sstevel@tonic-gate 	if (callback != SLEEP_FUNC && callback != NULL_FUNC) {
11080Sstevel@tonic-gate 		cb_flag = NULL_FUNC;
11090Sstevel@tonic-gate 	} else {
11100Sstevel@tonic-gate 		cb_flag = callback;
11110Sstevel@tonic-gate 	}
11120Sstevel@tonic-gate 	inq_bp = scsi_alloc_consistent_buf(ROUTE,
11130Sstevel@tonic-gate 	    (struct buf *)NULL, SUN_INQSIZE, B_READ, cb_flag, NULL);
11140Sstevel@tonic-gate 	if (inq_bp == NULL) {
11150Sstevel@tonic-gate 		goto out;
11160Sstevel@tonic-gate 	}
11170Sstevel@tonic-gate 
11180Sstevel@tonic-gate 	inq_pkt = scsi_init_pkt(ROUTE, (struct scsi_pkt *)NULL,
11190Sstevel@tonic-gate 	    inq_bp, CDB_GROUP0, sizeof (struct scsi_arq_status),
11200Sstevel@tonic-gate 	    0, PKT_CONSISTENT, callback, NULL);
11210Sstevel@tonic-gate 	if (inq_pkt == NULL) {
11220Sstevel@tonic-gate 		if (inq_bp->b_error == 0)
11230Sstevel@tonic-gate 			rval = SCSIPROBE_NOMEM_CB;
11240Sstevel@tonic-gate 		goto out;
11250Sstevel@tonic-gate 	}
11260Sstevel@tonic-gate 	ASSERT(inq_bp->b_error == 0);
11270Sstevel@tonic-gate 
11280Sstevel@tonic-gate 	(void) scsi_setup_cdb((union scsi_cdb *)inq_pkt->pkt_cdbp,
11290Sstevel@tonic-gate 	    SCMD_INQUIRY, 0, SUN_INQSIZE, 0);
11300Sstevel@tonic-gate 	inq_pkt->pkt_flags = FLAG_NOINTR|FLAG_NOPARITY;
11310Sstevel@tonic-gate 
11320Sstevel@tonic-gate 	/*
113310696SDavid.Hollister@Sun.COM 	 * set transport path
113410696SDavid.Hollister@Sun.COM 	 */
113510696SDavid.Hollister@Sun.COM 	if (pi && scsi_pkt_allocated_correctly(inq_pkt)) {
113610696SDavid.Hollister@Sun.COM 		inq_pkt->pkt_path_instance = pi;
113710696SDavid.Hollister@Sun.COM 		inq_pkt->pkt_flags |= FLAG_PKT_PATH_INSTANCE;
113810696SDavid.Hollister@Sun.COM 	}
113910696SDavid.Hollister@Sun.COM 
114010696SDavid.Hollister@Sun.COM 	/*
11410Sstevel@tonic-gate 	 * the first inquiry will tell us whether a target
11420Sstevel@tonic-gate 	 * responded
11430Sstevel@tonic-gate 	 *
11440Sstevel@tonic-gate 	 * The FILL_SCSI1_LUN below will find "ansi_ver != 1" on first pass
11450Sstevel@tonic-gate 	 * because of bzero initilization. If this assumption turns out to be
11460Sstevel@tonic-gate 	 * incorrect after we have real sd_inq data (for lun0) we will do a
11470Sstevel@tonic-gate 	 * second pass during which FILL_SCSI1_LUN will place lun in CDB.
11480Sstevel@tonic-gate 	 */
114910696SDavid.Hollister@Sun.COM 	bzero((caddr_t)sd->sd_inq, SUN_INQSIZE);
115010696SDavid.Hollister@Sun.COM again:	FILL_SCSI1_LUN(sd, inq_pkt);
11510Sstevel@tonic-gate 
115212213SGavin.Maltby@Sun.COM 	str = scsi_test(inq_pkt, STC_PROBE_FIRST_INQ);
115312213SGavin.Maltby@Sun.COM 	if (SCSI_TEST_FAILURE(str)) {
115412213SGavin.Maltby@Sun.COM 		if (str == SCSI_TEST_CMD_INCOMPLETE) {
11550Sstevel@tonic-gate 			rval = SCSIPROBE_NORESP;
11560Sstevel@tonic-gate 			goto out;
115712213SGavin.Maltby@Sun.COM 		}
115812213SGavin.Maltby@Sun.COM 
115912213SGavin.Maltby@Sun.COM 		/*
116012213SGavin.Maltby@Sun.COM 		 * Retry one more time for anything other than CMD_INCOMPLETE.
116112213SGavin.Maltby@Sun.COM 		 */
116212213SGavin.Maltby@Sun.COM 		str = scsi_test(inq_pkt, STC_PROBE_FIRST_INQ_RETRY);
116312213SGavin.Maltby@Sun.COM 		if (SCSI_TEST_FAILURE(str)) {
116412213SGavin.Maltby@Sun.COM 			rval = SCSIPROBE_FAILURE;
116512213SGavin.Maltby@Sun.COM 			goto out;
11660Sstevel@tonic-gate 		}
11670Sstevel@tonic-gate 	}
11680Sstevel@tonic-gate 
11690Sstevel@tonic-gate 	/*
117012213SGavin.Maltby@Sun.COM 	 * Did the inquiry complete and transfer inquiry information,
117112213SGavin.Maltby@Sun.COM 	 * perhaps after retry?
11720Sstevel@tonic-gate 	 */
117312213SGavin.Maltby@Sun.COM 	if (str == SCSI_TEST_CMPLT_GOOD)
11740Sstevel@tonic-gate 		goto done;
11750Sstevel@tonic-gate 
11760Sstevel@tonic-gate 	/*
117712213SGavin.Maltby@Sun.COM 	 * We get here for SCSI_TEST_CMPLT_{BUSY,CHECK,OTHER}. We term
117812213SGavin.Maltby@Sun.COM 	 * this "partial success" in that at least something is talking
117912213SGavin.Maltby@Sun.COM 	 * to us.
118012213SGavin.Maltby@Sun.COM 	 *
118112213SGavin.Maltby@Sun.COM 	 * A second inquiry allows the host adapter to negotiate
11820Sstevel@tonic-gate 	 * synchronous transfer period and offset
11830Sstevel@tonic-gate 	 */
118412213SGavin.Maltby@Sun.COM 	str = scsi_test(inq_pkt, STC_PROBE_PARTIAL_SUCCESS);
118512213SGavin.Maltby@Sun.COM 	if (SCSI_TEST_FAILURE(str)) {
118612213SGavin.Maltby@Sun.COM 		if (str == SCSI_TEST_CMD_INCOMPLETE)
11870Sstevel@tonic-gate 			rval = SCSIPROBE_NORESP;
11880Sstevel@tonic-gate 		else
11890Sstevel@tonic-gate 			rval = SCSIPROBE_FAILURE;
11900Sstevel@tonic-gate 		goto out;
11910Sstevel@tonic-gate 	}
11920Sstevel@tonic-gate 
11930Sstevel@tonic-gate 	/*
119412213SGavin.Maltby@Sun.COM 	 * If target is still busy, give up now.
119512213SGavin.Maltby@Sun.COM 	 * XXX There's no interval between retries - scsi_test should
119612213SGavin.Maltby@Sun.COM 	 * probably have a builtin retry on target busy.
11970Sstevel@tonic-gate 	 */
119812213SGavin.Maltby@Sun.COM 	if (str == SCSI_TEST_CMPLT_BUSY) {
11990Sstevel@tonic-gate 		rval = SCSIPROBE_BUSY;
12000Sstevel@tonic-gate 		goto out;
12010Sstevel@tonic-gate 	}
12020Sstevel@tonic-gate 
12030Sstevel@tonic-gate 	/*
120412213SGavin.Maltby@Sun.COM 	 * At this point we are SCSI_TEST_CMPLT_GOOD, SCSI_TEST_CMPLT_CHECK
120512213SGavin.Maltby@Sun.COM 	 * or SCSI_TEST_CMPLT_OTHER.
120612213SGavin.Maltby@Sun.COM 	 *
120712213SGavin.Maltby@Sun.COM 	 * Do a rqsense if there was a check condition and ARQ was not done
12080Sstevel@tonic-gate 	 */
120912213SGavin.Maltby@Sun.COM 	if (str == SCSI_TEST_CMPLT_CHECK &&
121012213SGavin.Maltby@Sun.COM 	    (inq_pkt->pkt_state & STATE_ARQ_DONE) == 0) {
121112213SGavin.Maltby@Sun.COM 		/*
121212213SGavin.Maltby@Sun.COM 		 * prepare rqsense packet
121312213SGavin.Maltby@Sun.COM 		 * there is no real need for this because the
121412213SGavin.Maltby@Sun.COM 		 * check condition should have been cleared by now.
121512213SGavin.Maltby@Sun.COM 		 */
121612213SGavin.Maltby@Sun.COM 		rq_bp = scsi_alloc_consistent_buf(ROUTE, (struct buf *)NULL,
121712213SGavin.Maltby@Sun.COM 		    (uint_t)SENSE_LENGTH, B_READ, cb_flag, NULL);
121812213SGavin.Maltby@Sun.COM 		if (rq_bp == NULL) {
121912213SGavin.Maltby@Sun.COM 			goto out;
122012213SGavin.Maltby@Sun.COM 		}
12210Sstevel@tonic-gate 
122212213SGavin.Maltby@Sun.COM 		rq_pkt = scsi_init_pkt(ROUTE, (struct scsi_pkt *)NULL,
122312213SGavin.Maltby@Sun.COM 		    rq_bp, CDB_GROUP0, 1, 0, PKT_CONSISTENT, callback, NULL);
12240Sstevel@tonic-gate 
122512213SGavin.Maltby@Sun.COM 		if (rq_pkt == NULL) {
122612213SGavin.Maltby@Sun.COM 			if (rq_bp->b_error == 0)
122712213SGavin.Maltby@Sun.COM 				rval = SCSIPROBE_NOMEM_CB;
122812213SGavin.Maltby@Sun.COM 			goto out;
122912213SGavin.Maltby@Sun.COM 		}
123012213SGavin.Maltby@Sun.COM 		ASSERT(rq_bp->b_error == 0);
12310Sstevel@tonic-gate 
123212213SGavin.Maltby@Sun.COM 		(void) scsi_setup_cdb((union scsi_cdb *)rq_pkt->
123312213SGavin.Maltby@Sun.COM 		    pkt_cdbp, SCMD_REQUEST_SENSE, 0, SENSE_LENGTH, 0);
123412213SGavin.Maltby@Sun.COM 		FILL_SCSI1_LUN(sd, rq_pkt);
123512213SGavin.Maltby@Sun.COM 		rq_pkt->pkt_flags = FLAG_NOINTR|FLAG_NOPARITY;
12360Sstevel@tonic-gate 
123712213SGavin.Maltby@Sun.COM 		/*
123812213SGavin.Maltby@Sun.COM 		 * set transport path
123912213SGavin.Maltby@Sun.COM 		 */
124012213SGavin.Maltby@Sun.COM 		if (pi && scsi_pkt_allocated_correctly(rq_pkt)) {
124112213SGavin.Maltby@Sun.COM 			rq_pkt->pkt_path_instance = pi;
124212213SGavin.Maltby@Sun.COM 			rq_pkt->pkt_flags |= FLAG_PKT_PATH_INSTANCE;
124312213SGavin.Maltby@Sun.COM 		}
124410696SDavid.Hollister@Sun.COM 
124512213SGavin.Maltby@Sun.COM 		/*
124612213SGavin.Maltby@Sun.COM 		 * The FILL_SCSI1_LUN above will find "inq_ansi != 1"
124712213SGavin.Maltby@Sun.COM 		 * on first pass, see "again" comment above.
124812213SGavin.Maltby@Sun.COM 		 *
124912213SGavin.Maltby@Sun.COM 		 * The controller type is as yet unknown, so we
125012213SGavin.Maltby@Sun.COM 		 * have to do a throwaway non-extended request sense,
125112213SGavin.Maltby@Sun.COM 		 * and hope that that clears the check condition for
125212213SGavin.Maltby@Sun.COM 		 * that unit until we can find out what kind of drive
125312213SGavin.Maltby@Sun.COM 		 * it is. A non-extended request sense is specified
125412213SGavin.Maltby@Sun.COM 		 * by stating that the sense block has 0 length,
125512213SGavin.Maltby@Sun.COM 		 * which is taken to mean that it is four bytes in
125612213SGavin.Maltby@Sun.COM 		 * length.
125712213SGavin.Maltby@Sun.COM 		 */
125812213SGavin.Maltby@Sun.COM 		if (SCSI_TEST_FAILURE(scsi_test(rq_pkt, STC_PROBE_RQSENSE1))) {
125912213SGavin.Maltby@Sun.COM 			rval = SCSIPROBE_FAILURE;
126012213SGavin.Maltby@Sun.COM 			goto out;
12610Sstevel@tonic-gate 		}
12620Sstevel@tonic-gate 	}
12630Sstevel@tonic-gate 
12640Sstevel@tonic-gate 	/*
12650Sstevel@tonic-gate 	 * At this point, we are guaranteed that something responded
12660Sstevel@tonic-gate 	 * to this scsi bus target id. We don't know yet what
12670Sstevel@tonic-gate 	 * kind of device it is, or even whether there really is
12680Sstevel@tonic-gate 	 * a logical unit attached (as some SCSI target controllers
12690Sstevel@tonic-gate 	 * lie about a unit being ready, e.g., the Emulex MD21).
12700Sstevel@tonic-gate 	 */
12710Sstevel@tonic-gate 
127212213SGavin.Maltby@Sun.COM 	str = scsi_test(inq_pkt, STC_PROBE_CHK_CLEARED);
127312213SGavin.Maltby@Sun.COM 	if (SCSI_TEST_FAILURE(str)) {
12740Sstevel@tonic-gate 		rval = SCSIPROBE_FAILURE;
12750Sstevel@tonic-gate 		goto out;
12760Sstevel@tonic-gate 	}
12770Sstevel@tonic-gate 
127812213SGavin.Maltby@Sun.COM 	if (str == SCSI_TEST_CMPLT_BUSY) {
12790Sstevel@tonic-gate 		rval = SCSIPROBE_BUSY;
12800Sstevel@tonic-gate 		goto out;
12810Sstevel@tonic-gate 	}
12820Sstevel@tonic-gate 
12830Sstevel@tonic-gate 	/*
12840Sstevel@tonic-gate 	 * Okay we sent the INQUIRY command.
12850Sstevel@tonic-gate 	 *
12860Sstevel@tonic-gate 	 * If enough data was transferred, we count that the
12870Sstevel@tonic-gate 	 * Inquiry command succeeded, else we have to assume
12880Sstevel@tonic-gate 	 * that this is a non-CCS scsi target (or a nonexistent
12890Sstevel@tonic-gate 	 * target/lun).
12900Sstevel@tonic-gate 	 */
12910Sstevel@tonic-gate 
129212213SGavin.Maltby@Sun.COM 	if (str == SCSI_TEST_CMPLT_CHECK) {
12930Sstevel@tonic-gate 		/*
12940Sstevel@tonic-gate 		 * try a request sense if we have a pkt, otherwise
12950Sstevel@tonic-gate 		 * just retry the inquiry one more time
12960Sstevel@tonic-gate 		 */
129712213SGavin.Maltby@Sun.COM 		if (rq_pkt)
129812213SGavin.Maltby@Sun.COM 			(void) scsi_test(rq_pkt, STC_PROBE_RQSENSE2);
12990Sstevel@tonic-gate 
13000Sstevel@tonic-gate 		/*
13010Sstevel@tonic-gate 		 * retry inquiry
13020Sstevel@tonic-gate 		 */
130312213SGavin.Maltby@Sun.COM 		str = scsi_test(inq_pkt, STC_PROBE_INQ_FINAL);
130412213SGavin.Maltby@Sun.COM 		if (SCSI_TEST_FAILURE(str)) {
13050Sstevel@tonic-gate 			rval = SCSIPROBE_FAILURE;
13060Sstevel@tonic-gate 			goto out;
130712213SGavin.Maltby@Sun.COM 		} else if (str == SCSI_TEST_CMPLT_CHECK) {
13080Sstevel@tonic-gate 			rval = SCSIPROBE_FAILURE;
13090Sstevel@tonic-gate 			goto out;
13100Sstevel@tonic-gate 		}
13110Sstevel@tonic-gate 	}
13120Sstevel@tonic-gate 
13130Sstevel@tonic-gate done:
13140Sstevel@tonic-gate 	/*
13150Sstevel@tonic-gate 	 * If we got a parity error on receive of inquiry data,
13160Sstevel@tonic-gate 	 * we're just plain out of luck because we told the host
13170Sstevel@tonic-gate 	 * adapter to not watch for parity errors.
13180Sstevel@tonic-gate 	 */
13190Sstevel@tonic-gate 	if ((inq_pkt->pkt_state & STATE_XFERRED_DATA) == 0 ||
13200Sstevel@tonic-gate 	    ((SUN_INQSIZE - inq_pkt->pkt_resid) < SUN_MIN_INQLEN)) {
13210Sstevel@tonic-gate 		rval = SCSIPROBE_NONCCS;
13220Sstevel@tonic-gate 	} else {
13238003SVitezslav.Batrla@Sun.COM 		ASSERT(inq_pkt->pkt_resid >= 0);
13240Sstevel@tonic-gate 		bcopy((caddr_t)inq_bp->b_un.b_addr,
132510696SDavid.Hollister@Sun.COM 		    (caddr_t)sd->sd_inq, (SUN_INQSIZE - inq_pkt->pkt_resid));
13260Sstevel@tonic-gate 		rval = SCSIPROBE_EXISTS;
13270Sstevel@tonic-gate 	}
13280Sstevel@tonic-gate 
13290Sstevel@tonic-gate out:
13300Sstevel@tonic-gate 	/*
13310Sstevel@tonic-gate 	 * If lun > 0 we need to figure out if this is a scsi-1 device where
13326640Scth 	 * the "real" lun needs to be embedded into the cdb.
13330Sstevel@tonic-gate 	 */
13340Sstevel@tonic-gate 	if ((rval == SCSIPROBE_EXISTS) && (pass == 1) &&
133510696SDavid.Hollister@Sun.COM 	    (sd->sd_address.a_lun > 0) && (sd->sd_inq->inq_ansi == 0x1)) {
13360Sstevel@tonic-gate 		pass++;
133710696SDavid.Hollister@Sun.COM 		if (sd->sd_address.a_lun <= 7)
13380Sstevel@tonic-gate 			goto again;
13390Sstevel@tonic-gate 
13400Sstevel@tonic-gate 		/*
13410Sstevel@tonic-gate 		 * invalid lun for scsi-1,
13420Sstevel@tonic-gate 		 * return probe failure.
13430Sstevel@tonic-gate 		 */
13440Sstevel@tonic-gate 		rval = SCSIPROBE_FAILURE;
13450Sstevel@tonic-gate 	}
13460Sstevel@tonic-gate 
13470Sstevel@tonic-gate 	if (rq_pkt) {
13480Sstevel@tonic-gate 		scsi_destroy_pkt(rq_pkt);
13490Sstevel@tonic-gate 	}
13500Sstevel@tonic-gate 	if (inq_pkt) {
13510Sstevel@tonic-gate 		scsi_destroy_pkt(inq_pkt);
13520Sstevel@tonic-gate 	}
13530Sstevel@tonic-gate 	if (rq_bp) {
13540Sstevel@tonic-gate 		scsi_free_consistent_buf(rq_bp);
13550Sstevel@tonic-gate 	}
13560Sstevel@tonic-gate 	if (inq_bp) {
13570Sstevel@tonic-gate 		scsi_free_consistent_buf(inq_bp);
13580Sstevel@tonic-gate 	}
13590Sstevel@tonic-gate 	return (rval);
13600Sstevel@tonic-gate }
13610Sstevel@tonic-gate 
13628335SChris.Horne@Sun.COM /*
13638335SChris.Horne@Sun.COM  * Convert from a scsi_device structure pointer to a scsi_hba_tran structure
13648335SChris.Horne@Sun.COM  * pointer. The correct way to do this is
13658335SChris.Horne@Sun.COM  *
136610696SDavid.Hollister@Sun.COM  *	#define	DEVP_TO_TRAN(sd)	((sd)->sd_address.a_hba_tran)
13678335SChris.Horne@Sun.COM  *
13688335SChris.Horne@Sun.COM  * however we have some consumers that place their own vector in a_hba_tran. To
13698335SChris.Horne@Sun.COM  * avoid problems, we implement this using the sd_tran_safe. See
13708335SChris.Horne@Sun.COM  * scsi_hba_initchild for more details.
13718335SChris.Horne@Sun.COM  */
137210696SDavid.Hollister@Sun.COM #define	DEVP_TO_TRAN(sd)	((sd)->sd_tran_safe)
13730Sstevel@tonic-gate 
13740Sstevel@tonic-gate /*
137510696SDavid.Hollister@Sun.COM  * Function, callable from SCSA framework, to get 'human' readable REPORTDEV
137610696SDavid.Hollister@Sun.COM  * addressing information from scsi_device properties.
137710696SDavid.Hollister@Sun.COM  */
137810696SDavid.Hollister@Sun.COM int
scsi_ua_get_reportdev(struct scsi_device * sd,char * ra,int len)137910696SDavid.Hollister@Sun.COM scsi_ua_get_reportdev(struct scsi_device *sd, char *ra, int len)
138010696SDavid.Hollister@Sun.COM {
138110696SDavid.Hollister@Sun.COM 	/* use deprecated tran_get_bus_addr interface if it is defined */
138210696SDavid.Hollister@Sun.COM 	/* NOTE: tran_get_bus_addr is a poor name choice for interface */
138310696SDavid.Hollister@Sun.COM 	if (DEVP_TO_TRAN(sd)->tran_get_bus_addr)
138410696SDavid.Hollister@Sun.COM 		return ((*DEVP_TO_TRAN(sd)->tran_get_bus_addr)(sd, ra, len));
138510696SDavid.Hollister@Sun.COM 	return (scsi_hba_ua_get_reportdev(sd, ra, len));
138610696SDavid.Hollister@Sun.COM }
138710696SDavid.Hollister@Sun.COM 
138810696SDavid.Hollister@Sun.COM /*
138910696SDavid.Hollister@Sun.COM  * Function, callable from HBA driver's tran_get_bus_addr(9E) implementation,
139010696SDavid.Hollister@Sun.COM  * to get standard form of human readable REPORTDEV addressing information
139110696SDavid.Hollister@Sun.COM  * from scsi_device properties.
13920Sstevel@tonic-gate  */
13930Sstevel@tonic-gate int
scsi_hba_ua_get_reportdev(struct scsi_device * sd,char * ra,int len)139410696SDavid.Hollister@Sun.COM scsi_hba_ua_get_reportdev(struct scsi_device *sd, char *ra, int len)
13950Sstevel@tonic-gate {
139610696SDavid.Hollister@Sun.COM 	int		tgt, lun, sfunc;
139710696SDavid.Hollister@Sun.COM 	char		*tgt_port;
139810696SDavid.Hollister@Sun.COM 	scsi_lun64_t	lun64;
139910696SDavid.Hollister@Sun.COM 
140010696SDavid.Hollister@Sun.COM 	/* get device unit-address properties */
140110696SDavid.Hollister@Sun.COM 	tgt = scsi_device_prop_get_int(sd, SCSI_DEVICE_PROP_PATH,
140210696SDavid.Hollister@Sun.COM 	    SCSI_ADDR_PROP_TARGET, -1);
140310696SDavid.Hollister@Sun.COM 	if (scsi_device_prop_lookup_string(sd, SCSI_DEVICE_PROP_PATH,
140410696SDavid.Hollister@Sun.COM 	    SCSI_ADDR_PROP_TARGET_PORT, &tgt_port) != DDI_PROP_SUCCESS)
140510696SDavid.Hollister@Sun.COM 		tgt_port = NULL;
140610696SDavid.Hollister@Sun.COM 	if ((tgt == -1) && (tgt_port == NULL))
140710696SDavid.Hollister@Sun.COM 		return (0);		/* no target */
140810696SDavid.Hollister@Sun.COM 
140910696SDavid.Hollister@Sun.COM 	lun = scsi_device_prop_get_int(sd, SCSI_DEVICE_PROP_PATH,
141010696SDavid.Hollister@Sun.COM 	    SCSI_ADDR_PROP_LUN, 0);
141110696SDavid.Hollister@Sun.COM 	lun64 = scsi_device_prop_get_int64(sd, SCSI_DEVICE_PROP_PATH,
141210696SDavid.Hollister@Sun.COM 	    SCSI_ADDR_PROP_LUN64, lun);
141310696SDavid.Hollister@Sun.COM 	sfunc = scsi_device_prop_get_int(sd, SCSI_DEVICE_PROP_PATH,
141410696SDavid.Hollister@Sun.COM 	    SCSI_ADDR_PROP_SFUNC, -1);
14150Sstevel@tonic-gate 
141610696SDavid.Hollister@Sun.COM 	/*
141710696SDavid.Hollister@Sun.COM 	 * XXX should the default be to print this in decimal for
141810696SDavid.Hollister@Sun.COM 	 * "human readable" form, so it matches conf files?
141910696SDavid.Hollister@Sun.COM 	 */
142010696SDavid.Hollister@Sun.COM 	if (tgt_port) {
142110696SDavid.Hollister@Sun.COM 		if (sfunc == -1)
142210696SDavid.Hollister@Sun.COM 			(void) snprintf(ra, len,
142310696SDavid.Hollister@Sun.COM 			    "%s %s lun %" PRIx64,
142410696SDavid.Hollister@Sun.COM 			    SCSI_ADDR_PROP_TARGET_PORT, tgt_port, lun64);
142510696SDavid.Hollister@Sun.COM 		else
142610696SDavid.Hollister@Sun.COM 			(void) snprintf(ra, len,
142710696SDavid.Hollister@Sun.COM 			    "%s %s lun %" PRIx64 " sfunc %x",
142810696SDavid.Hollister@Sun.COM 			    SCSI_ADDR_PROP_TARGET_PORT, tgt_port, lun64, sfunc);
142910696SDavid.Hollister@Sun.COM 		scsi_device_prop_free(sd, SCSI_DEVICE_PROP_PATH, tgt_port);
143010696SDavid.Hollister@Sun.COM 	} else {
143110696SDavid.Hollister@Sun.COM 		if (sfunc == -1)
143210696SDavid.Hollister@Sun.COM 			(void) snprintf(ra, len,
143310696SDavid.Hollister@Sun.COM 			    "%s %x lun %" PRIx64,
143410696SDavid.Hollister@Sun.COM 			    SCSI_ADDR_PROP_TARGET, tgt, lun64);
143510696SDavid.Hollister@Sun.COM 		else
143610696SDavid.Hollister@Sun.COM 			(void) snprintf(ra, len,
143710696SDavid.Hollister@Sun.COM 			    "%s %x lun %" PRIx64 " sfunc %x",
143810696SDavid.Hollister@Sun.COM 			    SCSI_ADDR_PROP_TARGET, tgt, lun64, sfunc);
143910696SDavid.Hollister@Sun.COM 	}
14408335SChris.Horne@Sun.COM 
14418335SChris.Horne@Sun.COM 	return (1);
14420Sstevel@tonic-gate }
14430Sstevel@tonic-gate 
14440Sstevel@tonic-gate /*
144510696SDavid.Hollister@Sun.COM  * scsi_ua_get: using properties, return "unit-address" string.
144610696SDavid.Hollister@Sun.COM  * Called by SCSA framework, may call HBAs tran function.
144710696SDavid.Hollister@Sun.COM  */
144810696SDavid.Hollister@Sun.COM int
scsi_ua_get(struct scsi_device * sd,char * ua,int len)144910696SDavid.Hollister@Sun.COM scsi_ua_get(struct scsi_device *sd, char *ua, int len)
145010696SDavid.Hollister@Sun.COM {
145110696SDavid.Hollister@Sun.COM 	char		*eua;
145210696SDavid.Hollister@Sun.COM 
145310696SDavid.Hollister@Sun.COM 	/* See if we already have established the unit-address. */
145410696SDavid.Hollister@Sun.COM 	if ((eua = scsi_device_unit_address(sd)) != NULL) {
145510696SDavid.Hollister@Sun.COM 		(void) strlcpy(ua, eua, len);
145610696SDavid.Hollister@Sun.COM 		return (1);
145710696SDavid.Hollister@Sun.COM 	}
145810696SDavid.Hollister@Sun.COM 
145910696SDavid.Hollister@Sun.COM 	/* Use deprecated tran_get_name interface if it is defined. */
146010696SDavid.Hollister@Sun.COM 	/* NOTE: tran_get_name is a poor name choice for interface */
146110696SDavid.Hollister@Sun.COM 	if (DEVP_TO_TRAN(sd)->tran_get_name)
146210696SDavid.Hollister@Sun.COM 		return ((*DEVP_TO_TRAN(sd)->tran_get_name)(sd, ua, len));
146310696SDavid.Hollister@Sun.COM 
146410696SDavid.Hollister@Sun.COM 	/* Use generic property implementation */
146510696SDavid.Hollister@Sun.COM 	return (scsi_hba_ua_get(sd, ua, len));
146610696SDavid.Hollister@Sun.COM }
146710696SDavid.Hollister@Sun.COM 
146810696SDavid.Hollister@Sun.COM /*
146910696SDavid.Hollister@Sun.COM  * scsi_hba_ua_get: using properties, return "unit-address" string.
147010696SDavid.Hollister@Sun.COM  * This function may be called from an HBAs tran function.
14718335SChris.Horne@Sun.COM  *
14728335SChris.Horne@Sun.COM  * Function to get "unit-address" in "name@unit-address" /devices path
147310696SDavid.Hollister@Sun.COM  * component form from the scsi_device unit-address properties on a node.
14748335SChris.Horne@Sun.COM  *
147510696SDavid.Hollister@Sun.COM  * NOTE: This function works in conjunction with scsi_hba_ua_set().
14760Sstevel@tonic-gate  */
14770Sstevel@tonic-gate int
scsi_hba_ua_get(struct scsi_device * sd,char * ua,int len)147810696SDavid.Hollister@Sun.COM scsi_hba_ua_get(struct scsi_device *sd, char *ua, int len)
14790Sstevel@tonic-gate {
148010696SDavid.Hollister@Sun.COM 	int		tgt, lun, sfunc;
148110696SDavid.Hollister@Sun.COM 	char		*tgt_port;
148210696SDavid.Hollister@Sun.COM 	scsi_lun64_t	lun64;
148310696SDavid.Hollister@Sun.COM 
148410696SDavid.Hollister@Sun.COM 	/* get device unit-address properties */
148510696SDavid.Hollister@Sun.COM 	tgt = scsi_device_prop_get_int(sd, SCSI_DEVICE_PROP_PATH,
148610696SDavid.Hollister@Sun.COM 	    SCSI_ADDR_PROP_TARGET, -1);
148710696SDavid.Hollister@Sun.COM 	if (scsi_device_prop_lookup_string(sd, SCSI_DEVICE_PROP_PATH,
148810696SDavid.Hollister@Sun.COM 	    SCSI_ADDR_PROP_TARGET_PORT, &tgt_port) != DDI_PROP_SUCCESS)
148910696SDavid.Hollister@Sun.COM 		tgt_port = NULL;
149010696SDavid.Hollister@Sun.COM 	if ((tgt == -1) && (tgt_port == NULL))
149110696SDavid.Hollister@Sun.COM 		return (0);		/* no target */
14920Sstevel@tonic-gate 
149310696SDavid.Hollister@Sun.COM 	lun = scsi_device_prop_get_int(sd, SCSI_DEVICE_PROP_PATH,
149410696SDavid.Hollister@Sun.COM 	    SCSI_ADDR_PROP_LUN, 0);
149510696SDavid.Hollister@Sun.COM 	lun64 = scsi_device_prop_get_int64(sd, SCSI_DEVICE_PROP_PATH,
149610696SDavid.Hollister@Sun.COM 	    SCSI_ADDR_PROP_LUN64, lun);
149710696SDavid.Hollister@Sun.COM 	sfunc = scsi_device_prop_get_int(sd, SCSI_DEVICE_PROP_PATH,
149810696SDavid.Hollister@Sun.COM 	    SCSI_ADDR_PROP_SFUNC, -1);
149910696SDavid.Hollister@Sun.COM 	if (tgt_port) {
150010696SDavid.Hollister@Sun.COM 		if (sfunc == -1)
150110696SDavid.Hollister@Sun.COM 			(void) snprintf(ua, len, "%s,%" PRIx64,
150210696SDavid.Hollister@Sun.COM 			    tgt_port, lun64);
150310696SDavid.Hollister@Sun.COM 		else
150410696SDavid.Hollister@Sun.COM 			(void) snprintf(ua, len, "%s,%" PRIx64 ",%x",
150510696SDavid.Hollister@Sun.COM 			    tgt_port, lun64, sfunc);
150610696SDavid.Hollister@Sun.COM 		scsi_device_prop_free(sd, SCSI_DEVICE_PROP_PATH, tgt_port);
150710696SDavid.Hollister@Sun.COM 	} else {
150810696SDavid.Hollister@Sun.COM 		if (sfunc == -1)
150910696SDavid.Hollister@Sun.COM 			(void) snprintf(ua, len, "%x,%" PRIx64, tgt, lun64);
151010696SDavid.Hollister@Sun.COM 		else
151110696SDavid.Hollister@Sun.COM 			(void) snprintf(ua, len, "%x,%" PRIx64 ",%x",
151210696SDavid.Hollister@Sun.COM 			    tgt, lun64, sfunc);
151310696SDavid.Hollister@Sun.COM 	}
15148335SChris.Horne@Sun.COM 	return (1);
15150Sstevel@tonic-gate }
15160Sstevel@tonic-gate 
151711052SChris.Horne@Sun.COM static void
create_inquiry_props(struct scsi_device * sd)151810696SDavid.Hollister@Sun.COM create_inquiry_props(struct scsi_device *sd)
15190Sstevel@tonic-gate {
152010696SDavid.Hollister@Sun.COM 	struct scsi_inquiry *inq = sd->sd_inq;
15210Sstevel@tonic-gate 
152210696SDavid.Hollister@Sun.COM 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, sd->sd_dev,
15230Sstevel@tonic-gate 	    INQUIRY_DEVICE_TYPE, (int)inq->inq_dtype);
15240Sstevel@tonic-gate 
15250Sstevel@tonic-gate 	/*
15260Sstevel@tonic-gate 	 * Create the following properties:
15270Sstevel@tonic-gate 	 *
152810696SDavid.Hollister@Sun.COM 	 * inquiry-vendor-id	Vendor id (INQUIRY data bytes 8-15)
152910696SDavid.Hollister@Sun.COM 	 * inquiry-product-id	Product id (INQUIRY data bytes 16-31)
153010696SDavid.Hollister@Sun.COM 	 * inquiry-revision-id	Product Rev level (INQUIRY data bytes 32-35)
15310Sstevel@tonic-gate 	 *
153211052SChris.Horne@Sun.COM 	 * NOTE: We don't support creation of these properties for scsi-1
15330Sstevel@tonic-gate 	 * devices (as the vid, pid and revision were not defined) and we
15340Sstevel@tonic-gate 	 * don't create the property if they are of zero length when
15350Sstevel@tonic-gate 	 * stripped of Nulls and spaces.
153611052SChris.Horne@Sun.COM 	 *
153711052SChris.Horne@Sun.COM 	 * NOTE: The first definition of these properties sticks. This gives
153811052SChris.Horne@Sun.COM 	 * a transport the ability to provide a higher-quality definition
153911052SChris.Horne@Sun.COM 	 * than the standard SCSI INQUIRY data.
15400Sstevel@tonic-gate 	 */
15410Sstevel@tonic-gate 	if (inq->inq_ansi != 1) {
154210696SDavid.Hollister@Sun.COM 		if (ddi_prop_exists(DDI_DEV_T_NONE, sd->sd_dev,
15434582Scth 		    DDI_PROP_TYPE_STRING, INQUIRY_VENDOR_ID) == 0)
154410696SDavid.Hollister@Sun.COM 			(void) scsi_device_prop_update_inqstring(sd,
15454582Scth 			    INQUIRY_VENDOR_ID,
15464582Scth 			    inq->inq_vid, sizeof (inq->inq_vid));
15470Sstevel@tonic-gate 
154810696SDavid.Hollister@Sun.COM 		if (ddi_prop_exists(DDI_DEV_T_NONE, sd->sd_dev,
15494582Scth 		    DDI_PROP_TYPE_STRING, INQUIRY_PRODUCT_ID) == 0)
155010696SDavid.Hollister@Sun.COM 			(void) scsi_device_prop_update_inqstring(sd,
15514582Scth 			    INQUIRY_PRODUCT_ID,
15524582Scth 			    inq->inq_pid, sizeof (inq->inq_pid));
15530Sstevel@tonic-gate 
155410696SDavid.Hollister@Sun.COM 		if (ddi_prop_exists(DDI_DEV_T_NONE, sd->sd_dev,
15554582Scth 		    DDI_PROP_TYPE_STRING, INQUIRY_REVISION_ID) == 0)
155610696SDavid.Hollister@Sun.COM 			(void) scsi_device_prop_update_inqstring(sd,
15574582Scth 			    INQUIRY_REVISION_ID,
15584582Scth 			    inq->inq_revision, sizeof (inq->inq_revision));
15590Sstevel@tonic-gate 	}
15600Sstevel@tonic-gate }
15610Sstevel@tonic-gate 
15620Sstevel@tonic-gate /*
15634582Scth  * Create 'inquiry' string properties.  An 'inquiry' string gets special
15644582Scth  * treatment to trim trailing blanks (etc) and ensure null termination.
15650Sstevel@tonic-gate  */
15664582Scth int
scsi_device_prop_update_inqstring(struct scsi_device * sd,char * name,char * data,size_t len)156710696SDavid.Hollister@Sun.COM scsi_device_prop_update_inqstring(struct scsi_device *sd,
15684582Scth     char *name, char *data, size_t len)
15690Sstevel@tonic-gate {
15704582Scth 	int	ilen;
15714582Scth 	char	*data_string;
15724582Scth 	int	rv;
15730Sstevel@tonic-gate 
157411052SChris.Horne@Sun.COM 	ilen = scsi_ascii_inquiry_len(data, len);
15754582Scth 	ASSERT(ilen <= (int)len);
15764582Scth 	if (ilen <= 0)
15774582Scth 		return (DDI_PROP_INVAL_ARG);
15780Sstevel@tonic-gate 
15794582Scth 	/* ensure null termination */
15804582Scth 	data_string = kmem_zalloc(ilen + 1, KM_SLEEP);
15814582Scth 	bcopy(data, data_string, ilen);
15824582Scth 	rv = ndi_prop_update_string(DDI_DEV_T_NONE,
158310696SDavid.Hollister@Sun.COM 	    sd->sd_dev, name, data_string);
15844582Scth 	kmem_free(data_string, ilen + 1);
15854582Scth 	return (rv);
15860Sstevel@tonic-gate }
15870Sstevel@tonic-gate 
15880Sstevel@tonic-gate /*
15898335SChris.Horne@Sun.COM  * Interfaces associated with SCSI_HBA_ADDR_COMPLEX
15908335SChris.Horne@Sun.COM  * per-scsi_device HBA private data support.
159112213SGavin.Maltby@Sun.COM  *
159212213SGavin.Maltby@Sun.COM  * scsi_address_device returns NULL if we're not SCSI_HBA_ADDR_COMPLEX,
159312213SGavin.Maltby@Sun.COM  * thereby allowing use of scsi_address_device as a test for
159412213SGavin.Maltby@Sun.COM  * SCSI_HBA_ADDR_COMPLEX.
15958335SChris.Horne@Sun.COM  */
15968335SChris.Horne@Sun.COM struct scsi_device *
scsi_address_device(struct scsi_address * sa)15978335SChris.Horne@Sun.COM scsi_address_device(struct scsi_address *sa)
15988335SChris.Horne@Sun.COM {
159912213SGavin.Maltby@Sun.COM 	return ((sa->a_hba_tran->tran_hba_flags & SCSI_HBA_ADDR_COMPLEX) ?
160012213SGavin.Maltby@Sun.COM 	    sa->a.a_sd : NULL);
16018335SChris.Horne@Sun.COM }
16028335SChris.Horne@Sun.COM 
16038335SChris.Horne@Sun.COM void
scsi_device_hba_private_set(struct scsi_device * sd,void * data)16048335SChris.Horne@Sun.COM scsi_device_hba_private_set(struct scsi_device *sd, void *data)
16058335SChris.Horne@Sun.COM {
16068335SChris.Horne@Sun.COM 	ASSERT(sd->sd_address.a_hba_tran->tran_hba_flags &
16078335SChris.Horne@Sun.COM 	    SCSI_HBA_ADDR_COMPLEX);
16088335SChris.Horne@Sun.COM 	sd->sd_hba_private = data;
16098335SChris.Horne@Sun.COM }
16108335SChris.Horne@Sun.COM 
16118335SChris.Horne@Sun.COM void *
scsi_device_hba_private_get(struct scsi_device * sd)16128335SChris.Horne@Sun.COM scsi_device_hba_private_get(struct scsi_device *sd)
16138335SChris.Horne@Sun.COM {
16148335SChris.Horne@Sun.COM 	ASSERT(sd->sd_address.a_hba_tran->tran_hba_flags &
16158335SChris.Horne@Sun.COM 	    SCSI_HBA_ADDR_COMPLEX);
16168335SChris.Horne@Sun.COM 	return (sd->sd_hba_private);
16178335SChris.Horne@Sun.COM }
16180Sstevel@tonic-gate 
16190Sstevel@tonic-gate /*
16208335SChris.Horne@Sun.COM  * This routine is called from the start of scsi_probe() if a tgt/LUN to be
16210Sstevel@tonic-gate  * probed *may* be a request to probe a strictly SCSI-2 target (with respect
16220Sstevel@tonic-gate  * to LUNs) -- and this probe may be for a LUN number greater than 7,
16230Sstevel@tonic-gate  * which can cause a hardware hang
16240Sstevel@tonic-gate  *
16250Sstevel@tonic-gate  * return 0 if the probe can proceed,
16260Sstevel@tonic-gate  * else return 1, meaning do *NOT* probe this target/LUN
16270Sstevel@tonic-gate  */
16280Sstevel@tonic-gate static int
scsi_check_ss2_LUN_limit(struct scsi_device * sd)162910696SDavid.Hollister@Sun.COM scsi_check_ss2_LUN_limit(struct scsi_device *sd)
16300Sstevel@tonic-gate {
163110696SDavid.Hollister@Sun.COM 	struct scsi_address	*ap = &(sd->sd_address);
16320Sstevel@tonic-gate 	dev_info_t		*pdevi =
163310696SDavid.Hollister@Sun.COM 	    (dev_info_t *)DEVI(sd->sd_dev)->devi_parent;
16340Sstevel@tonic-gate 	int			ret_val = 0;	/* default return value */
16350Sstevel@tonic-gate 	uchar_t			*tgt_list;
16360Sstevel@tonic-gate 	uint_t			tgt_nelements;
16370Sstevel@tonic-gate 	int			i;
16380Sstevel@tonic-gate 
16390Sstevel@tonic-gate 
16400Sstevel@tonic-gate 	/*
16410Sstevel@tonic-gate 	 * check for what *might* be a problem probe, only we don't
16420Sstevel@tonic-gate 	 * know yet what's really at the destination target/LUN
16430Sstevel@tonic-gate 	 */
16440Sstevel@tonic-gate 	if ((ap->a_target >= NTARGETS_WIDE) ||
16450Sstevel@tonic-gate 	    (ap->a_lun < NLUNS_PER_TARGET)) {
16460Sstevel@tonic-gate 		return (0);		/* okay to probe this target */
16470Sstevel@tonic-gate 	}
16480Sstevel@tonic-gate 
16490Sstevel@tonic-gate 	/*
16500Sstevel@tonic-gate 	 * this *might* be a problematic probe, so look to see
16510Sstevel@tonic-gate 	 * if the inquiry data matches
16520Sstevel@tonic-gate 	 */
16530Sstevel@tonic-gate 	SCSI_PROBE_DEBUG2(1, "SCSA pre-probe: checking tgt.LUN=%d.%d\n",
16540Sstevel@tonic-gate 	    ap->a_target, ap->a_lun);
16550Sstevel@tonic-gate 	SCSI_PROBE_DEBUG1(2,
16560Sstevel@tonic-gate 	    "SCSA pre-probe: scanning parent node name: %s ...\n",
16570Sstevel@tonic-gate 	    ddi_node_name(pdevi));
16580Sstevel@tonic-gate 
16590Sstevel@tonic-gate 	/*
16600Sstevel@tonic-gate 	 * look for a special property of our parent node that lists
16610Sstevel@tonic-gate 	 * the targets under it for which we do *NOT* want to probe
16620Sstevel@tonic-gate 	 * if LUN>7 -- if the property is found, look to see if our
16630Sstevel@tonic-gate 	 * target ID is on that list
16640Sstevel@tonic-gate 	 */
166511052SChris.Horne@Sun.COM 	if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, pdevi,
166611052SChris.Horne@Sun.COM 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, SS2_LUN0_TGT_LIST_PROP,
16670Sstevel@tonic-gate 	    &tgt_list, &tgt_nelements) != DDI_PROP_SUCCESS) {
16680Sstevel@tonic-gate 		/*
16690Sstevel@tonic-gate 		 * no list, so it must be okay to probe this target.LUN
16700Sstevel@tonic-gate 		 */
16710Sstevel@tonic-gate 		SCSI_PROBE_DEBUG0(3,
16720Sstevel@tonic-gate 		    "SCSA pre-probe: NO parent prop found\n");
16730Sstevel@tonic-gate 	} else {
16740Sstevel@tonic-gate 		for (i = 0; i < tgt_nelements; i++) {
16750Sstevel@tonic-gate 			if (tgt_list[i] == ap->a_target) {
16760Sstevel@tonic-gate 				/*
16770Sstevel@tonic-gate 				 * we found a match, which means we do *NOT*
16780Sstevel@tonic-gate 				 * want to probe the specified target.LUN
16790Sstevel@tonic-gate 				 */
16800Sstevel@tonic-gate 				ret_val = 1;
16810Sstevel@tonic-gate 				break;
16820Sstevel@tonic-gate 			}
16830Sstevel@tonic-gate 		}
16840Sstevel@tonic-gate 		ddi_prop_free(tgt_list);
16850Sstevel@tonic-gate #ifdef	DEBUG
16860Sstevel@tonic-gate 		if (ret_val == 1) {
16870Sstevel@tonic-gate 			SCSI_PROBE_DEBUG2(1,
16880Sstevel@tonic-gate 			    "SCSA pre-probe: marker node FOUND for "
16890Sstevel@tonic-gate 			    "tgt.LUN=%d.%d, so SKIPPING it\n",
16900Sstevel@tonic-gate 			    ap->a_target, ap->a_lun);
16910Sstevel@tonic-gate 		} else {
16920Sstevel@tonic-gate 			SCSI_PROBE_DEBUG0(2,
16930Sstevel@tonic-gate 			    "SCSA pre-probe: NO marker node found"
16940Sstevel@tonic-gate 			    " -- OK to probe\n");
16950Sstevel@tonic-gate 		}
16960Sstevel@tonic-gate #endif
16970Sstevel@tonic-gate 	}
16980Sstevel@tonic-gate 	return (ret_val);
16990Sstevel@tonic-gate }
17000Sstevel@tonic-gate 
17010Sstevel@tonic-gate 
17020Sstevel@tonic-gate /*
17030Sstevel@tonic-gate  * this routine is called from near the end of scsi_probe(),
17040Sstevel@tonic-gate  * to see if the just-probed node is on our list of strictly-SCSI-2 nodes,
17050Sstevel@tonic-gate  * and if it is we mark our parent node with this information
17060Sstevel@tonic-gate  */
17070Sstevel@tonic-gate static void
scsi_establish_LUN_limit(struct scsi_device * sd)170810696SDavid.Hollister@Sun.COM scsi_establish_LUN_limit(struct scsi_device *sd)
17090Sstevel@tonic-gate {
171010696SDavid.Hollister@Sun.COM 	struct scsi_address	*ap = &(sd->sd_address);
171110696SDavid.Hollister@Sun.COM 	struct scsi_inquiry	*inq = sd->sd_inq;
171210696SDavid.Hollister@Sun.COM 	dev_info_t		*devi = sd->sd_dev;
17130Sstevel@tonic-gate 	char			*vid = NULL;
17140Sstevel@tonic-gate 	char			*pid = NULL;
17150Sstevel@tonic-gate 	char			*rev = NULL;
17160Sstevel@tonic-gate 	int			i;
17170Sstevel@tonic-gate 	const ss2_lun0_info_t	*p;
17180Sstevel@tonic-gate 	int			bad_target_found = 0;
17190Sstevel@tonic-gate 
17200Sstevel@tonic-gate 
17210Sstevel@tonic-gate 	/*
17220Sstevel@tonic-gate 	 * if this inquiry data shows that we have a strictly-SCSI-2 device
17230Sstevel@tonic-gate 	 * at LUN 0, then add it to our list of strictly-SCSI-2 devices,
17240Sstevel@tonic-gate 	 * so that we can avoid probes where LUN>7 on this device later
17250Sstevel@tonic-gate 	 */
17260Sstevel@tonic-gate 	if ((ap->a_lun != 0) ||
17270Sstevel@tonic-gate 	    (ap->a_target >= NTARGETS_WIDE) ||
17280Sstevel@tonic-gate 	    (inq->inq_dtype != DTYPE_PROCESSOR) ||
17290Sstevel@tonic-gate 	    (inq->inq_ansi != 2)) {
17300Sstevel@tonic-gate 		/*
17310Sstevel@tonic-gate 		 * this can't possibly be a node we want to look at, since
17320Sstevel@tonic-gate 		 * either LUN is greater than 0, target is greater than or
17338335SChris.Horne@Sun.COM 		 * equal to 16, device type
17340Sstevel@tonic-gate 		 * is not processor, or SCSI level is not SCSI-2,
17350Sstevel@tonic-gate 		 * so don't bother checking for a strictly SCSI-2
17360Sstevel@tonic-gate 		 * (only 8 LUN) target
17370Sstevel@tonic-gate 		 */
17380Sstevel@tonic-gate 		return;				/* don't care */
17390Sstevel@tonic-gate 	}
17400Sstevel@tonic-gate 
17410Sstevel@tonic-gate 	SCSI_PROBE_DEBUG2(1, "SCSA post-probe: LUN limit on tgt.LUN=%d.%d, "
17420Sstevel@tonic-gate 	    "SCSI-2 PROCESSOR?\n", ap->a_target, ap->a_lun);
17430Sstevel@tonic-gate 
17440Sstevel@tonic-gate 	ASSERT(devi != NULL);
17450Sstevel@tonic-gate 
17460Sstevel@tonic-gate 	/*
17470Sstevel@tonic-gate 	 * we have a node that has been probed that is: LUN=0, target<16,
17480Sstevel@tonic-gate 	 * PROCESSOR-type SCSI target, and at the SCSI-2 level, so
17490Sstevel@tonic-gate 	 * check INQ properties to see if it's in our list of strictly
17500Sstevel@tonic-gate 	 * SCSI-2 targets
17510Sstevel@tonic-gate 	 *
17520Sstevel@tonic-gate 	 * first we have to get the VID/PID/REV INQUIRY properties for
17530Sstevel@tonic-gate 	 * comparison
17540Sstevel@tonic-gate 	 */
175511052SChris.Horne@Sun.COM 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, devi,
175611052SChris.Horne@Sun.COM 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
17570Sstevel@tonic-gate 	    INQUIRY_VENDOR_ID, &vid) != DDI_PROP_SUCCESS) {
17580Sstevel@tonic-gate 		SCSI_PROBE_DEBUG1(2, "SCSA post-probe: prop \"%s\" missing\n",
17590Sstevel@tonic-gate 		    INQUIRY_VENDOR_ID);
17600Sstevel@tonic-gate 		goto dun;
17610Sstevel@tonic-gate 	}
176211052SChris.Horne@Sun.COM 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, devi,
176311052SChris.Horne@Sun.COM 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
17640Sstevel@tonic-gate 	    INQUIRY_PRODUCT_ID, &pid) != DDI_PROP_SUCCESS) {
17650Sstevel@tonic-gate 		SCSI_PROBE_DEBUG1(2, "SCSA post-probe: prop \"%s\" missing\n",
17660Sstevel@tonic-gate 		    INQUIRY_PRODUCT_ID);
17670Sstevel@tonic-gate 		goto dun;
17680Sstevel@tonic-gate 	}
176911052SChris.Horne@Sun.COM 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, devi,
177011052SChris.Horne@Sun.COM 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
17710Sstevel@tonic-gate 	    INQUIRY_REVISION_ID, &rev) != DDI_PROP_SUCCESS) {
17720Sstevel@tonic-gate 		SCSI_PROBE_DEBUG1(2, "SCSA post-probe: prop \"%s\" missing\n",
17730Sstevel@tonic-gate 		    INQUIRY_REVISION_ID);
17740Sstevel@tonic-gate 		goto dun;
17750Sstevel@tonic-gate 	}
17760Sstevel@tonic-gate 
17770Sstevel@tonic-gate 	SCSI_PROBE_DEBUG3(3, "SCSA post-probe: looking for vid/pid/rev = "
17780Sstevel@tonic-gate 	    "\"%s\"/\"%s\"/\"%s\"\n", vid, pid, rev);
17790Sstevel@tonic-gate 
17800Sstevel@tonic-gate 	/*
17810Sstevel@tonic-gate 	 * now that we have the INQUIRY properties from the device node,
17820Sstevel@tonic-gate 	 * compare them with our known offenders
17830Sstevel@tonic-gate 	 *
17840Sstevel@tonic-gate 	 * Note: comparison is *CASE* *SENSITIVE*
17850Sstevel@tonic-gate 	 */
17860Sstevel@tonic-gate 	for (i = 0; i < scsi_probe_strict_s2_size; i++) {
17870Sstevel@tonic-gate 		p = &scsi_probe_strict_s2_list[i];
17880Sstevel@tonic-gate 
17890Sstevel@tonic-gate 		if ((strcmp(p->sli_vid, vid) == 0) &&
17900Sstevel@tonic-gate 		    (strcmp(p->sli_pid, pid) == 0) &&
17910Sstevel@tonic-gate 		    (strcmp(p->sli_rev, rev) == 0)) {
17920Sstevel@tonic-gate 			/*
17930Sstevel@tonic-gate 			 * we found a match -- do NOT want to probe this one
17940Sstevel@tonic-gate 			 */
17950Sstevel@tonic-gate 			SCSI_PROBE_DEBUG3(1,
17960Sstevel@tonic-gate 			    "SCSA post-probe: recording strict SCSI-2 node "
17970Sstevel@tonic-gate 			    "vid/pid/rev = \"%s\"/\"%s\"/\"%s\"\n",
17980Sstevel@tonic-gate 			    vid, pid, rev);
17990Sstevel@tonic-gate 
18000Sstevel@tonic-gate 			/*
18010Sstevel@tonic-gate 			 * set/update private parent-node property,
18020Sstevel@tonic-gate 			 * so we can find out about this node later
18030Sstevel@tonic-gate 			 */
18040Sstevel@tonic-gate 			bad_target_found = 1;
18050Sstevel@tonic-gate 			break;
18060Sstevel@tonic-gate 		}
18070Sstevel@tonic-gate 	}
18080Sstevel@tonic-gate 
18090Sstevel@tonic-gate 	/*
18100Sstevel@tonic-gate 	 * either add remove target number from parent property
18110Sstevel@tonic-gate 	 */
18120Sstevel@tonic-gate 	scsi_update_parent_ss2_prop(devi, ap->a_target, bad_target_found);
18130Sstevel@tonic-gate 
18140Sstevel@tonic-gate dun:
18150Sstevel@tonic-gate 	if (vid != NULL) {
18160Sstevel@tonic-gate 		ddi_prop_free(vid);
18170Sstevel@tonic-gate 	}
18180Sstevel@tonic-gate 	if (pid != NULL) {
18190Sstevel@tonic-gate 		ddi_prop_free(pid);
18200Sstevel@tonic-gate 	}
18210Sstevel@tonic-gate 	if (rev != NULL) {
18220Sstevel@tonic-gate 		ddi_prop_free(rev);
18230Sstevel@tonic-gate 	}
18240Sstevel@tonic-gate }
18250Sstevel@tonic-gate 
18260Sstevel@tonic-gate 
18270Sstevel@tonic-gate /*
18280Sstevel@tonic-gate  * update the parent node to add in the supplied tgt number to the target
18290Sstevel@tonic-gate  * list property already present (if any)
18300Sstevel@tonic-gate  *
18310Sstevel@tonic-gate  * since the target list can never be longer than 16, and each target
18320Sstevel@tonic-gate  * number is also small, we can save having to alloc memory by putting
18330Sstevel@tonic-gate  * a 16-byte array on the stack and using it for property memory
18340Sstevel@tonic-gate  *
18350Sstevel@tonic-gate  * if "add_tgt" is set then add the target to the parent's property, else
18360Sstevel@tonic-gate  * remove it (if present)
18370Sstevel@tonic-gate  */
18380Sstevel@tonic-gate static void
scsi_update_parent_ss2_prop(dev_info_t * devi,int tgt,int add_tgt)18390Sstevel@tonic-gate scsi_update_parent_ss2_prop(dev_info_t *devi, int tgt, int add_tgt)
18400Sstevel@tonic-gate {
18410Sstevel@tonic-gate 	dev_info_t	*pdevi = (dev_info_t *)DEVI(devi)->devi_parent;
18420Sstevel@tonic-gate 	uchar_t		*tgt_list;
18430Sstevel@tonic-gate 	uint_t		nelements;
18440Sstevel@tonic-gate 	uint_t		new_nelements;
18450Sstevel@tonic-gate 	int		i;
18460Sstevel@tonic-gate 	int		update_result;
18470Sstevel@tonic-gate 	uchar_t		new_tgt_list[NTARGETS_WIDE];
18480Sstevel@tonic-gate 
18490Sstevel@tonic-gate 
18500Sstevel@tonic-gate 	ASSERT(pdevi != NULL);
18510Sstevel@tonic-gate 
18520Sstevel@tonic-gate 	SCSI_PROBE_DEBUG3(3,
18530Sstevel@tonic-gate 	    "SCSA post-probe: updating parent=%s property to %s tgt=%d\n",
18540Sstevel@tonic-gate 	    ddi_node_name(pdevi), add_tgt ? "add" : "remove", tgt);
18550Sstevel@tonic-gate 
185611052SChris.Horne@Sun.COM 	if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, pdevi,
185711052SChris.Horne@Sun.COM 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
18580Sstevel@tonic-gate 	    SS2_LUN0_TGT_LIST_PROP, &tgt_list, &nelements) ==
18590Sstevel@tonic-gate 	    DDI_PROP_SUCCESS) {
18600Sstevel@tonic-gate 
18610Sstevel@tonic-gate 		if (add_tgt) {
18620Sstevel@tonic-gate 			/*
18630Sstevel@tonic-gate 			 * we found an existing property -- we might need
18640Sstevel@tonic-gate 			 *	to add to it
18650Sstevel@tonic-gate 			 */
18660Sstevel@tonic-gate 			for (i = 0; i < nelements; i++) {
18670Sstevel@tonic-gate 				if (tgt_list[i] == tgt) {
18680Sstevel@tonic-gate 					/* target already in list */
18690Sstevel@tonic-gate 					SCSI_PROBE_DEBUG1(2, "SCSA post-probe:"
18700Sstevel@tonic-gate 					    " tgt %d already listed\n", tgt);
18710Sstevel@tonic-gate 					ddi_prop_free(tgt_list);
18720Sstevel@tonic-gate 					return;
18730Sstevel@tonic-gate 				}
18740Sstevel@tonic-gate 			}
18750Sstevel@tonic-gate 
18760Sstevel@tonic-gate 			/*
18770Sstevel@tonic-gate 			 * need to append our target number to end of list
18780Sstevel@tonic-gate 			 *	(no need sorting list, as it's so short)
18790Sstevel@tonic-gate 			 */
18800Sstevel@tonic-gate 
18810Sstevel@tonic-gate 			/*
18820Sstevel@tonic-gate 			 * will this new entry fit ?? -- it should, since
18830Sstevel@tonic-gate 			 *	the array is 16-wide and only keep track of
18840Sstevel@tonic-gate 			 *	16 targets, but check just in case
18850Sstevel@tonic-gate 			 */
18860Sstevel@tonic-gate 			new_nelements = nelements + 1;
18870Sstevel@tonic-gate 			if (new_nelements >= NTARGETS_WIDE) {
18880Sstevel@tonic-gate 				SCSI_PROBE_DEBUG0(1, "SCSA post-probe: "
18890Sstevel@tonic-gate 				    "internal error: no room "
18900Sstevel@tonic-gate 				    "for more targets?\n");
18910Sstevel@tonic-gate 				ddi_prop_free(tgt_list);
18920Sstevel@tonic-gate 				return;
18930Sstevel@tonic-gate 			}
18940Sstevel@tonic-gate 
18950Sstevel@tonic-gate 			/* copy existing list then add our tgt number to end */
18960Sstevel@tonic-gate 			bcopy((void *)tgt_list, (void *)new_tgt_list,
18970Sstevel@tonic-gate 			    sizeof (uchar_t) * nelements);
18980Sstevel@tonic-gate 			new_tgt_list[new_nelements - 1] = (uchar_t)tgt;
18990Sstevel@tonic-gate 		} else {
19000Sstevel@tonic-gate 			/*
19010Sstevel@tonic-gate 			 * we need to remove our target number from the list,
19020Sstevel@tonic-gate 			 *	so copy all of the other target numbers,
19030Sstevel@tonic-gate 			 *	skipping ours
19040Sstevel@tonic-gate 			 */
19050Sstevel@tonic-gate 			int	tgt_removed = 0;
19060Sstevel@tonic-gate 
19070Sstevel@tonic-gate 			new_nelements = 0;
19080Sstevel@tonic-gate 			for (i = 0; i < nelements; i++) {
19090Sstevel@tonic-gate 				if (tgt_list[i] != tgt) {
19100Sstevel@tonic-gate 					new_tgt_list[new_nelements++] =
19110Sstevel@tonic-gate 					    tgt_list[i];
19120Sstevel@tonic-gate 				} else {
19130Sstevel@tonic-gate 					/* skip this target */
19140Sstevel@tonic-gate 					tgt_removed++;
19150Sstevel@tonic-gate 				}
19160Sstevel@tonic-gate 			}
19170Sstevel@tonic-gate 
19180Sstevel@tonic-gate 			if (!tgt_removed) {
19190Sstevel@tonic-gate 				SCSI_PROBE_DEBUG1(2, "SCSA post-probe:"
19200Sstevel@tonic-gate 				    " no need to remove tgt %d\n", tgt);
19210Sstevel@tonic-gate 				ddi_prop_free(tgt_list);
19220Sstevel@tonic-gate 				return;
19230Sstevel@tonic-gate 			}
19240Sstevel@tonic-gate 		}
19250Sstevel@tonic-gate 
19260Sstevel@tonic-gate 		update_result = ddi_prop_update_byte_array(DDI_DEV_T_NONE,
19270Sstevel@tonic-gate 		    pdevi, SS2_LUN0_TGT_LIST_PROP, new_tgt_list,
19280Sstevel@tonic-gate 		    new_nelements);
19290Sstevel@tonic-gate 
19300Sstevel@tonic-gate 		ddi_prop_free(tgt_list);
19310Sstevel@tonic-gate 	} else {
19320Sstevel@tonic-gate 		/*
19330Sstevel@tonic-gate 		 * no property yet
19340Sstevel@tonic-gate 		 */
19350Sstevel@tonic-gate 		if (add_tgt) {
19360Sstevel@tonic-gate 			/*
19370Sstevel@tonic-gate 			 * create a property with just our tgt
19380Sstevel@tonic-gate 			 */
19390Sstevel@tonic-gate 			new_tgt_list[0] = (uchar_t)tgt;
19400Sstevel@tonic-gate 			new_nelements = 1;	/* just one element */
19410Sstevel@tonic-gate 
19420Sstevel@tonic-gate 			update_result = ddi_prop_update_byte_array(
19430Sstevel@tonic-gate 			    DDI_DEV_T_NONE, pdevi, SS2_LUN0_TGT_LIST_PROP,
19440Sstevel@tonic-gate 			    new_tgt_list, new_nelements);
19450Sstevel@tonic-gate 		} else {
19460Sstevel@tonic-gate 			/*
19470Sstevel@tonic-gate 			 * no list so no need to remove tgt from that list
19480Sstevel@tonic-gate 			 */
19490Sstevel@tonic-gate 			return;
19500Sstevel@tonic-gate 		}
19510Sstevel@tonic-gate 	}
19520Sstevel@tonic-gate 
19530Sstevel@tonic-gate #ifdef	DEBUG
19540Sstevel@tonic-gate 	/*
19550Sstevel@tonic-gate 	 * if we get here we have tried to add/update properties
19560Sstevel@tonic-gate 	 */
19570Sstevel@tonic-gate 	if (update_result != DDI_PROP_SUCCESS) {
19580Sstevel@tonic-gate 		SCSI_PROBE_DEBUG2(1, "SCSA post-probe: can't update parent "
19590Sstevel@tonic-gate 		    "property with tgt=%d (%d)\n", tgt, update_result);
19600Sstevel@tonic-gate 	} else {
19610Sstevel@tonic-gate 		if (add_tgt) {
19620Sstevel@tonic-gate 			SCSI_PROBE_DEBUG3(2,
19630Sstevel@tonic-gate 			    "SCSA post-probe: added tgt=%d to parent "
19640Sstevel@tonic-gate 			    "prop=\"%s\" (now %d entries)\n",
19650Sstevel@tonic-gate 			    tgt, SS2_LUN0_TGT_LIST_PROP, new_nelements);
19660Sstevel@tonic-gate 		} else {
19670Sstevel@tonic-gate 			SCSI_PROBE_DEBUG3(2,
19680Sstevel@tonic-gate 			    "SCSA post-probe: removed tgt=%d from parent "
19690Sstevel@tonic-gate 			    "prop=\"%s\" (now %d entries)\n",
19700Sstevel@tonic-gate 			    tgt, SS2_LUN0_TGT_LIST_PROP, new_nelements);
19710Sstevel@tonic-gate 		}
19720Sstevel@tonic-gate 	}
19730Sstevel@tonic-gate #endif
19740Sstevel@tonic-gate }
197510696SDavid.Hollister@Sun.COM 
197610696SDavid.Hollister@Sun.COM 
197710696SDavid.Hollister@Sun.COM /* XXX BEGIN: find a better place for this: inquiry.h? */
197810696SDavid.Hollister@Sun.COM /*
197910696SDavid.Hollister@Sun.COM  * Definitions used by device id registration routines
198010696SDavid.Hollister@Sun.COM  */
198110696SDavid.Hollister@Sun.COM #define	VPD_HEAD_OFFSET		3	/* size of head for vpd page */
198210696SDavid.Hollister@Sun.COM #define	VPD_PAGE_LENGTH		3	/* offset for pge length data */
198310696SDavid.Hollister@Sun.COM #define	VPD_MODE_PAGE		1	/* offset into vpd pg for "page code" */
198410696SDavid.Hollister@Sun.COM 
198510696SDavid.Hollister@Sun.COM /* size for devid inquiries */
198610696SDavid.Hollister@Sun.COM #define	MAX_INQUIRY_SIZE	0xF0
198710696SDavid.Hollister@Sun.COM #define	MAX_INQUIRY_SIZE_EVPD	0xFF	/* XXX why is this longer */
198810696SDavid.Hollister@Sun.COM /* XXX END: find a better place for these */
198910696SDavid.Hollister@Sun.COM 
199010696SDavid.Hollister@Sun.COM 
199110696SDavid.Hollister@Sun.COM /*
199210696SDavid.Hollister@Sun.COM  * Decorate devinfo node with identity properties using information obtained
199310696SDavid.Hollister@Sun.COM  * from device. These properties are used by device enumeration code to derive
199410696SDavid.Hollister@Sun.COM  * the devid, and guid for the device. These properties are also used to
199510696SDavid.Hollister@Sun.COM  * determine if a device should be enumerated under the physical HBA (PHCI) or
199610696SDavid.Hollister@Sun.COM  * the virtual HBA (VHCI, for mpxio support).
199710696SDavid.Hollister@Sun.COM  *
199810696SDavid.Hollister@Sun.COM  * Return zero on success. If commands that should succeed fail or allocations
199910696SDavid.Hollister@Sun.COM  * fail then return failure (non-zero). It is possible for this function to
200010696SDavid.Hollister@Sun.COM  * return success and not have decorated the node with any additional identity
200110696SDavid.Hollister@Sun.COM  * information if the device correctly responds indicating that they are not
200210696SDavid.Hollister@Sun.COM  * supported.  When failure occurs the caller should consider not making the
200310696SDavid.Hollister@Sun.COM  * device accessible.
200410696SDavid.Hollister@Sun.COM  */
200510696SDavid.Hollister@Sun.COM int
scsi_device_identity(struct scsi_device * sd,int (* callback)())200610696SDavid.Hollister@Sun.COM scsi_device_identity(struct scsi_device *sd, int (*callback)())
200710696SDavid.Hollister@Sun.COM {
200810696SDavid.Hollister@Sun.COM 	dev_info_t	*devi		= sd->sd_dev;
200910696SDavid.Hollister@Sun.COM 	uchar_t		*inq80		= NULL;
201010696SDavid.Hollister@Sun.COM 	uchar_t		*inq83		= NULL;
201110696SDavid.Hollister@Sun.COM 	int		rval;
201210696SDavid.Hollister@Sun.COM 	size_t		len;
201310696SDavid.Hollister@Sun.COM 	int		pg80, pg83;
201410696SDavid.Hollister@Sun.COM 
201510696SDavid.Hollister@Sun.COM 	/* find out what pages are supported by device */
201610696SDavid.Hollister@Sun.COM 	if (check_vpd_page_support8083(sd, callback, &pg80, &pg83) == -1)
201710696SDavid.Hollister@Sun.COM 		return (-1);
201810696SDavid.Hollister@Sun.COM 
201910696SDavid.Hollister@Sun.COM 	/* if available, collect page 80 data and add as property */
202010696SDavid.Hollister@Sun.COM 	if (pg80) {
202110696SDavid.Hollister@Sun.COM 		inq80 = kmem_zalloc(MAX_INQUIRY_SIZE,
202210696SDavid.Hollister@Sun.COM 		    ((callback == SLEEP_FUNC) ? KM_SLEEP : KM_NOSLEEP));
202310696SDavid.Hollister@Sun.COM 		if (inq80 == NULL) {
202410696SDavid.Hollister@Sun.COM 			rval = -1;
202510696SDavid.Hollister@Sun.COM 			goto out;
202610696SDavid.Hollister@Sun.COM 		}
202710696SDavid.Hollister@Sun.COM 
202810696SDavid.Hollister@Sun.COM 		rval = send_scsi_INQUIRY(sd, callback, inq80,
202912213SGavin.Maltby@Sun.COM 		    MAX_INQUIRY_SIZE, 0x01, 0x80, &len, STC_IDENTITY_PG80);
203010696SDavid.Hollister@Sun.COM 		if (rval)
203110696SDavid.Hollister@Sun.COM 			goto out;		/* should have worked */
203210696SDavid.Hollister@Sun.COM 
203310696SDavid.Hollister@Sun.COM 		if (len && (ndi_prop_update_byte_array(DDI_DEV_T_NONE, devi,
203410696SDavid.Hollister@Sun.COM 		    "inquiry-page-80", inq80, len) != DDI_PROP_SUCCESS)) {
203510696SDavid.Hollister@Sun.COM 			cmn_err(CE_WARN, "scsi_device_identity: "
203610696SDavid.Hollister@Sun.COM 			    "failed to add page80 prop");
203710696SDavid.Hollister@Sun.COM 			rval = -1;
203810696SDavid.Hollister@Sun.COM 			goto out;
203910696SDavid.Hollister@Sun.COM 		}
204010696SDavid.Hollister@Sun.COM 	}
204110696SDavid.Hollister@Sun.COM 
204210696SDavid.Hollister@Sun.COM 	/* if available, collect page 83 data and add as property */
204310696SDavid.Hollister@Sun.COM 	if (pg83) {
204410696SDavid.Hollister@Sun.COM 		inq83 = kmem_zalloc(MAX_INQUIRY_SIZE,
204510696SDavid.Hollister@Sun.COM 		    ((callback == SLEEP_FUNC) ? KM_SLEEP : KM_NOSLEEP));
204610696SDavid.Hollister@Sun.COM 		if (inq83 == NULL) {
204710696SDavid.Hollister@Sun.COM 			rval = -1;
204810696SDavid.Hollister@Sun.COM 			goto out;
204910696SDavid.Hollister@Sun.COM 		}
205010696SDavid.Hollister@Sun.COM 
205110696SDavid.Hollister@Sun.COM 		rval = send_scsi_INQUIRY(sd, callback, inq83,
205212213SGavin.Maltby@Sun.COM 		    MAX_INQUIRY_SIZE, 0x01, 0x83, &len, STC_IDENTITY_PG83);
205310696SDavid.Hollister@Sun.COM 		if (rval)
205410696SDavid.Hollister@Sun.COM 			goto out;		/* should have worked */
205510696SDavid.Hollister@Sun.COM 
205610696SDavid.Hollister@Sun.COM 		if (len && (ndi_prop_update_byte_array(DDI_DEV_T_NONE, devi,
205710696SDavid.Hollister@Sun.COM 		    "inquiry-page-83", inq83, len) != DDI_PROP_SUCCESS)) {
205810696SDavid.Hollister@Sun.COM 			cmn_err(CE_WARN, "scsi_device_identity: "
205910696SDavid.Hollister@Sun.COM 			    "failed to add page83 prop");
206010696SDavid.Hollister@Sun.COM 			rval = -1;
206110696SDavid.Hollister@Sun.COM 			goto out;
206210696SDavid.Hollister@Sun.COM 		}
206310696SDavid.Hollister@Sun.COM 	}
206410696SDavid.Hollister@Sun.COM 
206510696SDavid.Hollister@Sun.COM 	/* Commands worked, identity information that exists has been added. */
206610696SDavid.Hollister@Sun.COM 	rval = 0;
206710696SDavid.Hollister@Sun.COM 
206810696SDavid.Hollister@Sun.COM 	/* clean up resources */
206910696SDavid.Hollister@Sun.COM out:	if (inq80 != NULL)
207010696SDavid.Hollister@Sun.COM 		kmem_free(inq80, MAX_INQUIRY_SIZE);
207110696SDavid.Hollister@Sun.COM 	if (inq83 != NULL)
207210696SDavid.Hollister@Sun.COM 		kmem_free(inq83, MAX_INQUIRY_SIZE);
207310696SDavid.Hollister@Sun.COM 
207410696SDavid.Hollister@Sun.COM 	return (rval);
207510696SDavid.Hollister@Sun.COM }
207610696SDavid.Hollister@Sun.COM 
207710696SDavid.Hollister@Sun.COM /*
207810696SDavid.Hollister@Sun.COM  * Send an INQUIRY command with the EVPD bit set and a page code of 0x00 to
207910696SDavid.Hollister@Sun.COM  * the device, returning zero on success. Returned INQUIRY data is used to
208010696SDavid.Hollister@Sun.COM  * determine which vital product pages are supported. The device idenity
208110696SDavid.Hollister@Sun.COM  * information we are looking for is in pages 0x83 and/or 0x80. If the device
208210696SDavid.Hollister@Sun.COM  * fails the EVPD inquiry then no pages are supported but the call succeeds.
208310696SDavid.Hollister@Sun.COM  * Return -1 (failure) if there were memory allocation failures or if a
208410696SDavid.Hollister@Sun.COM  * command faild that should have worked.
208510696SDavid.Hollister@Sun.COM  */
208610696SDavid.Hollister@Sun.COM static int
check_vpd_page_support8083(struct scsi_device * sd,int (* callback)(),int * ppg80,int * ppg83)208710696SDavid.Hollister@Sun.COM check_vpd_page_support8083(struct scsi_device *sd, int (*callback)(),
208810696SDavid.Hollister@Sun.COM 	int *ppg80, int *ppg83)
208910696SDavid.Hollister@Sun.COM {
209010696SDavid.Hollister@Sun.COM 	uchar_t *page_list;
209110696SDavid.Hollister@Sun.COM 	int	counter;
209210696SDavid.Hollister@Sun.COM 	int	rval;
209310696SDavid.Hollister@Sun.COM 
209410696SDavid.Hollister@Sun.COM 	/* pages are not supported */
209510696SDavid.Hollister@Sun.COM 	*ppg80 = 0;
209610696SDavid.Hollister@Sun.COM 	*ppg83 = 0;
209710696SDavid.Hollister@Sun.COM 
209810696SDavid.Hollister@Sun.COM 	/*
209910696SDavid.Hollister@Sun.COM 	 * We'll set the page length to the maximum to save figuring it out
210010696SDavid.Hollister@Sun.COM 	 * with an additional call.
210110696SDavid.Hollister@Sun.COM 	 */
210210696SDavid.Hollister@Sun.COM 	page_list =  kmem_zalloc(MAX_INQUIRY_SIZE_EVPD,
210310696SDavid.Hollister@Sun.COM 	    ((callback == SLEEP_FUNC) ? KM_SLEEP : KM_NOSLEEP));
210410696SDavid.Hollister@Sun.COM 	if (page_list == NULL)
210510696SDavid.Hollister@Sun.COM 		return (-1);		/* memory allocation problem */
210610696SDavid.Hollister@Sun.COM 
210710696SDavid.Hollister@Sun.COM 	/* issue page 0 (Supported VPD Pages) INQUIRY with evpd set */
210810696SDavid.Hollister@Sun.COM 	rval = send_scsi_INQUIRY(sd, callback,
210912213SGavin.Maltby@Sun.COM 	    page_list, MAX_INQUIRY_SIZE_EVPD, 1, 0, NULL, STC_VPD_CHECK);
211010696SDavid.Hollister@Sun.COM 
211110696SDavid.Hollister@Sun.COM 	/*
211210696SDavid.Hollister@Sun.COM 	 * Now we must validate that the device accepted the command (some
211310696SDavid.Hollister@Sun.COM 	 * devices do not support it) and if the idenity pages we are
211410696SDavid.Hollister@Sun.COM 	 * interested in are supported.
211510696SDavid.Hollister@Sun.COM 	 */
211610696SDavid.Hollister@Sun.COM 	if ((rval == 0) &&
211710696SDavid.Hollister@Sun.COM 	    (page_list[VPD_MODE_PAGE] == 0x00)) {
211810696SDavid.Hollister@Sun.COM 		/* Loop to find one of the 2 pages we need */
211910696SDavid.Hollister@Sun.COM 		counter = 4;  /* Supported pages start at byte 4, with 0x00 */
212010696SDavid.Hollister@Sun.COM 
212110696SDavid.Hollister@Sun.COM 		/*
212210696SDavid.Hollister@Sun.COM 		 * Pages are returned in ascending order, and 0x83 is the
212310696SDavid.Hollister@Sun.COM 		 * last page we are hoping to find.
212410696SDavid.Hollister@Sun.COM 		 */
212510696SDavid.Hollister@Sun.COM 		while ((page_list[counter] <= 0x83) &&
212610696SDavid.Hollister@Sun.COM 		    (counter <= (page_list[VPD_PAGE_LENGTH] +
212710696SDavid.Hollister@Sun.COM 		    VPD_HEAD_OFFSET))) {
212810696SDavid.Hollister@Sun.COM 			/*
212910696SDavid.Hollister@Sun.COM 			 * Add 3 because page_list[3] is the number of
213010696SDavid.Hollister@Sun.COM 			 * pages minus 3
213110696SDavid.Hollister@Sun.COM 			 */
213210696SDavid.Hollister@Sun.COM 
213310696SDavid.Hollister@Sun.COM 			switch (page_list[counter]) {
213410696SDavid.Hollister@Sun.COM 			case 0x80:
213510696SDavid.Hollister@Sun.COM 				*ppg80 = 1;
213610696SDavid.Hollister@Sun.COM 				break;
213710696SDavid.Hollister@Sun.COM 			case 0x83:
213810696SDavid.Hollister@Sun.COM 				*ppg83 = 1;
213910696SDavid.Hollister@Sun.COM 				break;
214010696SDavid.Hollister@Sun.COM 			}
214110696SDavid.Hollister@Sun.COM 			counter++;
214210696SDavid.Hollister@Sun.COM 		}
214310696SDavid.Hollister@Sun.COM 	}
214410696SDavid.Hollister@Sun.COM 
214510696SDavid.Hollister@Sun.COM 	kmem_free(page_list, MAX_INQUIRY_SIZE_EVPD);
214610696SDavid.Hollister@Sun.COM 	return (0);
214710696SDavid.Hollister@Sun.COM }
214810696SDavid.Hollister@Sun.COM 
214910696SDavid.Hollister@Sun.COM /*
215010696SDavid.Hollister@Sun.COM  * Send INQUIRY command with specified EVPD and page code.  Return
215110696SDavid.Hollister@Sun.COM  * zero on success.  On success, the amount of data transferred
215210696SDavid.Hollister@Sun.COM  * is returned in *lenp.
215310696SDavid.Hollister@Sun.COM  */
215410696SDavid.Hollister@Sun.COM static int
send_scsi_INQUIRY(struct scsi_device * sd,int (* callback)(),uchar_t * bufaddr,size_t buflen,uchar_t evpd,uchar_t page_code,size_t * lenp,enum scsi_test_ctxt ctxt)215510696SDavid.Hollister@Sun.COM send_scsi_INQUIRY(struct scsi_device *sd, int (*callback)(),
215610696SDavid.Hollister@Sun.COM     uchar_t *bufaddr, size_t buflen,
215712213SGavin.Maltby@Sun.COM     uchar_t evpd, uchar_t page_code, size_t *lenp,
215812213SGavin.Maltby@Sun.COM     enum scsi_test_ctxt ctxt)
215910696SDavid.Hollister@Sun.COM {
216010696SDavid.Hollister@Sun.COM 	int		(*cb_flag)();
216110696SDavid.Hollister@Sun.COM 	struct buf	*inq_bp;
216210696SDavid.Hollister@Sun.COM 	struct scsi_pkt *inq_pkt = NULL;
216310696SDavid.Hollister@Sun.COM 	int		rval = -1;
216410696SDavid.Hollister@Sun.COM 
216510696SDavid.Hollister@Sun.COM 	if (lenp)
216610696SDavid.Hollister@Sun.COM 		*lenp = 0;
216710696SDavid.Hollister@Sun.COM 	if (callback != SLEEP_FUNC && callback != NULL_FUNC)
216810696SDavid.Hollister@Sun.COM 		cb_flag = NULL_FUNC;
216910696SDavid.Hollister@Sun.COM 	else
217010696SDavid.Hollister@Sun.COM 		cb_flag = callback;
217110696SDavid.Hollister@Sun.COM 	inq_bp = scsi_alloc_consistent_buf(ROUTE,
217210696SDavid.Hollister@Sun.COM 	    (struct buf *)NULL, buflen, B_READ, cb_flag, NULL);
217310696SDavid.Hollister@Sun.COM 	if (inq_bp == NULL)
217410696SDavid.Hollister@Sun.COM 		goto out;		/* memory allocation problem */
217510696SDavid.Hollister@Sun.COM 
217610696SDavid.Hollister@Sun.COM 	inq_pkt = scsi_init_pkt(ROUTE, (struct scsi_pkt *)NULL,
217710696SDavid.Hollister@Sun.COM 	    inq_bp, CDB_GROUP0, sizeof (struct scsi_arq_status),
217810696SDavid.Hollister@Sun.COM 	    0, PKT_CONSISTENT, callback, NULL);
217910696SDavid.Hollister@Sun.COM 	if (inq_pkt == NULL)
218010696SDavid.Hollister@Sun.COM 		goto out;		/* memory allocation problem */
218110696SDavid.Hollister@Sun.COM 
218210696SDavid.Hollister@Sun.COM 	ASSERT(inq_bp->b_error == 0);
218310696SDavid.Hollister@Sun.COM 
218410696SDavid.Hollister@Sun.COM 	/* form INQUIRY cdb with specified EVPD and page code */
218510696SDavid.Hollister@Sun.COM 	(void) scsi_setup_cdb((union scsi_cdb *)inq_pkt->pkt_cdbp,
218610696SDavid.Hollister@Sun.COM 	    SCMD_INQUIRY, 0, buflen, 0);
218710696SDavid.Hollister@Sun.COM 	inq_pkt->pkt_cdbp[1] = evpd;
218810696SDavid.Hollister@Sun.COM 	inq_pkt->pkt_cdbp[2] = page_code;
218910696SDavid.Hollister@Sun.COM 
219010696SDavid.Hollister@Sun.COM 	inq_pkt->pkt_time = SCSI_POLL_TIMEOUT;	/* in seconds */
219110696SDavid.Hollister@Sun.COM 	inq_pkt->pkt_flags = FLAG_NOINTR|FLAG_NOPARITY;
219210696SDavid.Hollister@Sun.COM 
219310696SDavid.Hollister@Sun.COM 	/*
219410696SDavid.Hollister@Sun.COM 	 * Issue inquiry command thru scsi_test
219510696SDavid.Hollister@Sun.COM 	 *
219610696SDavid.Hollister@Sun.COM 	 * NOTE: This is important data about device identity, not sure why
219710696SDavid.Hollister@Sun.COM 	 * NOPARITY is used. Also seems like we should check pkt_stat for
219810696SDavid.Hollister@Sun.COM 	 * STATE_XFERRED_DATA.
219910696SDavid.Hollister@Sun.COM 	 */
220012213SGavin.Maltby@Sun.COM 	if (scsi_test(inq_pkt, ctxt) == SCSI_TEST_CMPLT_GOOD) {
220110696SDavid.Hollister@Sun.COM 		ASSERT(inq_pkt->pkt_resid >= 0);
220210696SDavid.Hollister@Sun.COM 		ASSERT(inq_pkt->pkt_resid <= buflen);
220310696SDavid.Hollister@Sun.COM 
220410696SDavid.Hollister@Sun.COM 		bcopy(inq_bp->b_un.b_addr,
220510696SDavid.Hollister@Sun.COM 		    bufaddr, buflen - inq_pkt->pkt_resid);
220610696SDavid.Hollister@Sun.COM 		if (lenp)
220710696SDavid.Hollister@Sun.COM 			*lenp = (buflen - inq_pkt->pkt_resid);
220810696SDavid.Hollister@Sun.COM 		rval = 0;
220910696SDavid.Hollister@Sun.COM 	}
221010696SDavid.Hollister@Sun.COM 
221112213SGavin.Maltby@Sun.COM 	/*
221212213SGavin.Maltby@Sun.COM 	 * XXX We should retry on target busy
221312213SGavin.Maltby@Sun.COM 	 */
221412213SGavin.Maltby@Sun.COM 
221510696SDavid.Hollister@Sun.COM out:	if (inq_pkt)
221610696SDavid.Hollister@Sun.COM 		scsi_destroy_pkt(inq_pkt);
221710696SDavid.Hollister@Sun.COM 	if (inq_bp)
221810696SDavid.Hollister@Sun.COM 		scsi_free_consistent_buf(inq_bp);
221910696SDavid.Hollister@Sun.COM 	return (rval);
222010696SDavid.Hollister@Sun.COM }
2221