17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
54ab75253Smrj  * Common Development and Distribution License (the "License").
64ab75253Smrj  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22392e836bSGavin Maltby  * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
237c478bd9Sstevel@tonic-gate  */
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate /*
267c478bd9Sstevel@tonic-gate  * Utility SCSI configuration routines
277c478bd9Sstevel@tonic-gate  */
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate  * Many routines in this file have built in parallel bus assumption
307c478bd9Sstevel@tonic-gate  * which might need to change as other interconnect evolve.
317c478bd9Sstevel@tonic-gate  */
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #include <sys/scsi/scsi.h>
347c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
35602ca9eaScth #include <sys/bitmap.h>
36392e836bSGavin Maltby #include <sys/fm/protocol.h>
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate /*
397c478bd9Sstevel@tonic-gate  * macro for filling in lun value for scsi-1 support
407c478bd9Sstevel@tonic-gate  */
417c478bd9Sstevel@tonic-gate 
424c06356bSdh #define	FILL_SCSI1_LUN(sd, pkt) \
434c06356bSdh 	if ((sd->sd_address.a_lun > 0) && \
444c06356bSdh 	    (sd->sd_inq->inq_ansi == 0x1)) { \
457c478bd9Sstevel@tonic-gate 		((union scsi_cdb *)(pkt)->pkt_cdbp)->scc_lun = \
464c06356bSdh 		    sd->sd_address.a_lun; \
477c478bd9Sstevel@tonic-gate 	}
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate extern struct mod_ops mod_miscops;
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate static struct modlmisc modlmisc = {
527c478bd9Sstevel@tonic-gate 	&mod_miscops,	/* Type of module */
537c478bd9Sstevel@tonic-gate 	"SCSI Bus Utility Routines"
547c478bd9Sstevel@tonic-gate };
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
577c478bd9Sstevel@tonic-gate 	MODREV_1, (void *)&modlmisc, NULL
587c478bd9Sstevel@tonic-gate };
597c478bd9Sstevel@tonic-gate 
60392e836bSGavin Maltby /*
61392e836bSGavin Maltby  * Contexts from which we call scsi_test
62392e836bSGavin Maltby  */
63392e836bSGavin Maltby enum scsi_test_ctxt {
64392e836bSGavin Maltby 	/*
65392e836bSGavin Maltby 	 * Those in scsi_hba_probe_pi()
66392e836bSGavin Maltby 	 */
67392e836bSGavin Maltby 	STC_PROBE_FIRST_INQ,
68392e836bSGavin Maltby 	STC_PROBE_FIRST_INQ_RETRY,
69392e836bSGavin Maltby 	STC_PROBE_PARTIAL_SUCCESS,
70392e836bSGavin Maltby 	STC_PROBE_RQSENSE1,
71392e836bSGavin Maltby 	STC_PROBE_CHK_CLEARED,
72392e836bSGavin Maltby 	STC_PROBE_RQSENSE2,
73392e836bSGavin Maltby 	STC_PROBE_INQ_FINAL,
74392e836bSGavin Maltby 	/*
75392e836bSGavin Maltby 	 * Those in check_vpd_page_support8083()
76392e836bSGavin Maltby 	 */
77392e836bSGavin Maltby 	STC_VPD_CHECK,
78392e836bSGavin Maltby 	/*
79392e836bSGavin Maltby 	 * Those in scsi_device_identity()
80392e836bSGavin Maltby 	 */
81392e836bSGavin Maltby 	STC_IDENTITY_PG80,
82392e836bSGavin Maltby 	STC_IDENTITY_PG83,
83392e836bSGavin Maltby };
84392e836bSGavin Maltby 
857c478bd9Sstevel@tonic-gate static void create_inquiry_props(struct scsi_device *);
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate static int scsi_check_ss2_LUN_limit(struct scsi_device *);
887c478bd9Sstevel@tonic-gate static void scsi_establish_LUN_limit(struct scsi_device *);
897c478bd9Sstevel@tonic-gate static void scsi_update_parent_ss2_prop(dev_info_t *, int, int);
907c478bd9Sstevel@tonic-gate 
914c06356bSdh static int check_vpd_page_support8083(struct scsi_device *sd,
924c06356bSdh 		int (*callback)(), int *, int *);
934c06356bSdh static int send_scsi_INQUIRY(struct scsi_device *sd,
944c06356bSdh 		int (*callback)(), uchar_t *bufaddr, size_t buflen,
95392e836bSGavin Maltby 		uchar_t evpd, uchar_t page_code, size_t *lenp,
96392e836bSGavin Maltby 		enum scsi_test_ctxt);
974c06356bSdh 
987c478bd9Sstevel@tonic-gate /*
997c478bd9Sstevel@tonic-gate  * this int-array HBA-node property keeps track of strictly SCSI-2
1007c478bd9Sstevel@tonic-gate  * target IDs
1017c478bd9Sstevel@tonic-gate  */
1027c478bd9Sstevel@tonic-gate #define	SS2_LUN0_TGT_LIST_PROP	"ss2-targets"
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate /*
1057c478bd9Sstevel@tonic-gate  * for keeping track of nodes for which we do *NOT* want to probe above LUN 7
1067c478bd9Sstevel@tonic-gate  * (i.e. strict SCSI-2 targets)
1077c478bd9Sstevel@tonic-gate  *
1087c478bd9Sstevel@tonic-gate  * note that we could also keep track of dtype (SCSI device type) and
1097c478bd9Sstevel@tonic-gate  * ANSI (SCSI standard conformance level), but all currently-known cases of
1107c478bd9Sstevel@tonic-gate  * this problem are on SCSI-2 PROCESSOR device types
1117c478bd9Sstevel@tonic-gate  */
1127c478bd9Sstevel@tonic-gate typedef struct ss2_lun0_info {
1137c478bd9Sstevel@tonic-gate 	const char	*sli_vid;	/* SCSI inquiry VID */
1147c478bd9Sstevel@tonic-gate 	const char	*sli_pid;	/* SCSI inquiry PID */
1157c478bd9Sstevel@tonic-gate 	const char	*sli_rev;	/* SCSI inquiry REV */
1167c478bd9Sstevel@tonic-gate } ss2_lun0_info_t;
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate /*
1197c478bd9Sstevel@tonic-gate  * these two workarounds are for the SCSI-2 GEM2* chips used in the
1207c478bd9Sstevel@tonic-gate  * D1000 and D240
1217c478bd9Sstevel@tonic-gate  */
1227c478bd9Sstevel@tonic-gate #define	SES_D1000_VID		"SYMBIOS"
1237c478bd9Sstevel@tonic-gate #define	SES_D1000_PID		"D1000"		/* the D1000 */
1247c478bd9Sstevel@tonic-gate #define	SES_D1000_REV		"2"
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate #define	SES_D240_VID		"SUN"
1277c478bd9Sstevel@tonic-gate #define	SES_D240_PID		"D240"		/* the D240 */
1287c478bd9Sstevel@tonic-gate #define	SES_D240_REV		"2"
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate /*
1317c478bd9Sstevel@tonic-gate  * a static list of targets where we do *not* want to probe above LUN 7
1327c478bd9Sstevel@tonic-gate  */
1337c478bd9Sstevel@tonic-gate static const ss2_lun0_info_t	scsi_probe_strict_s2_list[] = {
1347c478bd9Sstevel@tonic-gate 	{SES_D1000_VID, SES_D1000_PID, SES_D1000_REV},
1357c478bd9Sstevel@tonic-gate 	{SES_D240_VID, SES_D240_PID, SES_D240_REV},
1367c478bd9Sstevel@tonic-gate };
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate static const int		scsi_probe_strict_s2_size =
1397c478bd9Sstevel@tonic-gate 	sizeof (scsi_probe_strict_s2_list) / sizeof (struct ss2_lun0_info);
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate #ifdef	DEBUG
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate int	scsi_probe_debug = 0;
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate #define	SCSI_PROBE_DEBUG0(l, s)		\
1477c478bd9Sstevel@tonic-gate 		if (scsi_probe_debug >= (l)) printf(s)
1487c478bd9Sstevel@tonic-gate #define	SCSI_PROBE_DEBUG1(l, s, a1)	\
1497c478bd9Sstevel@tonic-gate 		if (scsi_probe_debug >= (l)) printf(s, a1)
1507c478bd9Sstevel@tonic-gate #define	SCSI_PROBE_DEBUG2(l, s, a1, a2)	\
1517c478bd9Sstevel@tonic-gate 		if (scsi_probe_debug >= (l)) printf(s, a1, a2)
1527c478bd9Sstevel@tonic-gate #define	SCSI_PROBE_DEBUG3(l, s, a1, a2, a3)	\
1537c478bd9Sstevel@tonic-gate 		if (scsi_probe_debug >= (l)) printf(s, a1, a2, a3)
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate #else	/* DEBUG */
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate #define	SCSI_PROBE_DEBUG0(l, s)
1587c478bd9Sstevel@tonic-gate #define	SCSI_PROBE_DEBUG1(l, s, a1)
1597c478bd9Sstevel@tonic-gate #define	SCSI_PROBE_DEBUG2(l, s, a1, a2)
1607c478bd9Sstevel@tonic-gate #define	SCSI_PROBE_DEBUG3(l, s, a1, a2, a3)
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate #endif	/* DEBUG */
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate int	scsi_test_busy_timeout = SCSI_POLL_TIMEOUT;	/* in seconds */
1657c478bd9Sstevel@tonic-gate int	scsi_test_busy_delay = 10000;			/* 10msec in usec */
1667c478bd9Sstevel@tonic-gate 
167392e836bSGavin Maltby 
168392e836bSGavin Maltby /*
169392e836bSGavin Maltby  * Returns from scsi_test.
170392e836bSGavin Maltby  *
171392e836bSGavin Maltby  * SCSI_TEST_CMPLT_GOOD => TRAN_ACCEPT, CMD_CMPLT, STATUS_GOOD
172392e836bSGavin Maltby  *
173392e836bSGavin Maltby  * SCSI_TEST_CMPLT_BUSY => TRAN_ACCEPT, CMD_CMPLT, STATUS_BUSY
174392e836bSGavin Maltby  *
175392e836bSGavin Maltby  * SCSI_TEST_CMPLT_CHECK => TRAN_ACCEPT, CMD_CMPLT, STATUS_CHECK
176392e836bSGavin Maltby  *
177392e836bSGavin Maltby  * SCSI_TEST_CMPLT_OTHER => TRAN_ACCEPT, CMD_CMPLT, !STATUS_{GOOD,BUSY,CHECK}
178392e836bSGavin Maltby  *
179392e836bSGavin Maltby  * SCSI_TEST_CMD_INCOMPLETE => TRAN_ACCEPT, CMD_INCOMPLETE
180392e836bSGavin Maltby  *
181392e836bSGavin Maltby  * SCSI_TEST_NOTCMPLT => TRAN_ACCEPT, pkt_reason != CMD_{CMPLT,INCOMPLETE}
182392e836bSGavin Maltby  *
183392e836bSGavin Maltby  * SCSI_TEST_TRAN_BUSY => (Repeated) TRAN_BUSY from attempt scsi_transport
184392e836bSGavin Maltby  *
185392e836bSGavin Maltby  * SCSI_TEST_TRAN_REJECT => TRAN_BADPKT or TRAN_FATAL_ERROR
186392e836bSGavin Maltby  *
187392e836bSGavin Maltby  */
188392e836bSGavin Maltby #define	SCSI_TEST_CMPLT_GOOD		0x01U
189392e836bSGavin Maltby #define	SCSI_TEST_CMPLT_BUSY		0x02U
190392e836bSGavin Maltby #define	SCSI_TEST_CMPLT_CHECK		0x04U
191392e836bSGavin Maltby #define	SCSI_TEST_CMPLT_OTHER		0x08U
192392e836bSGavin Maltby 
193392e836bSGavin Maltby #define	SCSI_TEST_CMPLTMASK \
194392e836bSGavin Maltby 	(SCSI_TEST_CMPLT_GOOD | SCSI_TEST_CMPLT_BUSY | \
195392e836bSGavin Maltby 	SCSI_TEST_CMPLT_CHECK | SCSI_TEST_CMPLT_OTHER)
196392e836bSGavin Maltby 
197392e836bSGavin Maltby #define	SCSI_TEST_PARTCMPLTMASK \
198392e836bSGavin Maltby 	(SCSI_TEST_CMPLTMASK & ~SCSI_TEST_CMPLT_GOOD)
199392e836bSGavin Maltby 
200392e836bSGavin Maltby #define	SCSI_TEST_CMD_INCOMPLETE	0x10U
201392e836bSGavin Maltby #define	SCSI_TEST_NOTCMPLT		0x20U
202392e836bSGavin Maltby #define	SCSI_TEST_TRAN_BUSY		0x40U
203392e836bSGavin Maltby #define	SCSI_TEST_TRAN_REJECT		0x80U
204392e836bSGavin Maltby 
205392e836bSGavin Maltby #define	SCSI_TEST_FAILMASK \
206392e836bSGavin Maltby 	(SCSI_TEST_CMD_INCOMPLETE | SCSI_TEST_NOTCMPLT | \
207392e836bSGavin Maltby 	SCSI_TEST_TRAN_BUSY | SCSI_TEST_TRAN_REJECT)
208392e836bSGavin Maltby 
209392e836bSGavin Maltby #define	SCSI_TEST_FAILURE(x) (((x) & SCSI_TEST_FAILMASK) != 0)
210392e836bSGavin Maltby 
2114ab75253Smrj /*
2124ab75253Smrj  * architecture dependent allocation restrictions. For x86, we'll set
2134ab75253Smrj  * dma_attr_addr_hi to scsi_max_phys_addr and dma_attr_sgllen to
2144ab75253Smrj  * scsi_sgl_size during _init().
2154ab75253Smrj  */
2164ab75253Smrj #if defined(__sparc)
2174ab75253Smrj ddi_dma_attr_t scsi_alloc_attr = {
2184ab75253Smrj 	DMA_ATTR_V0,	/* version number */
2194ab75253Smrj 	0x0,		/* lowest usable address */
2204ab75253Smrj 	0xFFFFFFFFull,	/* high DMA address range */
2214ab75253Smrj 	0xFFFFFFFFull,	/* DMA counter register */
2224ab75253Smrj 	1,		/* DMA address alignment */
2234ab75253Smrj 	1,		/* DMA burstsizes */
2244ab75253Smrj 	1,		/* min effective DMA size */
2254ab75253Smrj 	0xFFFFFFFFull,	/* max DMA xfer size */
2264ab75253Smrj 	0xFFFFFFFFull,	/* segment boundary */
2274ab75253Smrj 	1,		/* s/g list length */
2284ab75253Smrj 	512,		/* granularity of device */
2294ab75253Smrj 	0		/* DMA transfer flags */
2304ab75253Smrj };
2314ab75253Smrj #elif defined(__x86)
2324ab75253Smrj ddi_dma_attr_t scsi_alloc_attr = {
2334ab75253Smrj 	DMA_ATTR_V0,	/* version number */
2344ab75253Smrj 	0x0,		/* lowest usable address */
2354ab75253Smrj 	0x0,		/* high DMA address range [set in _init()] */
2364ab75253Smrj 	0xFFFFull,	/* DMA counter register */
2374ab75253Smrj 	1,		/* DMA address alignment */
2384ab75253Smrj 	1,		/* DMA burstsizes */
2394ab75253Smrj 	1,		/* min effective DMA size */
2404ab75253Smrj 	0xFFFFFFFFull,	/* max DMA xfer size */
2414ab75253Smrj 	0xFFFFFFFFull,  /* segment boundary */
2424ab75253Smrj 	0,		/* s/g list length */
2434ab75253Smrj 	512,		/* granularity of device [set in _init()] */
2444ab75253Smrj 	0		/* DMA transfer flags */
2454ab75253Smrj };
2464ab75253Smrj uint64_t scsi_max_phys_addr = 0xFFFFFFFFull;
2474ab75253Smrj int scsi_sgl_size = 0xFF;
2484ab75253Smrj #endif
2494ab75253Smrj 
250602ca9eaScth ulong_t	*scsi_pkt_bad_alloc_bitmap;
2514ab75253Smrj 
2527c478bd9Sstevel@tonic-gate int
_init()2537c478bd9Sstevel@tonic-gate _init()
2547c478bd9Sstevel@tonic-gate {
2557c478bd9Sstevel@tonic-gate 	scsi_initialize_hba_interface();
2567c478bd9Sstevel@tonic-gate 	scsi_watch_init();
2574ab75253Smrj 
2584ab75253Smrj #if defined(__x86)
2594ab75253Smrj 	/* set the max physical address for iob allocs on x86 */
2604ab75253Smrj 	scsi_alloc_attr.dma_attr_addr_hi = scsi_max_phys_addr;
2614ab75253Smrj 
2624ab75253Smrj 	/*
2634ab75253Smrj 	 * set the sgllen for iob allocs on x86. If this is set less than
2644ab75253Smrj 	 * the number of pages the buffer will take (taking into account
2654ab75253Smrj 	 * alignment), it would force the allocator to try and allocate
2664ab75253Smrj 	 * contiguous pages.
2674ab75253Smrj 	 */
2684ab75253Smrj 	scsi_alloc_attr.dma_attr_sgllen = scsi_sgl_size;
2694ab75253Smrj #endif
2704ab75253Smrj 
271602ca9eaScth 	/* bitmap to limit scsi_pkt allocation violation messages */
272602ca9eaScth 	scsi_pkt_bad_alloc_bitmap = kmem_zalloc(BT_SIZEOFMAP(devcnt), KM_SLEEP);
273602ca9eaScth 
2747c478bd9Sstevel@tonic-gate 	return (mod_install(&modlinkage));
2757c478bd9Sstevel@tonic-gate }
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate /*
2787c478bd9Sstevel@tonic-gate  * there is no _fini() routine because this module is never unloaded
2797c478bd9Sstevel@tonic-gate  */
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)2827c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
2837c478bd9Sstevel@tonic-gate {
2847c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
2857c478bd9Sstevel@tonic-gate }
2867c478bd9Sstevel@tonic-gate 
2874c06356bSdh #define	ROUTE	(&sd->sd_address)
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate static int
scsi_slave_do_rqsense(struct scsi_device * sd,int (* callback)())2904c06356bSdh scsi_slave_do_rqsense(struct scsi_device *sd, int (*callback)())
2917c478bd9Sstevel@tonic-gate {
2927c478bd9Sstevel@tonic-gate 	struct scsi_pkt *rq_pkt = NULL;
2937c478bd9Sstevel@tonic-gate 	struct buf *rq_bp = NULL;
2947c478bd9Sstevel@tonic-gate 	int rval = SCSIPROBE_EXISTS;
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate 	/*
2977c478bd9Sstevel@tonic-gate 	 * prepare rqsense packet
2987c478bd9Sstevel@tonic-gate 	 */
29953a7b6b6SChris Horne 	rq_bp = scsi_alloc_consistent_buf(ROUTE, (struct buf *)NULL,
3007c478bd9Sstevel@tonic-gate 	    (uint_t)SENSE_LENGTH, B_READ, callback, NULL);
3017c478bd9Sstevel@tonic-gate 	if (rq_bp == NULL) {
302184cd04cScth 		rval = SCSIPROBE_NOMEM;
303184cd04cScth 		goto out;
3047c478bd9Sstevel@tonic-gate 	}
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 	rq_pkt = scsi_init_pkt(ROUTE, (struct scsi_pkt *)NULL,
3077c478bd9Sstevel@tonic-gate 	    rq_bp, CDB_GROUP0, 1, 0, PKT_CONSISTENT,
3087c478bd9Sstevel@tonic-gate 	    callback, NULL);
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate 	if (rq_pkt == NULL) {
311184cd04cScth 		if (rq_bp->b_error == 0)
312184cd04cScth 			rval = SCSIPROBE_NOMEM_CB;
313184cd04cScth 		else
314184cd04cScth 			rval = SCSIPROBE_NOMEM;
315184cd04cScth 		goto out;
3167c478bd9Sstevel@tonic-gate 	}
3177c478bd9Sstevel@tonic-gate 	ASSERT(rq_bp->b_error == 0);
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 	(void) scsi_setup_cdb((union scsi_cdb *)rq_pkt->
3207c478bd9Sstevel@tonic-gate 	    pkt_cdbp, SCMD_REQUEST_SENSE, 0, SENSE_LENGTH, 0);
3214c06356bSdh 	FILL_SCSI1_LUN(sd, rq_pkt);
3227c478bd9Sstevel@tonic-gate 	rq_pkt->pkt_flags = FLAG_NOINTR|FLAG_NOPARITY|FLAG_SENSING;
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 	/*
3257c478bd9Sstevel@tonic-gate 	 * The controller type is as yet unknown, so we
3267c478bd9Sstevel@tonic-gate 	 * have to do a throwaway non-extended request sense,
3277c478bd9Sstevel@tonic-gate 	 * and hope that that clears the check condition
3287c478bd9Sstevel@tonic-gate 	 * for that unit until we can find out what kind
3297c478bd9Sstevel@tonic-gate 	 * of drive it is. A non-extended request sense
3307c478bd9Sstevel@tonic-gate 	 * is specified by stating that the sense block
3317c478bd9Sstevel@tonic-gate 	 * has 0 length, which is taken to mean that it
3327c478bd9Sstevel@tonic-gate 	 * is four bytes in length.
3337c478bd9Sstevel@tonic-gate 	 */
3347c478bd9Sstevel@tonic-gate 	if (scsi_poll(rq_pkt) < 0) {
335184cd04cScth 		rval = SCSIPROBE_FAILURE;
3367c478bd9Sstevel@tonic-gate 	}
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate out:
3397c478bd9Sstevel@tonic-gate 	if (rq_pkt) {
340184cd04cScth 		scsi_destroy_pkt(rq_pkt);
3417c478bd9Sstevel@tonic-gate 	}
3427c478bd9Sstevel@tonic-gate 	if (rq_bp) {
343184cd04cScth 		scsi_free_consistent_buf(rq_bp);
3447c478bd9Sstevel@tonic-gate 	}
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 	return (rval);
3477c478bd9Sstevel@tonic-gate }
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate /*
3507c478bd9Sstevel@tonic-gate  *
3517c478bd9Sstevel@tonic-gate  * SCSI slave probe routine - provided as a service to target drivers
3527c478bd9Sstevel@tonic-gate  *
3534c06356bSdh  * Mostly attempts to allocate and fill sd inquiry data..
3547c478bd9Sstevel@tonic-gate  */
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate int
scsi_slave(struct scsi_device * sd,int (* callback)())3574c06356bSdh scsi_slave(struct scsi_device *sd, int (*callback)())
3587c478bd9Sstevel@tonic-gate {
3597c478bd9Sstevel@tonic-gate 	struct scsi_pkt	*pkt;
3607c478bd9Sstevel@tonic-gate 	int		rval = SCSIPROBE_EXISTS;
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 	/*
3637c478bd9Sstevel@tonic-gate 	 * the first test unit ready will tell us whether a target
3647c478bd9Sstevel@tonic-gate 	 * responded and if there was one, it will clear the unit attention
3657c478bd9Sstevel@tonic-gate 	 * condition
3667c478bd9Sstevel@tonic-gate 	 */
3677c478bd9Sstevel@tonic-gate 	pkt = scsi_init_pkt(ROUTE, (struct scsi_pkt *)NULL, NULL,
3687c478bd9Sstevel@tonic-gate 	    CDB_GROUP0, sizeof (struct scsi_arq_status), 0, 0, callback, NULL);
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate 	if (pkt == NULL) {
3717c478bd9Sstevel@tonic-gate 		return (SCSIPROBE_NOMEM_CB);
3727c478bd9Sstevel@tonic-gate 	}
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate 	(void) scsi_setup_cdb((union scsi_cdb *)pkt->pkt_cdbp,
3757c478bd9Sstevel@tonic-gate 	    SCMD_TEST_UNIT_READY, 0, 0, 0);
3764c06356bSdh 	FILL_SCSI1_LUN(sd, pkt);
3777c478bd9Sstevel@tonic-gate 	pkt->pkt_flags = FLAG_NOINTR|FLAG_NOPARITY;
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 	if (scsi_poll(pkt) < 0) {
3807c478bd9Sstevel@tonic-gate 		if (pkt->pkt_reason == CMD_INCOMPLETE)
3817c478bd9Sstevel@tonic-gate 			rval = SCSIPROBE_NORESP;
3827c478bd9Sstevel@tonic-gate 		else
3837c478bd9Sstevel@tonic-gate 			rval = SCSIPROBE_FAILURE;
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 		if ((pkt->pkt_state & STATE_ARQ_DONE) == 0) {
386184cd04cScth 			if (((struct scsi_status *)pkt->pkt_scbp)->sts_chk)
387184cd04cScth 				/*
388184cd04cScth 				 * scanner and processor devices can return a
389184cd04cScth 				 * check condition here
390184cd04cScth 				 */
3914c06356bSdh 				rval = scsi_slave_do_rqsense(sd, callback);
3927c478bd9Sstevel@tonic-gate 		}
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 		if (rval != SCSIPROBE_EXISTS) {
3957c478bd9Sstevel@tonic-gate 			scsi_destroy_pkt(pkt);
3967c478bd9Sstevel@tonic-gate 			return (rval);
3977c478bd9Sstevel@tonic-gate 		}
3987c478bd9Sstevel@tonic-gate 	}
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 	/*
4017c478bd9Sstevel@tonic-gate 	 * the second test unit ready, allows the host adapter to negotiate
4027c478bd9Sstevel@tonic-gate 	 * synchronous transfer period and offset
4037c478bd9Sstevel@tonic-gate 	 */
4047c478bd9Sstevel@tonic-gate 	if (scsi_poll(pkt) < 0) {
4057c478bd9Sstevel@tonic-gate 		if (pkt->pkt_reason == CMD_INCOMPLETE)
4067c478bd9Sstevel@tonic-gate 			rval = SCSIPROBE_NORESP;
4077c478bd9Sstevel@tonic-gate 		else
4087c478bd9Sstevel@tonic-gate 			rval = SCSIPROBE_FAILURE;
4097c478bd9Sstevel@tonic-gate 	}
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 	/*
4127c478bd9Sstevel@tonic-gate 	 * do a rqsense if there was a check condition and ARQ was not done
4137c478bd9Sstevel@tonic-gate 	 */
4147c478bd9Sstevel@tonic-gate 	if ((pkt->pkt_state & STATE_ARQ_DONE) == 0) {
4157c478bd9Sstevel@tonic-gate 		if (((struct scsi_status *)pkt->pkt_scbp)->sts_chk) {
4164c06356bSdh 			rval = scsi_slave_do_rqsense(sd, callback);
4177c478bd9Sstevel@tonic-gate 		}
4187c478bd9Sstevel@tonic-gate 	}
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate 	/*
4217c478bd9Sstevel@tonic-gate 	 * call scsi_probe to do the inquiry
4224c06356bSdh 	 *
4234c06356bSdh 	 * NOTE: there is minor difference with the old scsi_slave
4244c06356bSdh 	 * implementation: busy conditions are not handled in scsi_probe.
4257c478bd9Sstevel@tonic-gate 	 */
4267c478bd9Sstevel@tonic-gate 	scsi_destroy_pkt(pkt);
4277c478bd9Sstevel@tonic-gate 	if (rval == SCSIPROBE_EXISTS) {
4284c06356bSdh 		return (scsi_probe(sd, callback));
4297c478bd9Sstevel@tonic-gate 	} else {
4307c478bd9Sstevel@tonic-gate 		return (rval);
4317c478bd9Sstevel@tonic-gate 	}
4327c478bd9Sstevel@tonic-gate }
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate /*
4357c478bd9Sstevel@tonic-gate  * Undo scsi_slave - older interface, but still supported
436d91393a8SChris Horne  *
437d91393a8SChris Horne  * NOTE: The 'sd_inq' inquiry data is now freed by scsi_hba/scsi_vhci code
438d91393a8SChris Horne  * as part of free of scsi_device(9S).
4397c478bd9Sstevel@tonic-gate  */
440d91393a8SChris Horne /*ARGSUSED*/
4417c478bd9Sstevel@tonic-gate void
scsi_unslave(struct scsi_device * sd)4424c06356bSdh scsi_unslave(struct scsi_device *sd)
4437c478bd9Sstevel@tonic-gate {
4447c478bd9Sstevel@tonic-gate }
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate /*
4477c478bd9Sstevel@tonic-gate  * Undo scsi_probe
448d91393a8SChris Horne  *
449d91393a8SChris Horne  * NOTE: The 'sd_inq' inquiry data is now freed by scsi_hba/scsi_vhci code
450d91393a8SChris Horne  * as part of free of scsi_device(9S).
4517c478bd9Sstevel@tonic-gate  */
452d91393a8SChris Horne /*ARGSUSED*/
4537c478bd9Sstevel@tonic-gate void
scsi_unprobe(struct scsi_device * sd)4544c06356bSdh scsi_unprobe(struct scsi_device *sd)
4557c478bd9Sstevel@tonic-gate {
4567c478bd9Sstevel@tonic-gate }
4577c478bd9Sstevel@tonic-gate 
458392e836bSGavin Maltby /*
459392e836bSGavin Maltby  * We log all scsi_test failures (as long as we are SE_HP etc).  The
460392e836bSGavin Maltby  * following table controls the "driver-assessment" payload item
461392e836bSGavin Maltby  * in the ereports we raise.  If a scsi_test return features in the
462392e836bSGavin Maltby  * retry mask then the calling context will retry; if it features in
463392e836bSGavin Maltby  * the fatal mask then the caller will not retry (although higher-level
464392e836bSGavin Maltby  * software might); if in neither (which shouldn't happen - you either
465392e836bSGavin Maltby  * retry or give up) default to 'retry'.
466392e836bSGavin Maltby  */
467392e836bSGavin Maltby static const struct scsi_test_profile {
468392e836bSGavin Maltby 	enum scsi_test_ctxt stp_ctxt;	/* Calling context */
469392e836bSGavin Maltby 	uint32_t stp_retrymask;		/* Returns caller will retry for */
470392e836bSGavin Maltby 	uint32_t stp_fatalmask;		/* Returns caller considers fatal */
471392e836bSGavin Maltby } scsi_test_profile[] = {
472392e836bSGavin Maltby 	/*
473392e836bSGavin Maltby 	 * This caller will retry on SCSI_TEST_FAILMASK as long as it was
474392e836bSGavin Maltby 	 * not SCSI_TEST_CMD_INCOMPLETE which is terminal.  A return from
475392e836bSGavin Maltby 	 * SCSI_TEST_PARTCMPLTMASK (command complete but status other than
476392e836bSGavin Maltby 	 * STATUS_GOOD) is not terminal and we'll move on to the context
477392e836bSGavin Maltby 	 * of STC_PROBE_PARTIAL_SUCCESS so that's a retry, too.
478392e836bSGavin Maltby 	 */
479392e836bSGavin Maltby 	{
480392e836bSGavin Maltby 		STC_PROBE_FIRST_INQ,
481392e836bSGavin Maltby 		SCSI_TEST_FAILMASK & ~SCSI_TEST_CMD_INCOMPLETE |
482392e836bSGavin Maltby 		    SCSI_TEST_PARTCMPLTMASK,
483392e836bSGavin Maltby 		SCSI_TEST_CMD_INCOMPLETE
484392e836bSGavin Maltby 	},
485392e836bSGavin Maltby 
486392e836bSGavin Maltby 	/*
487392e836bSGavin Maltby 	 * If the first inquiry fails outright we always retry just once
488392e836bSGavin Maltby 	 * (except for SCSI_TEST_CMD_INCOMPLETE as above).  A return in
489392e836bSGavin Maltby 	 * SCSI_TEST_FAILMASK is terminal; for SCSI_TEST_PARTCMPLTMASK
490392e836bSGavin Maltby 	 * we will retry at STC_PROBE_PARTIAL_SUCCESS.
491392e836bSGavin Maltby 	 */
492392e836bSGavin Maltby 	{
493392e836bSGavin Maltby 		STC_PROBE_FIRST_INQ_RETRY,
494392e836bSGavin Maltby 		SCSI_TEST_PARTCMPLTMASK,
495392e836bSGavin Maltby 		SCSI_TEST_FAILMASK
496392e836bSGavin Maltby 	},
497392e836bSGavin Maltby 
498392e836bSGavin Maltby 	/*
499392e836bSGavin Maltby 	 * If we've met with partial success we retry at caller context
500392e836bSGavin Maltby 	 * STC_PROBE_PARTIAL_SUCCESS.  Any SCSI_TEST_FAILMASK return
501392e836bSGavin Maltby 	 * here is terminal, as too is SCSI_TEST_CMPLT_BUSY.  A return in
502392e836bSGavin Maltby 	 * SCSI_TEST_PARTCMPLTMASK and we will continue with further
503392e836bSGavin Maltby 	 * inquiry attempts.
504392e836bSGavin Maltby 	 */
505392e836bSGavin Maltby 	{
506392e836bSGavin Maltby 		STC_PROBE_PARTIAL_SUCCESS,
507392e836bSGavin Maltby 		SCSI_TEST_PARTCMPLTMASK & ~SCSI_TEST_CMPLT_BUSY,
508392e836bSGavin Maltby 		SCSI_TEST_FAILMASK | SCSI_TEST_CMPLT_BUSY
509392e836bSGavin Maltby 	},
510392e836bSGavin Maltby 
511392e836bSGavin Maltby 	/*
512392e836bSGavin Maltby 	 * If we get past the above target busy case then we will
513392e836bSGavin Maltby 	 * perform a sense request if scsi_test indicates STATUS_CHECK
514392e836bSGavin Maltby 	 * and ARQ was not done.  We are not interested in logging telemetry
515392e836bSGavin Maltby 	 * for transports that do not perform ARQ automatically.
516392e836bSGavin Maltby 	 */
517392e836bSGavin Maltby 	{
518392e836bSGavin Maltby 		STC_PROBE_RQSENSE1,
519392e836bSGavin Maltby 		0,
520392e836bSGavin Maltby 		0
521392e836bSGavin Maltby 	},
522392e836bSGavin Maltby 
523392e836bSGavin Maltby 	/*
524392e836bSGavin Maltby 	 * If "something" responded to the probe but then the next inquiry
525392e836bSGavin Maltby 	 * sees a change of heart then we fail the probe on any of
526392e836bSGavin Maltby 	 * SCSI_TEST_FAILMASK or SCSI_TEST_CMPLT_BUSY.  For other values
527392e836bSGavin Maltby 	 * in SCSI_TEST_PARTCMPLTMASK we soldier on.
528392e836bSGavin Maltby 	 */
529392e836bSGavin Maltby 	{
530392e836bSGavin Maltby 		STC_PROBE_CHK_CLEARED,
531392e836bSGavin Maltby 		SCSI_TEST_PARTCMPLTMASK & ~SCSI_TEST_CMPLT_BUSY,
532392e836bSGavin Maltby 		SCSI_TEST_FAILMASK | SCSI_TEST_CMPLT_BUSY
533392e836bSGavin Maltby 	},
534392e836bSGavin Maltby 
535392e836bSGavin Maltby 	/*
536392e836bSGavin Maltby 	 * If after all that there we still have STATUS_CHECK from the
537392e836bSGavin Maltby 	 * inquiry status then we resend the sense request but the
538392e836bSGavin Maltby 	 * result is ignored (just clearing the condition).  Do not
539392e836bSGavin Maltby 	 * log.
540392e836bSGavin Maltby 	 */
541392e836bSGavin Maltby 	{
542392e836bSGavin Maltby 		STC_PROBE_RQSENSE2,
543392e836bSGavin Maltby 		0,
544392e836bSGavin Maltby 		0
545392e836bSGavin Maltby 	},
546392e836bSGavin Maltby 
547392e836bSGavin Maltby 	/*
548392e836bSGavin Maltby 	 * After the above sense request we once again send an inquiry.
549392e836bSGavin Maltby 	 * If it fails outright or STATUS_CHECK persists we give up.
550392e836bSGavin Maltby 	 * Any partial result is considered success.
551392e836bSGavin Maltby 	 */
552392e836bSGavin Maltby 	{
553392e836bSGavin Maltby 		STC_PROBE_INQ_FINAL,
554392e836bSGavin Maltby 		0,
555392e836bSGavin Maltby 		SCSI_TEST_FAILMASK | SCSI_TEST_CMPLT_CHECK
556392e836bSGavin Maltby 	},
557392e836bSGavin Maltby 
558392e836bSGavin Maltby 	/*
559392e836bSGavin Maltby 	 * check_vpd_page_support8083 called from scsi_device_identity
560392e836bSGavin Maltby 	 * performs an inquiry with EVPD set (and page necessarily 0)
561392e836bSGavin Maltby 	 * to see what pages are supported.
562392e836bSGavin Maltby 	 *
563392e836bSGavin Maltby 	 * Some devices do not support this command and therefore
564392e836bSGavin Maltby 	 * check_vpd_page_support8083 only returns an error of kmem_zalloc
565392e836bSGavin Maltby 	 * fails.  If the send_scsi_INQUIRY does not meet with complete
566392e836bSGavin Maltby 	 * success (SCSI_TEST_CMPLT_GOOD) it returns -1, othewise 0.
567392e836bSGavin Maltby 	 * So any scsi_test failure here will cause us to assume no page
568392e836bSGavin Maltby 	 * 80/83 support, and we will proceed without devid support.
569392e836bSGavin Maltby 	 * So -1 returns from send_scsi_INQUIRY are not terminal.
570392e836bSGavin Maltby 	 */
571392e836bSGavin Maltby 	{
572392e836bSGavin Maltby 		STC_VPD_CHECK,
573392e836bSGavin Maltby 		0,
574392e836bSGavin Maltby 		0
575392e836bSGavin Maltby 	},
576392e836bSGavin Maltby 
577392e836bSGavin Maltby 	/*
578392e836bSGavin Maltby 	 * If the above inquiry claims pg80 support then scsi_device_identity
579392e836bSGavin Maltby 	 * will perform a send_scsi_INQUIRY to retrieve that page.
580392e836bSGavin Maltby 	 * Anything other than SCSI_TEST_CMPLT_GOOD is a failure and will
581392e836bSGavin Maltby 	 * cause scsi_device_identity to return non-zero at which point the
582392e836bSGavin Maltby 	 * caller goes to SCSIPROBE_FAILURE.
583392e836bSGavin Maltby 	 */
584392e836bSGavin Maltby 	{
585392e836bSGavin Maltby 		STC_IDENTITY_PG80,
586392e836bSGavin Maltby 		0,
587392e836bSGavin Maltby 		SCSI_TEST_FAILMASK | SCSI_TEST_CMPLTMASK
588392e836bSGavin Maltby 	},
589392e836bSGavin Maltby 
590392e836bSGavin Maltby 	/*
591392e836bSGavin Maltby 	 * Similarly for pg83
592392e836bSGavin Maltby 	 */
593392e836bSGavin Maltby 	{
594392e836bSGavin Maltby 		STC_IDENTITY_PG83,
595392e836bSGavin Maltby 		0,
596392e836bSGavin Maltby 		SCSI_TEST_FAILMASK | SCSI_TEST_CMPLTMASK
597392e836bSGavin Maltby 	}
598392e836bSGavin Maltby };
599392e836bSGavin Maltby 
600392e836bSGavin Maltby int scsi_test_ereport_disable = 0;
601392e836bSGavin Maltby 
602392e836bSGavin Maltby extern int e_devid_cache_path_to_devid(char *, char *, char *, ddi_devid_t *);
603392e836bSGavin Maltby 
604392e836bSGavin Maltby static void
scsi_test_ereport_post(struct scsi_pkt * pkt,enum scsi_test_ctxt ctxt,uint32_t stresult)605392e836bSGavin Maltby scsi_test_ereport_post(struct scsi_pkt *pkt, enum scsi_test_ctxt ctxt,
606392e836bSGavin Maltby     uint32_t stresult)
607392e836bSGavin Maltby {
608392e836bSGavin Maltby 	char *nodename = NULL, *devidstr_buf = NULL, *devidstr = NULL;
609392e836bSGavin Maltby 	const struct scsi_test_profile *tp = &scsi_test_profile[ctxt];
610392e836bSGavin Maltby 	char ua[SCSI_MAXNAMELEN], nodenamebuf[SCSI_MAXNAMELEN];
611392e836bSGavin Maltby 	union scsi_cdb *cdbp = (union scsi_cdb *)pkt->pkt_cdbp;
612392e836bSGavin Maltby 	struct scsi_address *ap = &pkt->pkt_address;
613392e836bSGavin Maltby 	char *tgt_port, *tpl0 = NULL;
614392e836bSGavin Maltby 	ddi_devid_t devid = NULL;
615392e836bSGavin Maltby 	dev_info_t *probe, *hba;
616392e836bSGavin Maltby 	struct scsi_device *sd;
617392e836bSGavin Maltby 	scsi_lun64_t lun64;
618392e836bSGavin Maltby 	const char *d_ass;
619392e836bSGavin Maltby 	const char *class;
620392e836bSGavin Maltby 	char *pathbuf;
621392e836bSGavin Maltby 	nvlist_t *pl;
622392e836bSGavin Maltby 	uint64_t wwn;
623392e836bSGavin Maltby 	int err = 0;
624392e836bSGavin Maltby 	int dad = 0;
625392e836bSGavin Maltby 	size_t len;
626392e836bSGavin Maltby 	int lun;
627392e836bSGavin Maltby 
628392e836bSGavin Maltby 	if (scsi_test_ereport_disable)
629392e836bSGavin Maltby 		return;
630392e836bSGavin Maltby 
631392e836bSGavin Maltby 	ASSERT(tp->stp_ctxt == ctxt);
632392e836bSGavin Maltby 
633392e836bSGavin Maltby 	if ((sd = scsi_address_device(ap)) == NULL)
634392e836bSGavin Maltby 		return;		/* Not SCSI_HBA_ADDR_COMPLEX */
635392e836bSGavin Maltby 
636392e836bSGavin Maltby 	probe = sd->sd_dev;
637392e836bSGavin Maltby 	hba = ddi_get_parent(probe);
638392e836bSGavin Maltby 
639392e836bSGavin Maltby 	/*
640392e836bSGavin Maltby 	 * We only raise telemetry for SE_HP style enumeration
641392e836bSGavin Maltby 	 */
642392e836bSGavin Maltby 	if (!ndi_dev_is_hotplug_node(hba))
643392e836bSGavin Maltby 		return;
644392e836bSGavin Maltby 
645392e836bSGavin Maltby 	/*
646392e836bSGavin Maltby 	 * scsi_fm_ereport_post will use the hba for the fm-enabled devinfo
647392e836bSGavin Maltby 	 */
648392e836bSGavin Maltby 	if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(hba)))
649392e836bSGavin Maltby 		return;
650392e836bSGavin Maltby 
651392e836bSGavin Maltby 	/*
652392e836bSGavin Maltby 	 * Retrieve the unit address we were probing and the target
653392e836bSGavin Maltby 	 * port component thereof.
654392e836bSGavin Maltby 	 */
655392e836bSGavin Maltby 	if (!scsi_ua_get(sd, ua, sizeof (ua)) ||
656392e836bSGavin Maltby 	    scsi_device_prop_lookup_string(sd, SCSI_DEVICE_PROP_PATH,
657392e836bSGavin Maltby 	    SCSI_ADDR_PROP_TARGET_PORT, &tgt_port) != DDI_PROP_SUCCESS)
658392e836bSGavin Maltby 		return;
659392e836bSGavin Maltby 
660392e836bSGavin Maltby 	/*
661392e836bSGavin Maltby 	 * Determine whether unit address is location based or identity (wwn)
662392e836bSGavin Maltby 	 * based.  If we can't convert the target port address to a wwn then
663392e836bSGavin Maltby 	 * we're location based.
664392e836bSGavin Maltby 	 */
665392e836bSGavin Maltby 	if (scsi_wwnstr_to_wwn(tgt_port, &wwn) == DDI_FAILURE)
666392e836bSGavin Maltby 		return;
667392e836bSGavin Maltby 
668392e836bSGavin Maltby 	/*
669392e836bSGavin Maltby 	 * Get lun and lun64
670392e836bSGavin Maltby 	 */
671392e836bSGavin Maltby 	lun = scsi_device_prop_get_int(sd, SCSI_DEVICE_PROP_PATH,
672392e836bSGavin Maltby 	    SCSI_ADDR_PROP_LUN, 0);
673392e836bSGavin Maltby 	lun64 = scsi_device_prop_get_int64(sd, SCSI_DEVICE_PROP_PATH,
674392e836bSGavin Maltby 	    SCSI_ADDR_PROP_LUN64, lun);
675392e836bSGavin Maltby 
676392e836bSGavin Maltby 	/*
677392e836bSGavin Maltby 	 * We are guaranteed not to be in interrupt or any other
678392e836bSGavin Maltby 	 * problematic context.  So instead of repeated varargs
679392e836bSGavin Maltby 	 * style calls to scsi_fm_ereport_post for each flavour of
680392e836bSGavin Maltby 	 * ereport we have the luxury of being able to allocate
681392e836bSGavin Maltby 	 * and build an nvlist here.
682392e836bSGavin Maltby 	 *
683392e836bSGavin Maltby 	 * The ereports we raise here are all under the category
684392e836bSGavin Maltby 	 * ereport.io.scsi.cmd.disk category, namely
685392e836bSGavin Maltby 	 *
686392e836bSGavin Maltby 	 *	ereport.io.scsi.cmd.disk.
687392e836bSGavin Maltby 	 *			{dev.rqs.derr,dev.serr,tran}.
688392e836bSGavin Maltby 	 *
689392e836bSGavin Maltby 	 * For all ereports we also add the scsi_test specific payload.
690392e836bSGavin Maltby 	 * If we have it then we always include the devid in the payload
691392e836bSGavin Maltby 	 * (but only in the detector for device-as-detector ereports).
692392e836bSGavin Maltby 	 *
693392e836bSGavin Maltby 	 * Inherited From	Member Name
694392e836bSGavin Maltby 	 * -------------------- -------------------
695392e836bSGavin Maltby 	 *	.cmd		driver-assessment
696392e836bSGavin Maltby 	 *	.cmd		op-code
697392e836bSGavin Maltby 	 *	.cmd		cdb
698392e836bSGavin Maltby 	 *	.cmd		pkt-reason
699392e836bSGavin Maltby 	 *	.cmd		pkt-state
700392e836bSGavin Maltby 	 *	.cmd		pkt-stats
701392e836bSGavin Maltby 	 *	.cmd.disk	stat-code
702392e836bSGavin Maltby 	 *	-		scsi-test-return
703392e836bSGavin Maltby 	 *	-		scsi-test-context
704392e836bSGavin Maltby 	 */
705392e836bSGavin Maltby 
706392e836bSGavin Maltby 	if (nvlist_alloc(&pl, NV_UNIQUE_NAME, 0) != 0)
707392e836bSGavin Maltby 		return;
708392e836bSGavin Maltby 
709392e836bSGavin Maltby 	err |= nvlist_add_uint8(pl, "op-code", cdbp->scc_cmd);
710392e836bSGavin Maltby 	err |= nvlist_add_uint8_array(pl, "cdb", pkt->pkt_cdbp,
711392e836bSGavin Maltby 	    pkt->pkt_cdblen);
712392e836bSGavin Maltby 	err |= nvlist_add_uint8(pl, "pkt-reason", pkt->pkt_reason);
713392e836bSGavin Maltby 	err |= nvlist_add_uint32(pl, "pkt-state", pkt->pkt_state);
714392e836bSGavin Maltby 	err |= nvlist_add_uint32(pl, "pkt-stats", pkt->pkt_statistics);
715392e836bSGavin Maltby 	err |= nvlist_add_uint32(pl, "stat-code", *pkt->pkt_scbp);
716392e836bSGavin Maltby 	err |= nvlist_add_uint32(pl, "scsi-test-return", stresult);
717392e836bSGavin Maltby 	err |= nvlist_add_int32(pl, "scsi-test-context", ctxt);
718392e836bSGavin Maltby 
719392e836bSGavin Maltby 	switch (stresult) {
720392e836bSGavin Maltby 	case SCSI_TEST_CMPLT_BUSY:
721392e836bSGavin Maltby 		dad = 1;
722392e836bSGavin Maltby 		class = "cmd.disk.dev.serr";
723392e836bSGavin Maltby 		break;
724392e836bSGavin Maltby 
725392e836bSGavin Maltby 	case SCSI_TEST_CMPLT_CHECK:
726392e836bSGavin Maltby 		dad = 1;
727392e836bSGavin Maltby 
728392e836bSGavin Maltby 		if ((pkt->pkt_state & STATE_ARQ_DONE)) {
729392e836bSGavin Maltby 			struct scsi_arq_status *arqstat;
730392e836bSGavin Maltby 			uint8_t key, asc, ascq;
731392e836bSGavin Maltby 			uint8_t *sensep;
732392e836bSGavin Maltby 
733392e836bSGavin Maltby 			class = "cmd.disk.dev.rqs.derr";
734392e836bSGavin Maltby 			arqstat = (struct scsi_arq_status *)pkt->pkt_scbp;
735392e836bSGavin Maltby 			sensep = (uint8_t *)&arqstat->sts_sensedata;
736392e836bSGavin Maltby 			key = scsi_sense_key(sensep);
737392e836bSGavin Maltby 			asc = scsi_sense_asc(sensep);
738392e836bSGavin Maltby 			ascq = scsi_sense_ascq(sensep);
739392e836bSGavin Maltby 
740392e836bSGavin Maltby 			/*
741392e836bSGavin Maltby 			 * Add to payload.
742392e836bSGavin Maltby 			 */
743392e836bSGavin Maltby 			err |= nvlist_add_uint8(pl, "key", key);
744392e836bSGavin Maltby 			err |= nvlist_add_uint8(pl, "asc", asc);
745392e836bSGavin Maltby 			err |= nvlist_add_uint8(pl, "ascq", ascq);
746392e836bSGavin Maltby 			err |= nvlist_add_uint8_array(pl, "sense-data",
747392e836bSGavin Maltby 			    sensep, sizeof (arqstat->sts_sensedata));
748392e836bSGavin Maltby 		} else {
749392e836bSGavin Maltby 			class = "cmd.disk.dev.serr";
750392e836bSGavin Maltby 		}
751392e836bSGavin Maltby 
752392e836bSGavin Maltby 		break;
753392e836bSGavin Maltby 
754392e836bSGavin Maltby 	case SCSI_TEST_CMPLT_OTHER:
755392e836bSGavin Maltby 		dad = 1;
756392e836bSGavin Maltby 		class = "cmd.disk.dev.serr";
757392e836bSGavin Maltby 		break;
758392e836bSGavin Maltby 
759392e836bSGavin Maltby 	case SCSI_TEST_CMD_INCOMPLETE:
760392e836bSGavin Maltby 	case SCSI_TEST_NOTCMPLT:
761392e836bSGavin Maltby 	case SCSI_TEST_TRAN_BUSY:
762392e836bSGavin Maltby 	case SCSI_TEST_TRAN_REJECT:
763392e836bSGavin Maltby 		class = "cmd.disk.tran";
764392e836bSGavin Maltby 		break;
765392e836bSGavin Maltby 	}
766392e836bSGavin Maltby 
767392e836bSGavin Maltby 	/*
768392e836bSGavin Maltby 	 * Determine driver-assessment and add to payload.
769392e836bSGavin Maltby 	 */
770392e836bSGavin Maltby 	if (dad) {
771392e836bSGavin Maltby 		/*
772392e836bSGavin Maltby 		 * While higher level software can retry the enumeration
773392e836bSGavin Maltby 		 * the belief is that any device-as-detector style error
774392e836bSGavin Maltby 		 * will be persistent and will survive retries.  So we
775392e836bSGavin Maltby 		 * can make a local determination of driver assessment.
776392e836bSGavin Maltby 		 * Some day it may be more elegant to raise an ereport from
777392e836bSGavin Maltby 		 * scsi_tgtmap_scsi_deactivate to confirm retries failed,
778392e836bSGavin Maltby 		 * and correlate that ereport during diagnosis.
779392e836bSGavin Maltby 		 */
780392e836bSGavin Maltby 		if (stresult & tp->stp_fatalmask)
781392e836bSGavin Maltby 			d_ass = (const char *)"fatal";
782392e836bSGavin Maltby 		else if (stresult & tp->stp_retrymask)
783392e836bSGavin Maltby 			d_ass = (const char *)"retry";
784392e836bSGavin Maltby 		else
785392e836bSGavin Maltby 			d_ass = (const char *)"retry";
786392e836bSGavin Maltby 	} else {
787392e836bSGavin Maltby 		/* We do not diagnose transport errors (yet) */
788392e836bSGavin Maltby 			d_ass = (const char *)"retry";
789392e836bSGavin Maltby 	}
790392e836bSGavin Maltby 
791392e836bSGavin Maltby 	err |= nvlist_add_string(pl, "driver-assessment", d_ass);
792392e836bSGavin Maltby 
793392e836bSGavin Maltby 	/*
794392e836bSGavin Maltby 	 * If we're hoping for a device-as-detector style ereport then
795392e836bSGavin Maltby 	 * we're going to need a devid for the detector FMRI.  We
796392e836bSGavin Maltby 	 * don't have the devid because the target won't talk to us.
797392e836bSGavin Maltby 	 * But we do know which hba iport we were probing out of, and
798392e836bSGavin Maltby 	 * we know the unit address that was being probed (but not
799392e836bSGavin Maltby 	 * what type of device is or should be there).  So we
800392e836bSGavin Maltby 	 * search the devid cache for any cached devid matching
801392e836bSGavin Maltby 	 * path <iport-path>/<nodename>@<unit-address> with nodename
802392e836bSGavin Maltby 	 * wildcarded.  If a match is made we are returned not only the
803392e836bSGavin Maltby 	 * devid but also the nodename for the path that cached that
804392e836bSGavin Maltby 	 * entry.
805392e836bSGavin Maltby 	 *
806392e836bSGavin Maltby 	 * We also attempt to dig up a devid even for transport errors;
807392e836bSGavin Maltby 	 * we'll include that in the payload but not in the detector FMRI.
808392e836bSGavin Maltby 	 */
809392e836bSGavin Maltby 
810392e836bSGavin Maltby 	pathbuf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
811392e836bSGavin Maltby 	(void) ddi_pathname(hba, pathbuf);
812392e836bSGavin Maltby 
813392e836bSGavin Maltby 	if (e_devid_cache_path_to_devid(pathbuf, ua, nodenamebuf,
814392e836bSGavin Maltby 	    &devid) == DDI_SUCCESS) {
815392e836bSGavin Maltby 		nodename = nodenamebuf;
816392e836bSGavin Maltby 		devidstr = devidstr_buf = ddi_devid_str_encode(devid, NULL);
817392e836bSGavin Maltby 		kmem_free(devid, ddi_devid_sizeof(devid));
818392e836bSGavin Maltby 		err |= nvlist_add_string(pl, "devid", devidstr);
819392e836bSGavin Maltby 	}
820392e836bSGavin Maltby 
821392e836bSGavin Maltby 	/*
822392e836bSGavin Maltby 	 * If this is lun 0 we will include the target-port-l0id
823392e836bSGavin Maltby 	 * in the dev scheme detector for device-as-detector.
824392e836bSGavin Maltby 	 */
825392e836bSGavin Maltby 	if (dad && (lun == 0 || lun64 == 0))
826392e836bSGavin Maltby 		tpl0 = tgt_port;
827392e836bSGavin Maltby 
828392e836bSGavin Maltby 	/* Construct the devpath to use in the detector */
829392e836bSGavin Maltby 	(void) ddi_pathname(hba, pathbuf);
830392e836bSGavin Maltby 	len = strlen(pathbuf);
831392e836bSGavin Maltby 	(void) snprintf(pathbuf + len, MAXPATHLEN - len, "/%s@%s",
832392e836bSGavin Maltby 	    nodename ? nodename : "unknown", ua);
833392e836bSGavin Maltby 
834392e836bSGavin Maltby 	/*
835392e836bSGavin Maltby 	 * Let's review.
836392e836bSGavin Maltby 	 *
837392e836bSGavin Maltby 	 * Device-as-detector ereports for which the attempted lookup of
838392e836bSGavin Maltby 	 * devid and nodename succeeded:
839392e836bSGavin Maltby 	 *
840392e836bSGavin Maltby 	 *	- pathbuf has the full device path including nodename we
841392e836bSGavin Maltby 	 *	  dug up from the devid cache
842392e836bSGavin Maltby 	 *
843392e836bSGavin Maltby 	 *	- class is one of cmd.disk.{dev.rqs.derr,dev.serr}
844392e836bSGavin Maltby 	 *
845392e836bSGavin Maltby 	 *	- devidstr is non NULL and a valid devid string
846392e836bSGavin Maltby 	 *
847392e836bSGavin Maltby 	 * Would-be device-as-detector ereport for which the attempted lookup
848392e836bSGavin Maltby 	 * of devid failed:
849392e836bSGavin Maltby 	 *
850392e836bSGavin Maltby 	 *	- pathbuf has a device path with leaf nodename of "unknown"
851392e836bSGavin Maltby 	 *	  but still including the unit-address
852392e836bSGavin Maltby 	 *	- class is one of cmd.disk.{dev.rqs.derr,dev.serr}
853392e836bSGavin Maltby 	 *
854392e836bSGavin Maltby 	 * Transport errors:
855392e836bSGavin Maltby 	 *
856392e836bSGavin Maltby 	 *	class is cmd.disk.tran
857392e836bSGavin Maltby 	 *	devidstr is NULL
858392e836bSGavin Maltby 	 *
859392e836bSGavin Maltby 	 *	- we may have succeeded in looking up a devid and nodename -
860392e836bSGavin Maltby 	 *	  the devid we'll have added to the payload but we must not
861392e836bSGavin Maltby 	 *	  add to detector FMRI, and if we have have nodename then
862392e836bSGavin Maltby 	 *	  we have a full devpath otherwise one with "unknown" for
863392e836bSGavin Maltby 	 *	  nodename
864392e836bSGavin Maltby 	 */
865392e836bSGavin Maltby 
866392e836bSGavin Maltby 	if (err)
867392e836bSGavin Maltby 		(void) nvlist_add_boolean_value(pl, "payload-incomplete",
868392e836bSGavin Maltby 		    B_TRUE);
869392e836bSGavin Maltby 
870392e836bSGavin Maltby 	scsi_fm_ereport_post(
871392e836bSGavin Maltby 	    sd,
872392e836bSGavin Maltby 	    0,				/* path_instance - always 0 */
873392e836bSGavin Maltby 	    pathbuf,			/* devpath for detector */
874392e836bSGavin Maltby 	    class,			/* ereport class suffix */
875392e836bSGavin Maltby 	    0,				/* ENA - generate for us */
876392e836bSGavin Maltby 	    dad ? devidstr : NULL,	/* dtcr devid, dev-as-det only */
877392e836bSGavin Maltby 	    tpl0,			/* target-port-l0id */
878392e836bSGavin Maltby 	    DDI_SLEEP,
879392e836bSGavin Maltby 	    pl, /* preconstructed payload */
880392e836bSGavin Maltby 	    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0,
881392e836bSGavin Maltby 	    NULL);
882392e836bSGavin Maltby 
883392e836bSGavin Maltby 	nvlist_free(pl);
884392e836bSGavin Maltby 	if (devidstr_buf)
885392e836bSGavin Maltby 		ddi_devid_str_free(devidstr_buf);
886392e836bSGavin Maltby 	kmem_free(pathbuf, MAXPATHLEN);
887392e836bSGavin Maltby }
888392e836bSGavin Maltby 
889392e836bSGavin Maltby #ifdef	DEBUG
890392e836bSGavin Maltby /*
891392e836bSGavin Maltby  * Testing - fake scsi_test fails
892392e836bSGavin Maltby  */
893392e836bSGavin Maltby char scsi_test_fail_ua[SCSI_MAXNAMELEN];	/* unit address to object to */
894392e836bSGavin Maltby int scsi_test_fail_rc = TRAN_ACCEPT;		/* scsi_transport return */
895392e836bSGavin Maltby uchar_t scsi_test_fail_pkt_reason = CMD_CMPLT;	/* pkt_reason */
896392e836bSGavin Maltby uchar_t scsi_test_fail_status = STATUS_BUSY;	/* status */
897392e836bSGavin Maltby uint_t scsi_test_fail_repeat = (uint_t)-1;	/* number of times to fail ua */
898392e836bSGavin Maltby #endif
899392e836bSGavin Maltby 
9007c478bd9Sstevel@tonic-gate /*
9017c478bd9Sstevel@tonic-gate  * This is like scsi_poll, but only does retry for TRAN_BUSY.
9027c478bd9Sstevel@tonic-gate  */
903392e836bSGavin Maltby static uint32_t
scsi_test(struct scsi_pkt * pkt,enum scsi_test_ctxt ctxt)904392e836bSGavin Maltby scsi_test(struct scsi_pkt *pkt, enum scsi_test_ctxt ctxt)
9057c478bd9Sstevel@tonic-gate {
906392e836bSGavin Maltby 	uint32_t	rval;
9077c478bd9Sstevel@tonic-gate 	int		wait_usec;
9087c478bd9Sstevel@tonic-gate 	int		rc;
9097c478bd9Sstevel@tonic-gate 	extern int	do_polled_io;
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate 	pkt->pkt_flags |= FLAG_NOINTR;
9127c478bd9Sstevel@tonic-gate 	pkt->pkt_time = SCSI_POLL_TIMEOUT;	/* in seconds */
9137c478bd9Sstevel@tonic-gate 
9147c478bd9Sstevel@tonic-gate 	if (scsi_ifgetcap(&pkt->pkt_address, "tagged-qing", 1) == 1) {
9157c478bd9Sstevel@tonic-gate 		pkt->pkt_flags |= FLAG_STAG;
9167c478bd9Sstevel@tonic-gate 	}
9177c478bd9Sstevel@tonic-gate 
9187c478bd9Sstevel@tonic-gate 	/*
9197c478bd9Sstevel@tonic-gate 	 * Each TRAN_BUSY response waits scsi_test_busy_delay usec up to a
9207c478bd9Sstevel@tonic-gate 	 * maximum of scsi_test_busy_timeout.
9217c478bd9Sstevel@tonic-gate 	 */
9227c478bd9Sstevel@tonic-gate 	for (wait_usec = 0; (wait_usec / 1000000) <= scsi_test_busy_timeout;
9237c478bd9Sstevel@tonic-gate 	    wait_usec += scsi_test_busy_delay) {
9247c478bd9Sstevel@tonic-gate 
9257c478bd9Sstevel@tonic-gate 		/* Initialize pkt status variables */
9267c478bd9Sstevel@tonic-gate 		*pkt->pkt_scbp = pkt->pkt_reason = pkt->pkt_state = 0;
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate 		rc = scsi_transport(pkt);
9297c478bd9Sstevel@tonic-gate 		if ((rc != TRAN_BUSY) || (scsi_test_busy_delay == 0) ||
9307c478bd9Sstevel@tonic-gate 		    (scsi_test_busy_timeout == 0))
9317c478bd9Sstevel@tonic-gate 			break;
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate 		/* transport busy, wait */
9347c478bd9Sstevel@tonic-gate 		if ((curthread->t_flag & T_INTR_THREAD) == 0 && !do_polled_io) {
9357c478bd9Sstevel@tonic-gate 			delay(drv_usectohz(scsi_test_busy_delay));
9367c478bd9Sstevel@tonic-gate 		} else {
9377c478bd9Sstevel@tonic-gate 			/* we busy wait during cpr_dump or interrupt threads */
9387c478bd9Sstevel@tonic-gate 			drv_usecwait(scsi_test_busy_delay);
9397c478bd9Sstevel@tonic-gate 		}
9407c478bd9Sstevel@tonic-gate 	}
9417c478bd9Sstevel@tonic-gate 
942392e836bSGavin Maltby #ifdef	DEBUG
943392e836bSGavin Maltby 	if (scsi_test_fail_ua[0] != '\0' && scsi_test_fail_repeat > 0) {
944392e836bSGavin Maltby 		struct scsi_address *ap = &pkt->pkt_address;
945392e836bSGavin Maltby 		struct scsi_device *sd;
946392e836bSGavin Maltby 		dev_info_t *probe;
947392e836bSGavin Maltby 		char ua[SCSI_MAXNAMELEN];
948392e836bSGavin Maltby 
949392e836bSGavin Maltby 		if ((sd = scsi_address_device(ap)) != NULL) {
950392e836bSGavin Maltby 			probe = sd->sd_dev;
951392e836bSGavin Maltby 
952392e836bSGavin Maltby 			if (probe && scsi_ua_get(sd, ua, sizeof (ua)) &&
953392e836bSGavin Maltby 			    strncmp(ua, scsi_test_fail_ua, sizeof (ua)) == 0) {
954392e836bSGavin Maltby 				scsi_test_fail_repeat--;
955392e836bSGavin Maltby 				rc = scsi_test_fail_rc;
956392e836bSGavin Maltby 				if (rc == TRAN_ACCEPT)
957392e836bSGavin Maltby 					pkt->pkt_reason =
958392e836bSGavin Maltby 					    scsi_test_fail_pkt_reason;
959392e836bSGavin Maltby 				*pkt->pkt_scbp = scsi_test_fail_status;
960392e836bSGavin Maltby 				if (scsi_test_fail_status == STATUS_CHECK)
961392e836bSGavin Maltby 					pkt->pkt_state |= STATE_ARQ_DONE;
962392e836bSGavin Maltby 
963392e836bSGavin Maltby 			}
964392e836bSGavin Maltby 		}
965392e836bSGavin Maltby 	}
966392e836bSGavin Maltby #endif
967392e836bSGavin Maltby 
968392e836bSGavin Maltby 	switch (rc) {
969392e836bSGavin Maltby 	case TRAN_ACCEPT:
970392e836bSGavin Maltby 		switch (pkt->pkt_reason) {
971392e836bSGavin Maltby 		case CMD_CMPLT:
972392e836bSGavin Maltby 			switch ((*pkt->pkt_scbp) & STATUS_MASK) {
973392e836bSGavin Maltby 			case STATUS_GOOD:
974392e836bSGavin Maltby 				rval = SCSI_TEST_CMPLT_GOOD;
975392e836bSGavin Maltby 				break;
976392e836bSGavin Maltby 
977392e836bSGavin Maltby 			case STATUS_BUSY:
978392e836bSGavin Maltby 				rval = SCSI_TEST_CMPLT_BUSY;
979392e836bSGavin Maltby 				break;
980392e836bSGavin Maltby 
981392e836bSGavin Maltby 			case STATUS_CHECK:
982392e836bSGavin Maltby 				rval = SCSI_TEST_CMPLT_CHECK;
983392e836bSGavin Maltby 				break;
984392e836bSGavin Maltby 
985392e836bSGavin Maltby 			default:
986392e836bSGavin Maltby 				rval = SCSI_TEST_CMPLT_OTHER;
987392e836bSGavin Maltby 				break;
988392e836bSGavin Maltby 			}
989392e836bSGavin Maltby 			break;
990392e836bSGavin Maltby 
991392e836bSGavin Maltby 		case CMD_INCOMPLETE:
992392e836bSGavin Maltby 			rval = SCSI_TEST_CMD_INCOMPLETE;
993392e836bSGavin Maltby 			break;
994392e836bSGavin Maltby 
995392e836bSGavin Maltby 		default:
996392e836bSGavin Maltby 			rval = SCSI_TEST_NOTCMPLT;
997392e836bSGavin Maltby 			break;
998392e836bSGavin Maltby 		}
999392e836bSGavin Maltby 		break;
1000392e836bSGavin Maltby 
1001392e836bSGavin Maltby 	case TRAN_BUSY:
1002392e836bSGavin Maltby 		rval = SCSI_TEST_TRAN_BUSY;
1003392e836bSGavin Maltby 		break;
1004392e836bSGavin Maltby 
1005392e836bSGavin Maltby 	default:
1006392e836bSGavin Maltby 		rval = SCSI_TEST_TRAN_REJECT;
1007392e836bSGavin Maltby 		break;
10087c478bd9Sstevel@tonic-gate 	}
10097c478bd9Sstevel@tonic-gate 
1010392e836bSGavin Maltby 	if (rval != SCSI_TEST_CMPLT_GOOD)
1011392e836bSGavin Maltby 		scsi_test_ereport_post(pkt, ctxt, rval);
1012392e836bSGavin Maltby 
10137c478bd9Sstevel@tonic-gate 	return (rval);
10147c478bd9Sstevel@tonic-gate }
10157c478bd9Sstevel@tonic-gate 
10167c478bd9Sstevel@tonic-gate /*
10177c478bd9Sstevel@tonic-gate  * The implementation of scsi_probe now allows a particular
10187c478bd9Sstevel@tonic-gate  * HBA to intercept the call, for any post- or pre-processing
10197c478bd9Sstevel@tonic-gate  * it may need.  The default, if the HBA does not override it,
10207c478bd9Sstevel@tonic-gate  * is to call scsi_hba_probe(), which retains the old functionality
10217c478bd9Sstevel@tonic-gate  * intact.
10227c478bd9Sstevel@tonic-gate  */
10237c478bd9Sstevel@tonic-gate int
scsi_probe(struct scsi_device * sd,int (* callback)())10244c06356bSdh scsi_probe(struct scsi_device *sd, int (*callback)())
10257c478bd9Sstevel@tonic-gate {
10268c55a9c0SSrikanth Suravajhala 	int			ret, retry = 0;
1027*b979a950SSrikanth Suravajhala 	int			lr_cap, sr_ret;
10284c06356bSdh 	scsi_hba_tran_t		*tran = sd->sd_address.a_hba_tran;
10297c478bd9Sstevel@tonic-gate 
10304c06356bSdh 	if (scsi_check_ss2_LUN_limit(sd) != 0) {
10317c478bd9Sstevel@tonic-gate 		/*
10327c478bd9Sstevel@tonic-gate 		 * caller is trying to probe a strictly-SCSI-2 device
10337c478bd9Sstevel@tonic-gate 		 * with a LUN that is too large, so do not allow it
10347c478bd9Sstevel@tonic-gate 		 */
10357c478bd9Sstevel@tonic-gate 		return (SCSIPROBE_NORESP);	/* skip probing this one */
10367c478bd9Sstevel@tonic-gate 	}
10378c55a9c0SSrikanth Suravajhala again:
1038*b979a950SSrikanth Suravajhala 	ret = lr_cap = sr_ret = -1;
103953a7b6b6SChris Horne 	if (tran->tran_tgt_probe != NULL) {
10404c06356bSdh 		ret = (*tran->tran_tgt_probe)(sd, callback);
10417c478bd9Sstevel@tonic-gate 	} else {
10424c06356bSdh 		ret = scsi_hba_probe(sd, callback);
10437c478bd9Sstevel@tonic-gate 	}
10447c478bd9Sstevel@tonic-gate 
10458c55a9c0SSrikanth Suravajhala 	if ((ret != SCSIPROBE_EXISTS) && (retry == 0)) {
1046*b979a950SSrikanth Suravajhala 		lr_cap = (*tran->tran_getcap)(&sd->sd_address, "lun-reset", 1);
1047*b979a950SSrikanth Suravajhala 		sr_ret = scsi_reset(&sd->sd_address, RESET_LUN);
1048*b979a950SSrikanth Suravajhala 		if ((sr_ret != 1) && (lr_cap == 1)) {
1049*b979a950SSrikanth Suravajhala 			cmn_err(CE_WARN, "scsi_probe(%d): scsi_reset failed(%d)"
1050*b979a950SSrikanth Suravajhala 			    " lun-reset cap(%d)", ret, sr_ret, lr_cap);
10518c55a9c0SSrikanth Suravajhala 		}
10528c55a9c0SSrikanth Suravajhala 		retry = 1;
10538c55a9c0SSrikanth Suravajhala 		goto again;
10548c55a9c0SSrikanth Suravajhala 	}
10558c55a9c0SSrikanth Suravajhala 
10567c478bd9Sstevel@tonic-gate 	if (ret == SCSIPROBE_EXISTS) {
10574c06356bSdh 		create_inquiry_props(sd);
10587c478bd9Sstevel@tonic-gate 		/* is this a strictly-SCSI-2 node ?? */
10594c06356bSdh 		scsi_establish_LUN_limit(sd);
10607c478bd9Sstevel@tonic-gate 	}
10617c478bd9Sstevel@tonic-gate 
10627c478bd9Sstevel@tonic-gate 	return (ret);
10637c478bd9Sstevel@tonic-gate }
10644c06356bSdh /*
10654c06356bSdh  * probe scsi device using any available path
10664c06356bSdh  *
10674c06356bSdh  */
10684c06356bSdh int
scsi_hba_probe(struct scsi_device * sd,int (* callback)())10694c06356bSdh scsi_hba_probe(struct scsi_device *sd, int (*callback)())
10704c06356bSdh {
10714c06356bSdh 	return (scsi_hba_probe_pi(sd, callback, 0));
10724c06356bSdh }
10737c478bd9Sstevel@tonic-gate 
10747c478bd9Sstevel@tonic-gate /*
10754c06356bSdh  * probe scsi device using specific path
10764c06356bSdh  *
10774c06356bSdh  * scsi_hba_probe_pi does not do any test unit ready's which access the medium
10787c478bd9Sstevel@tonic-gate  * and could cause busy or not ready conditions.
10794c06356bSdh  * scsi_hba_probe_pi does 2 inquiries and a rqsense to clear unit attention
10807c478bd9Sstevel@tonic-gate  * and to allow sync negotiation to take place
10814c06356bSdh  * finally, scsi_hba_probe_pi does one more inquiry which should
10827c478bd9Sstevel@tonic-gate  * reliably tell us what kind of target we have.
10837c478bd9Sstevel@tonic-gate  * A scsi-2 compliant target should be able to	return inquiry with 250ms
10847c478bd9Sstevel@tonic-gate  * and we actually wait more than a second after reset.
10857c478bd9Sstevel@tonic-gate  */
10867c478bd9Sstevel@tonic-gate int
scsi_hba_probe_pi(struct scsi_device * sd,int (* callback)(),int pi)10874c06356bSdh scsi_hba_probe_pi(struct scsi_device *sd, int (*callback)(), int pi)
10887c478bd9Sstevel@tonic-gate {
10897c478bd9Sstevel@tonic-gate 	struct scsi_pkt		*inq_pkt = NULL;
10907c478bd9Sstevel@tonic-gate 	struct scsi_pkt		*rq_pkt = NULL;
10917c478bd9Sstevel@tonic-gate 	int			rval = SCSIPROBE_NOMEM;
10927c478bd9Sstevel@tonic-gate 	struct buf		*inq_bp = NULL;
10937c478bd9Sstevel@tonic-gate 	struct buf		*rq_bp = NULL;
10947c478bd9Sstevel@tonic-gate 	int			(*cb_flag)();
10957c478bd9Sstevel@tonic-gate 	int			pass = 1;
1096392e836bSGavin Maltby 	uint32_t		str;
10977c478bd9Sstevel@tonic-gate 
10984c06356bSdh 	if (sd->sd_inq == NULL) {
10994c06356bSdh 		sd->sd_inq = (struct scsi_inquiry *)
1100184cd04cScth 		    kmem_alloc(SUN_INQSIZE, ((callback == SLEEP_FUNC) ?
1101184cd04cScth 		    KM_SLEEP : KM_NOSLEEP));
11024c06356bSdh 		if (sd->sd_inq == NULL) {
11037c478bd9Sstevel@tonic-gate 			goto out;
11047c478bd9Sstevel@tonic-gate 		}
11057c478bd9Sstevel@tonic-gate 	}
11067c478bd9Sstevel@tonic-gate 
11077c478bd9Sstevel@tonic-gate 	if (callback != SLEEP_FUNC && callback != NULL_FUNC) {
11087c478bd9Sstevel@tonic-gate 		cb_flag = NULL_FUNC;
11097c478bd9Sstevel@tonic-gate 	} else {
11107c478bd9Sstevel@tonic-gate 		cb_flag = callback;
11117c478bd9Sstevel@tonic-gate 	}
11127c478bd9Sstevel@tonic-gate 	inq_bp = scsi_alloc_consistent_buf(ROUTE,
11137c478bd9Sstevel@tonic-gate 	    (struct buf *)NULL, SUN_INQSIZE, B_READ, cb_flag, NULL);
11147c478bd9Sstevel@tonic-gate 	if (inq_bp == NULL) {
11157c478bd9Sstevel@tonic-gate 		goto out;
11167c478bd9Sstevel@tonic-gate 	}
11177c478bd9Sstevel@tonic-gate 
11187c478bd9Sstevel@tonic-gate 	inq_pkt = scsi_init_pkt(ROUTE, (struct scsi_pkt *)NULL,
11197c478bd9Sstevel@tonic-gate 	    inq_bp, CDB_GROUP0, sizeof (struct scsi_arq_status),
11207c478bd9Sstevel@tonic-gate 	    0, PKT_CONSISTENT, callback, NULL);
11217c478bd9Sstevel@tonic-gate 	if (inq_pkt == NULL) {
11227c478bd9Sstevel@tonic-gate 		if (inq_bp->b_error == 0)
11237c478bd9Sstevel@tonic-gate 			rval = SCSIPROBE_NOMEM_CB;
11247c478bd9Sstevel@tonic-gate 		goto out;
11257c478bd9Sstevel@tonic-gate 	}
11267c478bd9Sstevel@tonic-gate 	ASSERT(inq_bp->b_error == 0);
11277c478bd9Sstevel@tonic-gate 
11287c478bd9Sstevel@tonic-gate 	(void) scsi_setup_cdb((union scsi_cdb *)inq_pkt->pkt_cdbp,
11297c478bd9Sstevel@tonic-gate 	    SCMD_INQUIRY, 0, SUN_INQSIZE, 0);
11307c478bd9Sstevel@tonic-gate 	inq_pkt->pkt_flags = FLAG_NOINTR|FLAG_NOPARITY;
11317c478bd9Sstevel@tonic-gate 
11324c06356bSdh 	/*
11334c06356bSdh 	 * set transport path
11344c06356bSdh 	 */
11354c06356bSdh 	if (pi && scsi_pkt_allocated_correctly(inq_pkt)) {
11364c06356bSdh 		inq_pkt->pkt_path_instance = pi;
11374c06356bSdh 		inq_pkt->pkt_flags |= FLAG_PKT_PATH_INSTANCE;
11384c06356bSdh 	}
11394c06356bSdh 
11407c478bd9Sstevel@tonic-gate 	/*
11417c478bd9Sstevel@tonic-gate 	 * the first inquiry will tell us whether a target
11427c478bd9Sstevel@tonic-gate 	 * responded
11437c478bd9Sstevel@tonic-gate 	 *
11447c478bd9Sstevel@tonic-gate 	 * The FILL_SCSI1_LUN below will find "ansi_ver != 1" on first pass
11457c478bd9Sstevel@tonic-gate 	 * because of bzero initilization. If this assumption turns out to be
11467c478bd9Sstevel@tonic-gate 	 * incorrect after we have real sd_inq data (for lun0) we will do a
11477c478bd9Sstevel@tonic-gate 	 * second pass during which FILL_SCSI1_LUN will place lun in CDB.
11487c478bd9Sstevel@tonic-gate 	 */
11494c06356bSdh 	bzero((caddr_t)sd->sd_inq, SUN_INQSIZE);
11504c06356bSdh again:	FILL_SCSI1_LUN(sd, inq_pkt);
11517c478bd9Sstevel@tonic-gate 
1152392e836bSGavin Maltby 	str = scsi_test(inq_pkt, STC_PROBE_FIRST_INQ);
1153392e836bSGavin Maltby 	if (SCSI_TEST_FAILURE(str)) {
1154392e836bSGavin Maltby 		if (str == SCSI_TEST_CMD_INCOMPLETE) {
11557c478bd9Sstevel@tonic-gate 			rval = SCSIPROBE_NORESP;
11567c478bd9Sstevel@tonic-gate 			goto out;
1157392e836bSGavin Maltby 		}
1158392e836bSGavin Maltby 
1159392e836bSGavin Maltby 		/*
1160392e836bSGavin Maltby 		 * Retry one more time for anything other than CMD_INCOMPLETE.
1161392e836bSGavin Maltby 		 */
1162392e836bSGavin Maltby 		str = scsi_test(inq_pkt, STC_PROBE_FIRST_INQ_RETRY);
1163392e836bSGavin Maltby 		if (SCSI_TEST_FAILURE(str)) {
1164392e836bSGavin Maltby 			rval = SCSIPROBE_FAILURE;
1165392e836bSGavin Maltby 			goto out;
11667c478bd9Sstevel@tonic-gate 		}
11677c478bd9Sstevel@tonic-gate 	}
11687c478bd9Sstevel@tonic-gate 
11697c478bd9Sstevel@tonic-gate 	/*
1170392e836bSGavin Maltby 	 * Did the inquiry complete and transfer inquiry information,
1171392e836bSGavin Maltby 	 * perhaps after retry?
11727c478bd9Sstevel@tonic-gate 	 */
1173392e836bSGavin Maltby 	if (str == SCSI_TEST_CMPLT_GOOD)
11747c478bd9Sstevel@tonic-gate 		goto done;
11757c478bd9Sstevel@tonic-gate 
11767c478bd9Sstevel@tonic-gate 	/*
1177392e836bSGavin Maltby 	 * We get here for SCSI_TEST_CMPLT_{BUSY,CHECK,OTHER}. We term
1178392e836bSGavin Maltby 	 * this "partial success" in that at least something is talking
1179392e836bSGavin Maltby 	 * to us.
1180392e836bSGavin Maltby 	 *
1181392e836bSGavin Maltby 	 * A second inquiry allows the host adapter to negotiate
11827c478bd9Sstevel@tonic-gate 	 * synchronous transfer period and offset
11837c478bd9Sstevel@tonic-gate 	 */
1184392e836bSGavin Maltby 	str = scsi_test(inq_pkt, STC_PROBE_PARTIAL_SUCCESS);
1185392e836bSGavin Maltby 	if (SCSI_TEST_FAILURE(str)) {
1186392e836bSGavin Maltby 		if (str == SCSI_TEST_CMD_INCOMPLETE)
11877c478bd9Sstevel@tonic-gate 			rval = SCSIPROBE_NORESP;
11887c478bd9Sstevel@tonic-gate 		else
11897c478bd9Sstevel@tonic-gate 			rval = SCSIPROBE_FAILURE;
11907c478bd9Sstevel@tonic-gate 		goto out;
11917c478bd9Sstevel@tonic-gate 	}
11927c478bd9Sstevel@tonic-gate 
11937c478bd9Sstevel@tonic-gate 	/*
1194392e836bSGavin Maltby 	 * If target is still busy, give up now.
1195392e836bSGavin Maltby 	 * XXX There's no interval between retries - scsi_test should
1196392e836bSGavin Maltby 	 * probably have a builtin retry on target busy.
11977c478bd9Sstevel@tonic-gate 	 */
1198392e836bSGavin Maltby 	if (str == SCSI_TEST_CMPLT_BUSY) {
11997c478bd9Sstevel@tonic-gate 		rval = SCSIPROBE_BUSY;
12007c478bd9Sstevel@tonic-gate 		goto out;
12017c478bd9Sstevel@tonic-gate 	}
12027c478bd9Sstevel@tonic-gate 
12037c478bd9Sstevel@tonic-gate 	/*
1204392e836bSGavin Maltby 	 * At this point we are SCSI_TEST_CMPLT_GOOD, SCSI_TEST_CMPLT_CHECK
1205392e836bSGavin Maltby 	 * or SCSI_TEST_CMPLT_OTHER.
1206392e836bSGavin Maltby 	 *
1207392e836bSGavin Maltby 	 * Do a rqsense if there was a check condition and ARQ was not done
12087c478bd9Sstevel@tonic-gate 	 */
1209392e836bSGavin Maltby 	if (str == SCSI_TEST_CMPLT_CHECK &&
1210392e836bSGavin Maltby 	    (inq_pkt->pkt_state & STATE_ARQ_DONE) == 0) {
1211392e836bSGavin Maltby 		/*
1212392e836bSGavin Maltby 		 * prepare rqsense packet
1213392e836bSGavin Maltby 		 * there is no real need for this because the
1214392e836bSGavin Maltby 		 * check condition should have been cleared by now.
1215392e836bSGavin Maltby 		 */
1216392e836bSGavin Maltby 		rq_bp = scsi_alloc_consistent_buf(ROUTE, (struct buf *)NULL,
1217392e836bSGavin Maltby 		    (uint_t)SENSE_LENGTH, B_READ, cb_flag, NULL);
1218392e836bSGavin Maltby 		if (rq_bp == NULL) {
1219392e836bSGavin Maltby 			goto out;
1220392e836bSGavin Maltby 		}
12217c478bd9Sstevel@tonic-gate 
1222392e836bSGavin Maltby 		rq_pkt = scsi_init_pkt(ROUTE, (struct scsi_pkt *)NULL,
1223392e836bSGavin Maltby 		    rq_bp, CDB_GROUP0, 1, 0, PKT_CONSISTENT, callback, NULL);
12247c478bd9Sstevel@tonic-gate 
1225392e836bSGavin Maltby 		if (rq_pkt == NULL) {
1226392e836bSGavin Maltby 			if (rq_bp->b_error == 0)
1227392e836bSGavin Maltby 				rval = SCSIPROBE_NOMEM_CB;
1228392e836bSGavin Maltby 			goto out;
1229392e836bSGavin Maltby 		}
1230392e836bSGavin Maltby 		ASSERT(rq_bp->b_error == 0);
12317c478bd9Sstevel@tonic-gate 
1232392e836bSGavin Maltby 		(void) scsi_setup_cdb((union scsi_cdb *)rq_pkt->
1233392e836bSGavin Maltby 		    pkt_cdbp, SCMD_REQUEST_SENSE, 0, SENSE_LENGTH, 0);
1234392e836bSGavin Maltby 		FILL_SCSI1_LUN(sd, rq_pkt);
1235392e836bSGavin Maltby 		rq_pkt->pkt_flags = FLAG_NOINTR|FLAG_NOPARITY;
12367c478bd9Sstevel@tonic-gate 
1237392e836bSGavin Maltby 		/*
1238392e836bSGavin Maltby 		 * set transport path
1239392e836bSGavin Maltby 		 */
1240392e836bSGavin Maltby 		if (pi && scsi_pkt_allocated_correctly(rq_pkt)) {
1241392e836bSGavin Maltby 			rq_pkt->pkt_path_instance = pi;
1242392e836bSGavin Maltby 			rq_pkt->pkt_flags |= FLAG_PKT_PATH_INSTANCE;
1243392e836bSGavin Maltby 		}
12444c06356bSdh 
1245392e836bSGavin Maltby 		/*
1246392e836bSGavin Maltby 		 * The FILL_SCSI1_LUN above will find "inq_ansi != 1"
1247392e836bSGavin Maltby 		 * on first pass, see "again" comment above.
1248392e836bSGavin Maltby 		 *
1249392e836bSGavin Maltby 		 * The controller type is as yet unknown, so we
1250392e836bSGavin Maltby 		 * have to do a throwaway non-extended request sense,
1251392e836bSGavin Maltby 		 * and hope that that clears the check condition for
1252392e836bSGavin Maltby 		 * that unit until we can find out what kind of drive
1253392e836bSGavin Maltby 		 * it is. A non-extended request sense is specified
1254392e836bSGavin Maltby 		 * by stating that the sense block has 0 length,
1255392e836bSGavin Maltby 		 * which is taken to mean that it is four bytes in
1256392e836bSGavin Maltby 		 * length.
1257392e836bSGavin Maltby 		 */
1258392e836bSGavin Maltby 		if (SCSI_TEST_FAILURE(scsi_test(rq_pkt, STC_PROBE_RQSENSE1))) {
1259392e836bSGavin Maltby 			rval = SCSIPROBE_FAILURE;
1260392e836bSGavin Maltby 			goto out;
12617c478bd9Sstevel@tonic-gate 		}
12627c478bd9Sstevel@tonic-gate 	}
12637c478bd9Sstevel@tonic-gate 
12647c478bd9Sstevel@tonic-gate 	/*
12657c478bd9Sstevel@tonic-gate 	 * At this point, we are guaranteed that something responded
12667c478bd9Sstevel@tonic-gate 	 * to this scsi bus target id. We don't know yet what
12677c478bd9Sstevel@tonic-gate 	 * kind of device it is, or even whether there really is
12687c478bd9Sstevel@tonic-gate 	 * a logical unit attached (as some SCSI target controllers
12697c478bd9Sstevel@tonic-gate 	 * lie about a unit being ready, e.g., the Emulex MD21).
12707c478bd9Sstevel@tonic-gate 	 */
12717c478bd9Sstevel@tonic-gate 
1272392e836bSGavin Maltby 	str = scsi_test(inq_pkt, STC_PROBE_CHK_CLEARED);
1273392e836bSGavin Maltby 	if (SCSI_TEST_FAILURE(str)) {
12747c478bd9Sstevel@tonic-gate 		rval = SCSIPROBE_FAILURE;
12757c478bd9Sstevel@tonic-gate 		goto out;
12767c478bd9Sstevel@tonic-gate 	}
12777c478bd9Sstevel@tonic-gate 
1278392e836bSGavin Maltby 	if (str == SCSI_TEST_CMPLT_BUSY) {
12797c478bd9Sstevel@tonic-gate 		rval = SCSIPROBE_BUSY;
12807c478bd9Sstevel@tonic-gate 		goto out;
12817c478bd9Sstevel@tonic-gate 	}
12827c478bd9Sstevel@tonic-gate 
12837c478bd9Sstevel@tonic-gate 	/*
12847c478bd9Sstevel@tonic-gate 	 * Okay we sent the INQUIRY command.
12857c478bd9Sstevel@tonic-gate 	 *
12867c478bd9Sstevel@tonic-gate 	 * If enough data was transferred, we count that the
12877c478bd9Sstevel@tonic-gate 	 * Inquiry command succeeded, else we have to assume
12887c478bd9Sstevel@tonic-gate 	 * that this is a non-CCS scsi target (or a nonexistent
12897c478bd9Sstevel@tonic-gate 	 * target/lun).
12907c478bd9Sstevel@tonic-gate 	 */
12917c478bd9Sstevel@tonic-gate 
1292392e836bSGavin Maltby 	if (str == SCSI_TEST_CMPLT_CHECK) {
12937c478bd9Sstevel@tonic-gate 		/*
12947c478bd9Sstevel@tonic-gate 		 * try a request sense if we have a pkt, otherwise
12957c478bd9Sstevel@tonic-gate 		 * just retry the inquiry one more time
12967c478bd9Sstevel@tonic-gate 		 */
1297392e836bSGavin Maltby 		if (rq_pkt)
1298392e836bSGavin Maltby 			(void) scsi_test(rq_pkt, STC_PROBE_RQSENSE2);
12997c478bd9Sstevel@tonic-gate 
13007c478bd9Sstevel@tonic-gate 		/*
13017c478bd9Sstevel@tonic-gate 		 * retry inquiry
13027c478bd9Sstevel@tonic-gate 		 */
1303392e836bSGavin Maltby 		str = scsi_test(inq_pkt, STC_PROBE_INQ_FINAL);
1304392e836bSGavin Maltby 		if (SCSI_TEST_FAILURE(str)) {
13057c478bd9Sstevel@tonic-gate 			rval = SCSIPROBE_FAILURE;
13067c478bd9Sstevel@tonic-gate 			goto out;
1307392e836bSGavin Maltby 		} else if (str == SCSI_TEST_CMPLT_CHECK) {
13087c478bd9Sstevel@tonic-gate 			rval = SCSIPROBE_FAILURE;
13097c478bd9Sstevel@tonic-gate 			goto out;
13107c478bd9Sstevel@tonic-gate 		}
13117c478bd9Sstevel@tonic-gate 	}
13127c478bd9Sstevel@tonic-gate 
13137c478bd9Sstevel@tonic-gate done:
13147c478bd9Sstevel@tonic-gate 	/*
13157c478bd9Sstevel@tonic-gate 	 * If we got a parity error on receive of inquiry data,
13167c478bd9Sstevel@tonic-gate 	 * we're just plain out of luck because we told the host
13177c478bd9Sstevel@tonic-gate 	 * adapter to not watch for parity errors.
13187c478bd9Sstevel@tonic-gate 	 */
13197c478bd9Sstevel@tonic-gate 	if ((inq_pkt->pkt_state & STATE_XFERRED_DATA) == 0 ||
13207c478bd9Sstevel@tonic-gate 	    ((SUN_INQSIZE - inq_pkt->pkt_resid) < SUN_MIN_INQLEN)) {
13217c478bd9Sstevel@tonic-gate 		rval = SCSIPROBE_NONCCS;
13227c478bd9Sstevel@tonic-gate 	} else {
13233fbe3e28Svitezslav batrla - Sun Microsystems - Prague Czech Republic 		ASSERT(inq_pkt->pkt_resid >= 0);
13247c478bd9Sstevel@tonic-gate 		bcopy((caddr_t)inq_bp->b_un.b_addr,
13254c06356bSdh 		    (caddr_t)sd->sd_inq, (SUN_INQSIZE - inq_pkt->pkt_resid));
13267c478bd9Sstevel@tonic-gate 		rval = SCSIPROBE_EXISTS;
13277c478bd9Sstevel@tonic-gate 	}
13287c478bd9Sstevel@tonic-gate 
13297c478bd9Sstevel@tonic-gate out:
13307c478bd9Sstevel@tonic-gate 	/*
13317c478bd9Sstevel@tonic-gate 	 * If lun > 0 we need to figure out if this is a scsi-1 device where
1332602ca9eaScth 	 * the "real" lun needs to be embedded into the cdb.
13337c478bd9Sstevel@tonic-gate 	 */
13347c478bd9Sstevel@tonic-gate 	if ((rval == SCSIPROBE_EXISTS) && (pass == 1) &&
13354c06356bSdh 	    (sd->sd_address.a_lun > 0) && (sd->sd_inq->inq_ansi == 0x1)) {
13367c478bd9Sstevel@tonic-gate 		pass++;
13374c06356bSdh 		if (sd->sd_address.a_lun <= 7)
13387c478bd9Sstevel@tonic-gate 			goto again;
13397c478bd9Sstevel@tonic-gate 
13407c478bd9Sstevel@tonic-gate 		/*
13417c478bd9Sstevel@tonic-gate 		 * invalid lun for scsi-1,
13427c478bd9Sstevel@tonic-gate 		 * return probe failure.
13437c478bd9Sstevel@tonic-gate 		 */
13447c478bd9Sstevel@tonic-gate 		rval = SCSIPROBE_FAILURE;
13457c478bd9Sstevel@tonic-gate 	}
13467c478bd9Sstevel@tonic-gate 
13477c478bd9Sstevel@tonic-gate 	if (rq_pkt) {
13487c478bd9Sstevel@tonic-gate 		scsi_destroy_pkt(rq_pkt);
13497c478bd9Sstevel@tonic-gate 	}
13507c478bd9Sstevel@tonic-gate 	if (inq_pkt) {
13517c478bd9Sstevel@tonic-gate 		scsi_destroy_pkt(inq_pkt);
13527c478bd9Sstevel@tonic-gate 	}
13537c478bd9Sstevel@tonic-gate 	if (rq_bp) {
13547c478bd9Sstevel@tonic-gate 		scsi_free_consistent_buf(rq_bp);
13557c478bd9Sstevel@tonic-gate 	}
13567c478bd9Sstevel@tonic-gate 	if (inq_bp) {
13577c478bd9Sstevel@tonic-gate 		scsi_free_consistent_buf(inq_bp);
13587c478bd9Sstevel@tonic-gate 	}
13597c478bd9Sstevel@tonic-gate 	return (rval);
13607c478bd9Sstevel@tonic-gate }
13617c478bd9Sstevel@tonic-gate 
136253a7b6b6SChris Horne /*
136353a7b6b6SChris Horne  * Convert from a scsi_device structure pointer to a scsi_hba_tran structure
136453a7b6b6SChris Horne  * pointer. The correct way to do this is
136553a7b6b6SChris Horne  *
13664c06356bSdh  *	#define	DEVP_TO_TRAN(sd)	((sd)->sd_address.a_hba_tran)
136753a7b6b6SChris Horne  *
136853a7b6b6SChris Horne  * however we have some consumers that place their own vector in a_hba_tran. To
136953a7b6b6SChris Horne  * avoid problems, we implement this using the sd_tran_safe. See
137053a7b6b6SChris Horne  * scsi_hba_initchild for more details.
137153a7b6b6SChris Horne  */
13724c06356bSdh #define	DEVP_TO_TRAN(sd)	((sd)->sd_tran_safe)
13737c478bd9Sstevel@tonic-gate 
13747c478bd9Sstevel@tonic-gate /*
13754c06356bSdh  * Function, callable from SCSA framework, to get 'human' readable REPORTDEV
13764c06356bSdh  * addressing information from scsi_device properties.
13777c478bd9Sstevel@tonic-gate  */
13787c478bd9Sstevel@tonic-gate int
scsi_ua_get_reportdev(struct scsi_device * sd,char * ra,int len)13794c06356bSdh scsi_ua_get_reportdev(struct scsi_device *sd, char *ra, int len)
13807c478bd9Sstevel@tonic-gate {
13814c06356bSdh 	/* use deprecated tran_get_bus_addr interface if it is defined */
13824c06356bSdh 	/* NOTE: tran_get_bus_addr is a poor name choice for interface */
13834c06356bSdh 	if (DEVP_TO_TRAN(sd)->tran_get_bus_addr)
13844c06356bSdh 		return ((*DEVP_TO_TRAN(sd)->tran_get_bus_addr)(sd, ra, len));
13854c06356bSdh 	return (scsi_hba_ua_get_reportdev(sd, ra, len));
13864c06356bSdh }
13877c478bd9Sstevel@tonic-gate 
13884c06356bSdh /*
13894c06356bSdh  * Function, callable from HBA driver's tran_get_bus_addr(9E) implementation,
13904c06356bSdh  * to get standard form of human readable REPORTDEV addressing information
13914c06356bSdh  * from scsi_device properties.
13924c06356bSdh  */
13934c06356bSdh int
scsi_hba_ua_get_reportdev(struct scsi_device * sd,char * ra,int len)13944c06356bSdh scsi_hba_ua_get_reportdev(struct scsi_device *sd, char *ra, int len)
13954c06356bSdh {
13964c06356bSdh 	int		tgt, lun, sfunc;
13974c06356bSdh 	char		*tgt_port;
13984c06356bSdh 	scsi_lun64_t	lun64;
13994c06356bSdh 
14004c06356bSdh 	/* get device unit-address properties */
14014c06356bSdh 	tgt = scsi_device_prop_get_int(sd, SCSI_DEVICE_PROP_PATH,
14024c06356bSdh 	    SCSI_ADDR_PROP_TARGET, -1);
14034c06356bSdh 	if (scsi_device_prop_lookup_string(sd, SCSI_DEVICE_PROP_PATH,
14044c06356bSdh 	    SCSI_ADDR_PROP_TARGET_PORT, &tgt_port) != DDI_PROP_SUCCESS)
14054c06356bSdh 		tgt_port = NULL;
14064c06356bSdh 	if ((tgt == -1) && (tgt_port == NULL))
14074c06356bSdh 		return (0);		/* no target */
14084c06356bSdh 
14094c06356bSdh 	lun = scsi_device_prop_get_int(sd, SCSI_DEVICE_PROP_PATH,
14104c06356bSdh 	    SCSI_ADDR_PROP_LUN, 0);
14114c06356bSdh 	lun64 = scsi_device_prop_get_int64(sd, SCSI_DEVICE_PROP_PATH,
14124c06356bSdh 	    SCSI_ADDR_PROP_LUN64, lun);
14134c06356bSdh 	sfunc = scsi_device_prop_get_int(sd, SCSI_DEVICE_PROP_PATH,
14144c06356bSdh 	    SCSI_ADDR_PROP_SFUNC, -1);
14154c06356bSdh 
14164c06356bSdh 	/*
14174c06356bSdh 	 * XXX should the default be to print this in decimal for
14184c06356bSdh 	 * "human readable" form, so it matches conf files?
14194c06356bSdh 	 */
14204c06356bSdh 	if (tgt_port) {
14214c06356bSdh 		if (sfunc == -1)
14224c06356bSdh 			(void) snprintf(ra, len,
14234c06356bSdh 			    "%s %s lun %" PRIx64,
14244c06356bSdh 			    SCSI_ADDR_PROP_TARGET_PORT, tgt_port, lun64);
14254c06356bSdh 		else
14264c06356bSdh 			(void) snprintf(ra, len,
14274c06356bSdh 			    "%s %s lun %" PRIx64 " sfunc %x",
14284c06356bSdh 			    SCSI_ADDR_PROP_TARGET_PORT, tgt_port, lun64, sfunc);
14294c06356bSdh 		scsi_device_prop_free(sd, SCSI_DEVICE_PROP_PATH, tgt_port);
14304c06356bSdh 	} else {
14314c06356bSdh 		if (sfunc == -1)
14324c06356bSdh 			(void) snprintf(ra, len,
14334c06356bSdh 			    "%s %x lun %" PRIx64,
14344c06356bSdh 			    SCSI_ADDR_PROP_TARGET, tgt, lun64);
14354c06356bSdh 		else
14364c06356bSdh 			(void) snprintf(ra, len,
14374c06356bSdh 			    "%s %x lun %" PRIx64 " sfunc %x",
14384c06356bSdh 			    SCSI_ADDR_PROP_TARGET, tgt, lun64, sfunc);
14394c06356bSdh 	}
144053a7b6b6SChris Horne 
144153a7b6b6SChris Horne 	return (1);
14427c478bd9Sstevel@tonic-gate }
14437c478bd9Sstevel@tonic-gate 
14447c478bd9Sstevel@tonic-gate /*
14454c06356bSdh  * scsi_ua_get: using properties, return "unit-address" string.
14464c06356bSdh  * Called by SCSA framework, may call HBAs tran function.
14474c06356bSdh  */
14484c06356bSdh int
scsi_ua_get(struct scsi_device * sd,char * ua,int len)14494c06356bSdh scsi_ua_get(struct scsi_device *sd, char *ua, int len)
14504c06356bSdh {
14514c06356bSdh 	char		*eua;
14524c06356bSdh 
14534c06356bSdh 	/* See if we already have established the unit-address. */
14544c06356bSdh 	if ((eua = scsi_device_unit_address(sd)) != NULL) {
14554c06356bSdh 		(void) strlcpy(ua, eua, len);
14564c06356bSdh 		return (1);
14574c06356bSdh 	}
14584c06356bSdh 
14594c06356bSdh 	/* Use deprecated tran_get_name interface if it is defined. */
14604c06356bSdh 	/* NOTE: tran_get_name is a poor name choice for interface */
14614c06356bSdh 	if (DEVP_TO_TRAN(sd)->tran_get_name)
14624c06356bSdh 		return ((*DEVP_TO_TRAN(sd)->tran_get_name)(sd, ua, len));
14634c06356bSdh 
14644c06356bSdh 	/* Use generic property implementation */
14654c06356bSdh 	return (scsi_hba_ua_get(sd, ua, len));
14664c06356bSdh }
14674c06356bSdh 
14684c06356bSdh /*
14694c06356bSdh  * scsi_hba_ua_get: using properties, return "unit-address" string.
14704c06356bSdh  * This function may be called from an HBAs tran function.
147153a7b6b6SChris Horne  *
147253a7b6b6SChris Horne  * Function to get "unit-address" in "name@unit-address" /devices path
14734c06356bSdh  * component form from the scsi_device unit-address properties on a node.
147453a7b6b6SChris Horne  *
14754c06356bSdh  * NOTE: This function works in conjunction with scsi_hba_ua_set().
14767c478bd9Sstevel@tonic-gate  */
14777c478bd9Sstevel@tonic-gate int
scsi_hba_ua_get(struct scsi_device * sd,char * ua,int len)14784c06356bSdh scsi_hba_ua_get(struct scsi_device *sd, char *ua, int len)
14797c478bd9Sstevel@tonic-gate {
14804c06356bSdh 	int		tgt, lun, sfunc;
14814c06356bSdh 	char		*tgt_port;
14824c06356bSdh 	scsi_lun64_t	lun64;
14834c06356bSdh 
14844c06356bSdh 	/* get device unit-address properties */
14854c06356bSdh 	tgt = scsi_device_prop_get_int(sd, SCSI_DEVICE_PROP_PATH,
14864c06356bSdh 	    SCSI_ADDR_PROP_TARGET, -1);
14874c06356bSdh 	if (scsi_device_prop_lookup_string(sd, SCSI_DEVICE_PROP_PATH,
14884c06356bSdh 	    SCSI_ADDR_PROP_TARGET_PORT, &tgt_port) != DDI_PROP_SUCCESS)
14894c06356bSdh 		tgt_port = NULL;
14904c06356bSdh 	if ((tgt == -1) && (tgt_port == NULL))
14914c06356bSdh 		return (0);		/* no target */
14924c06356bSdh 
14934c06356bSdh 	lun = scsi_device_prop_get_int(sd, SCSI_DEVICE_PROP_PATH,
14944c06356bSdh 	    SCSI_ADDR_PROP_LUN, 0);
14954c06356bSdh 	lun64 = scsi_device_prop_get_int64(sd, SCSI_DEVICE_PROP_PATH,
14964c06356bSdh 	    SCSI_ADDR_PROP_LUN64, lun);
14974c06356bSdh 	sfunc = scsi_device_prop_get_int(sd, SCSI_DEVICE_PROP_PATH,
14984c06356bSdh 	    SCSI_ADDR_PROP_SFUNC, -1);
14994c06356bSdh 	if (tgt_port) {
15004c06356bSdh 		if (sfunc == -1)
15014c06356bSdh 			(void) snprintf(ua, len, "%s,%" PRIx64,
15024c06356bSdh 			    tgt_port, lun64);
15034c06356bSdh 		else
15044c06356bSdh 			(void) snprintf(ua, len, "%s,%" PRIx64 ",%x",
15054c06356bSdh 			    tgt_port, lun64, sfunc);
15064c06356bSdh 		scsi_device_prop_free(sd, SCSI_DEVICE_PROP_PATH, tgt_port);
15074c06356bSdh 	} else {
15084c06356bSdh 		if (sfunc == -1)
15094c06356bSdh 			(void) snprintf(ua, len, "%x,%" PRIx64, tgt, lun64);
15104c06356bSdh 		else
15114c06356bSdh 			(void) snprintf(ua, len, "%x,%" PRIx64 ",%x",
15124c06356bSdh 			    tgt, lun64, sfunc);
15134c06356bSdh 	}
151453a7b6b6SChris Horne 	return (1);
15157c478bd9Sstevel@tonic-gate }
15167c478bd9Sstevel@tonic-gate 
151796c4a178SChris Horne static void
create_inquiry_props(struct scsi_device * sd)15184c06356bSdh create_inquiry_props(struct scsi_device *sd)
15197c478bd9Sstevel@tonic-gate {
15204c06356bSdh 	struct scsi_inquiry *inq = sd->sd_inq;
15217c478bd9Sstevel@tonic-gate 
15224c06356bSdh 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, sd->sd_dev,
15237c478bd9Sstevel@tonic-gate 	    INQUIRY_DEVICE_TYPE, (int)inq->inq_dtype);
15247c478bd9Sstevel@tonic-gate 
15257c478bd9Sstevel@tonic-gate 	/*
15267c478bd9Sstevel@tonic-gate 	 * Create the following properties:
15277c478bd9Sstevel@tonic-gate 	 *
15284c06356bSdh 	 * inquiry-vendor-id	Vendor id (INQUIRY data bytes 8-15)
15294c06356bSdh 	 * inquiry-product-id	Product id (INQUIRY data bytes 16-31)
15304c06356bSdh 	 * inquiry-revision-id	Product Rev level (INQUIRY data bytes 32-35)
15317c478bd9Sstevel@tonic-gate 	 *
153296c4a178SChris Horne 	 * NOTE: We don't support creation of these properties for scsi-1
15337c478bd9Sstevel@tonic-gate 	 * devices (as the vid, pid and revision were not defined) and we
15347c478bd9Sstevel@tonic-gate 	 * don't create the property if they are of zero length when
15357c478bd9Sstevel@tonic-gate 	 * stripped of Nulls and spaces.
153696c4a178SChris Horne 	 *
153796c4a178SChris Horne 	 * NOTE: The first definition of these properties sticks. This gives
153896c4a178SChris Horne 	 * a transport the ability to provide a higher-quality definition
153996c4a178SChris Horne 	 * than the standard SCSI INQUIRY data.
15407c478bd9Sstevel@tonic-gate 	 */
15417c478bd9Sstevel@tonic-gate 	if (inq->inq_ansi != 1) {
15424c06356bSdh 		if (ddi_prop_exists(DDI_DEV_T_NONE, sd->sd_dev,
1543184cd04cScth 		    DDI_PROP_TYPE_STRING, INQUIRY_VENDOR_ID) == 0)
15444c06356bSdh 			(void) scsi_device_prop_update_inqstring(sd,
1545184cd04cScth 			    INQUIRY_VENDOR_ID,
1546184cd04cScth 			    inq->inq_vid, sizeof (inq->inq_vid));
1547184cd04cScth 
15484c06356bSdh 		if (ddi_prop_exists(DDI_DEV_T_NONE, sd->sd_dev,
1549184cd04cScth 		    DDI_PROP_TYPE_STRING, INQUIRY_PRODUCT_ID) == 0)
15504c06356bSdh 			(void) scsi_device_prop_update_inqstring(sd,
1551184cd04cScth 			    INQUIRY_PRODUCT_ID,
1552184cd04cScth 			    inq->inq_pid, sizeof (inq->inq_pid));
1553184cd04cScth 
15544c06356bSdh 		if (ddi_prop_exists(DDI_DEV_T_NONE, sd->sd_dev,
1555184cd04cScth 		    DDI_PROP_TYPE_STRING, INQUIRY_REVISION_ID) == 0)
15564c06356bSdh 			(void) scsi_device_prop_update_inqstring(sd,
1557184cd04cScth 			    INQUIRY_REVISION_ID,
1558184cd04cScth 			    inq->inq_revision, sizeof (inq->inq_revision));
15597c478bd9Sstevel@tonic-gate 	}
15607c478bd9Sstevel@tonic-gate }
15617c478bd9Sstevel@tonic-gate 
15627c478bd9Sstevel@tonic-gate /*
1563184cd04cScth  * Create 'inquiry' string properties.  An 'inquiry' string gets special
1564184cd04cScth  * treatment to trim trailing blanks (etc) and ensure null termination.
15657c478bd9Sstevel@tonic-gate  */
1566184cd04cScth int
scsi_device_prop_update_inqstring(struct scsi_device * sd,char * name,char * data,size_t len)15674c06356bSdh scsi_device_prop_update_inqstring(struct scsi_device *sd,
1568184cd04cScth     char *name, char *data, size_t len)
15697c478bd9Sstevel@tonic-gate {
1570184cd04cScth 	int	ilen;
1571184cd04cScth 	char	*data_string;
1572184cd04cScth 	int	rv;
1573184cd04cScth 
157496c4a178SChris Horne 	ilen = scsi_ascii_inquiry_len(data, len);
1575184cd04cScth 	ASSERT(ilen <= (int)len);
1576184cd04cScth 	if (ilen <= 0)
1577184cd04cScth 		return (DDI_PROP_INVAL_ARG);
1578184cd04cScth 
1579184cd04cScth 	/* ensure null termination */
1580184cd04cScth 	data_string = kmem_zalloc(ilen + 1, KM_SLEEP);
1581184cd04cScth 	bcopy(data, data_string, ilen);
1582184cd04cScth 	rv = ndi_prop_update_string(DDI_DEV_T_NONE,
15834c06356bSdh 	    sd->sd_dev, name, data_string);
1584184cd04cScth 	kmem_free(data_string, ilen + 1);
1585184cd04cScth 	return (rv);
15867c478bd9Sstevel@tonic-gate }
15877c478bd9Sstevel@tonic-gate 
158853a7b6b6SChris Horne /*
158953a7b6b6SChris Horne  * Interfaces associated with SCSI_HBA_ADDR_COMPLEX
159053a7b6b6SChris Horne  * per-scsi_device HBA private data support.
1591392e836bSGavin Maltby  *
1592392e836bSGavin Maltby  * scsi_address_device returns NULL if we're not SCSI_HBA_ADDR_COMPLEX,
1593392e836bSGavin Maltby  * thereby allowing use of scsi_address_device as a test for
1594392e836bSGavin Maltby  * SCSI_HBA_ADDR_COMPLEX.
159553a7b6b6SChris Horne  */
159653a7b6b6SChris Horne struct scsi_device *
scsi_address_device(struct scsi_address * sa)159753a7b6b6SChris Horne scsi_address_device(struct scsi_address *sa)
159853a7b6b6SChris Horne {
1599392e836bSGavin Maltby 	return ((sa->a_hba_tran->tran_hba_flags & SCSI_HBA_ADDR_COMPLEX) ?
1600392e836bSGavin Maltby 	    sa->a.a_sd : NULL);
160153a7b6b6SChris Horne }
160253a7b6b6SChris Horne 
160353a7b6b6SChris Horne void
scsi_device_hba_private_set(struct scsi_device * sd,void * data)160453a7b6b6SChris Horne scsi_device_hba_private_set(struct scsi_device *sd, void *data)
160553a7b6b6SChris Horne {
160653a7b6b6SChris Horne 	ASSERT(sd->sd_address.a_hba_tran->tran_hba_flags &
160753a7b6b6SChris Horne 	    SCSI_HBA_ADDR_COMPLEX);
160853a7b6b6SChris Horne 	sd->sd_hba_private = data;
160953a7b6b6SChris Horne }
161053a7b6b6SChris Horne 
161153a7b6b6SChris Horne void *
scsi_device_hba_private_get(struct scsi_device * sd)161253a7b6b6SChris Horne scsi_device_hba_private_get(struct scsi_device *sd)
161353a7b6b6SChris Horne {
161453a7b6b6SChris Horne 	ASSERT(sd->sd_address.a_hba_tran->tran_hba_flags &
161553a7b6b6SChris Horne 	    SCSI_HBA_ADDR_COMPLEX);
161653a7b6b6SChris Horne 	return (sd->sd_hba_private);
161753a7b6b6SChris Horne }
16187c478bd9Sstevel@tonic-gate 
16197c478bd9Sstevel@tonic-gate /*
162053a7b6b6SChris Horne  * This routine is called from the start of scsi_probe() if a tgt/LUN to be
16217c478bd9Sstevel@tonic-gate  * probed *may* be a request to probe a strictly SCSI-2 target (with respect
16227c478bd9Sstevel@tonic-gate  * to LUNs) -- and this probe may be for a LUN number greater than 7,
16237c478bd9Sstevel@tonic-gate  * which can cause a hardware hang
16247c478bd9Sstevel@tonic-gate  *
16257c478bd9Sstevel@tonic-gate  * return 0 if the probe can proceed,
16267c478bd9Sstevel@tonic-gate  * else return 1, meaning do *NOT* probe this target/LUN
16277c478bd9Sstevel@tonic-gate  */
16287c478bd9Sstevel@tonic-gate static int
scsi_check_ss2_LUN_limit(struct scsi_device * sd)16294c06356bSdh scsi_check_ss2_LUN_limit(struct scsi_device *sd)
16307c478bd9Sstevel@tonic-gate {
16314c06356bSdh 	struct scsi_address	*ap = &(sd->sd_address);
16327c478bd9Sstevel@tonic-gate 	dev_info_t		*pdevi =
16334c06356bSdh 	    (dev_info_t *)DEVI(sd->sd_dev)->devi_parent;
16347c478bd9Sstevel@tonic-gate 	int			ret_val = 0;	/* default return value */
16357c478bd9Sstevel@tonic-gate 	uchar_t			*tgt_list;
16367c478bd9Sstevel@tonic-gate 	uint_t			tgt_nelements;
16377c478bd9Sstevel@tonic-gate 	int			i;
16387c478bd9Sstevel@tonic-gate 
16397c478bd9Sstevel@tonic-gate 
16407c478bd9Sstevel@tonic-gate 	/*
16417c478bd9Sstevel@tonic-gate 	 * check for what *might* be a problem probe, only we don't
16427c478bd9Sstevel@tonic-gate 	 * know yet what's really at the destination target/LUN
16437c478bd9Sstevel@tonic-gate 	 */
16447c478bd9Sstevel@tonic-gate 	if ((ap->a_target >= NTARGETS_WIDE) ||
16457c478bd9Sstevel@tonic-gate 	    (ap->a_lun < NLUNS_PER_TARGET)) {
16467c478bd9Sstevel@tonic-gate 		return (0);		/* okay to probe this target */
16477c478bd9Sstevel@tonic-gate 	}
16487c478bd9Sstevel@tonic-gate 
16497c478bd9Sstevel@tonic-gate 	/*
16507c478bd9Sstevel@tonic-gate 	 * this *might* be a problematic probe, so look to see
16517c478bd9Sstevel@tonic-gate 	 * if the inquiry data matches
16527c478bd9Sstevel@tonic-gate 	 */
16537c478bd9Sstevel@tonic-gate 	SCSI_PROBE_DEBUG2(1, "SCSA pre-probe: checking tgt.LUN=%d.%d\n",
16547c478bd9Sstevel@tonic-gate 	    ap->a_target, ap->a_lun);
16557c478bd9Sstevel@tonic-gate 	SCSI_PROBE_DEBUG1(2,
16567c478bd9Sstevel@tonic-gate 	    "SCSA pre-probe: scanning parent node name: %s ...\n",
16577c478bd9Sstevel@tonic-gate 	    ddi_node_name(pdevi));
16587c478bd9Sstevel@tonic-gate 
16597c478bd9Sstevel@tonic-gate 	/*
16607c478bd9Sstevel@tonic-gate 	 * look for a special property of our parent node that lists
16617c478bd9Sstevel@tonic-gate 	 * the targets under it for which we do *NOT* want to probe
16627c478bd9Sstevel@tonic-gate 	 * if LUN>7 -- if the property is found, look to see if our
16637c478bd9Sstevel@tonic-gate 	 * target ID is on that list
16647c478bd9Sstevel@tonic-gate 	 */
166596c4a178SChris Horne 	if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, pdevi,
166696c4a178SChris Horne 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, SS2_LUN0_TGT_LIST_PROP,
16677c478bd9Sstevel@tonic-gate 	    &tgt_list, &tgt_nelements) != DDI_PROP_SUCCESS) {
16687c478bd9Sstevel@tonic-gate 		/*
16697c478bd9Sstevel@tonic-gate 		 * no list, so it must be okay to probe this target.LUN
16707c478bd9Sstevel@tonic-gate 		 */
16717c478bd9Sstevel@tonic-gate 		SCSI_PROBE_DEBUG0(3,
16727c478bd9Sstevel@tonic-gate 		    "SCSA pre-probe: NO parent prop found\n");
16737c478bd9Sstevel@tonic-gate 	} else {
16747c478bd9Sstevel@tonic-gate 		for (i = 0; i < tgt_nelements; i++) {
16757c478bd9Sstevel@tonic-gate 			if (tgt_list[i] == ap->a_target) {
16767c478bd9Sstevel@tonic-gate 				/*
16777c478bd9Sstevel@tonic-gate 				 * we found a match, which means we do *NOT*
16787c478bd9Sstevel@tonic-gate 				 * want to probe the specified target.LUN
16797c478bd9Sstevel@tonic-gate 				 */
16807c478bd9Sstevel@tonic-gate 				ret_val = 1;
16817c478bd9Sstevel@tonic-gate 				break;
16827c478bd9Sstevel@tonic-gate 			}
16837c478bd9Sstevel@tonic-gate 		}
16847c478bd9Sstevel@tonic-gate 		ddi_prop_free(tgt_list);
16857c478bd9Sstevel@tonic-gate #ifdef	DEBUG
16867c478bd9Sstevel@tonic-gate 		if (ret_val == 1) {
16877c478bd9Sstevel@tonic-gate 			SCSI_PROBE_DEBUG2(1,
16887c478bd9Sstevel@tonic-gate 			    "SCSA pre-probe: marker node FOUND for "
16897c478bd9Sstevel@tonic-gate 			    "tgt.LUN=%d.%d, so SKIPPING it\n",
16907c478bd9Sstevel@tonic-gate 			    ap->a_target, ap->a_lun);
16917c478bd9Sstevel@tonic-gate 		} else {
16927c478bd9Sstevel@tonic-gate 			SCSI_PROBE_DEBUG0(2,
16937c478bd9Sstevel@tonic-gate 			    "SCSA pre-probe: NO marker node found"
16947c478bd9Sstevel@tonic-gate 			    " -- OK to probe\n");
16957c478bd9Sstevel@tonic-gate 		}
16967c478bd9Sstevel@tonic-gate #endif
16977c478bd9Sstevel@tonic-gate 	}
16987c478bd9Sstevel@tonic-gate 	return (ret_val);
16997c478bd9Sstevel@tonic-gate }
17007c478bd9Sstevel@tonic-gate 
17017c478bd9Sstevel@tonic-gate 
17027c478bd9Sstevel@tonic-gate /*
17037c478bd9Sstevel@tonic-gate  * this routine is called from near the end of scsi_probe(),
17047c478bd9Sstevel@tonic-gate  * to see if the just-probed node is on our list of strictly-SCSI-2 nodes,
17057c478bd9Sstevel@tonic-gate  * and if it is we mark our parent node with this information
17067c478bd9Sstevel@tonic-gate  */
17077c478bd9Sstevel@tonic-gate static void
scsi_establish_LUN_limit(struct scsi_device * sd)17084c06356bSdh scsi_establish_LUN_limit(struct scsi_device *sd)
17097c478bd9Sstevel@tonic-gate {
17104c06356bSdh 	struct scsi_address	*ap = &(sd->sd_address);
17114c06356bSdh 	struct scsi_inquiry	*inq = sd->sd_inq;
17124c06356bSdh 	dev_info_t		*devi = sd->sd_dev;
17137c478bd9Sstevel@tonic-gate 	char			*vid = NULL;
17147c478bd9Sstevel@tonic-gate 	char			*pid = NULL;
17157c478bd9Sstevel@tonic-gate 	char			*rev = NULL;
17167c478bd9Sstevel@tonic-gate 	int			i;
17177c478bd9Sstevel@tonic-gate 	const ss2_lun0_info_t	*p;
17187c478bd9Sstevel@tonic-gate 	int			bad_target_found = 0;
17197c478bd9Sstevel@tonic-gate 
17207c478bd9Sstevel@tonic-gate 
17217c478bd9Sstevel@tonic-gate 	/*
17227c478bd9Sstevel@tonic-gate 	 * if this inquiry data shows that we have a strictly-SCSI-2 device
17237c478bd9Sstevel@tonic-gate 	 * at LUN 0, then add it to our list of strictly-SCSI-2 devices,
17247c478bd9Sstevel@tonic-gate 	 * so that we can avoid probes where LUN>7 on this device later
17257c478bd9Sstevel@tonic-gate 	 */
17267c478bd9Sstevel@tonic-gate 	if ((ap->a_lun != 0) ||
17277c478bd9Sstevel@tonic-gate 	    (ap->a_target >= NTARGETS_WIDE) ||
17287c478bd9Sstevel@tonic-gate 	    (inq->inq_dtype != DTYPE_PROCESSOR) ||
17297c478bd9Sstevel@tonic-gate 	    (inq->inq_ansi != 2)) {
17307c478bd9Sstevel@tonic-gate 		/*
17317c478bd9Sstevel@tonic-gate 		 * this can't possibly be a node we want to look at, since
17327c478bd9Sstevel@tonic-gate 		 * either LUN is greater than 0, target is greater than or
173353a7b6b6SChris Horne 		 * equal to 16, device type
17347c478bd9Sstevel@tonic-gate 		 * is not processor, or SCSI level is not SCSI-2,
17357c478bd9Sstevel@tonic-gate 		 * so don't bother checking for a strictly SCSI-2
17367c478bd9Sstevel@tonic-gate 		 * (only 8 LUN) target
17377c478bd9Sstevel@tonic-gate 		 */
17387c478bd9Sstevel@tonic-gate 		return;				/* don't care */
17397c478bd9Sstevel@tonic-gate 	}
17407c478bd9Sstevel@tonic-gate 
17417c478bd9Sstevel@tonic-gate 	SCSI_PROBE_DEBUG2(1, "SCSA post-probe: LUN limit on tgt.LUN=%d.%d, "
17427c478bd9Sstevel@tonic-gate 	    "SCSI-2 PROCESSOR?\n", ap->a_target, ap->a_lun);
17437c478bd9Sstevel@tonic-gate 
17447c478bd9Sstevel@tonic-gate 	ASSERT(devi != NULL);
17457c478bd9Sstevel@tonic-gate 
17467c478bd9Sstevel@tonic-gate 	/*
17477c478bd9Sstevel@tonic-gate 	 * we have a node that has been probed that is: LUN=0, target<16,
17487c478bd9Sstevel@tonic-gate 	 * PROCESSOR-type SCSI target, and at the SCSI-2 level, so
17497c478bd9Sstevel@tonic-gate 	 * check INQ properties to see if it's in our list of strictly
17507c478bd9Sstevel@tonic-gate 	 * SCSI-2 targets
17517c478bd9Sstevel@tonic-gate 	 *
17527c478bd9Sstevel@tonic-gate 	 * first we have to get the VID/PID/REV INQUIRY properties for
17537c478bd9Sstevel@tonic-gate 	 * comparison
17547c478bd9Sstevel@tonic-gate 	 */
175596c4a178SChris Horne 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, devi,
175696c4a178SChris Horne 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
17577c478bd9Sstevel@tonic-gate 	    INQUIRY_VENDOR_ID, &vid) != DDI_PROP_SUCCESS) {
17587c478bd9Sstevel@tonic-gate 		SCSI_PROBE_DEBUG1(2, "SCSA post-probe: prop \"%s\" missing\n",
17597c478bd9Sstevel@tonic-gate 		    INQUIRY_VENDOR_ID);
17607c478bd9Sstevel@tonic-gate 		goto dun;
17617c478bd9Sstevel@tonic-gate 	}
176296c4a178SChris Horne 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, devi,
176396c4a178SChris Horne 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
17647c478bd9Sstevel@tonic-gate 	    INQUIRY_PRODUCT_ID, &pid) != DDI_PROP_SUCCESS) {
17657c478bd9Sstevel@tonic-gate 		SCSI_PROBE_DEBUG1(2, "SCSA post-probe: prop \"%s\" missing\n",
17667c478bd9Sstevel@tonic-gate 		    INQUIRY_PRODUCT_ID);
17677c478bd9Sstevel@tonic-gate 		goto dun;
17687c478bd9Sstevel@tonic-gate 	}
176996c4a178SChris Horne 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, devi,
177096c4a178SChris Horne 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
17717c478bd9Sstevel@tonic-gate 	    INQUIRY_REVISION_ID, &rev) != DDI_PROP_SUCCESS) {
17727c478bd9Sstevel@tonic-gate 		SCSI_PROBE_DEBUG1(2, "SCSA post-probe: prop \"%s\" missing\n",
17737c478bd9Sstevel@tonic-gate 		    INQUIRY_REVISION_ID);
17747c478bd9Sstevel@tonic-gate 		goto dun;
17757c478bd9Sstevel@tonic-gate 	}
17767c478bd9Sstevel@tonic-gate 
17777c478bd9Sstevel@tonic-gate 	SCSI_PROBE_DEBUG3(3, "SCSA post-probe: looking for vid/pid/rev = "
17787c478bd9Sstevel@tonic-gate 	    "\"%s\"/\"%s\"/\"%s\"\n", vid, pid, rev);
17797c478bd9Sstevel@tonic-gate 
17807c478bd9Sstevel@tonic-gate 	/*
17817c478bd9Sstevel@tonic-gate 	 * now that we have the INQUIRY properties from the device node,
17827c478bd9Sstevel@tonic-gate 	 * compare them with our known offenders
17837c478bd9Sstevel@tonic-gate 	 *
17847c478bd9Sstevel@tonic-gate 	 * Note: comparison is *CASE* *SENSITIVE*
17857c478bd9Sstevel@tonic-gate 	 */
17867c478bd9Sstevel@tonic-gate 	for (i = 0; i < scsi_probe_strict_s2_size; i++) {
17877c478bd9Sstevel@tonic-gate 		p = &scsi_probe_strict_s2_list[i];
17887c478bd9Sstevel@tonic-gate 
17897c478bd9Sstevel@tonic-gate 		if ((strcmp(p->sli_vid, vid) == 0) &&
17907c478bd9Sstevel@tonic-gate 		    (strcmp(p->sli_pid, pid) == 0) &&
17917c478bd9Sstevel@tonic-gate 		    (strcmp(p->sli_rev, rev) == 0)) {
17927c478bd9Sstevel@tonic-gate 			/*
17937c478bd9Sstevel@tonic-gate 			 * we found a match -- do NOT want to probe this one
17947c478bd9Sstevel@tonic-gate 			 */
17957c478bd9Sstevel@tonic-gate 			SCSI_PROBE_DEBUG3(1,
17967c478bd9Sstevel@tonic-gate 			    "SCSA post-probe: recording strict SCSI-2 node "
17977c478bd9Sstevel@tonic-gate 			    "vid/pid/rev = \"%s\"/\"%s\"/\"%s\"\n",
17987c478bd9Sstevel@tonic-gate 			    vid, pid, rev);
17997c478bd9Sstevel@tonic-gate 
18007c478bd9Sstevel@tonic-gate 			/*
18017c478bd9Sstevel@tonic-gate 			 * set/update private parent-node property,
18027c478bd9Sstevel@tonic-gate 			 * so we can find out about this node later
18037c478bd9Sstevel@tonic-gate 			 */
18047c478bd9Sstevel@tonic-gate 			bad_target_found = 1;
18057c478bd9Sstevel@tonic-gate 			break;
18067c478bd9Sstevel@tonic-gate 		}
18077c478bd9Sstevel@tonic-gate 	}
18087c478bd9Sstevel@tonic-gate 
18097c478bd9Sstevel@tonic-gate 	/*
18107c478bd9Sstevel@tonic-gate 	 * either add remove target number from parent property
18117c478bd9Sstevel@tonic-gate 	 */
18127c478bd9Sstevel@tonic-gate 	scsi_update_parent_ss2_prop(devi, ap->a_target, bad_target_found);
18137c478bd9Sstevel@tonic-gate 
18147c478bd9Sstevel@tonic-gate dun:
18157c478bd9Sstevel@tonic-gate 	if (vid != NULL) {
18167c478bd9Sstevel@tonic-gate 		ddi_prop_free(vid);
18177c478bd9Sstevel@tonic-gate 	}
18187c478bd9Sstevel@tonic-gate 	if (pid != NULL) {
18197c478bd9Sstevel@tonic-gate 		ddi_prop_free(pid);
18207c478bd9Sstevel@tonic-gate 	}
18217c478bd9Sstevel@tonic-gate 	if (rev != NULL) {
18227c478bd9Sstevel@tonic-gate 		ddi_prop_free(rev);
18237c478bd9Sstevel@tonic-gate 	}
18247c478bd9Sstevel@tonic-gate }
18257c478bd9Sstevel@tonic-gate 
18267c478bd9Sstevel@tonic-gate 
18277c478bd9Sstevel@tonic-gate /*
18287c478bd9Sstevel@tonic-gate  * update the parent node to add in the supplied tgt number to the target
18297c478bd9Sstevel@tonic-gate  * list property already present (if any)
18307c478bd9Sstevel@tonic-gate  *
18317c478bd9Sstevel@tonic-gate  * since the target list can never be longer than 16, and each target
18327c478bd9Sstevel@tonic-gate  * number is also small, we can save having to alloc memory by putting
18337c478bd9Sstevel@tonic-gate  * a 16-byte array on the stack and using it for property memory
18347c478bd9Sstevel@tonic-gate  *
18357c478bd9Sstevel@tonic-gate  * if "add_tgt" is set then add the target to the parent's property, else
18367c478bd9Sstevel@tonic-gate  * remove it (if present)
18377c478bd9Sstevel@tonic-gate  */
18387c478bd9Sstevel@tonic-gate static void
scsi_update_parent_ss2_prop(dev_info_t * devi,int tgt,int add_tgt)18397c478bd9Sstevel@tonic-gate scsi_update_parent_ss2_prop(dev_info_t *devi, int tgt, int add_tgt)
18407c478bd9Sstevel@tonic-gate {
18417c478bd9Sstevel@tonic-gate 	dev_info_t	*pdevi = (dev_info_t *)DEVI(devi)->devi_parent;
18427c478bd9Sstevel@tonic-gate 	uchar_t		*tgt_list;
18437c478bd9Sstevel@tonic-gate 	uint_t		nelements;
18447c478bd9Sstevel@tonic-gate 	uint_t		new_nelements;
18457c478bd9Sstevel@tonic-gate 	int		i;
18467c478bd9Sstevel@tonic-gate 	int		update_result;
18477c478bd9Sstevel@tonic-gate 	uchar_t		new_tgt_list[NTARGETS_WIDE];
18487c478bd9Sstevel@tonic-gate 
18497c478bd9Sstevel@tonic-gate 
18507c478bd9Sstevel@tonic-gate 	ASSERT(pdevi != NULL);
18517c478bd9Sstevel@tonic-gate 
18527c478bd9Sstevel@tonic-gate 	SCSI_PROBE_DEBUG3(3,
18537c478bd9Sstevel@tonic-gate 	    "SCSA post-probe: updating parent=%s property to %s tgt=%d\n",
18547c478bd9Sstevel@tonic-gate 	    ddi_node_name(pdevi), add_tgt ? "add" : "remove", tgt);
18557c478bd9Sstevel@tonic-gate 
185696c4a178SChris Horne 	if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, pdevi,
185796c4a178SChris Horne 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
18587c478bd9Sstevel@tonic-gate 	    SS2_LUN0_TGT_LIST_PROP, &tgt_list, &nelements) ==
18597c478bd9Sstevel@tonic-gate 	    DDI_PROP_SUCCESS) {
18607c478bd9Sstevel@tonic-gate 
18617c478bd9Sstevel@tonic-gate 		if (add_tgt) {
18627c478bd9Sstevel@tonic-gate 			/*
18637c478bd9Sstevel@tonic-gate 			 * we found an existing property -- we might need
18647c478bd9Sstevel@tonic-gate 			 *	to add to it
18657c478bd9Sstevel@tonic-gate 			 */
18667c478bd9Sstevel@tonic-gate 			for (i = 0; i < nelements; i++) {
18677c478bd9Sstevel@tonic-gate 				if (tgt_list[i] == tgt) {
18687c478bd9Sstevel@tonic-gate 					/* target already in list */
18697c478bd9Sstevel@tonic-gate 					SCSI_PROBE_DEBUG1(2, "SCSA post-probe:"
18707c478bd9Sstevel@tonic-gate 					    " tgt %d already listed\n", tgt);
18717c478bd9Sstevel@tonic-gate 					ddi_prop_free(tgt_list);
18727c478bd9Sstevel@tonic-gate 					return;
18737c478bd9Sstevel@tonic-gate 				}
18747c478bd9Sstevel@tonic-gate 			}
18757c478bd9Sstevel@tonic-gate 
18767c478bd9Sstevel@tonic-gate 			/*
18777c478bd9Sstevel@tonic-gate 			 * need to append our target number to end of list
18787c478bd9Sstevel@tonic-gate 			 *	(no need sorting list, as it's so short)
18797c478bd9Sstevel@tonic-gate 			 */
18807c478bd9Sstevel@tonic-gate 
18817c478bd9Sstevel@tonic-gate 			/*
18827c478bd9Sstevel@tonic-gate 			 * will this new entry fit ?? -- it should, since
18837c478bd9Sstevel@tonic-gate 			 *	the array is 16-wide and only keep track of
18847c478bd9Sstevel@tonic-gate 			 *	16 targets, but check just in case
18857c478bd9Sstevel@tonic-gate 			 */
18867c478bd9Sstevel@tonic-gate 			new_nelements = nelements + 1;
18877c478bd9Sstevel@tonic-gate 			if (new_nelements >= NTARGETS_WIDE) {
18887c478bd9Sstevel@tonic-gate 				SCSI_PROBE_DEBUG0(1, "SCSA post-probe: "
18897c478bd9Sstevel@tonic-gate 				    "internal error: no room "
18907c478bd9Sstevel@tonic-gate 				    "for more targets?\n");
18917c478bd9Sstevel@tonic-gate 				ddi_prop_free(tgt_list);
18927c478bd9Sstevel@tonic-gate 				return;
18937c478bd9Sstevel@tonic-gate 			}
18947c478bd9Sstevel@tonic-gate 
18957c478bd9Sstevel@tonic-gate 			/* copy existing list then add our tgt number to end */
18967c478bd9Sstevel@tonic-gate 			bcopy((void *)tgt_list, (void *)new_tgt_list,
18977c478bd9Sstevel@tonic-gate 			    sizeof (uchar_t) * nelements);
18987c478bd9Sstevel@tonic-gate 			new_tgt_list[new_nelements - 1] = (uchar_t)tgt;
18997c478bd9Sstevel@tonic-gate 		} else {
19007c478bd9Sstevel@tonic-gate 			/*
19017c478bd9Sstevel@tonic-gate 			 * we need to remove our target number from the list,
19027c478bd9Sstevel@tonic-gate 			 *	so copy all of the other target numbers,
19037c478bd9Sstevel@tonic-gate 			 *	skipping ours
19047c478bd9Sstevel@tonic-gate 			 */
19057c478bd9Sstevel@tonic-gate 			int	tgt_removed = 0;
19067c478bd9Sstevel@tonic-gate 
19077c478bd9Sstevel@tonic-gate 			new_nelements = 0;
19087c478bd9Sstevel@tonic-gate 			for (i = 0; i < nelements; i++) {
19097c478bd9Sstevel@tonic-gate 				if (tgt_list[i] != tgt) {
19107c478bd9Sstevel@tonic-gate 					new_tgt_list[new_nelements++] =
19117c478bd9Sstevel@tonic-gate 					    tgt_list[i];
19127c478bd9Sstevel@tonic-gate 				} else {
19137c478bd9Sstevel@tonic-gate 					/* skip this target */
19147c478bd9Sstevel@tonic-gate 					tgt_removed++;
19157c478bd9Sstevel@tonic-gate 				}
19167c478bd9Sstevel@tonic-gate 			}
19177c478bd9Sstevel@tonic-gate 
19187c478bd9Sstevel@tonic-gate 			if (!tgt_removed) {
19197c478bd9Sstevel@tonic-gate 				SCSI_PROBE_DEBUG1(2, "SCSA post-probe:"
19207c478bd9Sstevel@tonic-gate 				    " no need to remove tgt %d\n", tgt);
19217c478bd9Sstevel@tonic-gate 				ddi_prop_free(tgt_list);
19227c478bd9Sstevel@tonic-gate 				return;
19237c478bd9Sstevel@tonic-gate 			}
19247c478bd9Sstevel@tonic-gate 		}
19257c478bd9Sstevel@tonic-gate 
19267c478bd9Sstevel@tonic-gate 		update_result = ddi_prop_update_byte_array(DDI_DEV_T_NONE,
19277c478bd9Sstevel@tonic-gate 		    pdevi, SS2_LUN0_TGT_LIST_PROP, new_tgt_list,
19287c478bd9Sstevel@tonic-gate 		    new_nelements);
19297c478bd9Sstevel@tonic-gate 
19307c478bd9Sstevel@tonic-gate 		ddi_prop_free(tgt_list);
19317c478bd9Sstevel@tonic-gate 	} else {
19327c478bd9Sstevel@tonic-gate 		/*
19337c478bd9Sstevel@tonic-gate 		 * no property yet
19347c478bd9Sstevel@tonic-gate 		 */
19357c478bd9Sstevel@tonic-gate 		if (add_tgt) {
19367c478bd9Sstevel@tonic-gate 			/*
19377c478bd9Sstevel@tonic-gate 			 * create a property with just our tgt
19387c478bd9Sstevel@tonic-gate 			 */
19397c478bd9Sstevel@tonic-gate 			new_tgt_list[0] = (uchar_t)tgt;
19407c478bd9Sstevel@tonic-gate 			new_nelements = 1;	/* just one element */
19417c478bd9Sstevel@tonic-gate 
19427c478bd9Sstevel@tonic-gate 			update_result = ddi_prop_update_byte_array(
19437c478bd9Sstevel@tonic-gate 			    DDI_DEV_T_NONE, pdevi, SS2_LUN0_TGT_LIST_PROP,
19447c478bd9Sstevel@tonic-gate 			    new_tgt_list, new_nelements);
19457c478bd9Sstevel@tonic-gate 		} else {
19467c478bd9Sstevel@tonic-gate 			/*
19477c478bd9Sstevel@tonic-gate 			 * no list so no need to remove tgt from that list
19487c478bd9Sstevel@tonic-gate 			 */
19497c478bd9Sstevel@tonic-gate 			return;
19507c478bd9Sstevel@tonic-gate 		}
19517c478bd9Sstevel@tonic-gate 	}
19527c478bd9Sstevel@tonic-gate 
19537c478bd9Sstevel@tonic-gate #ifdef	DEBUG
19547c478bd9Sstevel@tonic-gate 	/*
19557c478bd9Sstevel@tonic-gate 	 * if we get here we have tried to add/update properties
19567c478bd9Sstevel@tonic-gate 	 */
19577c478bd9Sstevel@tonic-gate 	if (update_result != DDI_PROP_SUCCESS) {
19587c478bd9Sstevel@tonic-gate 		SCSI_PROBE_DEBUG2(1, "SCSA post-probe: can't update parent "
19597c478bd9Sstevel@tonic-gate 		    "property with tgt=%d (%d)\n", tgt, update_result);
19607c478bd9Sstevel@tonic-gate 	} else {
19617c478bd9Sstevel@tonic-gate 		if (add_tgt) {
19627c478bd9Sstevel@tonic-gate 			SCSI_PROBE_DEBUG3(2,
19637c478bd9Sstevel@tonic-gate 			    "SCSA post-probe: added tgt=%d to parent "
19647c478bd9Sstevel@tonic-gate 			    "prop=\"%s\" (now %d entries)\n",
19657c478bd9Sstevel@tonic-gate 			    tgt, SS2_LUN0_TGT_LIST_PROP, new_nelements);
19667c478bd9Sstevel@tonic-gate 		} else {
19677c478bd9Sstevel@tonic-gate 			SCSI_PROBE_DEBUG3(2,
19687c478bd9Sstevel@tonic-gate 			    "SCSA post-probe: removed tgt=%d from parent "
19697c478bd9Sstevel@tonic-gate 			    "prop=\"%s\" (now %d entries)\n",
19707c478bd9Sstevel@tonic-gate 			    tgt, SS2_LUN0_TGT_LIST_PROP, new_nelements);
19717c478bd9Sstevel@tonic-gate 		}
19727c478bd9Sstevel@tonic-gate 	}
19737c478bd9Sstevel@tonic-gate #endif
19747c478bd9Sstevel@tonic-gate }
19754c06356bSdh 
19764c06356bSdh 
19774c06356bSdh /* XXX BEGIN: find a better place for this: inquiry.h? */
19784c06356bSdh /*
19794c06356bSdh  * Definitions used by device id registration routines
19804c06356bSdh  */
19814c06356bSdh #define	VPD_HEAD_OFFSET		3	/* size of head for vpd page */
19824c06356bSdh #define	VPD_PAGE_LENGTH		3	/* offset for pge length data */
19834c06356bSdh #define	VPD_MODE_PAGE		1	/* offset into vpd pg for "page code" */
19844c06356bSdh 
19854c06356bSdh /* size for devid inquiries */
19864c06356bSdh #define	MAX_INQUIRY_SIZE	0xF0
19874c06356bSdh #define	MAX_INQUIRY_SIZE_EVPD	0xFF	/* XXX why is this longer */
19884c06356bSdh /* XXX END: find a better place for these */
19894c06356bSdh 
19904c06356bSdh 
19914c06356bSdh /*
19924c06356bSdh  * Decorate devinfo node with identity properties using information obtained
19934c06356bSdh  * from device. These properties are used by device enumeration code to derive
19944c06356bSdh  * the devid, and guid for the device. These properties are also used to
19954c06356bSdh  * determine if a device should be enumerated under the physical HBA (PHCI) or
19964c06356bSdh  * the virtual HBA (VHCI, for mpxio support).
19974c06356bSdh  *
19984c06356bSdh  * Return zero on success. If commands that should succeed fail or allocations
19994c06356bSdh  * fail then return failure (non-zero). It is possible for this function to
20004c06356bSdh  * return success and not have decorated the node with any additional identity
20014c06356bSdh  * information if the device correctly responds indicating that they are not
20024c06356bSdh  * supported.  When failure occurs the caller should consider not making the
20034c06356bSdh  * device accessible.
20044c06356bSdh  */
20054c06356bSdh int
scsi_device_identity(struct scsi_device * sd,int (* callback)())20064c06356bSdh scsi_device_identity(struct scsi_device *sd, int (*callback)())
20074c06356bSdh {
20084c06356bSdh 	dev_info_t	*devi		= sd->sd_dev;
20094c06356bSdh 	uchar_t		*inq80		= NULL;
20104c06356bSdh 	uchar_t		*inq83		= NULL;
20114c06356bSdh 	int		rval;
20124c06356bSdh 	size_t		len;
20134c06356bSdh 	int		pg80, pg83;
20144c06356bSdh 
20154c06356bSdh 	/* find out what pages are supported by device */
20164c06356bSdh 	if (check_vpd_page_support8083(sd, callback, &pg80, &pg83) == -1)
20174c06356bSdh 		return (-1);
20184c06356bSdh 
20194c06356bSdh 	/* if available, collect page 80 data and add as property */
20204c06356bSdh 	if (pg80) {
20214c06356bSdh 		inq80 = kmem_zalloc(MAX_INQUIRY_SIZE,
20224c06356bSdh 		    ((callback == SLEEP_FUNC) ? KM_SLEEP : KM_NOSLEEP));
20234c06356bSdh 		if (inq80 == NULL) {
20244c06356bSdh 			rval = -1;
20254c06356bSdh 			goto out;
20264c06356bSdh 		}
20274c06356bSdh 
20284c06356bSdh 		rval = send_scsi_INQUIRY(sd, callback, inq80,
2029392e836bSGavin Maltby 		    MAX_INQUIRY_SIZE, 0x01, 0x80, &len, STC_IDENTITY_PG80);
20304c06356bSdh 		if (rval)
20314c06356bSdh 			goto out;		/* should have worked */
20324c06356bSdh 
20334c06356bSdh 		if (len && (ndi_prop_update_byte_array(DDI_DEV_T_NONE, devi,
20344c06356bSdh 		    "inquiry-page-80", inq80, len) != DDI_PROP_SUCCESS)) {
20354c06356bSdh 			cmn_err(CE_WARN, "scsi_device_identity: "
20364c06356bSdh 			    "failed to add page80 prop");
20374c06356bSdh 			rval = -1;
20384c06356bSdh 			goto out;
20394c06356bSdh 		}
20404c06356bSdh 	}
20414c06356bSdh 
20424c06356bSdh 	/* if available, collect page 83 data and add as property */
20434c06356bSdh 	if (pg83) {
20444c06356bSdh 		inq83 = kmem_zalloc(MAX_INQUIRY_SIZE,
20454c06356bSdh 		    ((callback == SLEEP_FUNC) ? KM_SLEEP : KM_NOSLEEP));
20464c06356bSdh 		if (inq83 == NULL) {
20474c06356bSdh 			rval = -1;
20484c06356bSdh 			goto out;
20494c06356bSdh 		}
20504c06356bSdh 
20514c06356bSdh 		rval = send_scsi_INQUIRY(sd, callback, inq83,
2052392e836bSGavin Maltby 		    MAX_INQUIRY_SIZE, 0x01, 0x83, &len, STC_IDENTITY_PG83);
20534c06356bSdh 		if (rval)
20544c06356bSdh 			goto out;		/* should have worked */
20554c06356bSdh 
20564c06356bSdh 		if (len && (ndi_prop_update_byte_array(DDI_DEV_T_NONE, devi,
20574c06356bSdh 		    "inquiry-page-83", inq83, len) != DDI_PROP_SUCCESS)) {
20584c06356bSdh 			cmn_err(CE_WARN, "scsi_device_identity: "
20594c06356bSdh 			    "failed to add page83 prop");
20604c06356bSdh 			rval = -1;
20614c06356bSdh 			goto out;
20624c06356bSdh 		}
20634c06356bSdh 	}
20644c06356bSdh 
20654c06356bSdh 	/* Commands worked, identity information that exists has been added. */
20664c06356bSdh 	rval = 0;
20674c06356bSdh 
20684c06356bSdh 	/* clean up resources */
20694c06356bSdh out:	if (inq80 != NULL)
20704c06356bSdh 		kmem_free(inq80, MAX_INQUIRY_SIZE);
20714c06356bSdh 	if (inq83 != NULL)
20724c06356bSdh 		kmem_free(inq83, MAX_INQUIRY_SIZE);
20734c06356bSdh 
20744c06356bSdh 	return (rval);
20754c06356bSdh }
20764c06356bSdh 
20774c06356bSdh /*
20784c06356bSdh  * Send an INQUIRY command with the EVPD bit set and a page code of 0x00 to
20794c06356bSdh  * the device, returning zero on success. Returned INQUIRY data is used to
20804c06356bSdh  * determine which vital product pages are supported. The device idenity
20814c06356bSdh  * information we are looking for is in pages 0x83 and/or 0x80. If the device
20824c06356bSdh  * fails the EVPD inquiry then no pages are supported but the call succeeds.
20834c06356bSdh  * Return -1 (failure) if there were memory allocation failures or if a
20844c06356bSdh  * command faild that should have worked.
20854c06356bSdh  */
20864c06356bSdh static int
check_vpd_page_support8083(struct scsi_device * sd,int (* callback)(),int * ppg80,int * ppg83)20874c06356bSdh check_vpd_page_support8083(struct scsi_device *sd, int (*callback)(),
20884c06356bSdh 	int *ppg80, int *ppg83)
20894c06356bSdh {
20904c06356bSdh 	uchar_t *page_list;
20914c06356bSdh 	int	counter;
20924c06356bSdh 	int	rval;
20934c06356bSdh 
20944c06356bSdh 	/* pages are not supported */
20954c06356bSdh 	*ppg80 = 0;
20964c06356bSdh 	*ppg83 = 0;
20974c06356bSdh 
20984c06356bSdh 	/*
20994c06356bSdh 	 * We'll set the page length to the maximum to save figuring it out
21004c06356bSdh 	 * with an additional call.
21014c06356bSdh 	 */
21024c06356bSdh 	page_list =  kmem_zalloc(MAX_INQUIRY_SIZE_EVPD,
21034c06356bSdh 	    ((callback == SLEEP_FUNC) ? KM_SLEEP : KM_NOSLEEP));
21044c06356bSdh 	if (page_list == NULL)
21054c06356bSdh 		return (-1);		/* memory allocation problem */
21064c06356bSdh 
21074c06356bSdh 	/* issue page 0 (Supported VPD Pages) INQUIRY with evpd set */
21084c06356bSdh 	rval = send_scsi_INQUIRY(sd, callback,
2109392e836bSGavin Maltby 	    page_list, MAX_INQUIRY_SIZE_EVPD, 1, 0, NULL, STC_VPD_CHECK);
21104c06356bSdh 
21114c06356bSdh 	/*
21124c06356bSdh 	 * Now we must validate that the device accepted the command (some
21134c06356bSdh 	 * devices do not support it) and if the idenity pages we are
21144c06356bSdh 	 * interested in are supported.
21154c06356bSdh 	 */
21164c06356bSdh 	if ((rval == 0) &&
21174c06356bSdh 	    (page_list[VPD_MODE_PAGE] == 0x00)) {
21184c06356bSdh 		/* Loop to find one of the 2 pages we need */
21194c06356bSdh 		counter = 4;  /* Supported pages start at byte 4, with 0x00 */
21204c06356bSdh 
21214c06356bSdh 		/*
21224c06356bSdh 		 * Pages are returned in ascending order, and 0x83 is the
21234c06356bSdh 		 * last page we are hoping to find.
21244c06356bSdh 		 */
21254c06356bSdh 		while ((page_list[counter] <= 0x83) &&
21264c06356bSdh 		    (counter <= (page_list[VPD_PAGE_LENGTH] +
21274c06356bSdh 		    VPD_HEAD_OFFSET))) {
21284c06356bSdh 			/*
21294c06356bSdh 			 * Add 3 because page_list[3] is the number of
21304c06356bSdh 			 * pages minus 3
21314c06356bSdh 			 */
21324c06356bSdh 
21334c06356bSdh 			switch (page_list[counter]) {
21344c06356bSdh 			case 0x80:
21354c06356bSdh 				*ppg80 = 1;
21364c06356bSdh 				break;
21374c06356bSdh 			case 0x83:
21384c06356bSdh 				*ppg83 = 1;
21394c06356bSdh 				break;
21404c06356bSdh 			}
21414c06356bSdh 			counter++;
21424c06356bSdh 		}
21434c06356bSdh 	}
21444c06356bSdh 
21454c06356bSdh 	kmem_free(page_list, MAX_INQUIRY_SIZE_EVPD);
21464c06356bSdh 	return (0);
21474c06356bSdh }
21484c06356bSdh 
21494c06356bSdh /*
21504c06356bSdh  * Send INQUIRY command with specified EVPD and page code.  Return
21514c06356bSdh  * zero on success.  On success, the amount of data transferred
21524c06356bSdh  * is returned in *lenp.
21534c06356bSdh  */
21544c06356bSdh 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)21554c06356bSdh send_scsi_INQUIRY(struct scsi_device *sd, int (*callback)(),
21564c06356bSdh     uchar_t *bufaddr, size_t buflen,
2157392e836bSGavin Maltby     uchar_t evpd, uchar_t page_code, size_t *lenp,
2158392e836bSGavin Maltby     enum scsi_test_ctxt ctxt)
21594c06356bSdh {
21604c06356bSdh 	int		(*cb_flag)();
21614c06356bSdh 	struct buf	*inq_bp;
21624c06356bSdh 	struct scsi_pkt *inq_pkt = NULL;
21634c06356bSdh 	int		rval = -1;
21644c06356bSdh 
21654c06356bSdh 	if (lenp)
21664c06356bSdh 		*lenp = 0;
21674c06356bSdh 	if (callback != SLEEP_FUNC && callback != NULL_FUNC)
21684c06356bSdh 		cb_flag = NULL_FUNC;
21694c06356bSdh 	else
21704c06356bSdh 		cb_flag = callback;
21714c06356bSdh 	inq_bp = scsi_alloc_consistent_buf(ROUTE,
21724c06356bSdh 	    (struct buf *)NULL, buflen, B_READ, cb_flag, NULL);
21734c06356bSdh 	if (inq_bp == NULL)
21744c06356bSdh 		goto out;		/* memory allocation problem */
21754c06356bSdh 
21764c06356bSdh 	inq_pkt = scsi_init_pkt(ROUTE, (struct scsi_pkt *)NULL,
21774c06356bSdh 	    inq_bp, CDB_GROUP0, sizeof (struct scsi_arq_status),
21784c06356bSdh 	    0, PKT_CONSISTENT, callback, NULL);
21794c06356bSdh 	if (inq_pkt == NULL)
21804c06356bSdh 		goto out;		/* memory allocation problem */
21814c06356bSdh 
21824c06356bSdh 	ASSERT(inq_bp->b_error == 0);
21834c06356bSdh 
21844c06356bSdh 	/* form INQUIRY cdb with specified EVPD and page code */
21854c06356bSdh 	(void) scsi_setup_cdb((union scsi_cdb *)inq_pkt->pkt_cdbp,
21864c06356bSdh 	    SCMD_INQUIRY, 0, buflen, 0);
21874c06356bSdh 	inq_pkt->pkt_cdbp[1] = evpd;
21884c06356bSdh 	inq_pkt->pkt_cdbp[2] = page_code;
21894c06356bSdh 
21904c06356bSdh 	inq_pkt->pkt_time = SCSI_POLL_TIMEOUT;	/* in seconds */
21914c06356bSdh 	inq_pkt->pkt_flags = FLAG_NOINTR|FLAG_NOPARITY;
21924c06356bSdh 
21934c06356bSdh 	/*
21944c06356bSdh 	 * Issue inquiry command thru scsi_test
21954c06356bSdh 	 *
21964c06356bSdh 	 * NOTE: This is important data about device identity, not sure why
21974c06356bSdh 	 * NOPARITY is used. Also seems like we should check pkt_stat for
21984c06356bSdh 	 * STATE_XFERRED_DATA.
21994c06356bSdh 	 */
2200392e836bSGavin Maltby 	if (scsi_test(inq_pkt, ctxt) == SCSI_TEST_CMPLT_GOOD) {
22014c06356bSdh 		ASSERT(inq_pkt->pkt_resid >= 0);
22024c06356bSdh 		ASSERT(inq_pkt->pkt_resid <= buflen);
22034c06356bSdh 
22044c06356bSdh 		bcopy(inq_bp->b_un.b_addr,
22054c06356bSdh 		    bufaddr, buflen - inq_pkt->pkt_resid);
22064c06356bSdh 		if (lenp)
22074c06356bSdh 			*lenp = (buflen - inq_pkt->pkt_resid);
22084c06356bSdh 		rval = 0;
22094c06356bSdh 	}
22104c06356bSdh 
2211392e836bSGavin Maltby 	/*
2212392e836bSGavin Maltby 	 * XXX We should retry on target busy
2213392e836bSGavin Maltby 	 */
2214392e836bSGavin Maltby 
22154c06356bSdh out:	if (inq_pkt)
22164c06356bSdh 		scsi_destroy_pkt(inq_pkt);
22174c06356bSdh 	if (inq_bp)
22184c06356bSdh 		scsi_free_consistent_buf(inq_bp);
22194c06356bSdh 	return (rval);
22204c06356bSdh }
2221