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