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