xref: /illumos-gate/usr/src/uts/common/io/scsi/conf/scsi_confsubr.c (revision b31b5de1357c915fe7dab4d9646d9d84f9fe69bc)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * Utility SCSI configuration routines
28  */
29 /*
30  * Many routines in this file have built in parallel bus assumption
31  * which might need to change as other interconnect evolve.
32  */
33 
34 #include <sys/scsi/scsi.h>
35 #include <sys/modctl.h>
36 #include <sys/bitmap.h>
37 
38 /*
39  * macro for filling in lun value for scsi-1 support
40  */
41 
42 #define	FILL_SCSI1_LUN(devp, pkt) \
43 	if ((devp->sd_address.a_lun > 0) && \
44 	    (devp->sd_inq->inq_ansi == 0x1)) { \
45 		((union scsi_cdb *)(pkt)->pkt_cdbp)->scc_lun = \
46 		    devp->sd_address.a_lun; \
47 	}
48 
49 extern struct mod_ops mod_miscops;
50 
51 static struct modlmisc modlmisc = {
52 	&mod_miscops,	/* Type of module */
53 	"SCSI Bus Utility Routines"
54 };
55 
56 static struct modlinkage modlinkage = {
57 	MODREV_1, (void *)&modlmisc, NULL
58 };
59 
60 static void create_inquiry_props(struct scsi_device *);
61 static int get_inquiry_prop_len(char *, size_t);
62 
63 static int scsi_check_ss2_LUN_limit(struct scsi_device *);
64 static void scsi_establish_LUN_limit(struct scsi_device *);
65 static void scsi_update_parent_ss2_prop(dev_info_t *, int, int);
66 
67 /*
68  * this int-array HBA-node property keeps track of strictly SCSI-2
69  * target IDs
70  */
71 #define	SS2_LUN0_TGT_LIST_PROP	"ss2-targets"
72 
73 /*
74  * for keeping track of nodes for which we do *NOT* want to probe above LUN 7
75  * (i.e. strict SCSI-2 targets)
76  *
77  * note that we could also keep track of dtype (SCSI device type) and
78  * ANSI (SCSI standard conformance level), but all currently-known cases of
79  * this problem are on SCSI-2 PROCESSOR device types
80  */
81 typedef struct ss2_lun0_info {
82 	const char	*sli_vid;	/* SCSI inquiry VID */
83 	const char	*sli_pid;	/* SCSI inquiry PID */
84 	const char	*sli_rev;	/* SCSI inquiry REV */
85 } ss2_lun0_info_t;
86 
87 /*
88  * these two workarounds are for the SCSI-2 GEM2* chips used in the
89  * D1000 and D240
90  */
91 #define	SES_D1000_VID		"SYMBIOS"
92 #define	SES_D1000_PID		"D1000"		/* the D1000 */
93 #define	SES_D1000_REV		"2"
94 
95 #define	SES_D240_VID		"SUN"
96 #define	SES_D240_PID		"D240"		/* the D240 */
97 #define	SES_D240_REV		"2"
98 
99 /*
100  * a static list of targets where we do *not* want to probe above LUN 7
101  */
102 static const ss2_lun0_info_t	scsi_probe_strict_s2_list[] = {
103 	{SES_D1000_VID, SES_D1000_PID, SES_D1000_REV},
104 	{SES_D240_VID, SES_D240_PID, SES_D240_REV},
105 };
106 
107 static const int		scsi_probe_strict_s2_size =
108 	sizeof (scsi_probe_strict_s2_list) / sizeof (struct ss2_lun0_info);
109 
110 
111 #ifdef	DEBUG
112 
113 int	scsi_probe_debug = 0;
114 
115 #define	SCSI_PROBE_DEBUG0(l, s)		\
116 		if (scsi_probe_debug >= (l)) printf(s)
117 #define	SCSI_PROBE_DEBUG1(l, s, a1)	\
118 		if (scsi_probe_debug >= (l)) printf(s, a1)
119 #define	SCSI_PROBE_DEBUG2(l, s, a1, a2)	\
120 		if (scsi_probe_debug >= (l)) printf(s, a1, a2)
121 #define	SCSI_PROBE_DEBUG3(l, s, a1, a2, a3)	\
122 		if (scsi_probe_debug >= (l)) printf(s, a1, a2, a3)
123 
124 #else	/* DEBUG */
125 
126 #define	SCSI_PROBE_DEBUG0(l, s)
127 #define	SCSI_PROBE_DEBUG1(l, s, a1)
128 #define	SCSI_PROBE_DEBUG2(l, s, a1, a2)
129 #define	SCSI_PROBE_DEBUG3(l, s, a1, a2, a3)
130 
131 #endif	/* DEBUG */
132 
133 int	scsi_test_busy_timeout = SCSI_POLL_TIMEOUT;	/* in seconds */
134 int	scsi_test_busy_delay = 10000;			/* 10msec in usec */
135 
136 /*
137  * architecture dependent allocation restrictions. For x86, we'll set
138  * dma_attr_addr_hi to scsi_max_phys_addr and dma_attr_sgllen to
139  * scsi_sgl_size during _init().
140  */
141 #if defined(__sparc)
142 ddi_dma_attr_t scsi_alloc_attr = {
143 	DMA_ATTR_V0,	/* version number */
144 	0x0,		/* lowest usable address */
145 	0xFFFFFFFFull,	/* high DMA address range */
146 	0xFFFFFFFFull,	/* DMA counter register */
147 	1,		/* DMA address alignment */
148 	1,		/* DMA burstsizes */
149 	1,		/* min effective DMA size */
150 	0xFFFFFFFFull,	/* max DMA xfer size */
151 	0xFFFFFFFFull,	/* segment boundary */
152 	1,		/* s/g list length */
153 	512,		/* granularity of device */
154 	0		/* DMA transfer flags */
155 };
156 #elif defined(__x86)
157 ddi_dma_attr_t scsi_alloc_attr = {
158 	DMA_ATTR_V0,	/* version number */
159 	0x0,		/* lowest usable address */
160 	0x0,		/* high DMA address range [set in _init()] */
161 	0xFFFFull,	/* DMA counter register */
162 	1,		/* DMA address alignment */
163 	1,		/* DMA burstsizes */
164 	1,		/* min effective DMA size */
165 	0xFFFFFFFFull,	/* max DMA xfer size */
166 	0xFFFFFFFFull,  /* segment boundary */
167 	0,		/* s/g list length */
168 	512,		/* granularity of device [set in _init()] */
169 	0		/* DMA transfer flags */
170 };
171 uint64_t scsi_max_phys_addr = 0xFFFFFFFFull;
172 int scsi_sgl_size = 0xFF;
173 #endif
174 
175 ulong_t	*scsi_pkt_bad_alloc_bitmap;
176 
177 int
178 _init()
179 {
180 	scsi_initialize_hba_interface();
181 	scsi_watch_init();
182 
183 #if defined(__x86)
184 	/* set the max physical address for iob allocs on x86 */
185 	scsi_alloc_attr.dma_attr_addr_hi = scsi_max_phys_addr;
186 
187 	/*
188 	 * set the sgllen for iob allocs on x86. If this is set less than
189 	 * the number of pages the buffer will take (taking into account
190 	 * alignment), it would force the allocator to try and allocate
191 	 * contiguous pages.
192 	 */
193 	scsi_alloc_attr.dma_attr_sgllen = scsi_sgl_size;
194 #endif
195 
196 	/* bitmap to limit scsi_pkt allocation violation messages */
197 	scsi_pkt_bad_alloc_bitmap = kmem_zalloc(BT_SIZEOFMAP(devcnt), KM_SLEEP);
198 
199 	return (mod_install(&modlinkage));
200 }
201 
202 /*
203  * there is no _fini() routine because this module is never unloaded
204  */
205 
206 int
207 _info(struct modinfo *modinfop)
208 {
209 	return (mod_info(&modlinkage, modinfop));
210 }
211 
212 #define	ROUTE	(&devp->sd_address)
213 
214 static int
215 scsi_slave_do_rqsense(struct scsi_device *devp, int (*callback)())
216 {
217 	struct scsi_pkt *rq_pkt = NULL;
218 	struct buf *rq_bp = NULL;
219 	int rval = SCSIPROBE_EXISTS;
220 
221 	/*
222 	 * prepare rqsense packet
223 	 */
224 	rq_bp = scsi_alloc_consistent_buf(ROUTE, (struct buf *)NULL,
225 	    (uint_t)SENSE_LENGTH, B_READ, callback, NULL);
226 	if (rq_bp == NULL) {
227 		rval = SCSIPROBE_NOMEM;
228 		goto out;
229 	}
230 
231 	rq_pkt = scsi_init_pkt(ROUTE, (struct scsi_pkt *)NULL,
232 	    rq_bp, CDB_GROUP0, 1, 0, PKT_CONSISTENT,
233 	    callback, NULL);
234 
235 	if (rq_pkt == NULL) {
236 		if (rq_bp->b_error == 0)
237 			rval = SCSIPROBE_NOMEM_CB;
238 		else
239 			rval = SCSIPROBE_NOMEM;
240 		goto out;
241 	}
242 	ASSERT(rq_bp->b_error == 0);
243 
244 	(void) scsi_setup_cdb((union scsi_cdb *)rq_pkt->
245 	    pkt_cdbp, SCMD_REQUEST_SENSE, 0, SENSE_LENGTH, 0);
246 	FILL_SCSI1_LUN(devp, rq_pkt);
247 	rq_pkt->pkt_flags = FLAG_NOINTR|FLAG_NOPARITY|FLAG_SENSING;
248 
249 	/*
250 	 * The controller type is as yet unknown, so we
251 	 * have to do a throwaway non-extended request sense,
252 	 * and hope that that clears the check condition
253 	 * for that unit until we can find out what kind
254 	 * of drive it is. A non-extended request sense
255 	 * is specified by stating that the sense block
256 	 * has 0 length, which is taken to mean that it
257 	 * is four bytes in length.
258 	 */
259 	if (scsi_poll(rq_pkt) < 0) {
260 		rval = SCSIPROBE_FAILURE;
261 	}
262 
263 out:
264 	if (rq_pkt) {
265 		scsi_destroy_pkt(rq_pkt);
266 	}
267 	if (rq_bp) {
268 		scsi_free_consistent_buf(rq_bp);
269 	}
270 
271 	return (rval);
272 }
273 
274 /*
275  *
276  * SCSI slave probe routine - provided as a service to target drivers
277  *
278  * Mostly attempts to allocate and fill devp inquiry data..
279  */
280 
281 int
282 scsi_slave(struct scsi_device *devp, int (*callback)())
283 {
284 	struct scsi_pkt	*pkt;
285 	int		rval = SCSIPROBE_EXISTS;
286 
287 	/*
288 	 * the first test unit ready will tell us whether a target
289 	 * responded and if there was one, it will clear the unit attention
290 	 * condition
291 	 */
292 	pkt = scsi_init_pkt(ROUTE, (struct scsi_pkt *)NULL, NULL,
293 	    CDB_GROUP0, sizeof (struct scsi_arq_status), 0, 0, callback, NULL);
294 
295 	if (pkt == NULL) {
296 		return (SCSIPROBE_NOMEM_CB);
297 	}
298 
299 	(void) scsi_setup_cdb((union scsi_cdb *)pkt->pkt_cdbp,
300 	    SCMD_TEST_UNIT_READY, 0, 0, 0);
301 	FILL_SCSI1_LUN(devp, pkt);
302 	pkt->pkt_flags = FLAG_NOINTR|FLAG_NOPARITY;
303 
304 	if (scsi_poll(pkt) < 0) {
305 		if (pkt->pkt_reason == CMD_INCOMPLETE)
306 			rval = SCSIPROBE_NORESP;
307 		else
308 			rval = SCSIPROBE_FAILURE;
309 
310 		if ((pkt->pkt_state & STATE_ARQ_DONE) == 0) {
311 			if (((struct scsi_status *)pkt->pkt_scbp)->sts_chk)
312 				/*
313 				 * scanner and processor devices can return a
314 				 * check condition here
315 				 */
316 				rval = scsi_slave_do_rqsense(devp, callback);
317 		}
318 
319 		if (rval != SCSIPROBE_EXISTS) {
320 			scsi_destroy_pkt(pkt);
321 			return (rval);
322 		}
323 	}
324 
325 	/*
326 	 * the second test unit ready, allows the host adapter to negotiate
327 	 * synchronous transfer period and offset
328 	 */
329 	if (scsi_poll(pkt) < 0) {
330 		if (pkt->pkt_reason == CMD_INCOMPLETE)
331 			rval = SCSIPROBE_NORESP;
332 		else
333 			rval = SCSIPROBE_FAILURE;
334 	}
335 
336 	/*
337 	 * do a rqsense if there was a check condition and ARQ was not done
338 	 */
339 	if ((pkt->pkt_state & STATE_ARQ_DONE) == 0) {
340 		if (((struct scsi_status *)pkt->pkt_scbp)->sts_chk) {
341 			rval = scsi_slave_do_rqsense(devp, callback);
342 		}
343 	}
344 
345 	/*
346 	 * call scsi_probe to do the inquiry
347 	 * XXX there is minor difference with the old scsi_slave implementation:
348 	 * busy conditions are not handled in scsi_probe.
349 	 */
350 	scsi_destroy_pkt(pkt);
351 	if (rval == SCSIPROBE_EXISTS) {
352 		return (scsi_probe(devp, callback));
353 	} else {
354 		return (rval);
355 	}
356 }
357 
358 /*
359  * Undo scsi_slave - older interface, but still supported
360  *
361  * NOTE: The 'sd_inq' inquiry data is now freed by scsi_hba/scsi_vhci code
362  * as part of free of scsi_device(9S).
363  */
364 /*ARGSUSED*/
365 void
366 scsi_unslave(struct scsi_device *devp)
367 {
368 }
369 
370 /*
371  * Undo scsi_probe
372  *
373  * NOTE: The 'sd_inq' inquiry data is now freed by scsi_hba/scsi_vhci code
374  * as part of free of scsi_device(9S).
375  */
376 /*ARGSUSED*/
377 void
378 scsi_unprobe(struct scsi_device *devp)
379 {
380 }
381 
382 /*
383  * This is like scsi_poll, but only does retry for TRAN_BUSY.
384  */
385 static int
386 scsi_test(struct scsi_pkt *pkt)
387 {
388 	int		rval = -1;
389 	int		wait_usec;
390 	int		rc;
391 	extern int	do_polled_io;
392 
393 	pkt->pkt_flags |= FLAG_NOINTR;
394 	pkt->pkt_time = SCSI_POLL_TIMEOUT;	/* in seconds */
395 
396 	if (scsi_ifgetcap(&pkt->pkt_address, "tagged-qing", 1) == 1) {
397 		pkt->pkt_flags |= FLAG_STAG;
398 	}
399 
400 	/*
401 	 * Each TRAN_BUSY response waits scsi_test_busy_delay usec up to a
402 	 * maximum of scsi_test_busy_timeout.
403 	 */
404 	for (wait_usec = 0; (wait_usec / 1000000) <= scsi_test_busy_timeout;
405 	    wait_usec += scsi_test_busy_delay) {
406 
407 		/* Initialize pkt status variables */
408 		*pkt->pkt_scbp = pkt->pkt_reason = pkt->pkt_state = 0;
409 
410 		rc = scsi_transport(pkt);
411 		if ((rc != TRAN_BUSY) || (scsi_test_busy_delay == 0) ||
412 		    (scsi_test_busy_timeout == 0))
413 			break;
414 
415 		/* transport busy, wait */
416 		if ((curthread->t_flag & T_INTR_THREAD) == 0 && !do_polled_io) {
417 			delay(drv_usectohz(scsi_test_busy_delay));
418 		} else {
419 			/* we busy wait during cpr_dump or interrupt threads */
420 			drv_usecwait(scsi_test_busy_delay);
421 		}
422 	}
423 
424 	if (rc != TRAN_ACCEPT) {
425 		goto exit;
426 	} else if (pkt->pkt_reason == CMD_INCOMPLETE && pkt->pkt_state == 0) {
427 		goto exit;
428 	} else if (pkt->pkt_reason != CMD_CMPLT) {
429 		goto exit;
430 	} else if (((*pkt->pkt_scbp) & STATUS_MASK) == STATUS_BUSY) {
431 		rval = 0;
432 	} else {
433 		rval = 0;
434 	}
435 
436 exit:
437 	return (rval);
438 }
439 
440 /*
441  * The implementation of scsi_probe now allows a particular
442  * HBA to intercept the call, for any post- or pre-processing
443  * it may need.  The default, if the HBA does not override it,
444  * is to call scsi_hba_probe(), which retains the old functionality
445  * intact.
446  */
447 int
448 scsi_probe(struct scsi_device *devp, int (*callback)())
449 {
450 	int ret;
451 	scsi_hba_tran_t		*tran = devp->sd_address.a_hba_tran;
452 
453 	if (scsi_check_ss2_LUN_limit(devp) != 0) {
454 		/*
455 		 * caller is trying to probe a strictly-SCSI-2 device
456 		 * with a LUN that is too large, so do not allow it
457 		 */
458 		return (SCSIPROBE_NORESP);	/* skip probing this one */
459 	}
460 
461 	if (tran->tran_tgt_probe != NULL) {
462 		ret = (*tran->tran_tgt_probe)(devp, callback);
463 	} else {
464 		ret = scsi_hba_probe(devp, callback);
465 	}
466 
467 	if (ret == SCSIPROBE_EXISTS) {
468 		create_inquiry_props(devp);
469 		/* is this a strictly-SCSI-2 node ?? */
470 		scsi_establish_LUN_limit(devp);
471 	}
472 
473 	return (ret);
474 }
475 
476 /*
477  * scsi_hba_probe does not do any test unit ready's which access the medium
478  * and could cause busy or not ready conditions.
479  * scsi_hba_probe does 2 inquiries and a rqsense to clear unit attention
480  * and to allow sync negotiation to take place
481  * finally, scsi_hba_probe does one more inquiry which should
482  * reliably tell us what kind of target we have.
483  * A scsi-2 compliant target should be able to	return inquiry with 250ms
484  * and we actually wait more than a second after reset.
485  */
486 int
487 scsi_hba_probe(struct scsi_device *devp, int (*callback)())
488 {
489 	struct scsi_pkt		*inq_pkt = NULL;
490 	struct scsi_pkt		*rq_pkt = NULL;
491 	int			rval = SCSIPROBE_NOMEM;
492 	struct buf		*inq_bp = NULL;
493 	struct buf		*rq_bp = NULL;
494 	int			(*cb_flag)();
495 	int			pass = 1;
496 
497 	if (devp->sd_inq == NULL) {
498 		devp->sd_inq = (struct scsi_inquiry *)
499 		    kmem_alloc(SUN_INQSIZE, ((callback == SLEEP_FUNC) ?
500 		    KM_SLEEP : KM_NOSLEEP));
501 		if (devp->sd_inq == NULL) {
502 			goto out;
503 		}
504 	}
505 
506 	if (callback != SLEEP_FUNC && callback != NULL_FUNC) {
507 		cb_flag = NULL_FUNC;
508 	} else {
509 		cb_flag = callback;
510 	}
511 	inq_bp = scsi_alloc_consistent_buf(ROUTE,
512 	    (struct buf *)NULL, SUN_INQSIZE, B_READ, cb_flag, NULL);
513 	if (inq_bp == NULL) {
514 		goto out;
515 	}
516 
517 	inq_pkt = scsi_init_pkt(ROUTE, (struct scsi_pkt *)NULL,
518 	    inq_bp, CDB_GROUP0, sizeof (struct scsi_arq_status),
519 	    0, PKT_CONSISTENT, callback, NULL);
520 	if (inq_pkt == NULL) {
521 		if (inq_bp->b_error == 0)
522 			rval = SCSIPROBE_NOMEM_CB;
523 		goto out;
524 	}
525 	ASSERT(inq_bp->b_error == 0);
526 
527 	(void) scsi_setup_cdb((union scsi_cdb *)inq_pkt->pkt_cdbp,
528 	    SCMD_INQUIRY, 0, SUN_INQSIZE, 0);
529 	inq_pkt->pkt_flags = FLAG_NOINTR|FLAG_NOPARITY;
530 
531 	/*
532 	 * the first inquiry will tell us whether a target
533 	 * responded
534 	 *
535 	 * The FILL_SCSI1_LUN below will find "ansi_ver != 1" on first pass
536 	 * because of bzero initilization. If this assumption turns out to be
537 	 * incorrect after we have real sd_inq data (for lun0) we will do a
538 	 * second pass during which FILL_SCSI1_LUN will place lun in CDB.
539 	 */
540 	bzero((caddr_t)devp->sd_inq, SUN_INQSIZE);
541 again:	FILL_SCSI1_LUN(devp, inq_pkt);
542 
543 	if (scsi_test(inq_pkt) < 0) {
544 		if (inq_pkt->pkt_reason == CMD_INCOMPLETE) {
545 			rval = SCSIPROBE_NORESP;
546 			goto out;
547 		} else {
548 			/*
549 			 * retry one more time
550 			 */
551 			if (scsi_test(inq_pkt) < 0) {
552 				rval = SCSIPROBE_FAILURE;
553 				goto out;
554 			}
555 		}
556 	}
557 
558 	/*
559 	 * if we are lucky, this inquiry succeeded
560 	 */
561 	if ((inq_pkt->pkt_reason == CMD_CMPLT) &&
562 	    (((*inq_pkt->pkt_scbp) & STATUS_MASK) == 0)) {
563 		goto done;
564 	}
565 
566 	/*
567 	 * the second inquiry, allows the host adapter to negotiate
568 	 * synchronous transfer period and offset
569 	 */
570 	if (scsi_test(inq_pkt) < 0) {
571 		if (inq_pkt->pkt_reason == CMD_INCOMPLETE)
572 			rval = SCSIPROBE_NORESP;
573 		else
574 			rval = SCSIPROBE_FAILURE;
575 		goto out;
576 	}
577 
578 	/*
579 	 * if target is still busy, give up now
580 	 */
581 	if (((struct scsi_status *)inq_pkt->pkt_scbp)->sts_busy) {
582 		rval = SCSIPROBE_BUSY;
583 		goto out;
584 	}
585 
586 	/*
587 	 * do a rqsense if there was a check condition and ARQ was not done
588 	 */
589 	if ((inq_pkt->pkt_state & STATE_ARQ_DONE) == 0) {
590 		if (((struct scsi_status *)inq_pkt->pkt_scbp)->sts_chk) {
591 
592 			/*
593 			 * prepare rqsense packet
594 			 * there is no real need for this because the
595 			 * check condition should have been cleared by now.
596 			 */
597 			rq_bp = scsi_alloc_consistent_buf(ROUTE,
598 			    (struct buf *)NULL,
599 			    (uint_t)SENSE_LENGTH, B_READ, cb_flag, NULL);
600 			if (rq_bp == NULL) {
601 				goto out;
602 			}
603 
604 			rq_pkt = scsi_init_pkt(ROUTE, (struct scsi_pkt *)NULL,
605 			    rq_bp, CDB_GROUP0, 1, 0, PKT_CONSISTENT, callback,
606 			    NULL);
607 
608 			if (rq_pkt == NULL) {
609 				if (rq_bp->b_error == 0)
610 					rval = SCSIPROBE_NOMEM_CB;
611 				goto out;
612 			}
613 			ASSERT(rq_bp->b_error == 0);
614 
615 			(void) scsi_setup_cdb((union scsi_cdb *)rq_pkt->
616 			    pkt_cdbp, SCMD_REQUEST_SENSE, 0, SENSE_LENGTH, 0);
617 			FILL_SCSI1_LUN(devp, rq_pkt);
618 			rq_pkt->pkt_flags = FLAG_NOINTR|FLAG_NOPARITY;
619 
620 			/*
621 			 * The FILL_SCSI1_LUN above will find "inq_ansi != 1"
622 			 * on first pass, see "again" comment above.
623 			 *
624 			 * The controller type is as yet unknown, so we
625 			 * have to do a throwaway non-extended request sense,
626 			 * and hope that that clears the check condition for
627 			 * that unit until we can find out what kind of drive
628 			 * it is. A non-extended request sense is specified
629 			 * by stating that the sense block has 0 length,
630 			 * which is taken to mean that it is four bytes in
631 			 * length.
632 			 */
633 			if (scsi_test(rq_pkt) < 0) {
634 				rval = SCSIPROBE_FAILURE;
635 				goto out;
636 			}
637 		}
638 	}
639 
640 	/*
641 	 * At this point, we are guaranteed that something responded
642 	 * to this scsi bus target id. We don't know yet what
643 	 * kind of device it is, or even whether there really is
644 	 * a logical unit attached (as some SCSI target controllers
645 	 * lie about a unit being ready, e.g., the Emulex MD21).
646 	 */
647 
648 	if (scsi_test(inq_pkt) < 0) {
649 		rval = SCSIPROBE_FAILURE;
650 		goto out;
651 	}
652 
653 	if (((struct scsi_status *)inq_pkt->pkt_scbp)->sts_busy) {
654 		rval = SCSIPROBE_BUSY;
655 		goto out;
656 	}
657 
658 	/*
659 	 * Okay we sent the INQUIRY command.
660 	 *
661 	 * If enough data was transferred, we count that the
662 	 * Inquiry command succeeded, else we have to assume
663 	 * that this is a non-CCS scsi target (or a nonexistent
664 	 * target/lun).
665 	 */
666 
667 	if (((struct scsi_status *)inq_pkt->pkt_scbp)->sts_chk) {
668 		/*
669 		 * try a request sense if we have a pkt, otherwise
670 		 * just retry the inquiry one more time
671 		 */
672 		if (rq_pkt) {
673 			(void) scsi_test(rq_pkt);
674 		}
675 
676 		/*
677 		 * retry inquiry
678 		 */
679 		if (scsi_test(inq_pkt) < 0) {
680 			rval = SCSIPROBE_FAILURE;
681 			goto out;
682 		}
683 		if (((struct scsi_status *)inq_pkt->pkt_scbp)->sts_chk) {
684 			rval = SCSIPROBE_FAILURE;
685 			goto out;
686 		}
687 	}
688 
689 done:
690 	/*
691 	 * If we got a parity error on receive of inquiry data,
692 	 * we're just plain out of luck because we told the host
693 	 * adapter to not watch for parity errors.
694 	 */
695 	if ((inq_pkt->pkt_state & STATE_XFERRED_DATA) == 0 ||
696 	    ((SUN_INQSIZE - inq_pkt->pkt_resid) < SUN_MIN_INQLEN)) {
697 		rval = SCSIPROBE_NONCCS;
698 	} else {
699 		ASSERT(inq_pkt->pkt_resid >= 0);
700 		bcopy((caddr_t)inq_bp->b_un.b_addr,
701 		    (caddr_t)devp->sd_inq, (SUN_INQSIZE - inq_pkt->pkt_resid));
702 		rval = SCSIPROBE_EXISTS;
703 	}
704 
705 out:
706 	/*
707 	 * If lun > 0 we need to figure out if this is a scsi-1 device where
708 	 * the "real" lun needs to be embedded into the cdb.
709 	 */
710 	if ((rval == SCSIPROBE_EXISTS) && (pass == 1) &&
711 	    (devp->sd_address.a_lun > 0) && (devp->sd_inq->inq_ansi == 0x1)) {
712 		pass++;
713 		if (devp->sd_address.a_lun <= 7)
714 			goto again;
715 
716 		/*
717 		 * invalid lun for scsi-1,
718 		 * return probe failure.
719 		 */
720 		rval = SCSIPROBE_FAILURE;
721 	}
722 
723 	if (rq_pkt) {
724 		scsi_destroy_pkt(rq_pkt);
725 	}
726 	if (inq_pkt) {
727 		scsi_destroy_pkt(inq_pkt);
728 	}
729 	if (rq_bp) {
730 		scsi_free_consistent_buf(rq_bp);
731 	}
732 	if (inq_bp) {
733 		scsi_free_consistent_buf(inq_bp);
734 	}
735 	return (rval);
736 }
737 
738 /*
739  * Convert from a scsi_device structure pointer to a scsi_hba_tran structure
740  * pointer. The correct way to do this is
741  *
742  *	#define	DEVP_TO_TRAN(devp)	((devp)->sd_address.a_hba_tran)
743  *
744  * however we have some consumers that place their own vector in a_hba_tran. To
745  * avoid problems, we implement this using the sd_tran_safe. See
746  * scsi_hba_initchild for more details.
747  */
748 #define	DEVP_TO_TRAN(devp)	((devp)->sd_tran_safe)
749 
750 /*
751  * Function to get human readable REPORTDEV addressing information from
752  * scsi address structure for SPI when tran_get_bus_addr is not implemented.
753  */
754 int
755 scsi_get_bus_addr(struct scsi_device *devp, char *ba, int len)
756 {
757 	struct scsi_address	*ap;
758 
759 	/* use tran_get_bus_addr interface if it is defined */
760 	if (DEVP_TO_TRAN(devp)->tran_get_bus_addr)
761 		return ((*DEVP_TO_TRAN(devp)->tran_get_bus_addr)
762 		    (devp, ba, len));
763 
764 	ap = &devp->sd_address;
765 	(void) snprintf(ba, len, "target %x lun %x", ap->a_target, ap->a_lun);
766 	return (1);
767 }
768 
769 /*
770  * scsi_set_name: using properties, return "unit-address" string.
771  *
772  * Function to get "unit-address" in "name@unit-address" /devices path
773  * 'name' form from the unit-address properties on a node.
774  *
775  * NOTE: a better name for this function would be scsi_get_unit_address.
776  */
777 int
778 scsi_get_name(struct scsi_device *devp, char *ua, int len)
779 {
780 	struct scsi_address	*ap;
781 
782 	/* use tran_get_name interface if it is defined */
783 	if (DEVP_TO_TRAN(devp)->tran_get_name)
784 		return ((*DEVP_TO_TRAN(devp)->tran_get_name)
785 		    (devp, ua, len));
786 
787 	ap = &devp->sd_address;
788 	(void) snprintf(ua, len, "%x,%x", ap->a_target, ap->a_lun);
789 	return (1);
790 }
791 
792 void
793 create_inquiry_props(struct scsi_device *devp)
794 {
795 	struct scsi_inquiry *inq = devp->sd_inq;
796 
797 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, devp->sd_dev,
798 	    INQUIRY_DEVICE_TYPE, (int)inq->inq_dtype);
799 
800 	/*
801 	 * Create the following properties:
802 	 *
803 	 * inquiry-vendor-id 	Vendor id (INQUIRY data bytes 8-15)
804 	 * inquiry-product-id 	Product id (INQUIRY data bytes 16-31)
805 	 * inquiry-revision-id 	Product Rev level (INQUIRY data bytes 32-35)
806 	 *
807 	 * Note we don't support creation of these properties for scsi-1
808 	 * devices (as the vid, pid and revision were not defined) and we
809 	 * don't create the property if they are of zero length when
810 	 * stripped of Nulls and spaces.
811 	 */
812 	if (inq->inq_ansi != 1) {
813 		if (ddi_prop_exists(DDI_DEV_T_NONE, devp->sd_dev,
814 		    DDI_PROP_TYPE_STRING, INQUIRY_VENDOR_ID) == 0)
815 			(void) scsi_hba_prop_update_inqstring(devp,
816 			    INQUIRY_VENDOR_ID,
817 			    inq->inq_vid, sizeof (inq->inq_vid));
818 
819 		if (ddi_prop_exists(DDI_DEV_T_NONE, devp->sd_dev,
820 		    DDI_PROP_TYPE_STRING, INQUIRY_PRODUCT_ID) == 0)
821 			(void) scsi_hba_prop_update_inqstring(devp,
822 			    INQUIRY_PRODUCT_ID,
823 			    inq->inq_pid, sizeof (inq->inq_pid));
824 
825 		if (ddi_prop_exists(DDI_DEV_T_NONE, devp->sd_dev,
826 		    DDI_PROP_TYPE_STRING, INQUIRY_REVISION_ID) == 0)
827 			(void) scsi_hba_prop_update_inqstring(devp,
828 			    INQUIRY_REVISION_ID,
829 			    inq->inq_revision, sizeof (inq->inq_revision));
830 	}
831 }
832 
833 /*
834  * Create 'inquiry' string properties.  An 'inquiry' string gets special
835  * treatment to trim trailing blanks (etc) and ensure null termination.
836  */
837 int
838 scsi_hba_prop_update_inqstring(struct scsi_device *devp,
839     char *name, char *data, size_t len)
840 {
841 	int	ilen;
842 	char	*data_string;
843 	int	rv;
844 
845 	ilen = get_inquiry_prop_len(data, len);
846 	ASSERT(ilen <= (int)len);
847 	if (ilen <= 0)
848 		return (DDI_PROP_INVAL_ARG);
849 
850 	/* ensure null termination */
851 	data_string = kmem_zalloc(ilen + 1, KM_SLEEP);
852 	bcopy(data, data_string, ilen);
853 	rv = ndi_prop_update_string(DDI_DEV_T_NONE,
854 	    devp->sd_dev, name, data_string);
855 	kmem_free(data_string, ilen + 1);
856 	return (rv);
857 }
858 
859 /*
860  * This routine returns the true length of the inquiry properties that are to
861  * be created by removing the padded spaces at the end of the inquiry data.
862  * This routine was designed for trimming spaces from the vid, pid and revision
863  * which are defined as being left aligned.  In addition, we return 0 length
864  * if the property is full of all 0's or spaces, indicating to the caller that
865  * the device was not ready to return the proper inquiry data as per note 65 in
866  * the scsi-2 spec.
867  */
868 static int
869 get_inquiry_prop_len(char *property, size_t length)
870 {
871 	int retval;
872 	int trailer;
873 	char *p;
874 
875 	retval = length;
876 
877 	/*
878 	 * The vid, pid and revision are left-aligned ascii fields within the
879 	 * inquiry data.  Here we trim the end of these fields by discounting
880 	 * length associated with trailing spaces or NULL bytes.  The remaining
881 	 * bytes shall be only graphics codes - 0x20 through 0x7e as per the
882 	 * scsi spec definition.  If we have all 0's or spaces, we return 0
883 	 * length.  For devices that store inquiry data on the device, they
884 	 * can return 0's or spaces in these fields until the data is avail-
885 	 * able from the device (See NOTE 65 in the scsi-2 specification
886 	 * around the inquiry command.)  We don't want to create a property in
887 	 * the case of a device not able to return valid data.
888 	 */
889 	trailer = 1;
890 	for (p = property + length - 1; p >= property; p--) {
891 		if (trailer) {
892 			if ((*p == ' ') || (*p == '\0')) {
893 				retval--;
894 				continue;
895 			}
896 			trailer = 0;
897 		}
898 
899 		/* each char must be within 0x20 - 0x7e */
900 		if (*p < 0x20 || *p > 0x7e) {
901 			retval = -1;
902 			break;
903 		}
904 
905 	}
906 
907 	return (retval);
908 }
909 
910 /*
911  * Interfaces associated with SCSI_HBA_ADDR_COMPLEX
912  * per-scsi_device HBA private data support.
913  */
914 struct scsi_device *
915 scsi_address_device(struct scsi_address *sa)
916 {
917 	ASSERT(sa->a_hba_tran->tran_hba_flags & SCSI_HBA_ADDR_COMPLEX);
918 	return (sa->a.a_sd);
919 }
920 
921 void
922 scsi_device_hba_private_set(struct scsi_device *sd, void *data)
923 {
924 	ASSERT(sd->sd_address.a_hba_tran->tran_hba_flags &
925 	    SCSI_HBA_ADDR_COMPLEX);
926 	sd->sd_hba_private = data;
927 }
928 
929 void *
930 scsi_device_hba_private_get(struct scsi_device *sd)
931 {
932 	ASSERT(sd->sd_address.a_hba_tran->tran_hba_flags &
933 	    SCSI_HBA_ADDR_COMPLEX);
934 	return (sd->sd_hba_private);
935 }
936 
937 /*
938  * This routine is called from the start of scsi_probe() if a tgt/LUN to be
939  * probed *may* be a request to probe a strictly SCSI-2 target (with respect
940  * to LUNs) -- and this probe may be for a LUN number greater than 7,
941  * which can cause a hardware hang
942  *
943  * return 0 if the probe can proceed,
944  * else return 1, meaning do *NOT* probe this target/LUN
945  */
946 static int
947 scsi_check_ss2_LUN_limit(struct scsi_device *devp)
948 {
949 	struct scsi_address	*ap = &(devp->sd_address);
950 	dev_info_t		*pdevi =
951 	    (dev_info_t *)DEVI(devp->sd_dev)->devi_parent;
952 	int			ret_val = 0;	/* default return value */
953 	uchar_t			*tgt_list;
954 	uint_t			tgt_nelements;
955 	int			i;
956 
957 
958 	/*
959 	 * check for what *might* be a problem probe, only we don't
960 	 * know yet what's really at the destination target/LUN
961 	 */
962 	if ((ap->a_target >= NTARGETS_WIDE) ||
963 	    (ap->a_lun < NLUNS_PER_TARGET)) {
964 		return (0);		/* okay to probe this target */
965 	}
966 
967 	/*
968 	 * this *might* be a problematic probe, so look to see
969 	 * if the inquiry data matches
970 	 */
971 	SCSI_PROBE_DEBUG2(1, "SCSA pre-probe: checking tgt.LUN=%d.%d\n",
972 	    ap->a_target, ap->a_lun);
973 	SCSI_PROBE_DEBUG1(2,
974 	    "SCSA pre-probe: scanning parent node name: %s ...\n",
975 	    ddi_node_name(pdevi));
976 
977 	/*
978 	 * look for a special property of our parent node that lists
979 	 * the targets under it for which we do *NOT* want to probe
980 	 * if LUN>7 -- if the property is found, look to see if our
981 	 * target ID is on that list
982 	 */
983 	if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY,
984 	    pdevi, DDI_PROP_DONTPASS, SS2_LUN0_TGT_LIST_PROP,
985 	    &tgt_list, &tgt_nelements) != DDI_PROP_SUCCESS) {
986 		/*
987 		 * no list, so it must be okay to probe this target.LUN
988 		 */
989 		SCSI_PROBE_DEBUG0(3,
990 		    "SCSA pre-probe: NO parent prop found\n");
991 	} else {
992 		for (i = 0; i < tgt_nelements; i++) {
993 			if (tgt_list[i] == ap->a_target) {
994 				/*
995 				 * we found a match, which means we do *NOT*
996 				 * want to probe the specified target.LUN
997 				 */
998 				ret_val = 1;
999 				break;
1000 			}
1001 		}
1002 		ddi_prop_free(tgt_list);
1003 #ifdef	DEBUG
1004 		if (ret_val == 1) {
1005 			SCSI_PROBE_DEBUG2(1,
1006 			    "SCSA pre-probe: marker node FOUND for "
1007 			    "tgt.LUN=%d.%d, so SKIPPING it\n",
1008 			    ap->a_target, ap->a_lun);
1009 		} else {
1010 			SCSI_PROBE_DEBUG0(2,
1011 			    "SCSA pre-probe: NO marker node found"
1012 			    " -- OK to probe\n");
1013 		}
1014 #endif
1015 	}
1016 	return (ret_val);
1017 }
1018 
1019 
1020 /*
1021  * this routine is called from near the end of scsi_probe(),
1022  * to see if the just-probed node is on our list of strictly-SCSI-2 nodes,
1023  * and if it is we mark our parent node with this information
1024  */
1025 static void
1026 scsi_establish_LUN_limit(struct scsi_device *devp)
1027 {
1028 	struct scsi_address	*ap = &(devp->sd_address);
1029 	struct scsi_inquiry	*inq = devp->sd_inq;
1030 	dev_info_t		*devi = devp->sd_dev;
1031 	char			*vid = NULL;
1032 	char			*pid = NULL;
1033 	char			*rev = NULL;
1034 	int			i;
1035 	const ss2_lun0_info_t	*p;
1036 	int			bad_target_found = 0;
1037 
1038 
1039 	/*
1040 	 * if this inquiry data shows that we have a strictly-SCSI-2 device
1041 	 * at LUN 0, then add it to our list of strictly-SCSI-2 devices,
1042 	 * so that we can avoid probes where LUN>7 on this device later
1043 	 */
1044 	if ((ap->a_lun != 0) ||
1045 	    (ap->a_target >= NTARGETS_WIDE) ||
1046 	    (inq->inq_dtype != DTYPE_PROCESSOR) ||
1047 	    (inq->inq_ansi != 2)) {
1048 		/*
1049 		 * this can't possibly be a node we want to look at, since
1050 		 * either LUN is greater than 0, target is greater than or
1051 		 * equal to 16, device type
1052 		 * is not processor, or SCSI level is not SCSI-2,
1053 		 * so don't bother checking for a strictly SCSI-2
1054 		 * (only 8 LUN) target
1055 		 */
1056 		return;				/* don't care */
1057 	}
1058 
1059 	SCSI_PROBE_DEBUG2(1, "SCSA post-probe: LUN limit on tgt.LUN=%d.%d, "
1060 	    "SCSI-2 PROCESSOR?\n", ap->a_target, ap->a_lun);
1061 
1062 	ASSERT(devi != NULL);
1063 
1064 	/*
1065 	 * we have a node that has been probed that is: LUN=0, target<16,
1066 	 * PROCESSOR-type SCSI target, and at the SCSI-2 level, so
1067 	 * check INQ properties to see if it's in our list of strictly
1068 	 * SCSI-2 targets
1069 	 *
1070 	 * first we have to get the VID/PID/REV INQUIRY properties for
1071 	 * comparison
1072 	 */
1073 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
1074 	    INQUIRY_VENDOR_ID, &vid) != DDI_PROP_SUCCESS) {
1075 		SCSI_PROBE_DEBUG1(2, "SCSA post-probe: prop \"%s\" missing\n",
1076 		    INQUIRY_VENDOR_ID);
1077 		goto dun;
1078 	}
1079 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
1080 	    INQUIRY_PRODUCT_ID, &pid) != DDI_PROP_SUCCESS) {
1081 		SCSI_PROBE_DEBUG1(2, "SCSA post-probe: prop \"%s\" missing\n",
1082 		    INQUIRY_PRODUCT_ID);
1083 		goto dun;
1084 	}
1085 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
1086 	    INQUIRY_REVISION_ID, &rev) != DDI_PROP_SUCCESS) {
1087 		SCSI_PROBE_DEBUG1(2, "SCSA post-probe: prop \"%s\" missing\n",
1088 		    INQUIRY_REVISION_ID);
1089 		goto dun;
1090 	}
1091 
1092 	SCSI_PROBE_DEBUG3(3, "SCSA post-probe: looking for vid/pid/rev = "
1093 	    "\"%s\"/\"%s\"/\"%s\"\n", vid, pid, rev);
1094 
1095 	/*
1096 	 * now that we have the INQUIRY properties from the device node,
1097 	 * compare them with our known offenders
1098 	 *
1099 	 * Note: comparison is *CASE* *SENSITIVE*
1100 	 */
1101 	for (i = 0; i < scsi_probe_strict_s2_size; i++) {
1102 		p = &scsi_probe_strict_s2_list[i];
1103 
1104 		if ((strcmp(p->sli_vid, vid) == 0) &&
1105 		    (strcmp(p->sli_pid, pid) == 0) &&
1106 		    (strcmp(p->sli_rev, rev) == 0)) {
1107 			/*
1108 			 * we found a match -- do NOT want to probe this one
1109 			 */
1110 			SCSI_PROBE_DEBUG3(1,
1111 			    "SCSA post-probe: recording strict SCSI-2 node "
1112 			    "vid/pid/rev = \"%s\"/\"%s\"/\"%s\"\n",
1113 			    vid, pid, rev);
1114 
1115 			/*
1116 			 * set/update private parent-node property,
1117 			 * so we can find out about this node later
1118 			 */
1119 			bad_target_found = 1;
1120 			break;
1121 		}
1122 	}
1123 
1124 	/*
1125 	 * either add remove target number from parent property
1126 	 */
1127 	scsi_update_parent_ss2_prop(devi, ap->a_target, bad_target_found);
1128 
1129 dun:
1130 	if (vid != NULL) {
1131 		ddi_prop_free(vid);
1132 	}
1133 	if (pid != NULL) {
1134 		ddi_prop_free(pid);
1135 	}
1136 	if (rev != NULL) {
1137 		ddi_prop_free(rev);
1138 	}
1139 }
1140 
1141 
1142 /*
1143  * update the parent node to add in the supplied tgt number to the target
1144  * list property already present (if any)
1145  *
1146  * since the target list can never be longer than 16, and each target
1147  * number is also small, we can save having to alloc memory by putting
1148  * a 16-byte array on the stack and using it for property memory
1149  *
1150  * if "add_tgt" is set then add the target to the parent's property, else
1151  * remove it (if present)
1152  */
1153 static void
1154 scsi_update_parent_ss2_prop(dev_info_t *devi, int tgt, int add_tgt)
1155 {
1156 	dev_info_t	*pdevi = (dev_info_t *)DEVI(devi)->devi_parent;
1157 	uchar_t		*tgt_list;
1158 	uint_t		nelements;
1159 	uint_t		new_nelements;
1160 	int		i;
1161 	int		update_result;
1162 	uchar_t		new_tgt_list[NTARGETS_WIDE];
1163 
1164 
1165 	ASSERT(pdevi != NULL);
1166 
1167 	SCSI_PROBE_DEBUG3(3,
1168 	    "SCSA post-probe: updating parent=%s property to %s tgt=%d\n",
1169 	    ddi_node_name(pdevi), add_tgt ? "add" : "remove", tgt);
1170 
1171 	if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, pdevi, DDI_PROP_DONTPASS,
1172 	    SS2_LUN0_TGT_LIST_PROP, &tgt_list, &nelements) ==
1173 	    DDI_PROP_SUCCESS) {
1174 
1175 		if (add_tgt) {
1176 			/*
1177 			 * we found an existing property -- we might need
1178 			 *	to add to it
1179 			 */
1180 			for (i = 0; i < nelements; i++) {
1181 				if (tgt_list[i] == tgt) {
1182 					/* target already in list */
1183 					SCSI_PROBE_DEBUG1(2, "SCSA post-probe:"
1184 					    " tgt %d already listed\n", tgt);
1185 					ddi_prop_free(tgt_list);
1186 					return;
1187 				}
1188 			}
1189 
1190 			/*
1191 			 * need to append our target number to end of list
1192 			 *	(no need sorting list, as it's so short)
1193 			 */
1194 
1195 			/*
1196 			 * will this new entry fit ?? -- it should, since
1197 			 *	the array is 16-wide and only keep track of
1198 			 *	16 targets, but check just in case
1199 			 */
1200 			new_nelements = nelements + 1;
1201 			if (new_nelements >= NTARGETS_WIDE) {
1202 				SCSI_PROBE_DEBUG0(1, "SCSA post-probe: "
1203 				    "internal error: no room "
1204 				    "for more targets?\n");
1205 				ddi_prop_free(tgt_list);
1206 				return;
1207 			}
1208 
1209 			/* copy existing list then add our tgt number to end */
1210 			bcopy((void *)tgt_list, (void *)new_tgt_list,
1211 			    sizeof (uchar_t) * nelements);
1212 			new_tgt_list[new_nelements - 1] = (uchar_t)tgt;
1213 		} else {
1214 			/*
1215 			 * we need to remove our target number from the list,
1216 			 *	so copy all of the other target numbers,
1217 			 *	skipping ours
1218 			 */
1219 			int	tgt_removed = 0;
1220 
1221 			new_nelements = 0;
1222 			for (i = 0; i < nelements; i++) {
1223 				if (tgt_list[i] != tgt) {
1224 					new_tgt_list[new_nelements++] =
1225 					    tgt_list[i];
1226 				} else {
1227 					/* skip this target */
1228 					tgt_removed++;
1229 				}
1230 			}
1231 
1232 			if (!tgt_removed) {
1233 				SCSI_PROBE_DEBUG1(2, "SCSA post-probe:"
1234 				    " no need to remove tgt %d\n", tgt);
1235 				ddi_prop_free(tgt_list);
1236 				return;
1237 			}
1238 		}
1239 
1240 		update_result = ddi_prop_update_byte_array(DDI_DEV_T_NONE,
1241 		    pdevi, SS2_LUN0_TGT_LIST_PROP, new_tgt_list,
1242 		    new_nelements);
1243 
1244 		ddi_prop_free(tgt_list);
1245 	} else {
1246 		/*
1247 		 * no property yet
1248 		 */
1249 		if (add_tgt) {
1250 			/*
1251 			 * create a property with just our tgt
1252 			 */
1253 			new_tgt_list[0] = (uchar_t)tgt;
1254 			new_nelements = 1;	/* just one element */
1255 
1256 			update_result = ddi_prop_update_byte_array(
1257 			    DDI_DEV_T_NONE, pdevi, SS2_LUN0_TGT_LIST_PROP,
1258 			    new_tgt_list, new_nelements);
1259 		} else {
1260 			/*
1261 			 * no list so no need to remove tgt from that list
1262 			 */
1263 			return;
1264 		}
1265 	}
1266 
1267 #ifdef	DEBUG
1268 	/*
1269 	 * if we get here we have tried to add/update properties
1270 	 */
1271 	if (update_result != DDI_PROP_SUCCESS) {
1272 		SCSI_PROBE_DEBUG2(1, "SCSA post-probe: can't update parent "
1273 		    "property with tgt=%d (%d)\n", tgt, update_result);
1274 	} else {
1275 		if (add_tgt) {
1276 			SCSI_PROBE_DEBUG3(2,
1277 			    "SCSA post-probe: added tgt=%d to parent "
1278 			    "prop=\"%s\" (now %d entries)\n",
1279 			    tgt, SS2_LUN0_TGT_LIST_PROP, new_nelements);
1280 		} else {
1281 			SCSI_PROBE_DEBUG3(2,
1282 			    "SCSA post-probe: removed tgt=%d from parent "
1283 			    "prop=\"%s\" (now %d entries)\n",
1284 			    tgt, SS2_LUN0_TGT_LIST_PROP, new_nelements);
1285 		}
1286 	}
1287 #endif
1288 }
1289