scsi_xpt.c revision 256843
1195534Sscottl/*-
2195534Sscottl * Implementation of the SCSI Transport
3195534Sscottl *
4195534Sscottl * Copyright (c) 1997, 1998, 1999 Justin T. Gibbs.
5195534Sscottl * Copyright (c) 1997, 1998, 1999 Kenneth D. Merry.
6195534Sscottl * All rights reserved.
7195534Sscottl *
8195534Sscottl * Redistribution and use in source and binary forms, with or without
9195534Sscottl * modification, are permitted provided that the following conditions
10195534Sscottl * are met:
11195534Sscottl * 1. Redistributions of source code must retain the above copyright
12195534Sscottl *    notice, this list of conditions, and the following disclaimer,
13195534Sscottl *    without modification, immediately at the beginning of the file.
14195534Sscottl * 2. The name of the author may not be used to endorse or promote products
15195534Sscottl *    derived from this software without specific prior written permission.
16195534Sscottl *
17195534Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18195534Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19195534Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20195534Sscottl * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
21195534Sscottl * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22195534Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23195534Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24195534Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25195534Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26195534Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27195534Sscottl * SUCH DAMAGE.
28195534Sscottl */
29195534Sscottl
30195534Sscottl#include <sys/cdefs.h>
31195534Sscottl__FBSDID("$FreeBSD: head/sys/cam/scsi/scsi_xpt.c 256843 2013-10-21 12:00:26Z mav $");
32195534Sscottl
33195534Sscottl#include <sys/param.h>
34195534Sscottl#include <sys/bus.h>
35195534Sscottl#include <sys/systm.h>
36195534Sscottl#include <sys/types.h>
37195534Sscottl#include <sys/malloc.h>
38195534Sscottl#include <sys/kernel.h>
39195534Sscottl#include <sys/time.h>
40195534Sscottl#include <sys/conf.h>
41195534Sscottl#include <sys/fcntl.h>
42195534Sscottl#include <sys/md5.h>
43195534Sscottl#include <sys/interrupt.h>
44195534Sscottl#include <sys/sbuf.h>
45195534Sscottl
46195534Sscottl#include <sys/lock.h>
47195534Sscottl#include <sys/mutex.h>
48195534Sscottl#include <sys/sysctl.h>
49195534Sscottl
50195534Sscottl#include <cam/cam.h>
51195534Sscottl#include <cam/cam_ccb.h>
52195534Sscottl#include <cam/cam_queue.h>
53195534Sscottl#include <cam/cam_periph.h>
54195534Sscottl#include <cam/cam_sim.h>
55195534Sscottl#include <cam/cam_xpt.h>
56195534Sscottl#include <cam/cam_xpt_sim.h>
57195534Sscottl#include <cam/cam_xpt_periph.h>
58195534Sscottl#include <cam/cam_xpt_internal.h>
59195534Sscottl#include <cam/cam_debug.h>
60195534Sscottl
61195534Sscottl#include <cam/scsi/scsi_all.h>
62195534Sscottl#include <cam/scsi/scsi_message.h>
63195534Sscottl#include <cam/scsi/scsi_pass.h>
64195534Sscottl#include <machine/stdarg.h>	/* for xpt_print below */
65195534Sscottl#include "opt_cam.h"
66195534Sscottl
67195534Sscottlstruct scsi_quirk_entry {
68195534Sscottl	struct scsi_inquiry_pattern inq_pat;
69195534Sscottl	u_int8_t quirks;
70195534Sscottl#define	CAM_QUIRK_NOLUNS	0x01
71216088Sken#define	CAM_QUIRK_NOVPDS	0x02
72195534Sscottl#define	CAM_QUIRK_HILUNS	0x04
73195534Sscottl#define	CAM_QUIRK_NOHILUNS	0x08
74208911Smjacob#define	CAM_QUIRK_NORPTLUNS	0x10
75195534Sscottl	u_int mintags;
76195534Sscottl	u_int maxtags;
77195534Sscottl};
78195534Sscottl#define SCSI_QUIRK(dev)	((struct scsi_quirk_entry *)((dev)->quirk))
79195534Sscottl
80195534Sscottlstatic int cam_srch_hi = 0;
81195534SscottlTUNABLE_INT("kern.cam.cam_srch_hi", &cam_srch_hi);
82195534Sscottlstatic int sysctl_cam_search_luns(SYSCTL_HANDLER_ARGS);
83195534SscottlSYSCTL_PROC(_kern_cam, OID_AUTO, cam_srch_hi, CTLTYPE_INT|CTLFLAG_RW, 0, 0,
84195534Sscottl    sysctl_cam_search_luns, "I",
85195534Sscottl    "allow search above LUN 7 for SCSI3 and greater devices");
86195534Sscottl
87195534Sscottl#define	CAM_SCSI2_MAXLUN	8
88208911Smjacob#define	CAM_CAN_GET_SIMPLE_LUN(x, i)				\
89208911Smjacob	((((x)->luns[i].lundata[0] & RPL_LUNDATA_ATYP_MASK) ==	\
90208911Smjacob	RPL_LUNDATA_ATYP_PERIPH) ||				\
91208911Smjacob	(((x)->luns[i].lundata[0] & RPL_LUNDATA_ATYP_MASK) ==	\
92208911Smjacob	RPL_LUNDATA_ATYP_FLAT))
93208911Smjacob#define	CAM_GET_SIMPLE_LUN(lp, i, lval)					\
94208911Smjacob	if (((lp)->luns[(i)].lundata[0] & RPL_LUNDATA_ATYP_MASK) == 	\
95208911Smjacob	    RPL_LUNDATA_ATYP_PERIPH) {					\
96208911Smjacob		(lval) = (lp)->luns[(i)].lundata[1];			\
97208911Smjacob	} else {							\
98208911Smjacob		(lval) = (lp)->luns[(i)].lundata[0];			\
99208911Smjacob		(lval) &= RPL_LUNDATA_FLAT_LUN_MASK;			\
100208911Smjacob		(lval) <<= 8;						\
101208911Smjacob		(lval) |=  (lp)->luns[(i)].lundata[1];			\
102208911Smjacob	}
103195534Sscottl/*
104195534Sscottl * If we're not quirked to search <= the first 8 luns
105195534Sscottl * and we are either quirked to search above lun 8,
106195534Sscottl * or we're > SCSI-2 and we've enabled hilun searching,
107195534Sscottl * or we're > SCSI-2 and the last lun was a success,
108195534Sscottl * we can look for luns above lun 8.
109195534Sscottl */
110195534Sscottl#define	CAN_SRCH_HI_SPARSE(dv)					\
111195534Sscottl  (((SCSI_QUIRK(dv)->quirks & CAM_QUIRK_NOHILUNS) == 0) 	\
112195534Sscottl  && ((SCSI_QUIRK(dv)->quirks & CAM_QUIRK_HILUNS)		\
113195534Sscottl  || (SID_ANSI_REV(&dv->inq_data) > SCSI_REV_2 && cam_srch_hi)))
114195534Sscottl
115195534Sscottl#define	CAN_SRCH_HI_DENSE(dv)					\
116195534Sscottl  (((SCSI_QUIRK(dv)->quirks & CAM_QUIRK_NOHILUNS) == 0) 	\
117195534Sscottl  && ((SCSI_QUIRK(dv)->quirks & CAM_QUIRK_HILUNS)		\
118195534Sscottl  || (SID_ANSI_REV(&dv->inq_data) > SCSI_REV_2)))
119195534Sscottl
120195534Sscottlstatic periph_init_t probe_periph_init;
121195534Sscottl
122195534Sscottlstatic struct periph_driver probe_driver =
123195534Sscottl{
124195534Sscottl	probe_periph_init, "probe",
125198708Smav	TAILQ_HEAD_INITIALIZER(probe_driver.units), /* generation */ 0,
126198708Smav	CAM_PERIPH_DRV_EARLY
127195534Sscottl};
128195534Sscottl
129195534SscottlPERIPHDRIVER_DECLARE(probe, probe_driver);
130195534Sscottl
131195534Sscottltypedef enum {
132195534Sscottl	PROBE_TUR,
133195534Sscottl	PROBE_INQUIRY,	/* this counts as DV0 for Basic Domain Validation */
134195534Sscottl	PROBE_FULL_INQUIRY,
135208911Smjacob	PROBE_REPORT_LUNS,
136195534Sscottl	PROBE_MODE_SENSE,
137216088Sken	PROBE_SUPPORTED_VPD_LIST,
138216088Sken	PROBE_DEVICE_ID,
139216088Sken	PROBE_SERIAL_NUM,
140195534Sscottl	PROBE_TUR_FOR_NEGOTIATION,
141195534Sscottl	PROBE_INQUIRY_BASIC_DV1,
142195534Sscottl	PROBE_INQUIRY_BASIC_DV2,
143195534Sscottl	PROBE_DV_EXIT,
144236613Smav	PROBE_DONE,
145195534Sscottl	PROBE_INVALID
146195534Sscottl} probe_action;
147195534Sscottl
148195534Sscottlstatic char *probe_action_text[] = {
149195534Sscottl	"PROBE_TUR",
150195534Sscottl	"PROBE_INQUIRY",
151195534Sscottl	"PROBE_FULL_INQUIRY",
152208911Smjacob	"PROBE_REPORT_LUNS",
153195534Sscottl	"PROBE_MODE_SENSE",
154216088Sken	"PROBE_SUPPORTED_VPD_LIST",
155216088Sken	"PROBE_DEVICE_ID",
156216088Sken	"PROBE_SERIAL_NUM",
157195534Sscottl	"PROBE_TUR_FOR_NEGOTIATION",
158195534Sscottl	"PROBE_INQUIRY_BASIC_DV1",
159195534Sscottl	"PROBE_INQUIRY_BASIC_DV2",
160195534Sscottl	"PROBE_DV_EXIT",
161236613Smav	"PROBE_DONE",
162195534Sscottl	"PROBE_INVALID"
163195534Sscottl};
164195534Sscottl
165195534Sscottl#define PROBE_SET_ACTION(softc, newaction)	\
166195534Sscottldo {									\
167195534Sscottl	char **text;							\
168195534Sscottl	text = probe_action_text;					\
169236613Smav	CAM_DEBUG((softc)->periph->path, CAM_DEBUG_PROBE,		\
170195534Sscottl	    ("Probe %s to %s\n", text[(softc)->action],			\
171195534Sscottl	    text[(newaction)]));					\
172195534Sscottl	(softc)->action = (newaction);					\
173195534Sscottl} while(0)
174195534Sscottl
175195534Sscottltypedef enum {
176195534Sscottl	PROBE_INQUIRY_CKSUM	= 0x01,
177195534Sscottl	PROBE_SERIAL_CKSUM	= 0x02,
178195534Sscottl	PROBE_NO_ANNOUNCE	= 0x04
179195534Sscottl} probe_flags;
180195534Sscottl
181195534Sscottltypedef struct {
182195534Sscottl	TAILQ_HEAD(, ccb_hdr) request_ccbs;
183195534Sscottl	probe_action	action;
184195534Sscottl	union ccb	saved_ccb;
185195534Sscottl	probe_flags	flags;
186195534Sscottl	MD5_CTX		context;
187195534Sscottl	u_int8_t	digest[16];
188195534Sscottl	struct cam_periph *periph;
189195534Sscottl} probe_softc;
190195534Sscottl
191195534Sscottlstatic const char quantum[] = "QUANTUM";
192195534Sscottlstatic const char sony[] = "SONY";
193195534Sscottlstatic const char west_digital[] = "WDIGTL";
194195534Sscottlstatic const char samsung[] = "SAMSUNG";
195195534Sscottlstatic const char seagate[] = "SEAGATE";
196195534Sscottlstatic const char microp[] = "MICROP";
197195534Sscottl
198195534Sscottlstatic struct scsi_quirk_entry scsi_quirk_table[] =
199195534Sscottl{
200195534Sscottl	{
201195534Sscottl		/* Reports QUEUE FULL for temporary resource shortages */
202195534Sscottl		{ T_DIRECT, SIP_MEDIA_FIXED, quantum, "XP39100*", "*" },
203195534Sscottl		/*quirks*/0, /*mintags*/24, /*maxtags*/32
204195534Sscottl	},
205195534Sscottl	{
206195534Sscottl		/* Reports QUEUE FULL for temporary resource shortages */
207195534Sscottl		{ T_DIRECT, SIP_MEDIA_FIXED, quantum, "XP34550*", "*" },
208195534Sscottl		/*quirks*/0, /*mintags*/24, /*maxtags*/32
209195534Sscottl	},
210195534Sscottl	{
211195534Sscottl		/* Reports QUEUE FULL for temporary resource shortages */
212195534Sscottl		{ T_DIRECT, SIP_MEDIA_FIXED, quantum, "XP32275*", "*" },
213195534Sscottl		/*quirks*/0, /*mintags*/24, /*maxtags*/32
214195534Sscottl	},
215195534Sscottl	{
216195534Sscottl		/* Broken tagged queuing drive */
217195534Sscottl		{ T_DIRECT, SIP_MEDIA_FIXED, microp, "4421-07*", "*" },
218195534Sscottl		/*quirks*/0, /*mintags*/0, /*maxtags*/0
219195534Sscottl	},
220195534Sscottl	{
221195534Sscottl		/* Broken tagged queuing drive */
222195534Sscottl		{ T_DIRECT, SIP_MEDIA_FIXED, "HP", "C372*", "*" },
223195534Sscottl		/*quirks*/0, /*mintags*/0, /*maxtags*/0
224195534Sscottl	},
225195534Sscottl	{
226195534Sscottl		/* Broken tagged queuing drive */
227195534Sscottl		{ T_DIRECT, SIP_MEDIA_FIXED, microp, "3391*", "x43h" },
228195534Sscottl		/*quirks*/0, /*mintags*/0, /*maxtags*/0
229195534Sscottl	},
230195534Sscottl	{
231195534Sscottl		/*
232195534Sscottl		 * Unfortunately, the Quantum Atlas III has the same
233195534Sscottl		 * problem as the Atlas II drives above.
234195534Sscottl		 * Reported by: "Johan Granlund" <johan@granlund.nu>
235195534Sscottl		 *
236195534Sscottl		 * For future reference, the drive with the problem was:
237195534Sscottl		 * QUANTUM QM39100TD-SW N1B0
238195534Sscottl		 *
239195534Sscottl		 * It's possible that Quantum will fix the problem in later
240195534Sscottl		 * firmware revisions.  If that happens, the quirk entry
241195534Sscottl		 * will need to be made specific to the firmware revisions
242195534Sscottl		 * with the problem.
243195534Sscottl		 *
244195534Sscottl		 */
245195534Sscottl		/* Reports QUEUE FULL for temporary resource shortages */
246195534Sscottl		{ T_DIRECT, SIP_MEDIA_FIXED, quantum, "QM39100*", "*" },
247195534Sscottl		/*quirks*/0, /*mintags*/24, /*maxtags*/32
248195534Sscottl	},
249195534Sscottl	{
250195534Sscottl		/*
251195534Sscottl		 * 18 Gig Atlas III, same problem as the 9G version.
252195534Sscottl		 * Reported by: Andre Albsmeier
253195534Sscottl		 *		<andre.albsmeier@mchp.siemens.de>
254195534Sscottl		 *
255195534Sscottl		 * For future reference, the drive with the problem was:
256195534Sscottl		 * QUANTUM QM318000TD-S N491
257195534Sscottl		 */
258195534Sscottl		/* Reports QUEUE FULL for temporary resource shortages */
259195534Sscottl		{ T_DIRECT, SIP_MEDIA_FIXED, quantum, "QM318000*", "*" },
260195534Sscottl		/*quirks*/0, /*mintags*/24, /*maxtags*/32
261195534Sscottl	},
262195534Sscottl	{
263195534Sscottl		/*
264195534Sscottl		 * Broken tagged queuing drive
265195534Sscottl		 * Reported by: Bret Ford <bford@uop.cs.uop.edu>
266195534Sscottl		 *         and: Martin Renters <martin@tdc.on.ca>
267195534Sscottl		 */
268195534Sscottl		{ T_DIRECT, SIP_MEDIA_FIXED, seagate, "ST410800*", "71*" },
269195534Sscottl		/*quirks*/0, /*mintags*/0, /*maxtags*/0
270195534Sscottl	},
271195534Sscottl		/*
272195534Sscottl		 * The Seagate Medalist Pro drives have very poor write
273195534Sscottl		 * performance with anything more than 2 tags.
274195534Sscottl		 *
275195534Sscottl		 * Reported by:  Paul van der Zwan <paulz@trantor.xs4all.nl>
276195534Sscottl		 * Drive:  <SEAGATE ST36530N 1444>
277195534Sscottl		 *
278195534Sscottl		 * Reported by:  Jeremy Lea <reg@shale.csir.co.za>
279195534Sscottl		 * Drive:  <SEAGATE ST34520W 1281>
280195534Sscottl		 *
281195534Sscottl		 * No one has actually reported that the 9G version
282195534Sscottl		 * (ST39140*) of the Medalist Pro has the same problem, but
283195534Sscottl		 * we're assuming that it does because the 4G and 6.5G
284195534Sscottl		 * versions of the drive are broken.
285195534Sscottl		 */
286195534Sscottl	{
287195534Sscottl		{ T_DIRECT, SIP_MEDIA_FIXED, seagate, "ST34520*", "*"},
288195534Sscottl		/*quirks*/0, /*mintags*/2, /*maxtags*/2
289195534Sscottl	},
290195534Sscottl	{
291195534Sscottl		{ T_DIRECT, SIP_MEDIA_FIXED, seagate, "ST36530*", "*"},
292195534Sscottl		/*quirks*/0, /*mintags*/2, /*maxtags*/2
293195534Sscottl	},
294195534Sscottl	{
295195534Sscottl		{ T_DIRECT, SIP_MEDIA_FIXED, seagate, "ST39140*", "*"},
296195534Sscottl		/*quirks*/0, /*mintags*/2, /*maxtags*/2
297195534Sscottl	},
298195534Sscottl	{
299195534Sscottl		/*
300231745Sgibbs		 * Experiences command timeouts under load with a
301231745Sgibbs		 * tag count higher than 55.
302231745Sgibbs		 */
303231745Sgibbs		{ T_DIRECT, SIP_MEDIA_FIXED, seagate, "ST3146855LW", "*"},
304231745Sgibbs		/*quirks*/0, /*mintags*/2, /*maxtags*/55
305231745Sgibbs	},
306231745Sgibbs	{
307231745Sgibbs		/*
308195534Sscottl		 * Slow when tagged queueing is enabled.  Write performance
309195534Sscottl		 * steadily drops off with more and more concurrent
310195534Sscottl		 * transactions.  Best sequential write performance with
311195534Sscottl		 * tagged queueing turned off and write caching turned on.
312195534Sscottl		 *
313195534Sscottl		 * PR:  kern/10398
314195534Sscottl		 * Submitted by:  Hideaki Okada <hokada@isl.melco.co.jp>
315195534Sscottl		 * Drive:  DCAS-34330 w/ "S65A" firmware.
316195534Sscottl		 *
317195534Sscottl		 * The drive with the problem had the "S65A" firmware
318195534Sscottl		 * revision, and has also been reported (by Stephen J.
319195534Sscottl		 * Roznowski <sjr@home.net>) for a drive with the "S61A"
320195534Sscottl		 * firmware revision.
321195534Sscottl		 *
322195534Sscottl		 * Although no one has reported problems with the 2 gig
323195534Sscottl		 * version of the DCAS drive, the assumption is that it
324195534Sscottl		 * has the same problems as the 4 gig version.  Therefore
325195534Sscottl		 * this quirk entries disables tagged queueing for all
326195534Sscottl		 * DCAS drives.
327195534Sscottl		 */
328195534Sscottl		{ T_DIRECT, SIP_MEDIA_FIXED, "IBM", "DCAS*", "*" },
329195534Sscottl		/*quirks*/0, /*mintags*/0, /*maxtags*/0
330195534Sscottl	},
331195534Sscottl	{
332195534Sscottl		/* Broken tagged queuing drive */
333195534Sscottl		{ T_DIRECT, SIP_MEDIA_REMOVABLE, "iomega", "jaz*", "*" },
334195534Sscottl		/*quirks*/0, /*mintags*/0, /*maxtags*/0
335195534Sscottl	},
336195534Sscottl	{
337195534Sscottl		/* Broken tagged queuing drive */
338195534Sscottl		{ T_DIRECT, SIP_MEDIA_FIXED, "CONNER", "CFP2107*", "*" },
339195534Sscottl		/*quirks*/0, /*mintags*/0, /*maxtags*/0
340195534Sscottl	},
341195534Sscottl	{
342195534Sscottl		/* This does not support other than LUN 0 */
343195534Sscottl		{ T_DIRECT, SIP_MEDIA_FIXED, "VMware*", "*", "*" },
344195534Sscottl		CAM_QUIRK_NOLUNS, /*mintags*/2, /*maxtags*/255
345195534Sscottl	},
346195534Sscottl	{
347195534Sscottl		/*
348195534Sscottl		 * Broken tagged queuing drive.
349195534Sscottl		 * Submitted by:
350195534Sscottl		 * NAKAJI Hiroyuki <nakaji@zeisei.dpri.kyoto-u.ac.jp>
351195534Sscottl		 * in PR kern/9535
352195534Sscottl		 */
353195534Sscottl		{ T_DIRECT, SIP_MEDIA_FIXED, samsung, "WN34324U*", "*" },
354195534Sscottl		/*quirks*/0, /*mintags*/0, /*maxtags*/0
355195534Sscottl	},
356195534Sscottl        {
357195534Sscottl		/*
358195534Sscottl		 * Slow when tagged queueing is enabled. (1.5MB/sec versus
359195534Sscottl		 * 8MB/sec.)
360195534Sscottl		 * Submitted by: Andrew Gallatin <gallatin@cs.duke.edu>
361195534Sscottl		 * Best performance with these drives is achieved with
362195534Sscottl		 * tagged queueing turned off, and write caching turned on.
363195534Sscottl		 */
364195534Sscottl		{ T_DIRECT, SIP_MEDIA_FIXED, west_digital, "WDE*", "*" },
365195534Sscottl		/*quirks*/0, /*mintags*/0, /*maxtags*/0
366195534Sscottl        },
367195534Sscottl        {
368195534Sscottl		/*
369195534Sscottl		 * Slow when tagged queueing is enabled. (1.5MB/sec versus
370195534Sscottl		 * 8MB/sec.)
371195534Sscottl		 * Submitted by: Andrew Gallatin <gallatin@cs.duke.edu>
372195534Sscottl		 * Best performance with these drives is achieved with
373195534Sscottl		 * tagged queueing turned off, and write caching turned on.
374195534Sscottl		 */
375195534Sscottl		{ T_DIRECT, SIP_MEDIA_FIXED, west_digital, "ENTERPRISE", "*" },
376195534Sscottl		/*quirks*/0, /*mintags*/0, /*maxtags*/0
377195534Sscottl        },
378195534Sscottl	{
379195534Sscottl		/*
380195534Sscottl		 * Doesn't handle queue full condition correctly,
381195534Sscottl		 * so we need to limit maxtags to what the device
382195534Sscottl		 * can handle instead of determining this automatically.
383195534Sscottl		 */
384195534Sscottl		{ T_DIRECT, SIP_MEDIA_FIXED, samsung, "WN321010S*", "*" },
385195534Sscottl		/*quirks*/0, /*mintags*/2, /*maxtags*/32
386195534Sscottl	},
387195534Sscottl	{
388195534Sscottl		/* Really only one LUN */
389195534Sscottl		{ T_ENCLOSURE, SIP_MEDIA_FIXED, "SUN", "SENA", "*" },
390195534Sscottl		CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0
391195534Sscottl	},
392195534Sscottl	{
393195534Sscottl		/* I can't believe we need a quirk for DPT volumes. */
394195534Sscottl		{ T_ANY, SIP_MEDIA_FIXED|SIP_MEDIA_REMOVABLE, "DPT", "*", "*" },
395195534Sscottl		CAM_QUIRK_NOLUNS,
396195534Sscottl		/*mintags*/0, /*maxtags*/255
397195534Sscottl	},
398195534Sscottl	{
399195534Sscottl		/*
400195534Sscottl		 * Many Sony CDROM drives don't like multi-LUN probing.
401195534Sscottl		 */
402195534Sscottl		{ T_CDROM, SIP_MEDIA_REMOVABLE, sony, "CD-ROM CDU*", "*" },
403195534Sscottl		CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0
404195534Sscottl	},
405195534Sscottl	{
406195534Sscottl		/*
407195534Sscottl		 * This drive doesn't like multiple LUN probing.
408195534Sscottl		 * Submitted by:  Parag Patel <parag@cgt.com>
409195534Sscottl		 */
410195534Sscottl		{ T_WORM, SIP_MEDIA_REMOVABLE, sony, "CD-R   CDU9*", "*" },
411195534Sscottl		CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0
412195534Sscottl	},
413195534Sscottl	{
414195534Sscottl		{ T_WORM, SIP_MEDIA_REMOVABLE, "YAMAHA", "CDR100*", "*" },
415195534Sscottl		CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0
416195534Sscottl	},
417195534Sscottl	{
418195534Sscottl		/*
419195534Sscottl		 * The 8200 doesn't like multi-lun probing, and probably
420195534Sscottl		 * don't like serial number requests either.
421195534Sscottl		 */
422195534Sscottl		{
423195534Sscottl			T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "EXABYTE",
424195534Sscottl			"EXB-8200*", "*"
425195534Sscottl		},
426195534Sscottl		CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0
427195534Sscottl	},
428195534Sscottl	{
429195534Sscottl		/*
430195534Sscottl		 * Let's try the same as above, but for a drive that says
431195534Sscottl		 * it's an IPL-6860 but is actually an EXB 8200.
432195534Sscottl		 */
433195534Sscottl		{
434195534Sscottl			T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "EXABYTE",
435195534Sscottl			"IPL-6860*", "*"
436195534Sscottl		},
437195534Sscottl		CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0
438195534Sscottl	},
439195534Sscottl	{
440195534Sscottl		/*
441195534Sscottl		 * These Hitachi drives don't like multi-lun probing.
442195534Sscottl		 * The PR submitter has a DK319H, but says that the Linux
443195534Sscottl		 * kernel has a similar work-around for the DK312 and DK314,
444195534Sscottl		 * so all DK31* drives are quirked here.
445195534Sscottl		 * PR:            misc/18793
446195534Sscottl		 * Submitted by:  Paul Haddad <paul@pth.com>
447195534Sscottl		 */
448195534Sscottl		{ T_DIRECT, SIP_MEDIA_FIXED, "HITACHI", "DK31*", "*" },
449195534Sscottl		CAM_QUIRK_NOLUNS, /*mintags*/2, /*maxtags*/255
450195534Sscottl	},
451195534Sscottl	{
452195534Sscottl		/*
453195534Sscottl		 * The Hitachi CJ series with J8A8 firmware apparantly has
454195534Sscottl		 * problems with tagged commands.
455195534Sscottl		 * PR: 23536
456195534Sscottl		 * Reported by: amagai@nue.org
457195534Sscottl		 */
458195534Sscottl		{ T_DIRECT, SIP_MEDIA_FIXED, "HITACHI", "DK32CJ*", "J8A8" },
459195534Sscottl		CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0
460195534Sscottl	},
461195534Sscottl	{
462195534Sscottl		/*
463195534Sscottl		 * These are the large storage arrays.
464195534Sscottl		 * Submitted by:  William Carrel <william.carrel@infospace.com>
465195534Sscottl		 */
466195534Sscottl		{ T_DIRECT, SIP_MEDIA_FIXED, "HITACHI", "OPEN*", "*" },
467195534Sscottl		CAM_QUIRK_HILUNS, 2, 1024
468195534Sscottl	},
469195534Sscottl	{
470195534Sscottl		/*
471195534Sscottl		 * This old revision of the TDC3600 is also SCSI-1, and
472195534Sscottl		 * hangs upon serial number probing.
473195534Sscottl		 */
474195534Sscottl		{
475195534Sscottl			T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG",
476195534Sscottl			" TDC 3600", "U07:"
477195534Sscottl		},
478216088Sken		CAM_QUIRK_NOVPDS, /*mintags*/0, /*maxtags*/0
479195534Sscottl	},
480195534Sscottl	{
481195534Sscottl		/*
482195534Sscottl		 * Would repond to all LUNs if asked for.
483195534Sscottl		 */
484195534Sscottl		{
485195534Sscottl			T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "CALIPER",
486195534Sscottl			"CP150", "*"
487195534Sscottl		},
488195534Sscottl		CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0
489195534Sscottl	},
490195534Sscottl	{
491195534Sscottl		/*
492195534Sscottl		 * Would repond to all LUNs if asked for.
493195534Sscottl		 */
494195534Sscottl		{
495195534Sscottl			T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "KENNEDY",
496195534Sscottl			"96X2*", "*"
497195534Sscottl		},
498195534Sscottl		CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0
499195534Sscottl	},
500195534Sscottl	{
501195534Sscottl		/* Submitted by: Matthew Dodd <winter@jurai.net> */
502195534Sscottl		{ T_PROCESSOR, SIP_MEDIA_FIXED, "Cabletrn", "EA41*", "*" },
503195534Sscottl		CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0
504195534Sscottl	},
505195534Sscottl	{
506195534Sscottl		/* Submitted by: Matthew Dodd <winter@jurai.net> */
507195534Sscottl		{ T_PROCESSOR, SIP_MEDIA_FIXED, "CABLETRN", "EA41*", "*" },
508195534Sscottl		CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0
509195534Sscottl	},
510195534Sscottl	{
511195534Sscottl		/* TeraSolutions special settings for TRC-22 RAID */
512195534Sscottl		{ T_DIRECT, SIP_MEDIA_FIXED, "TERASOLU", "TRC-22", "*" },
513195534Sscottl		  /*quirks*/0, /*mintags*/55, /*maxtags*/255
514195534Sscottl	},
515195534Sscottl	{
516195534Sscottl		/* Veritas Storage Appliance */
517195534Sscottl		{ T_DIRECT, SIP_MEDIA_FIXED, "VERITAS", "*", "*" },
518195534Sscottl		  CAM_QUIRK_HILUNS, /*mintags*/2, /*maxtags*/1024
519195534Sscottl	},
520195534Sscottl	{
521195534Sscottl		/*
522195534Sscottl		 * Would respond to all LUNs.  Device type and removable
523195534Sscottl		 * flag are jumper-selectable.
524195534Sscottl		 */
525195534Sscottl		{ T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED, "MaxOptix",
526195534Sscottl		  "Tahiti 1", "*"
527195534Sscottl		},
528195534Sscottl		CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0
529195534Sscottl	},
530195534Sscottl	{
531195534Sscottl		/* EasyRAID E5A aka. areca ARC-6010 */
532195534Sscottl		{ T_DIRECT, SIP_MEDIA_FIXED, "easyRAID", "*", "*" },
533195534Sscottl		  CAM_QUIRK_NOHILUNS, /*mintags*/2, /*maxtags*/255
534195534Sscottl	},
535195534Sscottl	{
536195534Sscottl		{ T_ENCLOSURE, SIP_MEDIA_FIXED, "DP", "BACKPLANE", "*" },
537195534Sscottl		CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0
538195534Sscottl	},
539195534Sscottl	{
540236283Seadler		{ T_DIRECT, SIP_MEDIA_REMOVABLE, "Garmin", "*", "*" },
541236283Seadler		CAM_QUIRK_NORPTLUNS, /*mintags*/2, /*maxtags*/255
542236283Seadler	},
543236283Seadler	{
544195534Sscottl		/* Default tagged queuing parameters for all devices */
545195534Sscottl		{
546195534Sscottl		  T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED,
547195534Sscottl		  /*vendor*/"*", /*product*/"*", /*revision*/"*"
548195534Sscottl		},
549195534Sscottl		/*quirks*/0, /*mintags*/2, /*maxtags*/255
550195534Sscottl	},
551195534Sscottl};
552195534Sscottl
553195534Sscottlstatic const int scsi_quirk_table_size =
554195534Sscottl	sizeof(scsi_quirk_table) / sizeof(*scsi_quirk_table);
555195534Sscottl
556195534Sscottlstatic cam_status	proberegister(struct cam_periph *periph,
557195534Sscottl				      void *arg);
558195534Sscottlstatic void	 probeschedule(struct cam_periph *probe_periph);
559195534Sscottlstatic void	 probestart(struct cam_periph *periph, union ccb *start_ccb);
560195534Sscottlstatic void	 proberequestdefaultnegotiation(struct cam_periph *periph);
561195534Sscottlstatic int       proberequestbackoff(struct cam_periph *periph,
562195534Sscottl				     struct cam_ed *device);
563195534Sscottlstatic void	 probedone(struct cam_periph *periph, union ccb *done_ccb);
564208911Smjacobstatic int	 probe_strange_rpl_data(struct scsi_report_luns_data *rp,
565208911Smjacob					uint32_t maxlun);
566208911Smjacobstatic void	 probe_purge_old(struct cam_path *path,
567208911Smjacob				 struct scsi_report_luns_data *new);
568195534Sscottlstatic void	 probecleanup(struct cam_periph *periph);
569195534Sscottlstatic void	 scsi_find_quirk(struct cam_ed *device);
570195534Sscottlstatic void	 scsi_scan_bus(struct cam_periph *periph, union ccb *ccb);
571195534Sscottlstatic void	 scsi_scan_lun(struct cam_periph *periph,
572195534Sscottl			       struct cam_path *path, cam_flags flags,
573195534Sscottl			       union ccb *ccb);
574195534Sscottlstatic void	 xptscandone(struct cam_periph *periph, union ccb *done_ccb);
575195534Sscottlstatic struct cam_ed *
576195534Sscottl		 scsi_alloc_device(struct cam_eb *bus, struct cam_et *target,
577195534Sscottl				   lun_id_t lun_id);
578195534Sscottlstatic void	 scsi_devise_transport(struct cam_path *path);
579195534Sscottlstatic void	 scsi_set_transfer_settings(struct ccb_trans_settings *cts,
580256843Smav					    struct cam_path *path,
581195534Sscottl					    int async_update);
582195534Sscottlstatic void	 scsi_toggle_tags(struct cam_path *path);
583195534Sscottlstatic void	 scsi_dev_async(u_int32_t async_code,
584195534Sscottl				struct cam_eb *bus,
585195534Sscottl				struct cam_et *target,
586195534Sscottl				struct cam_ed *device,
587195534Sscottl				void *async_arg);
588195534Sscottlstatic void	 scsi_action(union ccb *start_ccb);
589204220Smavstatic void	 scsi_announce_periph(struct cam_periph *periph);
590195534Sscottl
591195534Sscottlstatic struct xpt_xport scsi_xport = {
592195534Sscottl	.alloc_device = scsi_alloc_device,
593195534Sscottl	.action = scsi_action,
594195534Sscottl	.async = scsi_dev_async,
595204220Smav	.announce = scsi_announce_periph,
596195534Sscottl};
597195534Sscottl
598195534Sscottlstruct xpt_xport *
599195534Sscottlscsi_get_xport(void)
600195534Sscottl{
601195534Sscottl	return (&scsi_xport);
602195534Sscottl}
603195534Sscottl
604195534Sscottlstatic void
605195534Sscottlprobe_periph_init()
606195534Sscottl{
607195534Sscottl}
608195534Sscottl
609195534Sscottlstatic cam_status
610195534Sscottlproberegister(struct cam_periph *periph, void *arg)
611195534Sscottl{
612195534Sscottl	union ccb *request_ccb;	/* CCB representing the probe request */
613195534Sscottl	cam_status status;
614195534Sscottl	probe_softc *softc;
615195534Sscottl
616195534Sscottl	request_ccb = (union ccb *)arg;
617195534Sscottl	if (request_ccb == NULL) {
618195534Sscottl		printf("proberegister: no probe CCB, "
619195534Sscottl		       "can't register device\n");
620195534Sscottl		return(CAM_REQ_CMP_ERR);
621195534Sscottl	}
622195534Sscottl
623195534Sscottl	softc = (probe_softc *)malloc(sizeof(*softc), M_CAMXPT, M_NOWAIT);
624195534Sscottl
625195534Sscottl	if (softc == NULL) {
626195534Sscottl		printf("proberegister: Unable to probe new device. "
627195534Sscottl		       "Unable to allocate softc\n");
628195534Sscottl		return(CAM_REQ_CMP_ERR);
629195534Sscottl	}
630195534Sscottl	TAILQ_INIT(&softc->request_ccbs);
631195534Sscottl	TAILQ_INSERT_TAIL(&softc->request_ccbs, &request_ccb->ccb_h,
632195534Sscottl			  periph_links.tqe);
633195534Sscottl	softc->flags = 0;
634195534Sscottl	periph->softc = softc;
635195534Sscottl	softc->periph = periph;
636195534Sscottl	softc->action = PROBE_INVALID;
637195534Sscottl	status = cam_periph_acquire(periph);
638195534Sscottl	if (status != CAM_REQ_CMP) {
639195534Sscottl		return (status);
640195534Sscottl	}
641236613Smav	CAM_DEBUG(periph->path, CAM_DEBUG_PROBE, ("Probe started\n"));
642256843Smav	scsi_devise_transport(periph->path);
643195534Sscottl
644195534Sscottl	/*
645195534Sscottl	 * Ensure we've waited at least a bus settle
646195534Sscottl	 * delay before attempting to probe the device.
647195534Sscottl	 * For HBAs that don't do bus resets, this won't make a difference.
648195534Sscottl	 */
649195534Sscottl	cam_periph_freeze_after_event(periph, &periph->path->bus->last_reset,
650195534Sscottl				      scsi_delay);
651195534Sscottl	probeschedule(periph);
652195534Sscottl	return(CAM_REQ_CMP);
653195534Sscottl}
654195534Sscottl
655195534Sscottlstatic void
656195534Sscottlprobeschedule(struct cam_periph *periph)
657195534Sscottl{
658195534Sscottl	struct ccb_pathinq cpi;
659195534Sscottl	union ccb *ccb;
660195534Sscottl	probe_softc *softc;
661195534Sscottl
662195534Sscottl	softc = (probe_softc *)periph->softc;
663195534Sscottl	ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs);
664195534Sscottl
665203108Smav	xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NONE);
666195534Sscottl	cpi.ccb_h.func_code = XPT_PATH_INQ;
667195534Sscottl	xpt_action((union ccb *)&cpi);
668195534Sscottl
669195534Sscottl	/*
670195534Sscottl	 * If a device has gone away and another device, or the same one,
671195534Sscottl	 * is back in the same place, it should have a unit attention
672195534Sscottl	 * condition pending.  It will not report the unit attention in
673195534Sscottl	 * response to an inquiry, which may leave invalid transfer
674195534Sscottl	 * negotiations in effect.  The TUR will reveal the unit attention
675195534Sscottl	 * condition.  Only send the TUR for lun 0, since some devices
676195534Sscottl	 * will get confused by commands other than inquiry to non-existent
677195534Sscottl	 * luns.  If you think a device has gone away start your scan from
678195534Sscottl	 * lun 0.  This will insure that any bogus transfer settings are
679195534Sscottl	 * invalidated.
680195534Sscottl	 *
681195534Sscottl	 * If we haven't seen the device before and the controller supports
682195534Sscottl	 * some kind of transfer negotiation, negotiate with the first
683195534Sscottl	 * sent command if no bus reset was performed at startup.  This
684195534Sscottl	 * ensures that the device is not confused by transfer negotiation
685195534Sscottl	 * settings left over by loader or BIOS action.
686195534Sscottl	 */
687195534Sscottl	if (((ccb->ccb_h.path->device->flags & CAM_DEV_UNCONFIGURED) == 0)
688195534Sscottl	 && (ccb->ccb_h.target_lun == 0)) {
689195534Sscottl		PROBE_SET_ACTION(softc, PROBE_TUR);
690195534Sscottl	} else if ((cpi.hba_inquiry & (PI_WIDE_32|PI_WIDE_16|PI_SDTR_ABLE)) != 0
691195534Sscottl	      && (cpi.hba_misc & PIM_NOBUSRESET) != 0) {
692195534Sscottl		proberequestdefaultnegotiation(periph);
693195534Sscottl		PROBE_SET_ACTION(softc, PROBE_INQUIRY);
694195534Sscottl	} else {
695195534Sscottl		PROBE_SET_ACTION(softc, PROBE_INQUIRY);
696195534Sscottl	}
697195534Sscottl
698195534Sscottl	if (ccb->crcn.flags & CAM_EXPECT_INQ_CHANGE)
699195534Sscottl		softc->flags |= PROBE_NO_ANNOUNCE;
700195534Sscottl	else
701195534Sscottl		softc->flags &= ~PROBE_NO_ANNOUNCE;
702195534Sscottl
703203108Smav	xpt_schedule(periph, CAM_PRIORITY_XPT);
704195534Sscottl}
705195534Sscottl
706195534Sscottlstatic void
707195534Sscottlprobestart(struct cam_periph *periph, union ccb *start_ccb)
708195534Sscottl{
709195534Sscottl	/* Probe the device that our peripheral driver points to */
710195534Sscottl	struct ccb_scsiio *csio;
711195534Sscottl	probe_softc *softc;
712195534Sscottl
713195534Sscottl	CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probestart\n"));
714195534Sscottl
715195534Sscottl	softc = (probe_softc *)periph->softc;
716195534Sscottl	csio = &start_ccb->csio;
717208911Smjacobagain:
718195534Sscottl
719195534Sscottl	switch (softc->action) {
720195534Sscottl	case PROBE_TUR:
721195534Sscottl	case PROBE_TUR_FOR_NEGOTIATION:
722195534Sscottl	case PROBE_DV_EXIT:
723195534Sscottl	{
724195534Sscottl		scsi_test_unit_ready(csio,
725236814Smav				     /*retries*/4,
726195534Sscottl				     probedone,
727195534Sscottl				     MSG_SIMPLE_Q_TAG,
728195534Sscottl				     SSD_FULL_SIZE,
729195534Sscottl				     /*timeout*/60000);
730195534Sscottl		break;
731195534Sscottl	}
732195534Sscottl	case PROBE_INQUIRY:
733195534Sscottl	case PROBE_FULL_INQUIRY:
734195534Sscottl	case PROBE_INQUIRY_BASIC_DV1:
735195534Sscottl	case PROBE_INQUIRY_BASIC_DV2:
736195534Sscottl	{
737195534Sscottl		u_int inquiry_len;
738195534Sscottl		struct scsi_inquiry_data *inq_buf;
739195534Sscottl
740195534Sscottl		inq_buf = &periph->path->device->inq_data;
741195534Sscottl
742195534Sscottl		/*
743195534Sscottl		 * If the device is currently configured, we calculate an
744195534Sscottl		 * MD5 checksum of the inquiry data, and if the serial number
745195534Sscottl		 * length is greater than 0, add the serial number data
746195534Sscottl		 * into the checksum as well.  Once the inquiry and the
747195534Sscottl		 * serial number check finish, we attempt to figure out
748195534Sscottl		 * whether we still have the same device.
749195534Sscottl		 */
750195534Sscottl		if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) == 0) {
751195534Sscottl
752195534Sscottl			MD5Init(&softc->context);
753195534Sscottl			MD5Update(&softc->context, (unsigned char *)inq_buf,
754195534Sscottl				  sizeof(struct scsi_inquiry_data));
755195534Sscottl			softc->flags |= PROBE_INQUIRY_CKSUM;
756195534Sscottl			if (periph->path->device->serial_num_len > 0) {
757195534Sscottl				MD5Update(&softc->context,
758195534Sscottl					  periph->path->device->serial_num,
759195534Sscottl					  periph->path->device->serial_num_len);
760195534Sscottl				softc->flags |= PROBE_SERIAL_CKSUM;
761195534Sscottl			}
762195534Sscottl			MD5Final(softc->digest, &softc->context);
763195534Sscottl		}
764195534Sscottl
765195534Sscottl		if (softc->action == PROBE_INQUIRY)
766195534Sscottl			inquiry_len = SHORT_INQUIRY_LENGTH;
767195534Sscottl		else
768195534Sscottl			inquiry_len = SID_ADDITIONAL_LENGTH(inq_buf);
769195534Sscottl
770195534Sscottl		/*
771195534Sscottl		 * Some parallel SCSI devices fail to send an
772195534Sscottl		 * ignore wide residue message when dealing with
773195534Sscottl		 * odd length inquiry requests.  Round up to be
774195534Sscottl		 * safe.
775195534Sscottl		 */
776195534Sscottl		inquiry_len = roundup2(inquiry_len, 2);
777195534Sscottl
778195534Sscottl		if (softc->action == PROBE_INQUIRY_BASIC_DV1
779195534Sscottl		 || softc->action == PROBE_INQUIRY_BASIC_DV2) {
780195534Sscottl			inq_buf = malloc(inquiry_len, M_CAMXPT, M_NOWAIT);
781195534Sscottl		}
782195534Sscottl		if (inq_buf == NULL) {
783195534Sscottl			xpt_print(periph->path, "malloc failure- skipping Basic"
784195534Sscottl			    "Domain Validation\n");
785195534Sscottl			PROBE_SET_ACTION(softc, PROBE_DV_EXIT);
786195534Sscottl			scsi_test_unit_ready(csio,
787195534Sscottl					     /*retries*/4,
788195534Sscottl					     probedone,
789195534Sscottl					     MSG_SIMPLE_Q_TAG,
790195534Sscottl					     SSD_FULL_SIZE,
791195534Sscottl					     /*timeout*/60000);
792195534Sscottl			break;
793195534Sscottl		}
794195534Sscottl		scsi_inquiry(csio,
795195534Sscottl			     /*retries*/4,
796195534Sscottl			     probedone,
797195534Sscottl			     MSG_SIMPLE_Q_TAG,
798195534Sscottl			     (u_int8_t *)inq_buf,
799195534Sscottl			     inquiry_len,
800195534Sscottl			     /*evpd*/FALSE,
801195534Sscottl			     /*page_code*/0,
802195534Sscottl			     SSD_MIN_SIZE,
803195534Sscottl			     /*timeout*/60 * 1000);
804195534Sscottl		break;
805195534Sscottl	}
806208911Smjacob	case PROBE_REPORT_LUNS:
807208911Smjacob	{
808208911Smjacob		void *rp;
809208911Smjacob
810208911Smjacob		rp = malloc(periph->path->target->rpl_size,
811208911Smjacob		    M_CAMXPT, M_NOWAIT | M_ZERO);
812208911Smjacob		if (rp == NULL) {
813208911Smjacob			struct scsi_inquiry_data *inq_buf;
814208911Smjacob			inq_buf = &periph->path->device->inq_data;
815208911Smjacob			xpt_print(periph->path,
816208911Smjacob			    "Unable to alloc report luns storage\n");
817208911Smjacob			if (INQ_DATA_TQ_ENABLED(inq_buf))
818208911Smjacob				PROBE_SET_ACTION(softc, PROBE_MODE_SENSE);
819208911Smjacob			else
820216088Sken				PROBE_SET_ACTION(softc,
821216088Sken				    PROBE_SUPPORTED_VPD_LIST);
822208911Smjacob			goto again;
823208911Smjacob		}
824208911Smjacob		scsi_report_luns(csio, 5, probedone, MSG_SIMPLE_Q_TAG,
825208911Smjacob		    RPL_REPORT_DEFAULT, rp, periph->path->target->rpl_size,
826208911Smjacob		    SSD_FULL_SIZE, 60000); break;
827208911Smjacob		break;
828208911Smjacob	}
829195534Sscottl	case PROBE_MODE_SENSE:
830195534Sscottl	{
831195534Sscottl		void  *mode_buf;
832195534Sscottl		int    mode_buf_len;
833195534Sscottl
834195534Sscottl		mode_buf_len = sizeof(struct scsi_mode_header_6)
835195534Sscottl			     + sizeof(struct scsi_mode_blk_desc)
836195534Sscottl			     + sizeof(struct scsi_control_page);
837195534Sscottl		mode_buf = malloc(mode_buf_len, M_CAMXPT, M_NOWAIT);
838195534Sscottl		if (mode_buf != NULL) {
839195534Sscottl	                scsi_mode_sense(csio,
840195534Sscottl					/*retries*/4,
841195534Sscottl					probedone,
842195534Sscottl					MSG_SIMPLE_Q_TAG,
843195534Sscottl					/*dbd*/FALSE,
844195534Sscottl					SMS_PAGE_CTRL_CURRENT,
845195534Sscottl					SMS_CONTROL_MODE_PAGE,
846195534Sscottl					mode_buf,
847195534Sscottl					mode_buf_len,
848195534Sscottl					SSD_FULL_SIZE,
849195534Sscottl					/*timeout*/60000);
850195534Sscottl			break;
851195534Sscottl		}
852195534Sscottl		xpt_print(periph->path, "Unable to mode sense control page - "
853195534Sscottl		    "malloc failure\n");
854216088Sken		PROBE_SET_ACTION(softc, PROBE_SUPPORTED_VPD_LIST);
855195534Sscottl	}
856195534Sscottl	/* FALLTHROUGH */
857216088Sken	case PROBE_SUPPORTED_VPD_LIST:
858195534Sscottl	{
859216088Sken		struct scsi_vpd_supported_page_list *vpd_list;
860195534Sscottl		struct cam_ed *device;
861195534Sscottl
862216088Sken		vpd_list = NULL;
863195534Sscottl		device = periph->path->device;
864216088Sken
865216088Sken		if ((SCSI_QUIRK(device)->quirks & CAM_QUIRK_NOVPDS) == 0)
866195534Sscottl			vpd_list = malloc(sizeof(*vpd_list), M_CAMXPT,
867195534Sscottl			    M_NOWAIT | M_ZERO);
868195534Sscottl
869195534Sscottl		if (vpd_list != NULL) {
870195534Sscottl			scsi_inquiry(csio,
871195534Sscottl				     /*retries*/4,
872195534Sscottl				     probedone,
873195534Sscottl				     MSG_SIMPLE_Q_TAG,
874195534Sscottl				     (u_int8_t *)vpd_list,
875195534Sscottl				     sizeof(*vpd_list),
876195534Sscottl				     /*evpd*/TRUE,
877195534Sscottl				     SVPD_SUPPORTED_PAGE_LIST,
878195534Sscottl				     SSD_MIN_SIZE,
879195534Sscottl				     /*timeout*/60 * 1000);
880195534Sscottl			break;
881195534Sscottl		}
882195534Sscottl		/*
883195534Sscottl		 * We'll have to do without, let our probedone
884195534Sscottl		 * routine finish up for us.
885195534Sscottl		 */
886195534Sscottl		start_ccb->csio.data_ptr = NULL;
887250025Smav		cam_freeze_devq(periph->path);
888195534Sscottl		probedone(periph, start_ccb);
889195534Sscottl		return;
890195534Sscottl	}
891216088Sken	case PROBE_DEVICE_ID:
892195534Sscottl	{
893216088Sken		struct scsi_vpd_device_id *devid;
894216088Sken
895216088Sken		devid = NULL;
896249937Ssmh		if (scsi_vpd_supported_page(periph, SVPD_DEVICE_ID))
897216088Sken			devid = malloc(SVPD_DEVICE_ID_MAX_SIZE, M_CAMXPT,
898216088Sken			    M_NOWAIT | M_ZERO);
899216088Sken
900216088Sken		if (devid != NULL) {
901216088Sken			scsi_inquiry(csio,
902216088Sken				     /*retries*/4,
903216088Sken				     probedone,
904216088Sken				     MSG_SIMPLE_Q_TAG,
905216088Sken				     (uint8_t *)devid,
906216088Sken				     SVPD_DEVICE_ID_MAX_SIZE,
907216088Sken				     /*evpd*/TRUE,
908216088Sken				     SVPD_DEVICE_ID,
909216088Sken				     SSD_MIN_SIZE,
910216088Sken				     /*timeout*/60 * 1000);
911216088Sken			break;
912216088Sken		}
913216088Sken		/*
914216088Sken		 * We'll have to do without, let our probedone
915216088Sken		 * routine finish up for us.
916216088Sken		 */
917216088Sken		start_ccb->csio.data_ptr = NULL;
918250025Smav		cam_freeze_devq(periph->path);
919216088Sken		probedone(periph, start_ccb);
920216088Sken		return;
921216088Sken	}
922216088Sken	case PROBE_SERIAL_NUM:
923216088Sken	{
924195534Sscottl		struct scsi_vpd_unit_serial_number *serial_buf;
925195534Sscottl		struct cam_ed* device;
926195534Sscottl
927195534Sscottl		serial_buf = NULL;
928195534Sscottl		device = periph->path->device;
929195685Semaste		if (device->serial_num != NULL) {
930195685Semaste			free(device->serial_num, M_CAMXPT);
931195685Semaste			device->serial_num = NULL;
932195685Semaste			device->serial_num_len = 0;
933195685Semaste		}
934195534Sscottl
935249937Ssmh		if (scsi_vpd_supported_page(periph, SVPD_UNIT_SERIAL_NUMBER))
936216088Sken			serial_buf = (struct scsi_vpd_unit_serial_number *)
937216088Sken				malloc(sizeof(*serial_buf), M_CAMXPT,
938216088Sken				    M_NOWAIT|M_ZERO);
939195534Sscottl
940195534Sscottl		if (serial_buf != NULL) {
941195534Sscottl			scsi_inquiry(csio,
942195534Sscottl				     /*retries*/4,
943195534Sscottl				     probedone,
944195534Sscottl				     MSG_SIMPLE_Q_TAG,
945195534Sscottl				     (u_int8_t *)serial_buf,
946195534Sscottl				     sizeof(*serial_buf),
947195534Sscottl				     /*evpd*/TRUE,
948195534Sscottl				     SVPD_UNIT_SERIAL_NUMBER,
949195534Sscottl				     SSD_MIN_SIZE,
950195534Sscottl				     /*timeout*/60 * 1000);
951195534Sscottl			break;
952195534Sscottl		}
953195534Sscottl		/*
954195534Sscottl		 * We'll have to do without, let our probedone
955195534Sscottl		 * routine finish up for us.
956195534Sscottl		 */
957195534Sscottl		start_ccb->csio.data_ptr = NULL;
958250025Smav		cam_freeze_devq(periph->path);
959195534Sscottl		probedone(periph, start_ccb);
960195534Sscottl		return;
961195534Sscottl	}
962195534Sscottl	default:
963236613Smav		panic("probestart: invalid action state 0x%x\n", softc->action);
964195534Sscottl	}
965249466Smav	start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE;
966195534Sscottl	xpt_action(start_ccb);
967195534Sscottl}
968195534Sscottl
969195534Sscottlstatic void
970195534Sscottlproberequestdefaultnegotiation(struct cam_periph *periph)
971195534Sscottl{
972195534Sscottl	struct ccb_trans_settings cts;
973195534Sscottl
974203108Smav	xpt_setup_ccb(&cts.ccb_h, periph->path, CAM_PRIORITY_NONE);
975195534Sscottl	cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
976195534Sscottl	cts.type = CTS_TYPE_USER_SETTINGS;
977195534Sscottl	xpt_action((union ccb *)&cts);
978252382Sscottl	if (cam_ccb_status((union ccb *)&cts) != CAM_REQ_CMP) {
979195534Sscottl		return;
980195534Sscottl	}
981195534Sscottl	cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
982195534Sscottl	cts.type = CTS_TYPE_CURRENT_SETTINGS;
983195534Sscottl	xpt_action((union ccb *)&cts);
984195534Sscottl}
985195534Sscottl
986195534Sscottl/*
987195534Sscottl * Backoff Negotiation Code- only pertinent for SPI devices.
988195534Sscottl */
989195534Sscottlstatic int
990195534Sscottlproberequestbackoff(struct cam_periph *periph, struct cam_ed *device)
991195534Sscottl{
992195534Sscottl	struct ccb_trans_settings cts;
993195534Sscottl	struct ccb_trans_settings_spi *spi;
994195534Sscottl
995195534Sscottl	memset(&cts, 0, sizeof (cts));
996203108Smav	xpt_setup_ccb(&cts.ccb_h, periph->path, CAM_PRIORITY_NONE);
997195534Sscottl	cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
998195534Sscottl	cts.type = CTS_TYPE_CURRENT_SETTINGS;
999195534Sscottl	xpt_action((union ccb *)&cts);
1000252382Sscottl	if (cam_ccb_status((union ccb *)&cts) != CAM_REQ_CMP) {
1001195534Sscottl		if (bootverbose) {
1002195534Sscottl			xpt_print(periph->path,
1003195534Sscottl			    "failed to get current device settings\n");
1004195534Sscottl		}
1005195534Sscottl		return (0);
1006195534Sscottl	}
1007195534Sscottl	if (cts.transport != XPORT_SPI) {
1008195534Sscottl		if (bootverbose) {
1009195534Sscottl			xpt_print(periph->path, "not SPI transport\n");
1010195534Sscottl		}
1011195534Sscottl		return (0);
1012195534Sscottl	}
1013195534Sscottl	spi = &cts.xport_specific.spi;
1014195534Sscottl
1015195534Sscottl	/*
1016195534Sscottl	 * We cannot renegotiate sync rate if we don't have one.
1017195534Sscottl	 */
1018195534Sscottl	if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0) {
1019195534Sscottl		if (bootverbose) {
1020195534Sscottl			xpt_print(periph->path, "no sync rate known\n");
1021195534Sscottl		}
1022195534Sscottl		return (0);
1023195534Sscottl	}
1024195534Sscottl
1025195534Sscottl	/*
1026195534Sscottl	 * We'll assert that we don't have to touch PPR options- the
1027195534Sscottl	 * SIM will see what we do with period and offset and adjust
1028195534Sscottl	 * the PPR options as appropriate.
1029195534Sscottl	 */
1030195534Sscottl
1031195534Sscottl	/*
1032195534Sscottl	 * A sync rate with unknown or zero offset is nonsensical.
1033195534Sscottl	 * A sync period of zero means Async.
1034195534Sscottl	 */
1035195534Sscottl	if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0
1036195534Sscottl	 || spi->sync_offset == 0 || spi->sync_period == 0) {
1037195534Sscottl		if (bootverbose) {
1038195534Sscottl			xpt_print(periph->path, "no sync rate available\n");
1039195534Sscottl		}
1040195534Sscottl		return (0);
1041195534Sscottl	}
1042195534Sscottl
1043195534Sscottl	if (device->flags & CAM_DEV_DV_HIT_BOTTOM) {
1044236613Smav		CAM_DEBUG(periph->path, CAM_DEBUG_PROBE,
1045195534Sscottl		    ("hit async: giving up on DV\n"));
1046195534Sscottl		return (0);
1047195534Sscottl	}
1048195534Sscottl
1049195534Sscottl
1050195534Sscottl	/*
1051195534Sscottl	 * Jump sync_period up by one, but stop at 5MHz and fall back to Async.
1052195534Sscottl	 * We don't try to remember 'last' settings to see if the SIM actually
1053195534Sscottl	 * gets into the speed we want to set. We check on the SIM telling
1054195534Sscottl	 * us that a requested speed is bad, but otherwise don't try and
1055195534Sscottl	 * check the speed due to the asynchronous and handshake nature
1056195534Sscottl	 * of speed setting.
1057195534Sscottl	 */
1058195534Sscottl	spi->valid = CTS_SPI_VALID_SYNC_RATE | CTS_SPI_VALID_SYNC_OFFSET;
1059195534Sscottl	for (;;) {
1060195534Sscottl		spi->sync_period++;
1061195534Sscottl		if (spi->sync_period >= 0xf) {
1062195534Sscottl			spi->sync_period = 0;
1063195534Sscottl			spi->sync_offset = 0;
1064236613Smav			CAM_DEBUG(periph->path, CAM_DEBUG_PROBE,
1065195534Sscottl			    ("setting to async for DV\n"));
1066195534Sscottl			/*
1067195534Sscottl			 * Once we hit async, we don't want to try
1068195534Sscottl			 * any more settings.
1069195534Sscottl			 */
1070195534Sscottl			device->flags |= CAM_DEV_DV_HIT_BOTTOM;
1071195534Sscottl		} else if (bootverbose) {
1072236613Smav			CAM_DEBUG(periph->path, CAM_DEBUG_PROBE,
1073195534Sscottl			    ("DV: period 0x%x\n", spi->sync_period));
1074195534Sscottl			printf("setting period to 0x%x\n", spi->sync_period);
1075195534Sscottl		}
1076195534Sscottl		cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
1077195534Sscottl		cts.type = CTS_TYPE_CURRENT_SETTINGS;
1078195534Sscottl		xpt_action((union ccb *)&cts);
1079252382Sscottl		if (cam_ccb_status((union ccb *)&cts) != CAM_REQ_CMP) {
1080195534Sscottl			break;
1081195534Sscottl		}
1082236613Smav		CAM_DEBUG(periph->path, CAM_DEBUG_PROBE,
1083195534Sscottl		    ("DV: failed to set period 0x%x\n", spi->sync_period));
1084195534Sscottl		if (spi->sync_period == 0) {
1085195534Sscottl			return (0);
1086195534Sscottl		}
1087195534Sscottl	}
1088195534Sscottl	return (1);
1089195534Sscottl}
1090195534Sscottl
1091216088Sken#define CCB_COMPLETED_OK(ccb) (((ccb).status & CAM_STATUS_MASK) == CAM_REQ_CMP)
1092216088Sken
1093195534Sscottlstatic void
1094195534Sscottlprobedone(struct cam_periph *periph, union ccb *done_ccb)
1095195534Sscottl{
1096195534Sscottl	probe_softc *softc;
1097195534Sscottl	struct cam_path *path;
1098195534Sscottl	u_int32_t  priority;
1099195534Sscottl
1100195534Sscottl	CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probedone\n"));
1101195534Sscottl
1102195534Sscottl	softc = (probe_softc *)periph->softc;
1103195534Sscottl	path = done_ccb->ccb_h.path;
1104195534Sscottl	priority = done_ccb->ccb_h.pinfo.priority;
1105195534Sscottl
1106195534Sscottl	switch (softc->action) {
1107195534Sscottl	case PROBE_TUR:
1108195534Sscottl	{
1109252382Sscottl		if (cam_ccb_status(done_ccb) != CAM_REQ_CMP) {
1110195534Sscottl
1111195534Sscottl			if (cam_periph_error(done_ccb, 0,
1112249466Smav					     SF_NO_PRINT, NULL) == ERESTART) {
1113249466Smavout:
1114249466Smav				/* Drop freeze taken due to CAM_DEV_QFREEZE */
1115249466Smav				cam_release_devq(path, 0, 0, 0, FALSE);
1116195534Sscottl				return;
1117249466Smav			}
1118195534Sscottl			else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
1119195534Sscottl				/* Don't wedge the queue */
1120195534Sscottl				xpt_release_devq(done_ccb->ccb_h.path,
1121195534Sscottl						 /*count*/1,
1122195534Sscottl						 /*run_queue*/TRUE);
1123195534Sscottl		}
1124195534Sscottl		PROBE_SET_ACTION(softc, PROBE_INQUIRY);
1125195534Sscottl		xpt_release_ccb(done_ccb);
1126195534Sscottl		xpt_schedule(periph, priority);
1127249466Smav		goto out;
1128195534Sscottl	}
1129195534Sscottl	case PROBE_INQUIRY:
1130195534Sscottl	case PROBE_FULL_INQUIRY:
1131195534Sscottl	{
1132252382Sscottl		if (cam_ccb_status(done_ccb) == CAM_REQ_CMP) {
1133195534Sscottl			struct scsi_inquiry_data *inq_buf;
1134195534Sscottl			u_int8_t periph_qual;
1135195534Sscottl
1136195534Sscottl			path->device->flags |= CAM_DEV_INQUIRY_DATA_VALID;
1137195534Sscottl			inq_buf = &path->device->inq_data;
1138195534Sscottl
1139195534Sscottl			periph_qual = SID_QUAL(inq_buf);
1140195534Sscottl
1141208911Smjacob			if (periph_qual == SID_QUAL_LU_CONNECTED) {
1142195534Sscottl				u_int8_t len;
1143195534Sscottl
1144195534Sscottl				/*
1145195534Sscottl				 * We conservatively request only
1146195534Sscottl				 * SHORT_INQUIRY_LEN bytes of inquiry
1147195534Sscottl				 * information during our first try
1148195534Sscottl				 * at sending an INQUIRY. If the device
1149195534Sscottl				 * has more information to give,
1150195534Sscottl				 * perform a second request specifying
1151195534Sscottl				 * the amount of information the device
1152195534Sscottl				 * is willing to give.
1153195534Sscottl				 */
1154195534Sscottl				len = inq_buf->additional_length
1155195534Sscottl				    + offsetof(struct scsi_inquiry_data,
1156195534Sscottl                                               additional_length) + 1;
1157195534Sscottl				if (softc->action == PROBE_INQUIRY
1158195534Sscottl				    && len > SHORT_INQUIRY_LENGTH) {
1159195534Sscottl					PROBE_SET_ACTION(softc, PROBE_FULL_INQUIRY);
1160195534Sscottl					xpt_release_ccb(done_ccb);
1161195534Sscottl					xpt_schedule(periph, priority);
1162249466Smav					goto out;
1163195534Sscottl				}
1164195534Sscottl
1165195534Sscottl				scsi_find_quirk(path->device);
1166195534Sscottl
1167195534Sscottl				scsi_devise_transport(path);
1168208911Smjacob
1169208911Smjacob				if (path->device->lun_id == 0 &&
1170208911Smjacob				    SID_ANSI_REV(inq_buf) > SCSI_REV_SPC2 &&
1171208911Smjacob				    (SCSI_QUIRK(path->device)->quirks &
1172208911Smjacob				     CAM_QUIRK_NORPTLUNS) == 0) {
1173208911Smjacob					PROBE_SET_ACTION(softc,
1174208911Smjacob					    PROBE_REPORT_LUNS);
1175208911Smjacob					/*
1176208911Smjacob					 * Start with room for *one* lun.
1177208911Smjacob					 */
1178208911Smjacob					periph->path->target->rpl_size = 16;
1179208911Smjacob				} else if (INQ_DATA_TQ_ENABLED(inq_buf))
1180208911Smjacob					PROBE_SET_ACTION(softc,
1181208911Smjacob					    PROBE_MODE_SENSE);
1182195534Sscottl				else
1183208911Smjacob					PROBE_SET_ACTION(softc,
1184216088Sken					    PROBE_SUPPORTED_VPD_LIST);
1185195534Sscottl
1186198748Smav				if (path->device->flags & CAM_DEV_UNCONFIGURED) {
1187198748Smav					path->device->flags &= ~CAM_DEV_UNCONFIGURED;
1188198748Smav					xpt_acquire_device(path->device);
1189198748Smav				}
1190195534Sscottl				xpt_release_ccb(done_ccb);
1191195534Sscottl				xpt_schedule(periph, priority);
1192249466Smav				goto out;
1193208911Smjacob			} else if (path->device->lun_id == 0 &&
1194208911Smjacob			    SID_ANSI_REV(inq_buf) > SCSI_REV_SPC2 &&
1195208911Smjacob			    (SCSI_QUIRK(path->device)->quirks &
1196208911Smjacob			     CAM_QUIRK_NORPTLUNS) == 0) {
1197208911Smjacob				if (path->device->flags &
1198208911Smjacob				    CAM_DEV_UNCONFIGURED) {
1199208911Smjacob					path->device->flags &=
1200208911Smjacob					    ~CAM_DEV_UNCONFIGURED;
1201208911Smjacob					xpt_acquire_device(path->device);
1202208911Smjacob				}
1203208911Smjacob				PROBE_SET_ACTION(softc, PROBE_REPORT_LUNS);
1204208911Smjacob				periph->path->target->rpl_size = 16;
1205208911Smjacob				xpt_release_ccb(done_ccb);
1206208911Smjacob				xpt_schedule(periph, priority);
1207249466Smav				goto out;
1208195534Sscottl			}
1209195534Sscottl		} else if (cam_periph_error(done_ccb, 0,
1210195534Sscottl					    done_ccb->ccb_h.target_lun > 0
1211195534Sscottl					    ? SF_RETRY_UA|SF_QUIET_IR
1212195534Sscottl					    : SF_RETRY_UA,
1213195534Sscottl					    &softc->saved_ccb) == ERESTART) {
1214249466Smav			goto out;
1215195534Sscottl		} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
1216195534Sscottl			/* Don't wedge the queue */
1217195534Sscottl			xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
1218195534Sscottl					 /*run_queue*/TRUE);
1219195534Sscottl		}
1220195534Sscottl		/*
1221195534Sscottl		 * If we get to this point, we got an error status back
1222195534Sscottl		 * from the inquiry and the error status doesn't require
1223195534Sscottl		 * automatically retrying the command.  Therefore, the
1224195534Sscottl		 * inquiry failed.  If we had inquiry information before
1225195534Sscottl		 * for this device, but this latest inquiry command failed,
1226195534Sscottl		 * the device has probably gone away.  If this device isn't
1227195534Sscottl		 * already marked unconfigured, notify the peripheral
1228195534Sscottl		 * drivers that this device is no more.
1229195534Sscottl		 */
1230195534Sscottl		if ((path->device->flags & CAM_DEV_UNCONFIGURED) == 0)
1231195534Sscottl			/* Send the async notification. */
1232195534Sscottl			xpt_async(AC_LOST_DEVICE, path, NULL);
1233236613Smav		PROBE_SET_ACTION(softc, PROBE_INVALID);
1234195534Sscottl
1235195534Sscottl		xpt_release_ccb(done_ccb);
1236195534Sscottl		break;
1237195534Sscottl	}
1238208911Smjacob	case PROBE_REPORT_LUNS:
1239208911Smjacob	{
1240208911Smjacob		struct ccb_scsiio *csio;
1241208911Smjacob		struct scsi_report_luns_data *lp;
1242208911Smjacob		u_int nlun, maxlun;
1243208911Smjacob
1244208911Smjacob		csio = &done_ccb->csio;
1245208911Smjacob
1246208911Smjacob		lp = (struct scsi_report_luns_data *)csio->data_ptr;
1247208911Smjacob		nlun = scsi_4btoul(lp->length) / 8;
1248208911Smjacob		maxlun = (csio->dxfer_len / 8) - 1;
1249208911Smjacob
1250252382Sscottl		if (cam_ccb_status(done_ccb) != CAM_REQ_CMP) {
1251208911Smjacob			if (cam_periph_error(done_ccb, 0,
1252208911Smjacob			    done_ccb->ccb_h.target_lun > 0 ?
1253208911Smjacob			    SF_RETRY_UA|SF_QUIET_IR : SF_RETRY_UA,
1254208911Smjacob			    &softc->saved_ccb) == ERESTART) {
1255249466Smav				goto out;
1256208911Smjacob			}
1257208911Smjacob			if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
1258208911Smjacob				xpt_release_devq(done_ccb->ccb_h.path, 1,
1259208911Smjacob				    TRUE);
1260208911Smjacob			}
1261208911Smjacob			free(lp, M_CAMXPT);
1262208911Smjacob			lp = NULL;
1263208911Smjacob		} else if (nlun > maxlun) {
1264208911Smjacob			/*
1265208911Smjacob			 * Reallocate and retry to cover all luns
1266208911Smjacob			 */
1267236613Smav			CAM_DEBUG(path, CAM_DEBUG_PROBE,
1268236613Smav			    ("Probe: reallocating REPORT_LUNS for %u luns\n",
1269236613Smav			     nlun));
1270208911Smjacob			free(lp, M_CAMXPT);
1271208911Smjacob			path->target->rpl_size = (nlun << 3) + 8;
1272208911Smjacob			xpt_release_ccb(done_ccb);
1273208911Smjacob			xpt_schedule(periph, priority);
1274249466Smav			goto out;
1275208911Smjacob		} else if (nlun == 0) {
1276208911Smjacob			/*
1277208911Smjacob			 * If there don't appear to be any luns, bail.
1278208911Smjacob			 */
1279208911Smjacob			free(lp, M_CAMXPT);
1280208911Smjacob			lp = NULL;
1281208911Smjacob		} else if (probe_strange_rpl_data(lp, maxlun)) {
1282208911Smjacob			/*
1283208911Smjacob			 * If we can't understand the lun format
1284208911Smjacob			 * of any entry, bail.
1285208911Smjacob			 */
1286208911Smjacob			free(lp, M_CAMXPT);
1287208911Smjacob			lp = NULL;
1288208911Smjacob		} else {
1289208911Smjacob			lun_id_t lun;
1290208911Smjacob			int idx;
1291208911Smjacob
1292236613Smav			CAM_DEBUG(path, CAM_DEBUG_PROBE,
1293236613Smav			   ("Probe: %u lun(s) reported\n", nlun));
1294208911Smjacob
1295208911Smjacob			CAM_GET_SIMPLE_LUN(lp, 0, lun);
1296208911Smjacob			/*
1297208911Smjacob			 * If the first lun is not lun 0, then either there
1298208911Smjacob			 * is no lun 0 in the list, or the list is unsorted.
1299208911Smjacob			 */
1300208911Smjacob			if (lun != 0) {
1301208911Smjacob				for (idx = 0; idx < nlun; idx++) {
1302208911Smjacob					CAM_GET_SIMPLE_LUN(lp, idx, lun);
1303208911Smjacob					if (lun == 0) {
1304208911Smjacob						break;
1305208911Smjacob					}
1306208911Smjacob				}
1307208911Smjacob				if (idx != nlun) {
1308208911Smjacob					uint8_t tlun[8];
1309208911Smjacob					memcpy(tlun,
1310208911Smjacob					    lp->luns[0].lundata, 8);
1311208911Smjacob					memcpy(lp->luns[0].lundata,
1312208911Smjacob					    lp->luns[idx].lundata, 8);
1313208911Smjacob					memcpy(lp->luns[idx].lundata,
1314208911Smjacob					    tlun, 8);
1315236613Smav					CAM_DEBUG(path, CAM_DEBUG_PROBE,
1316236613Smav					    ("lun 0 in position %u\n", idx));
1317208911Smjacob				} else {
1318208911Smjacob					/*
1319208911Smjacob					 * There is no lun 0 in our list. Destroy
1320208911Smjacob					 * the validity of the inquiry data so we
1321208911Smjacob					 * bail here and now.
1322208911Smjacob					 */
1323208911Smjacob					path->device->flags &=
1324208911Smjacob					    ~CAM_DEV_INQUIRY_DATA_VALID;
1325208911Smjacob				}
1326208911Smjacob			}
1327208911Smjacob			/*
1328208911Smjacob			 * If we have an old lun list, We can either
1329208911Smjacob			 * retest luns that appear to have been dropped,
1330208911Smjacob			 * or just nuke them.  We'll opt for the latter.
1331208911Smjacob			 * This function will also install the new list
1332208911Smjacob			 * in the target structure.
1333208911Smjacob			 */
1334208911Smjacob			probe_purge_old(path, lp);
1335208911Smjacob			lp = NULL;
1336208911Smjacob		}
1337208911Smjacob		if (path->device->flags & CAM_DEV_INQUIRY_DATA_VALID) {
1338208911Smjacob			struct scsi_inquiry_data *inq_buf;
1339208911Smjacob			inq_buf = &path->device->inq_data;
1340208911Smjacob			if (INQ_DATA_TQ_ENABLED(inq_buf))
1341208911Smjacob				PROBE_SET_ACTION(softc, PROBE_MODE_SENSE);
1342208911Smjacob			else
1343216088Sken				PROBE_SET_ACTION(softc,
1344216088Sken				    PROBE_SUPPORTED_VPD_LIST);
1345208911Smjacob			xpt_release_ccb(done_ccb);
1346208911Smjacob			xpt_schedule(periph, priority);
1347249466Smav			goto out;
1348208911Smjacob		}
1349208911Smjacob		if (lp) {
1350208911Smjacob			free(lp, M_CAMXPT);
1351208911Smjacob		}
1352208911Smjacob		break;
1353208911Smjacob	}
1354195534Sscottl	case PROBE_MODE_SENSE:
1355195534Sscottl	{
1356195534Sscottl		struct ccb_scsiio *csio;
1357195534Sscottl		struct scsi_mode_header_6 *mode_hdr;
1358195534Sscottl
1359195534Sscottl		csio = &done_ccb->csio;
1360195534Sscottl		mode_hdr = (struct scsi_mode_header_6 *)csio->data_ptr;
1361252382Sscottl		if (cam_ccb_status(done_ccb) == CAM_REQ_CMP) {
1362195534Sscottl			struct scsi_control_page *page;
1363195534Sscottl			u_int8_t *offset;
1364195534Sscottl
1365195534Sscottl			offset = ((u_int8_t *)&mode_hdr[1])
1366195534Sscottl			    + mode_hdr->blk_desc_len;
1367195534Sscottl			page = (struct scsi_control_page *)offset;
1368195534Sscottl			path->device->queue_flags = page->queue_flags;
1369195534Sscottl		} else if (cam_periph_error(done_ccb, 0,
1370195534Sscottl					    SF_RETRY_UA|SF_NO_PRINT,
1371195534Sscottl					    &softc->saved_ccb) == ERESTART) {
1372249466Smav			goto out;
1373195534Sscottl		} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
1374195534Sscottl			/* Don't wedge the queue */
1375195534Sscottl			xpt_release_devq(done_ccb->ccb_h.path,
1376195534Sscottl					 /*count*/1, /*run_queue*/TRUE);
1377195534Sscottl		}
1378195534Sscottl		xpt_release_ccb(done_ccb);
1379195534Sscottl		free(mode_hdr, M_CAMXPT);
1380216088Sken		PROBE_SET_ACTION(softc, PROBE_SUPPORTED_VPD_LIST);
1381195534Sscottl		xpt_schedule(periph, priority);
1382249466Smav		goto out;
1383195534Sscottl	}
1384216088Sken	case PROBE_SUPPORTED_VPD_LIST:
1385195534Sscottl	{
1386195534Sscottl		struct ccb_scsiio *csio;
1387195534Sscottl		struct scsi_vpd_supported_page_list *page_list;
1388195534Sscottl
1389195534Sscottl		csio = &done_ccb->csio;
1390195534Sscottl		page_list =
1391195534Sscottl		    (struct scsi_vpd_supported_page_list *)csio->data_ptr;
1392195534Sscottl
1393216088Sken		if (path->device->supported_vpds != NULL) {
1394216088Sken			free(path->device->supported_vpds, M_CAMXPT);
1395216088Sken			path->device->supported_vpds = NULL;
1396216088Sken			path->device->supported_vpds_len = 0;
1397216088Sken		}
1398216088Sken
1399195534Sscottl		if (page_list == NULL) {
1400195534Sscottl			/*
1401195534Sscottl			 * Don't process the command as it was never sent
1402195534Sscottl			 */
1403216088Sken		} else if (CCB_COMPLETED_OK(csio->ccb_h)) {
1404216088Sken			/* Got vpd list */
1405216088Sken			path->device->supported_vpds_len = page_list->length +
1406216088Sken			    SVPD_SUPPORTED_PAGES_HDR_LEN;
1407216088Sken			path->device->supported_vpds = (uint8_t *)page_list;
1408216088Sken			xpt_release_ccb(done_ccb);
1409216088Sken			PROBE_SET_ACTION(softc, PROBE_DEVICE_ID);
1410216088Sken			xpt_schedule(periph, priority);
1411249466Smav			goto out;
1412195534Sscottl		} else if (cam_periph_error(done_ccb, 0,
1413195534Sscottl					    SF_RETRY_UA|SF_NO_PRINT,
1414195534Sscottl					    &softc->saved_ccb) == ERESTART) {
1415249466Smav			goto out;
1416195534Sscottl		} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
1417195534Sscottl			/* Don't wedge the queue */
1418195534Sscottl			xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
1419195534Sscottl					 /*run_queue*/TRUE);
1420195534Sscottl		}
1421195534Sscottl
1422216088Sken		if (page_list)
1423195685Semaste			free(page_list, M_CAMXPT);
1424216088Sken		/* No VPDs available, skip to device check. */
1425216088Sken		csio->data_ptr = NULL;
1426216088Sken		goto probe_device_check;
1427216088Sken	}
1428216088Sken	case PROBE_DEVICE_ID:
1429216088Sken	{
1430216088Sken		struct scsi_vpd_device_id *devid;
1431216088Sken		struct ccb_scsiio *csio;
1432216088Sken		uint32_t length = 0;
1433195534Sscottl
1434216088Sken		csio = &done_ccb->csio;
1435216088Sken		devid = (struct scsi_vpd_device_id *)csio->data_ptr;
1436216088Sken
1437216088Sken		/* Clean up from previous instance of this device */
1438216088Sken		if (path->device->device_id != NULL) {
1439216088Sken			path->device->device_id_len = 0;
1440216088Sken			free(path->device->device_id, M_CAMXPT);
1441216088Sken			path->device->device_id = NULL;
1442216088Sken		}
1443216088Sken
1444216088Sken		if (devid == NULL) {
1445216088Sken			/* Don't process the command as it was never sent */
1446216088Sken		} else if (CCB_COMPLETED_OK(csio->ccb_h)) {
1447216088Sken			length = scsi_2btoul(devid->length);
1448216088Sken			if (length != 0) {
1449216088Sken				/*
1450216088Sken				 * NB: device_id_len is actual response
1451216088Sken				 * size, not buffer size.
1452216088Sken				 */
1453216088Sken				path->device->device_id_len = length +
1454216088Sken				    SVPD_DEVICE_ID_HDR_LEN;
1455216088Sken				path->device->device_id = (uint8_t *)devid;
1456216088Sken			}
1457216088Sken		} else if (cam_periph_error(done_ccb, 0,
1458223081Sgibbs					    SF_RETRY_UA,
1459216088Sken					    &softc->saved_ccb) == ERESTART) {
1460249466Smav			goto out;
1461216088Sken		} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
1462216088Sken			/* Don't wedge the queue */
1463216088Sken			xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
1464216088Sken					 /*run_queue*/TRUE);
1465195534Sscottl		}
1466195534Sscottl
1467216088Sken		/* Free the device id space if we don't use it */
1468216088Sken		if (devid && length == 0)
1469216088Sken			free(devid, M_CAMXPT);
1470216088Sken		xpt_release_ccb(done_ccb);
1471216088Sken		PROBE_SET_ACTION(softc, PROBE_SERIAL_NUM);
1472216088Sken		xpt_schedule(periph, priority);
1473249466Smav		goto out;
1474195534Sscottl	}
1475195534Sscottl
1476216088Skenprobe_device_check:
1477216088Sken	case PROBE_SERIAL_NUM:
1478195534Sscottl	{
1479195534Sscottl		struct ccb_scsiio *csio;
1480195534Sscottl		struct scsi_vpd_unit_serial_number *serial_buf;
1481195534Sscottl		u_int32_t  priority;
1482195534Sscottl		int changed;
1483195534Sscottl		int have_serialnum;
1484195534Sscottl
1485195534Sscottl		changed = 1;
1486195534Sscottl		have_serialnum = 0;
1487195534Sscottl		csio = &done_ccb->csio;
1488195534Sscottl		priority = done_ccb->ccb_h.pinfo.priority;
1489195534Sscottl		serial_buf =
1490195534Sscottl		    (struct scsi_vpd_unit_serial_number *)csio->data_ptr;
1491195534Sscottl
1492195534Sscottl		if (serial_buf == NULL) {
1493195534Sscottl			/*
1494195534Sscottl			 * Don't process the command as it was never sent
1495195534Sscottl			 */
1496252382Sscottl		} else if (cam_ccb_status(done_ccb) == CAM_REQ_CMP
1497195534Sscottl			&& (serial_buf->length > 0)) {
1498195534Sscottl
1499195534Sscottl			have_serialnum = 1;
1500195534Sscottl			path->device->serial_num =
1501195534Sscottl				(u_int8_t *)malloc((serial_buf->length + 1),
1502195534Sscottl						   M_CAMXPT, M_NOWAIT);
1503195534Sscottl			if (path->device->serial_num != NULL) {
1504223081Sgibbs				memcpy(path->device->serial_num,
1505223081Sgibbs				       serial_buf->serial_num,
1506223081Sgibbs				       serial_buf->length);
1507195534Sscottl				path->device->serial_num_len =
1508195534Sscottl				    serial_buf->length;
1509195534Sscottl				path->device->serial_num[serial_buf->length]
1510195534Sscottl				    = '\0';
1511195534Sscottl			}
1512195534Sscottl		} else if (cam_periph_error(done_ccb, 0,
1513195534Sscottl					    SF_RETRY_UA|SF_NO_PRINT,
1514195534Sscottl					    &softc->saved_ccb) == ERESTART) {
1515249466Smav			goto out;
1516195534Sscottl		} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
1517195534Sscottl			/* Don't wedge the queue */
1518195534Sscottl			xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
1519195534Sscottl					 /*run_queue*/TRUE);
1520195534Sscottl		}
1521195534Sscottl
1522195534Sscottl		/*
1523195534Sscottl		 * Let's see if we have seen this device before.
1524195534Sscottl		 */
1525195534Sscottl		if ((softc->flags & PROBE_INQUIRY_CKSUM) != 0) {
1526195534Sscottl			MD5_CTX context;
1527195534Sscottl			u_int8_t digest[16];
1528195534Sscottl
1529195534Sscottl			MD5Init(&context);
1530195534Sscottl
1531195534Sscottl			MD5Update(&context,
1532195534Sscottl				  (unsigned char *)&path->device->inq_data,
1533195534Sscottl				  sizeof(struct scsi_inquiry_data));
1534195534Sscottl
1535195534Sscottl			if (have_serialnum)
1536195534Sscottl				MD5Update(&context, serial_buf->serial_num,
1537195534Sscottl					  serial_buf->length);
1538195534Sscottl
1539195534Sscottl			MD5Final(digest, &context);
1540195534Sscottl			if (bcmp(softc->digest, digest, 16) == 0)
1541195534Sscottl				changed = 0;
1542195534Sscottl
1543195534Sscottl			/*
1544195534Sscottl			 * XXX Do we need to do a TUR in order to ensure
1545195534Sscottl			 *     that the device really hasn't changed???
1546195534Sscottl			 */
1547195534Sscottl			if ((changed != 0)
1548195534Sscottl			 && ((softc->flags & PROBE_NO_ANNOUNCE) == 0))
1549195534Sscottl				xpt_async(AC_LOST_DEVICE, path, NULL);
1550195534Sscottl		}
1551195534Sscottl		if (serial_buf != NULL)
1552195534Sscottl			free(serial_buf, M_CAMXPT);
1553195534Sscottl
1554195534Sscottl		if (changed != 0) {
1555195534Sscottl			/*
1556195534Sscottl			 * Now that we have all the necessary
1557195534Sscottl			 * information to safely perform transfer
1558195534Sscottl			 * negotiations... Controllers don't perform
1559195534Sscottl			 * any negotiation or tagged queuing until
1560195534Sscottl			 * after the first XPT_SET_TRAN_SETTINGS ccb is
1561195534Sscottl			 * received.  So, on a new device, just retrieve
1562195534Sscottl			 * the user settings, and set them as the current
1563195534Sscottl			 * settings to set the device up.
1564195534Sscottl			 */
1565195534Sscottl			proberequestdefaultnegotiation(periph);
1566195534Sscottl			xpt_release_ccb(done_ccb);
1567195534Sscottl
1568195534Sscottl			/*
1569195534Sscottl			 * Perform a TUR to allow the controller to
1570195534Sscottl			 * perform any necessary transfer negotiation.
1571195534Sscottl			 */
1572195534Sscottl			PROBE_SET_ACTION(softc, PROBE_TUR_FOR_NEGOTIATION);
1573195534Sscottl			xpt_schedule(periph, priority);
1574249466Smav			goto out;
1575195534Sscottl		}
1576195534Sscottl		xpt_release_ccb(done_ccb);
1577195534Sscottl		break;
1578195534Sscottl	}
1579195534Sscottl	case PROBE_TUR_FOR_NEGOTIATION:
1580236814Smav	case PROBE_DV_EXIT:
1581252382Sscottl		if (cam_ccb_status(done_ccb) != CAM_REQ_CMP) {
1582236814Smav			cam_periph_error(done_ccb, 0,
1583236814Smav			    SF_NO_PRINT | SF_NO_RECOVERY | SF_NO_RETRY, NULL);
1584195534Sscottl		}
1585195534Sscottl		if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
1586195534Sscottl			/* Don't wedge the queue */
1587195534Sscottl			xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
1588195534Sscottl					 /*run_queue*/TRUE);
1589195534Sscottl		}
1590195534Sscottl		/*
1591195534Sscottl		 * Do Domain Validation for lun 0 on devices that claim
1592195534Sscottl		 * to support Synchronous Transfer modes.
1593195534Sscottl		 */
1594195534Sscottl	 	if (softc->action == PROBE_TUR_FOR_NEGOTIATION
1595195534Sscottl		 && done_ccb->ccb_h.target_lun == 0
1596195534Sscottl		 && (path->device->inq_data.flags & SID_Sync) != 0
1597195534Sscottl                 && (path->device->flags & CAM_DEV_IN_DV) == 0) {
1598236613Smav			CAM_DEBUG(periph->path, CAM_DEBUG_PROBE,
1599195534Sscottl			    ("Begin Domain Validation\n"));
1600195534Sscottl			path->device->flags |= CAM_DEV_IN_DV;
1601195534Sscottl			xpt_release_ccb(done_ccb);
1602195534Sscottl			PROBE_SET_ACTION(softc, PROBE_INQUIRY_BASIC_DV1);
1603195534Sscottl			xpt_schedule(periph, priority);
1604249466Smav			goto out;
1605195534Sscottl		}
1606195534Sscottl		if (softc->action == PROBE_DV_EXIT) {
1607236613Smav			CAM_DEBUG(periph->path, CAM_DEBUG_PROBE,
1608195534Sscottl			    ("Leave Domain Validation\n"));
1609195534Sscottl		}
1610198748Smav		if (path->device->flags & CAM_DEV_UNCONFIGURED) {
1611198748Smav			path->device->flags &= ~CAM_DEV_UNCONFIGURED;
1612198748Smav			xpt_acquire_device(path->device);
1613198748Smav		}
1614195534Sscottl		path->device->flags &=
1615198748Smav		    ~(CAM_DEV_IN_DV|CAM_DEV_DV_HIT_BOTTOM);
1616195534Sscottl		if ((softc->flags & PROBE_NO_ANNOUNCE) == 0) {
1617195534Sscottl			/* Inform the XPT that a new device has been found */
1618195534Sscottl			done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
1619195534Sscottl			xpt_action(done_ccb);
1620195534Sscottl			xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path,
1621195534Sscottl				  done_ccb);
1622195534Sscottl		}
1623236613Smav		PROBE_SET_ACTION(softc, PROBE_DONE);
1624195534Sscottl		xpt_release_ccb(done_ccb);
1625195534Sscottl		break;
1626195534Sscottl	case PROBE_INQUIRY_BASIC_DV1:
1627195534Sscottl	case PROBE_INQUIRY_BASIC_DV2:
1628195534Sscottl	{
1629195534Sscottl		struct scsi_inquiry_data *nbuf;
1630195534Sscottl		struct ccb_scsiio *csio;
1631195534Sscottl
1632252382Sscottl		if (cam_ccb_status(done_ccb) != CAM_REQ_CMP) {
1633236814Smav			cam_periph_error(done_ccb, 0,
1634236814Smav			    SF_NO_PRINT | SF_NO_RECOVERY | SF_NO_RETRY, NULL);
1635236814Smav		}
1636195534Sscottl		if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
1637195534Sscottl			/* Don't wedge the queue */
1638195534Sscottl			xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
1639195534Sscottl					 /*run_queue*/TRUE);
1640195534Sscottl		}
1641195534Sscottl		csio = &done_ccb->csio;
1642195534Sscottl		nbuf = (struct scsi_inquiry_data *)csio->data_ptr;
1643195534Sscottl		if (bcmp(nbuf, &path->device->inq_data, SHORT_INQUIRY_LENGTH)) {
1644195534Sscottl			xpt_print(path,
1645195534Sscottl			    "inquiry data fails comparison at DV%d step\n",
1646195534Sscottl			    softc->action == PROBE_INQUIRY_BASIC_DV1 ? 1 : 2);
1647195534Sscottl			if (proberequestbackoff(periph, path->device)) {
1648195534Sscottl				path->device->flags &= ~CAM_DEV_IN_DV;
1649195534Sscottl				PROBE_SET_ACTION(softc, PROBE_TUR_FOR_NEGOTIATION);
1650195534Sscottl			} else {
1651195534Sscottl				/* give up */
1652195534Sscottl				PROBE_SET_ACTION(softc, PROBE_DV_EXIT);
1653195534Sscottl			}
1654195534Sscottl			free(nbuf, M_CAMXPT);
1655195534Sscottl			xpt_release_ccb(done_ccb);
1656195534Sscottl			xpt_schedule(periph, priority);
1657249466Smav			goto out;
1658195534Sscottl		}
1659195534Sscottl		free(nbuf, M_CAMXPT);
1660195534Sscottl		if (softc->action == PROBE_INQUIRY_BASIC_DV1) {
1661195534Sscottl			PROBE_SET_ACTION(softc, PROBE_INQUIRY_BASIC_DV2);
1662195534Sscottl			xpt_release_ccb(done_ccb);
1663195534Sscottl			xpt_schedule(periph, priority);
1664249466Smav			goto out;
1665195534Sscottl		}
1666195534Sscottl		if (softc->action == PROBE_INQUIRY_BASIC_DV2) {
1667236613Smav			CAM_DEBUG(periph->path, CAM_DEBUG_PROBE,
1668195534Sscottl			    ("Leave Domain Validation Successfully\n"));
1669195534Sscottl		}
1670198748Smav		if (path->device->flags & CAM_DEV_UNCONFIGURED) {
1671198748Smav			path->device->flags &= ~CAM_DEV_UNCONFIGURED;
1672198748Smav			xpt_acquire_device(path->device);
1673198748Smav		}
1674195534Sscottl		path->device->flags &=
1675198748Smav		    ~(CAM_DEV_IN_DV|CAM_DEV_DV_HIT_BOTTOM);
1676195534Sscottl		if ((softc->flags & PROBE_NO_ANNOUNCE) == 0) {
1677195534Sscottl			/* Inform the XPT that a new device has been found */
1678195534Sscottl			done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
1679195534Sscottl			xpt_action(done_ccb);
1680195534Sscottl			xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path,
1681195534Sscottl				  done_ccb);
1682195534Sscottl		}
1683236613Smav		PROBE_SET_ACTION(softc, PROBE_DONE);
1684195534Sscottl		xpt_release_ccb(done_ccb);
1685195534Sscottl		break;
1686195534Sscottl	}
1687195534Sscottl	default:
1688236613Smav		panic("probedone: invalid action state 0x%x\n", softc->action);
1689195534Sscottl	}
1690195534Sscottl	done_ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs);
1691195534Sscottl	TAILQ_REMOVE(&softc->request_ccbs, &done_ccb->ccb_h, periph_links.tqe);
1692195534Sscottl	done_ccb->ccb_h.status = CAM_REQ_CMP;
1693195534Sscottl	xpt_done(done_ccb);
1694195534Sscottl	if (TAILQ_FIRST(&softc->request_ccbs) == NULL) {
1695236613Smav		CAM_DEBUG(periph->path, CAM_DEBUG_PROBE, ("Probe completed\n"));
1696249466Smav		/* Drop freeze taken due to CAM_DEV_QFREEZE flag set. */
1697249466Smav		cam_release_devq(path, 0, 0, 0, FALSE);
1698236228Smav		cam_periph_invalidate(periph);
1699195534Sscottl		cam_periph_release_locked(periph);
1700195534Sscottl	} else {
1701195534Sscottl		probeschedule(periph);
1702249466Smav		goto out;
1703195534Sscottl	}
1704195534Sscottl}
1705195534Sscottl
1706208911Smjacobstatic int
1707208911Smjacobprobe_strange_rpl_data(struct scsi_report_luns_data *rp, uint32_t maxlun)
1708208911Smjacob{
1709208911Smjacob	uint32_t idx;
1710208911Smjacob	uint32_t nlun = MIN(maxlun, (scsi_4btoul(rp->length) / 8));
1711208911Smjacob
1712208911Smjacob	for (idx = 0; idx < nlun; idx++) {
1713208911Smjacob		if (!CAM_CAN_GET_SIMPLE_LUN(rp, idx)) {
1714208911Smjacob			return (-1);
1715208911Smjacob		}
1716208911Smjacob	}
1717208911Smjacob	return (0);
1718208911Smjacob}
1719208911Smjacob
1720195534Sscottlstatic void
1721208911Smjacobprobe_purge_old(struct cam_path *path, struct scsi_report_luns_data *new)
1722208911Smjacob{
1723208911Smjacob	struct cam_path *tp;
1724208911Smjacob	struct scsi_report_luns_data *old;
1725208911Smjacob	u_int idx1, idx2, nlun_old, nlun_new, this_lun;
1726208911Smjacob	u_int8_t *ol, *nl;
1727208911Smjacob
1728208911Smjacob	if (path->target == NULL) {
1729208911Smjacob		return;
1730208911Smjacob	}
1731256843Smav	mtx_lock(&path->target->luns_mtx);
1732256843Smav	old = path->target->luns;
1733256843Smav	path->target->luns = new;
1734256843Smav	mtx_unlock(&path->target->luns_mtx);
1735256843Smav	if (old == NULL)
1736208911Smjacob		return;
1737208911Smjacob	nlun_old = scsi_4btoul(old->length) / 8;
1738208911Smjacob	nlun_new = scsi_4btoul(new->length) / 8;
1739208911Smjacob
1740208911Smjacob	/*
1741208911Smjacob	 * We are not going to assume sorted lists. Deal.
1742208911Smjacob	 */
1743208911Smjacob	for (idx1 = 0; idx1 < nlun_old; idx1++) {
1744208911Smjacob		ol = old->luns[idx1].lundata;
1745208911Smjacob		for (idx2 = 0; idx2 < nlun_new; idx2++) {
1746208911Smjacob			nl = new->luns[idx2].lundata;
1747208911Smjacob			if (memcmp(nl, ol, 8) == 0) {
1748208911Smjacob				break;
1749208911Smjacob			}
1750208911Smjacob		}
1751208911Smjacob		if (idx2 < nlun_new) {
1752208911Smjacob			continue;
1753208911Smjacob		}
1754208911Smjacob		/*
1755208911Smjacob		 * An 'old' item not in the 'new' list.
1756208911Smjacob		 * Nuke it. Except that if it is lun 0,
1757208911Smjacob		 * that would be what the probe state
1758208911Smjacob		 * machine is currently working on,
1759208911Smjacob		 * so we won't do that.
1760208911Smjacob		 *
1761208911Smjacob		 * We also cannot nuke it if it is
1762208911Smjacob		 * not in a lun format we understand.
1763208911Smjacob		 */
1764208911Smjacob		if (!CAM_CAN_GET_SIMPLE_LUN(old, idx1)) {
1765208911Smjacob			continue;
1766208911Smjacob		}
1767208911Smjacob		CAM_GET_SIMPLE_LUN(old, idx1, this_lun);
1768208911Smjacob		if (this_lun == 0) {
1769208911Smjacob			continue;
1770208911Smjacob		}
1771208911Smjacob		if (xpt_create_path(&tp, NULL, xpt_path_path_id(path),
1772208911Smjacob		    xpt_path_target_id(path), this_lun) == CAM_REQ_CMP) {
1773208911Smjacob			xpt_async(AC_LOST_DEVICE, tp, NULL);
1774208911Smjacob			xpt_free_path(tp);
1775208911Smjacob		}
1776208911Smjacob	}
1777208911Smjacob	free(old, M_CAMXPT);
1778208911Smjacob}
1779208911Smjacob
1780208911Smjacobstatic void
1781195534Sscottlprobecleanup(struct cam_periph *periph)
1782195534Sscottl{
1783195534Sscottl	free(periph->softc, M_CAMXPT);
1784195534Sscottl}
1785195534Sscottl
1786195534Sscottlstatic void
1787195534Sscottlscsi_find_quirk(struct cam_ed *device)
1788195534Sscottl{
1789195534Sscottl	struct scsi_quirk_entry *quirk;
1790195534Sscottl	caddr_t	match;
1791195534Sscottl
1792195534Sscottl	match = cam_quirkmatch((caddr_t)&device->inq_data,
1793195534Sscottl			       (caddr_t)scsi_quirk_table,
1794195534Sscottl			       sizeof(scsi_quirk_table) /
1795195534Sscottl			       sizeof(*scsi_quirk_table),
1796195534Sscottl			       sizeof(*scsi_quirk_table), scsi_inquiry_match);
1797195534Sscottl
1798195534Sscottl	if (match == NULL)
1799195534Sscottl		panic("xpt_find_quirk: device didn't match wildcard entry!!");
1800195534Sscottl
1801195534Sscottl	quirk = (struct scsi_quirk_entry *)match;
1802195534Sscottl	device->quirk = quirk;
1803195534Sscottl	device->mintags = quirk->mintags;
1804195534Sscottl	device->maxtags = quirk->maxtags;
1805195534Sscottl}
1806195534Sscottl
1807195534Sscottlstatic int
1808195534Sscottlsysctl_cam_search_luns(SYSCTL_HANDLER_ARGS)
1809195534Sscottl{
1810228442Smdf	int error, val;
1811195534Sscottl
1812228442Smdf	val = cam_srch_hi;
1813228442Smdf	error = sysctl_handle_int(oidp, &val, 0, req);
1814195534Sscottl	if (error != 0 || req->newptr == NULL)
1815195534Sscottl		return (error);
1816228442Smdf	if (val == 0 || val == 1) {
1817228442Smdf		cam_srch_hi = val;
1818195534Sscottl		return (0);
1819195534Sscottl	} else {
1820195534Sscottl		return (EINVAL);
1821195534Sscottl	}
1822195534Sscottl}
1823195534Sscottl
1824195534Sscottltypedef struct {
1825195534Sscottl	union	ccb *request_ccb;
1826195534Sscottl	struct 	ccb_pathinq *cpi;
1827195534Sscottl	int	counter;
1828208911Smjacob	int	lunindex[0];
1829195534Sscottl} scsi_scan_bus_info;
1830195534Sscottl
1831195534Sscottl/*
1832195534Sscottl * To start a scan, request_ccb is an XPT_SCAN_BUS ccb.
1833195688Semaste * As the scan progresses, scsi_scan_bus is used as the
1834195534Sscottl * callback on completion function.
1835195534Sscottl */
1836195534Sscottlstatic void
1837195534Sscottlscsi_scan_bus(struct cam_periph *periph, union ccb *request_ccb)
1838195534Sscottl{
1839256843Smav	struct mtx *mtx;
1840256843Smav
1841195534Sscottl	CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_TRACE,
1842195688Semaste		  ("scsi_scan_bus\n"));
1843195534Sscottl	switch (request_ccb->ccb_h.func_code) {
1844195534Sscottl	case XPT_SCAN_BUS:
1845208582Smjacob	case XPT_SCAN_TGT:
1846195534Sscottl	{
1847195534Sscottl		scsi_scan_bus_info *scan_info;
1848203108Smav		union	ccb *work_ccb, *reset_ccb;
1849195534Sscottl		struct	cam_path *path;
1850195534Sscottl		u_int	i;
1851208582Smjacob		u_int	low_target, max_target;
1852195534Sscottl		u_int	initiator_id;
1853195534Sscottl
1854195534Sscottl		/* Find out the characteristics of the bus */
1855195534Sscottl		work_ccb = xpt_alloc_ccb_nowait();
1856195534Sscottl		if (work_ccb == NULL) {
1857195534Sscottl			request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
1858195534Sscottl			xpt_done(request_ccb);
1859195534Sscottl			return;
1860195534Sscottl		}
1861195534Sscottl		xpt_setup_ccb(&work_ccb->ccb_h, request_ccb->ccb_h.path,
1862195534Sscottl			      request_ccb->ccb_h.pinfo.priority);
1863195534Sscottl		work_ccb->ccb_h.func_code = XPT_PATH_INQ;
1864195534Sscottl		xpt_action(work_ccb);
1865195534Sscottl		if (work_ccb->ccb_h.status != CAM_REQ_CMP) {
1866195534Sscottl			request_ccb->ccb_h.status = work_ccb->ccb_h.status;
1867195534Sscottl			xpt_free_ccb(work_ccb);
1868195534Sscottl			xpt_done(request_ccb);
1869195534Sscottl			return;
1870195534Sscottl		}
1871195534Sscottl
1872195534Sscottl		if ((work_ccb->cpi.hba_misc & PIM_NOINITIATOR) != 0) {
1873195534Sscottl			/*
1874195534Sscottl			 * Can't scan the bus on an adapter that
1875195534Sscottl			 * cannot perform the initiator role.
1876195534Sscottl			 */
1877195534Sscottl			request_ccb->ccb_h.status = CAM_REQ_CMP;
1878195534Sscottl			xpt_free_ccb(work_ccb);
1879195534Sscottl			xpt_done(request_ccb);
1880195534Sscottl			return;
1881195534Sscottl		}
1882195534Sscottl
1883203108Smav		/* We may need to reset bus first, if we haven't done it yet. */
1884203108Smav		if ((work_ccb->cpi.hba_inquiry &
1885203108Smav		    (PI_WIDE_32|PI_WIDE_16|PI_SDTR_ABLE)) &&
1886203108Smav		    !(work_ccb->cpi.hba_misc & PIM_NOBUSRESET) &&
1887253370Smav		    !timevalisset(&request_ccb->ccb_h.path->bus->last_reset) &&
1888253370Smav		    (reset_ccb = xpt_alloc_ccb_nowait()) != NULL) {
1889203108Smav			xpt_setup_ccb(&reset_ccb->ccb_h, request_ccb->ccb_h.path,
1890203108Smav			      CAM_PRIORITY_NONE);
1891203108Smav			reset_ccb->ccb_h.func_code = XPT_RESET_BUS;
1892203108Smav			xpt_action(reset_ccb);
1893203108Smav			if (reset_ccb->ccb_h.status != CAM_REQ_CMP) {
1894203108Smav				request_ccb->ccb_h.status = reset_ccb->ccb_h.status;
1895203108Smav				xpt_free_ccb(reset_ccb);
1896203108Smav				xpt_free_ccb(work_ccb);
1897203108Smav				xpt_done(request_ccb);
1898203108Smav				return;
1899203108Smav			}
1900203108Smav			xpt_free_ccb(reset_ccb);
1901203108Smav		}
1902203108Smav
1903195534Sscottl		/* Save some state for use while we probe for devices */
1904208911Smjacob		scan_info = (scsi_scan_bus_info *) malloc(sizeof(scsi_scan_bus_info) +
1905208911Smjacob		    (work_ccb->cpi.max_target * sizeof (u_int)), M_CAMXPT, M_ZERO|M_NOWAIT);
1906195534Sscottl		if (scan_info == NULL) {
1907195534Sscottl			request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
1908256843Smav			xpt_free_ccb(work_ccb);
1909195534Sscottl			xpt_done(request_ccb);
1910195534Sscottl			return;
1911195534Sscottl		}
1912236613Smav		CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_TRACE,
1913208911Smjacob		   ("SCAN start for %p\n", scan_info));
1914195534Sscottl		scan_info->request_ccb = request_ccb;
1915195534Sscottl		scan_info->cpi = &work_ccb->cpi;
1916195534Sscottl
1917195534Sscottl		/* Cache on our stack so we can work asynchronously */
1918195534Sscottl		max_target = scan_info->cpi->max_target;
1919208582Smjacob		low_target = 0;
1920195534Sscottl		initiator_id = scan_info->cpi->initiator_id;
1921195534Sscottl
1922195534Sscottl
1923195534Sscottl		/*
1924195534Sscottl		 * We can scan all targets in parallel, or do it sequentially.
1925195534Sscottl		 */
1926208582Smjacob
1927208582Smjacob		if (request_ccb->ccb_h.func_code == XPT_SCAN_TGT) {
1928208582Smjacob			max_target = low_target = request_ccb->ccb_h.target_id;
1929208582Smjacob			scan_info->counter = 0;
1930208582Smjacob		} else if (scan_info->cpi->hba_misc & PIM_SEQSCAN) {
1931195534Sscottl			max_target = 0;
1932195534Sscottl			scan_info->counter = 0;
1933195534Sscottl		} else {
1934195534Sscottl			scan_info->counter = scan_info->cpi->max_target + 1;
1935195534Sscottl			if (scan_info->cpi->initiator_id < scan_info->counter) {
1936195534Sscottl				scan_info->counter--;
1937195534Sscottl			}
1938195534Sscottl		}
1939256843Smav		mtx = xpt_path_mtx(scan_info->request_ccb->ccb_h.path);
1940256843Smav		mtx_unlock(mtx);
1941195534Sscottl
1942208582Smjacob		for (i = low_target; i <= max_target; i++) {
1943195534Sscottl			cam_status status;
1944195534Sscottl			if (i == initiator_id)
1945195534Sscottl				continue;
1946195534Sscottl
1947249468Smav			status = xpt_create_path(&path, NULL,
1948195534Sscottl						 request_ccb->ccb_h.path_id,
1949195534Sscottl						 i, 0);
1950195534Sscottl			if (status != CAM_REQ_CMP) {
1951195688Semaste				printf("scsi_scan_bus: xpt_create_path failed"
1952195534Sscottl				       " with status %#x, bus scan halted\n",
1953195534Sscottl				       status);
1954195534Sscottl				free(scan_info, M_CAMXPT);
1955195534Sscottl				request_ccb->ccb_h.status = status;
1956195534Sscottl				xpt_free_ccb(work_ccb);
1957195534Sscottl				xpt_done(request_ccb);
1958195534Sscottl				break;
1959195534Sscottl			}
1960195534Sscottl			work_ccb = xpt_alloc_ccb_nowait();
1961195534Sscottl			if (work_ccb == NULL) {
1962195685Semaste				xpt_free_ccb((union ccb *)scan_info->cpi);
1963195534Sscottl				free(scan_info, M_CAMXPT);
1964195534Sscottl				xpt_free_path(path);
1965195534Sscottl				request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
1966195534Sscottl				xpt_done(request_ccb);
1967195534Sscottl				break;
1968195534Sscottl			}
1969195534Sscottl			xpt_setup_ccb(&work_ccb->ccb_h, path,
1970195534Sscottl				      request_ccb->ccb_h.pinfo.priority);
1971195534Sscottl			work_ccb->ccb_h.func_code = XPT_SCAN_LUN;
1972195534Sscottl			work_ccb->ccb_h.cbfcnp = scsi_scan_bus;
1973256843Smav			work_ccb->ccb_h.flags |= CAM_UNLOCKED;
1974195534Sscottl			work_ccb->ccb_h.ppriv_ptr0 = scan_info;
1975195534Sscottl			work_ccb->crcn.flags = request_ccb->crcn.flags;
1976195534Sscottl			xpt_action(work_ccb);
1977195534Sscottl		}
1978256843Smav
1979256843Smav		mtx_lock(mtx);
1980195534Sscottl		break;
1981195534Sscottl	}
1982195534Sscottl	case XPT_SCAN_LUN:
1983195534Sscottl	{
1984195534Sscottl		cam_status status;
1985208911Smjacob		struct cam_path *path, *oldpath;
1986195534Sscottl		scsi_scan_bus_info *scan_info;
1987208911Smjacob		struct cam_et *target;
1988208911Smjacob		struct cam_ed *device;
1989208911Smjacob		int next_target;
1990195534Sscottl		path_id_t path_id;
1991195534Sscottl		target_id_t target_id;
1992195534Sscottl		lun_id_t lun_id;
1993195534Sscottl
1994208911Smjacob		oldpath = request_ccb->ccb_h.path;
1995208911Smjacob
1996252382Sscottl		status = cam_ccb_status(request_ccb);
1997195534Sscottl		/* Reuse the same CCB to query if a device was really found */
1998195534Sscottl		scan_info = (scsi_scan_bus_info *)request_ccb->ccb_h.ppriv_ptr0;
1999195534Sscottl		xpt_setup_ccb(&request_ccb->ccb_h, request_ccb->ccb_h.path,
2000195534Sscottl			      request_ccb->ccb_h.pinfo.priority);
2001195534Sscottl		request_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
2002195534Sscottl
2003208911Smjacob
2004195534Sscottl		path_id = request_ccb->ccb_h.path_id;
2005195534Sscottl		target_id = request_ccb->ccb_h.target_id;
2006195534Sscottl		lun_id = request_ccb->ccb_h.target_lun;
2007195534Sscottl		xpt_action(request_ccb);
2008195534Sscottl
2009208911Smjacob		target = request_ccb->ccb_h.path->target;
2010208911Smjacob		next_target = 1;
2011208911Smjacob
2012256843Smav		mtx = xpt_path_mtx(scan_info->request_ccb->ccb_h.path);
2013256843Smav		mtx_lock(mtx);
2014256843Smav		mtx_lock(&target->luns_mtx);
2015208911Smjacob		if (target->luns) {
2016208911Smjacob			uint32_t first;
2017208911Smjacob			u_int nluns = scsi_4btoul(target->luns->length) / 8;
2018208911Smjacob
2019208911Smjacob			/*
2020208911Smjacob			 * Make sure we skip over lun 0 if it's the first member
2021208911Smjacob			 * of the list as we've actually just finished probing
2022208911Smjacob			 * it.
2023208911Smjacob			 */
2024208911Smjacob			CAM_GET_SIMPLE_LUN(target->luns, 0, first);
2025208911Smjacob			if (first == 0 && scan_info->lunindex[target_id] == 0) {
2026208911Smjacob				scan_info->lunindex[target_id]++;
2027208911Smjacob			}
2028208911Smjacob
2029208911Smjacob			if (scan_info->lunindex[target_id] < nluns) {
2030208911Smjacob				CAM_GET_SIMPLE_LUN(target->luns,
2031208911Smjacob				    scan_info->lunindex[target_id], lun_id);
2032256843Smav				mtx_unlock(&target->luns_mtx);
2033208911Smjacob				next_target = 0;
2034236613Smav				CAM_DEBUG(request_ccb->ccb_h.path,
2035236613Smav				    CAM_DEBUG_PROBE,
2036208911Smjacob				   ("next lun to try at index %u is %u\n",
2037208911Smjacob				   scan_info->lunindex[target_id], lun_id));
2038208911Smjacob				scan_info->lunindex[target_id]++;
2039208911Smjacob			} else {
2040256843Smav				mtx_unlock(&target->luns_mtx);
2041208911Smjacob				/*
2042208911Smjacob				 * We're done with scanning all luns.
2043208911Smjacob				 *
2044208911Smjacob				 * Nuke the bogus device for lun 0 if lun 0
2045208911Smjacob				 * wasn't on the list.
2046208911Smjacob				 */
2047208911Smjacob				if (first != 0) {
2048208911Smjacob					TAILQ_FOREACH(device,
2049208911Smjacob					    &target->ed_entries, links) {
2050208911Smjacob						if (device->lun_id == 0) {
2051208911Smjacob							break;
2052208911Smjacob						}
2053208911Smjacob					}
2054208911Smjacob					if (device) {
2055208911Smjacob						xpt_release_device(device);
2056208911Smjacob					}
2057208911Smjacob				}
2058208911Smjacob			}
2059256843Smav		} else {
2060256843Smav		    mtx_unlock(&target->luns_mtx);
2061256843Smav		    if (request_ccb->ccb_h.status != CAM_REQ_CMP) {
2062195534Sscottl			int phl;
2063195534Sscottl
2064195534Sscottl			/*
2065195534Sscottl			 * If we already probed lun 0 successfully, or
2066195534Sscottl			 * we have additional configured luns on this
2067195534Sscottl			 * target that might have "gone away", go onto
2068195534Sscottl			 * the next lun.
2069195534Sscottl			 */
2070195534Sscottl			/*
2071195534Sscottl			 * We may touch devices that we don't
2072195534Sscottl			 * hold references too, so ensure they
2073195534Sscottl			 * don't disappear out from under us.
2074195534Sscottl			 * The target above is referenced by the
2075195534Sscottl			 * path in the request ccb.
2076195534Sscottl			 */
2077195534Sscottl			phl = 0;
2078195534Sscottl			device = TAILQ_FIRST(&target->ed_entries);
2079195534Sscottl			if (device != NULL) {
2080195534Sscottl				phl = CAN_SRCH_HI_SPARSE(device);
2081195534Sscottl				if (device->lun_id == 0)
2082195534Sscottl					device = TAILQ_NEXT(device, links);
2083195534Sscottl			}
2084195534Sscottl			if ((lun_id != 0) || (device != NULL)) {
2085208911Smjacob				if (lun_id < (CAM_SCSI2_MAXLUN-1) || phl) {
2086195534Sscottl					lun_id++;
2087208911Smjacob					next_target = 0;
2088208911Smjacob				}
2089195534Sscottl			}
2090208911Smjacob			if (lun_id == request_ccb->ccb_h.target_lun
2091208911Smjacob			    || lun_id > scan_info->cpi->max_lun)
2092208911Smjacob				next_target = 1;
2093256843Smav		    } else {
2094195534Sscottl
2095195534Sscottl			device = request_ccb->ccb_h.path->device;
2096195534Sscottl
2097195534Sscottl			if ((SCSI_QUIRK(device)->quirks &
2098195534Sscottl			    CAM_QUIRK_NOLUNS) == 0) {
2099195534Sscottl				/* Try the next lun */
2100195534Sscottl				if (lun_id < (CAM_SCSI2_MAXLUN-1)
2101208911Smjacob				  || CAN_SRCH_HI_DENSE(device)) {
2102195534Sscottl					lun_id++;
2103208911Smjacob					next_target = 0;
2104208911Smjacob				}
2105195534Sscottl			}
2106208911Smjacob			if (lun_id == request_ccb->ccb_h.target_lun
2107208911Smjacob			    || lun_id > scan_info->cpi->max_lun)
2108208911Smjacob				next_target = 1;
2109256843Smav		    }
2110195534Sscottl		}
2111195534Sscottl
2112195534Sscottl		/*
2113195534Sscottl		 * Check to see if we scan any further luns.
2114195534Sscottl		 */
2115208911Smjacob		if (next_target) {
2116195534Sscottl			int done;
2117195534Sscottl
2118208911Smjacob			/*
2119208911Smjacob			 * Free the current request path- we're done with it.
2120208911Smjacob			 */
2121208911Smjacob			xpt_free_path(oldpath);
2122195534Sscottl hop_again:
2123195534Sscottl			done = 0;
2124208582Smjacob			if (scan_info->request_ccb->ccb_h.func_code == XPT_SCAN_TGT) {
2125208582Smjacob				done = 1;
2126208582Smjacob			} else if (scan_info->cpi->hba_misc & PIM_SEQSCAN) {
2127195534Sscottl				scan_info->counter++;
2128195534Sscottl				if (scan_info->counter ==
2129195534Sscottl				    scan_info->cpi->initiator_id) {
2130195534Sscottl					scan_info->counter++;
2131195534Sscottl				}
2132195534Sscottl				if (scan_info->counter >=
2133195534Sscottl				    scan_info->cpi->max_target+1) {
2134195534Sscottl					done = 1;
2135195534Sscottl				}
2136195534Sscottl			} else {
2137195534Sscottl				scan_info->counter--;
2138195534Sscottl				if (scan_info->counter == 0) {
2139195534Sscottl					done = 1;
2140195534Sscottl				}
2141195534Sscottl			}
2142195534Sscottl			if (done) {
2143256843Smav				mtx_unlock(mtx);
2144195534Sscottl				xpt_free_ccb(request_ccb);
2145195534Sscottl				xpt_free_ccb((union ccb *)scan_info->cpi);
2146195534Sscottl				request_ccb = scan_info->request_ccb;
2147236613Smav				CAM_DEBUG(request_ccb->ccb_h.path,
2148236613Smav				    CAM_DEBUG_TRACE,
2149208911Smjacob				   ("SCAN done for %p\n", scan_info));
2150195534Sscottl				free(scan_info, M_CAMXPT);
2151195534Sscottl				request_ccb->ccb_h.status = CAM_REQ_CMP;
2152195534Sscottl				xpt_done(request_ccb);
2153195534Sscottl				break;
2154195534Sscottl			}
2155195534Sscottl
2156195534Sscottl			if ((scan_info->cpi->hba_misc & PIM_SEQSCAN) == 0) {
2157256843Smav				mtx_unlock(mtx);
2158195685Semaste				xpt_free_ccb(request_ccb);
2159195534Sscottl				break;
2160195534Sscottl			}
2161249468Smav			status = xpt_create_path(&path, NULL,
2162195534Sscottl			    scan_info->request_ccb->ccb_h.path_id,
2163195534Sscottl			    scan_info->counter, 0);
2164195534Sscottl			if (status != CAM_REQ_CMP) {
2165256843Smav				mtx_unlock(mtx);
2166195688Semaste				printf("scsi_scan_bus: xpt_create_path failed"
2167195534Sscottl				    " with status %#x, bus scan halted\n",
2168195534Sscottl			       	    status);
2169195534Sscottl				xpt_free_ccb(request_ccb);
2170195534Sscottl				xpt_free_ccb((union ccb *)scan_info->cpi);
2171195534Sscottl				request_ccb = scan_info->request_ccb;
2172195534Sscottl				free(scan_info, M_CAMXPT);
2173195534Sscottl				request_ccb->ccb_h.status = status;
2174195534Sscottl				xpt_done(request_ccb);
2175195534Sscottl				break;
2176195534Sscottl			}
2177195534Sscottl			xpt_setup_ccb(&request_ccb->ccb_h, path,
2178195534Sscottl			    request_ccb->ccb_h.pinfo.priority);
2179195534Sscottl			request_ccb->ccb_h.func_code = XPT_SCAN_LUN;
2180195534Sscottl			request_ccb->ccb_h.cbfcnp = scsi_scan_bus;
2181256843Smav			request_ccb->ccb_h.flags |= CAM_UNLOCKED;
2182195534Sscottl			request_ccb->ccb_h.ppriv_ptr0 = scan_info;
2183195534Sscottl			request_ccb->crcn.flags =
2184195534Sscottl			    scan_info->request_ccb->crcn.flags;
2185195534Sscottl		} else {
2186249468Smav			status = xpt_create_path(&path, NULL,
2187195534Sscottl						 path_id, target_id, lun_id);
2188208911Smjacob			/*
2189208911Smjacob			 * Free the old request path- we're done with it. We
2190208911Smjacob			 * do this *after* creating the new path so that
2191208911Smjacob			 * we don't remove a target that has our lun list
2192208911Smjacob			 * in the case that lun 0 is not present.
2193208911Smjacob			 */
2194208911Smjacob			xpt_free_path(oldpath);
2195195534Sscottl			if (status != CAM_REQ_CMP) {
2196195688Semaste				printf("scsi_scan_bus: xpt_create_path failed "
2197195534Sscottl				       "with status %#x, halting LUN scan\n",
2198195534Sscottl			 	       status);
2199195534Sscottl				goto hop_again;
2200195534Sscottl			}
2201195534Sscottl			xpt_setup_ccb(&request_ccb->ccb_h, path,
2202195534Sscottl				      request_ccb->ccb_h.pinfo.priority);
2203195534Sscottl			request_ccb->ccb_h.func_code = XPT_SCAN_LUN;
2204195534Sscottl			request_ccb->ccb_h.cbfcnp = scsi_scan_bus;
2205256843Smav			request_ccb->ccb_h.flags |= CAM_UNLOCKED;
2206195534Sscottl			request_ccb->ccb_h.ppriv_ptr0 = scan_info;
2207195534Sscottl			request_ccb->crcn.flags =
2208195534Sscottl				scan_info->request_ccb->crcn.flags;
2209195534Sscottl		}
2210256843Smav		mtx_unlock(mtx);
2211195534Sscottl		xpt_action(request_ccb);
2212195534Sscottl		break;
2213195534Sscottl	}
2214195534Sscottl	default:
2215195534Sscottl		break;
2216195534Sscottl	}
2217195534Sscottl}
2218195534Sscottl
2219195534Sscottlstatic void
2220195534Sscottlscsi_scan_lun(struct cam_periph *periph, struct cam_path *path,
2221195534Sscottl	     cam_flags flags, union ccb *request_ccb)
2222195534Sscottl{
2223195534Sscottl	struct ccb_pathinq cpi;
2224195534Sscottl	cam_status status;
2225195534Sscottl	struct cam_path *new_path;
2226195534Sscottl	struct cam_periph *old_periph;
2227256843Smav	int lock;
2228195534Sscottl
2229203108Smav	CAM_DEBUG(path, CAM_DEBUG_TRACE, ("scsi_scan_lun\n"));
2230195534Sscottl
2231203108Smav	xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NONE);
2232195534Sscottl	cpi.ccb_h.func_code = XPT_PATH_INQ;
2233195534Sscottl	xpt_action((union ccb *)&cpi);
2234195534Sscottl
2235195534Sscottl	if (cpi.ccb_h.status != CAM_REQ_CMP) {
2236195534Sscottl		if (request_ccb != NULL) {
2237195534Sscottl			request_ccb->ccb_h.status = cpi.ccb_h.status;
2238195534Sscottl			xpt_done(request_ccb);
2239195534Sscottl		}
2240195534Sscottl		return;
2241195534Sscottl	}
2242195534Sscottl
2243195534Sscottl	if ((cpi.hba_misc & PIM_NOINITIATOR) != 0) {
2244195534Sscottl		/*
2245195534Sscottl		 * Can't scan the bus on an adapter that
2246195534Sscottl		 * cannot perform the initiator role.
2247195534Sscottl		 */
2248195534Sscottl		if (request_ccb != NULL) {
2249195534Sscottl			request_ccb->ccb_h.status = CAM_REQ_CMP;
2250195534Sscottl			xpt_done(request_ccb);
2251195534Sscottl		}
2252195534Sscottl		return;
2253195534Sscottl	}
2254195534Sscottl
2255195534Sscottl	if (request_ccb == NULL) {
2256241455Smav		request_ccb = xpt_alloc_ccb_nowait();
2257195534Sscottl		if (request_ccb == NULL) {
2258195688Semaste			xpt_print(path, "scsi_scan_lun: can't allocate CCB, "
2259195534Sscottl			    "can't continue\n");
2260195534Sscottl			return;
2261195534Sscottl		}
2262249468Smav		status = xpt_create_path(&new_path, NULL,
2263195534Sscottl					  path->bus->path_id,
2264195534Sscottl					  path->target->target_id,
2265195534Sscottl					  path->device->lun_id);
2266195534Sscottl		if (status != CAM_REQ_CMP) {
2267241455Smav			xpt_print(path, "scsi_scan_lun: can't create path, "
2268195534Sscottl			    "can't continue\n");
2269241455Smav			xpt_free_ccb(request_ccb);
2270195534Sscottl			return;
2271195534Sscottl		}
2272203108Smav		xpt_setup_ccb(&request_ccb->ccb_h, new_path, CAM_PRIORITY_XPT);
2273195534Sscottl		request_ccb->ccb_h.cbfcnp = xptscandone;
2274195534Sscottl		request_ccb->ccb_h.func_code = XPT_SCAN_LUN;
2275256843Smav		request_ccb->ccb_h.flags |= CAM_UNLOCKED;
2276195534Sscottl		request_ccb->crcn.flags = flags;
2277195534Sscottl	}
2278195534Sscottl
2279256843Smav	lock = (xpt_path_owned(path) == 0);
2280256843Smav	if (lock)
2281256843Smav		xpt_path_lock(path);
2282195534Sscottl	if ((old_periph = cam_periph_find(path, "probe")) != NULL) {
2283236228Smav		if ((old_periph->flags & CAM_PERIPH_INVALID) == 0) {
2284236228Smav			probe_softc *softc;
2285195534Sscottl
2286236228Smav			softc = (probe_softc *)old_periph->softc;
2287236228Smav			TAILQ_INSERT_TAIL(&softc->request_ccbs,
2288236228Smav			    &request_ccb->ccb_h, periph_links.tqe);
2289236228Smav		} else {
2290236228Smav			request_ccb->ccb_h.status = CAM_REQ_CMP_ERR;
2291236228Smav			xpt_done(request_ccb);
2292236228Smav		}
2293195534Sscottl	} else {
2294195534Sscottl		status = cam_periph_alloc(proberegister, NULL, probecleanup,
2295195534Sscottl					  probestart, "probe",
2296195534Sscottl					  CAM_PERIPH_BIO,
2297195534Sscottl					  request_ccb->ccb_h.path, NULL, 0,
2298195534Sscottl					  request_ccb);
2299195534Sscottl
2300195534Sscottl		if (status != CAM_REQ_CMP) {
2301195688Semaste			xpt_print(path, "scsi_scan_lun: cam_alloc_periph "
2302195534Sscottl			    "returned an error, can't continue probe\n");
2303195534Sscottl			request_ccb->ccb_h.status = status;
2304195534Sscottl			xpt_done(request_ccb);
2305195534Sscottl		}
2306195534Sscottl	}
2307256843Smav	if (lock)
2308256843Smav		xpt_path_unlock(path);
2309195534Sscottl}
2310195534Sscottl
2311195534Sscottlstatic void
2312195534Sscottlxptscandone(struct cam_periph *periph, union ccb *done_ccb)
2313195534Sscottl{
2314241455Smav
2315241455Smav	xpt_free_path(done_ccb->ccb_h.path);
2316241455Smav	xpt_free_ccb(done_ccb);
2317195534Sscottl}
2318195534Sscottl
2319195534Sscottlstatic struct cam_ed *
2320195534Sscottlscsi_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id)
2321195534Sscottl{
2322195534Sscottl	struct scsi_quirk_entry *quirk;
2323195534Sscottl	struct cam_ed *device;
2324195534Sscottl
2325195534Sscottl	device = xpt_alloc_device(bus, target, lun_id);
2326195534Sscottl	if (device == NULL)
2327195534Sscottl		return (NULL);
2328195534Sscottl
2329195534Sscottl	/*
2330195534Sscottl	 * Take the default quirk entry until we have inquiry
2331195534Sscottl	 * data and can determine a better quirk to use.
2332195534Sscottl	 */
2333195534Sscottl	quirk = &scsi_quirk_table[scsi_quirk_table_size - 1];
2334195534Sscottl	device->quirk = (void *)quirk;
2335195534Sscottl	device->mintags = quirk->mintags;
2336195534Sscottl	device->maxtags = quirk->maxtags;
2337195534Sscottl	bzero(&device->inq_data, sizeof(device->inq_data));
2338195534Sscottl	device->inq_flags = 0;
2339195534Sscottl	device->queue_flags = 0;
2340195534Sscottl	device->serial_num = NULL;
2341195534Sscottl	device->serial_num_len = 0;
2342216088Sken	device->device_id = NULL;
2343216088Sken	device->device_id_len = 0;
2344216088Sken	device->supported_vpds = NULL;
2345216088Sken	device->supported_vpds_len = 0;
2346195534Sscottl	return (device);
2347195534Sscottl}
2348195534Sscottl
2349195534Sscottlstatic void
2350195534Sscottlscsi_devise_transport(struct cam_path *path)
2351195534Sscottl{
2352195534Sscottl	struct ccb_pathinq cpi;
2353195534Sscottl	struct ccb_trans_settings cts;
2354195534Sscottl	struct scsi_inquiry_data *inq_buf;
2355195534Sscottl
2356195534Sscottl	/* Get transport information from the SIM */
2357203108Smav	xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NONE);
2358195534Sscottl	cpi.ccb_h.func_code = XPT_PATH_INQ;
2359195534Sscottl	xpt_action((union ccb *)&cpi);
2360195534Sscottl
2361195534Sscottl	inq_buf = NULL;
2362195534Sscottl	if ((path->device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0)
2363195534Sscottl		inq_buf = &path->device->inq_data;
2364195534Sscottl	path->device->protocol = PROTO_SCSI;
2365195534Sscottl	path->device->protocol_version =
2366195534Sscottl	    inq_buf != NULL ? SID_ANSI_REV(inq_buf) : cpi.protocol_version;
2367195534Sscottl	path->device->transport = cpi.transport;
2368195534Sscottl	path->device->transport_version = cpi.transport_version;
2369195534Sscottl
2370195534Sscottl	/*
2371195534Sscottl	 * Any device not using SPI3 features should
2372195534Sscottl	 * be considered SPI2 or lower.
2373195534Sscottl	 */
2374195534Sscottl	if (inq_buf != NULL) {
2375195534Sscottl		if (path->device->transport == XPORT_SPI
2376195534Sscottl		 && (inq_buf->spi3data & SID_SPI_MASK) == 0
2377195534Sscottl		 && path->device->transport_version > 2)
2378195534Sscottl			path->device->transport_version = 2;
2379195534Sscottl	} else {
2380195534Sscottl		struct cam_ed* otherdev;
2381195534Sscottl
2382195534Sscottl		for (otherdev = TAILQ_FIRST(&path->target->ed_entries);
2383195534Sscottl		     otherdev != NULL;
2384195534Sscottl		     otherdev = TAILQ_NEXT(otherdev, links)) {
2385195534Sscottl			if (otherdev != path->device)
2386195534Sscottl				break;
2387195534Sscottl		}
2388195534Sscottl
2389195534Sscottl		if (otherdev != NULL) {
2390195534Sscottl			/*
2391195534Sscottl			 * Initially assume the same versioning as
2392195534Sscottl			 * prior luns for this target.
2393195534Sscottl			 */
2394195534Sscottl			path->device->protocol_version =
2395195534Sscottl			    otherdev->protocol_version;
2396195534Sscottl			path->device->transport_version =
2397195534Sscottl			    otherdev->transport_version;
2398195534Sscottl		} else {
2399195534Sscottl			/* Until we know better, opt for safty */
2400195534Sscottl			path->device->protocol_version = 2;
2401195534Sscottl			if (path->device->transport == XPORT_SPI)
2402195534Sscottl				path->device->transport_version = 2;
2403195534Sscottl			else
2404195534Sscottl				path->device->transport_version = 0;
2405195534Sscottl		}
2406195534Sscottl	}
2407195534Sscottl
2408195534Sscottl	/*
2409195534Sscottl	 * XXX
2410195534Sscottl	 * For a device compliant with SPC-2 we should be able
2411195534Sscottl	 * to determine the transport version supported by
2412195534Sscottl	 * scrutinizing the version descriptors in the
2413195534Sscottl	 * inquiry buffer.
2414195534Sscottl	 */
2415195534Sscottl
2416195534Sscottl	/* Tell the controller what we think */
2417203108Smav	xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
2418195534Sscottl	cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
2419195534Sscottl	cts.type = CTS_TYPE_CURRENT_SETTINGS;
2420195534Sscottl	cts.transport = path->device->transport;
2421195534Sscottl	cts.transport_version = path->device->transport_version;
2422195534Sscottl	cts.protocol = path->device->protocol;
2423195534Sscottl	cts.protocol_version = path->device->protocol_version;
2424195534Sscottl	cts.proto_specific.valid = 0;
2425195534Sscottl	cts.xport_specific.valid = 0;
2426195534Sscottl	xpt_action((union ccb *)&cts);
2427195534Sscottl}
2428195534Sscottl
2429195534Sscottlstatic void
2430223081Sgibbsscsi_dev_advinfo(union ccb *start_ccb)
2431216088Sken{
2432216088Sken	struct cam_ed *device;
2433223081Sgibbs	struct ccb_dev_advinfo *cdai;
2434216088Sken	off_t amt;
2435216088Sken
2436223448Swill	start_ccb->ccb_h.status = CAM_REQ_INVALID;
2437216088Sken	device = start_ccb->ccb_h.path->device;
2438223081Sgibbs	cdai = &start_ccb->cdai;
2439223081Sgibbs	switch(cdai->buftype) {
2440223081Sgibbs	case CDAI_TYPE_SCSI_DEVID:
2441223081Sgibbs		if (cdai->flags & CDAI_FLAG_STORE)
2442223448Swill			return;
2443223081Sgibbs		cdai->provsiz = device->device_id_len;
2444216088Sken		if (device->device_id_len == 0)
2445216088Sken			break;
2446216088Sken		amt = device->device_id_len;
2447223081Sgibbs		if (cdai->provsiz > cdai->bufsiz)
2448223081Sgibbs			amt = cdai->bufsiz;
2449223081Sgibbs		memcpy(cdai->buf, device->device_id, amt);
2450216088Sken		break;
2451223081Sgibbs	case CDAI_TYPE_SERIAL_NUM:
2452223081Sgibbs		if (cdai->flags & CDAI_FLAG_STORE)
2453223448Swill			return;
2454223081Sgibbs		cdai->provsiz = device->serial_num_len;
2455223081Sgibbs		if (device->serial_num_len == 0)
2456223081Sgibbs			break;
2457223081Sgibbs		amt = device->serial_num_len;
2458223081Sgibbs		if (cdai->provsiz > cdai->bufsiz)
2459223081Sgibbs			amt = cdai->bufsiz;
2460223081Sgibbs		memcpy(cdai->buf, device->serial_num, amt);
2461223081Sgibbs		break;
2462223081Sgibbs	case CDAI_TYPE_PHYS_PATH:
2463223081Sgibbs		if (cdai->flags & CDAI_FLAG_STORE) {
2464230590Sken			if (device->physpath != NULL) {
2465223081Sgibbs				free(device->physpath, M_CAMXPT);
2466230590Sken				device->physpath = NULL;
2467230590Sken			}
2468223081Sgibbs			device->physpath_len = cdai->bufsiz;
2469223081Sgibbs			/* Clear existing buffer if zero length */
2470223081Sgibbs			if (cdai->bufsiz == 0)
2471223081Sgibbs				break;
2472223081Sgibbs			device->physpath = malloc(cdai->bufsiz, M_CAMXPT, M_NOWAIT);
2473223081Sgibbs			if (device->physpath == NULL) {
2474223081Sgibbs				start_ccb->ccb_h.status = CAM_REQ_ABORTED;
2475223081Sgibbs				return;
2476223081Sgibbs			}
2477223081Sgibbs			memcpy(device->physpath, cdai->buf, cdai->bufsiz);
2478223081Sgibbs		} else {
2479223081Sgibbs			cdai->provsiz = device->physpath_len;
2480223081Sgibbs			if (device->physpath_len == 0)
2481223081Sgibbs				break;
2482223081Sgibbs			amt = device->physpath_len;
2483223081Sgibbs			if (cdai->provsiz > cdai->bufsiz)
2484223081Sgibbs				amt = cdai->bufsiz;
2485223081Sgibbs			memcpy(cdai->buf, device->physpath, amt);
2486223081Sgibbs		}
2487223081Sgibbs		break;
2488230590Sken	case CDAI_TYPE_RCAPLONG:
2489230590Sken		if (cdai->flags & CDAI_FLAG_STORE) {
2490230590Sken			if (device->rcap_buf != NULL) {
2491230590Sken				free(device->rcap_buf, M_CAMXPT);
2492230590Sken				device->rcap_buf = NULL;
2493230590Sken			}
2494230590Sken
2495230590Sken			device->rcap_len = cdai->bufsiz;
2496230590Sken			/* Clear existing buffer if zero length */
2497230590Sken			if (cdai->bufsiz == 0)
2498230590Sken				break;
2499230590Sken
2500230590Sken			device->rcap_buf = malloc(cdai->bufsiz, M_CAMXPT,
2501230590Sken						  M_NOWAIT);
2502230590Sken			if (device->rcap_buf == NULL) {
2503230590Sken				start_ccb->ccb_h.status = CAM_REQ_ABORTED;
2504230590Sken				return;
2505230590Sken			}
2506230590Sken
2507230590Sken			memcpy(device->rcap_buf, cdai->buf, cdai->bufsiz);
2508230590Sken		} else {
2509230590Sken			cdai->provsiz = device->rcap_len;
2510230590Sken			if (device->rcap_len == 0)
2511230590Sken				break;
2512230590Sken			amt = device->rcap_len;
2513230590Sken			if (cdai->provsiz > cdai->bufsiz)
2514230590Sken				amt = cdai->bufsiz;
2515230590Sken			memcpy(cdai->buf, device->rcap_buf, amt);
2516230590Sken		}
2517230590Sken		break;
2518216088Sken	default:
2519223448Swill		return;
2520216088Sken	}
2521216088Sken	start_ccb->ccb_h.status = CAM_REQ_CMP;
2522223081Sgibbs
2523223081Sgibbs	if (cdai->flags & CDAI_FLAG_STORE) {
2524223081Sgibbs		xpt_async(AC_ADVINFO_CHANGED, start_ccb->ccb_h.path,
2525223081Sgibbs			  (void *)(uintptr_t)cdai->buftype);
2526223081Sgibbs	}
2527216088Sken}
2528216088Sken
2529216088Skenstatic void
2530195534Sscottlscsi_action(union ccb *start_ccb)
2531195534Sscottl{
2532195534Sscottl
2533195534Sscottl	switch (start_ccb->ccb_h.func_code) {
2534195534Sscottl	case XPT_SET_TRAN_SETTINGS:
2535195534Sscottl	{
2536195534Sscottl		scsi_set_transfer_settings(&start_ccb->cts,
2537256843Smav					   start_ccb->ccb_h.path,
2538195534Sscottl					   /*async_update*/FALSE);
2539195534Sscottl		break;
2540195534Sscottl	}
2541195534Sscottl	case XPT_SCAN_BUS:
2542208582Smjacob	case XPT_SCAN_TGT:
2543195534Sscottl		scsi_scan_bus(start_ccb->ccb_h.path->periph, start_ccb);
2544195534Sscottl		break;
2545195534Sscottl	case XPT_SCAN_LUN:
2546195534Sscottl		scsi_scan_lun(start_ccb->ccb_h.path->periph,
2547195534Sscottl			      start_ccb->ccb_h.path, start_ccb->crcn.flags,
2548195534Sscottl			      start_ccb);
2549195534Sscottl		break;
2550223081Sgibbs	case XPT_DEV_ADVINFO:
2551216088Sken	{
2552223081Sgibbs		scsi_dev_advinfo(start_ccb);
2553216088Sken		break;
2554216088Sken	}
2555195534Sscottl	default:
2556195534Sscottl		xpt_action_default(start_ccb);
2557195534Sscottl		break;
2558195534Sscottl	}
2559195534Sscottl}
2560195534Sscottl
2561195534Sscottlstatic void
2562256843Smavscsi_set_transfer_settings(struct ccb_trans_settings *cts, struct cam_path *path,
2563195534Sscottl			   int async_update)
2564195534Sscottl{
2565195534Sscottl	struct	ccb_pathinq cpi;
2566195534Sscottl	struct	ccb_trans_settings cur_cts;
2567195534Sscottl	struct	ccb_trans_settings_scsi *scsi;
2568195534Sscottl	struct	ccb_trans_settings_scsi *cur_scsi;
2569195534Sscottl	struct	scsi_inquiry_data *inq_data;
2570256843Smav	struct	cam_ed *device;
2571195534Sscottl
2572256843Smav	if (path == NULL || (device = path->device) == NULL) {
2573195534Sscottl		cts->ccb_h.status = CAM_PATH_INVALID;
2574195534Sscottl		xpt_done((union ccb *)cts);
2575195534Sscottl		return;
2576195534Sscottl	}
2577195534Sscottl
2578195534Sscottl	if (cts->protocol == PROTO_UNKNOWN
2579195534Sscottl	 || cts->protocol == PROTO_UNSPECIFIED) {
2580195534Sscottl		cts->protocol = device->protocol;
2581195534Sscottl		cts->protocol_version = device->protocol_version;
2582195534Sscottl	}
2583195534Sscottl
2584195534Sscottl	if (cts->protocol_version == PROTO_VERSION_UNKNOWN
2585195534Sscottl	 || cts->protocol_version == PROTO_VERSION_UNSPECIFIED)
2586195534Sscottl		cts->protocol_version = device->protocol_version;
2587195534Sscottl
2588195534Sscottl	if (cts->protocol != device->protocol) {
2589256843Smav		xpt_print(path, "Uninitialized Protocol %x:%x?\n",
2590195534Sscottl		       cts->protocol, device->protocol);
2591195534Sscottl		cts->protocol = device->protocol;
2592195534Sscottl	}
2593195534Sscottl
2594195534Sscottl	if (cts->protocol_version > device->protocol_version) {
2595195534Sscottl		if (bootverbose) {
2596256843Smav			xpt_print(path, "Down reving Protocol "
2597195534Sscottl			    "Version from %d to %d?\n", cts->protocol_version,
2598195534Sscottl			    device->protocol_version);
2599195534Sscottl		}
2600195534Sscottl		cts->protocol_version = device->protocol_version;
2601195534Sscottl	}
2602195534Sscottl
2603195534Sscottl	if (cts->transport == XPORT_UNKNOWN
2604195534Sscottl	 || cts->transport == XPORT_UNSPECIFIED) {
2605195534Sscottl		cts->transport = device->transport;
2606195534Sscottl		cts->transport_version = device->transport_version;
2607195534Sscottl	}
2608195534Sscottl
2609195534Sscottl	if (cts->transport_version == XPORT_VERSION_UNKNOWN
2610195534Sscottl	 || cts->transport_version == XPORT_VERSION_UNSPECIFIED)
2611195534Sscottl		cts->transport_version = device->transport_version;
2612195534Sscottl
2613195534Sscottl	if (cts->transport != device->transport) {
2614256843Smav		xpt_print(path, "Uninitialized Transport %x:%x?\n",
2615195534Sscottl		    cts->transport, device->transport);
2616195534Sscottl		cts->transport = device->transport;
2617195534Sscottl	}
2618195534Sscottl
2619195534Sscottl	if (cts->transport_version > device->transport_version) {
2620195534Sscottl		if (bootverbose) {
2621256843Smav			xpt_print(path, "Down reving Transport "
2622195534Sscottl			    "Version from %d to %d?\n", cts->transport_version,
2623195534Sscottl			    device->transport_version);
2624195534Sscottl		}
2625195534Sscottl		cts->transport_version = device->transport_version;
2626195534Sscottl	}
2627195534Sscottl
2628195534Sscottl	/*
2629195534Sscottl	 * Nothing more of interest to do unless
2630195534Sscottl	 * this is a device connected via the
2631195534Sscottl	 * SCSI protocol.
2632195534Sscottl	 */
2633195534Sscottl	if (cts->protocol != PROTO_SCSI) {
2634195534Sscottl		if (async_update == FALSE)
2635256843Smav			xpt_action_default((union ccb *)cts);
2636195534Sscottl		return;
2637195534Sscottl	}
2638195534Sscottl
2639195534Sscottl	inq_data = &device->inq_data;
2640195534Sscottl	scsi = &cts->proto_specific.scsi;
2641256843Smav	xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NONE);
2642195534Sscottl	cpi.ccb_h.func_code = XPT_PATH_INQ;
2643195534Sscottl	xpt_action((union ccb *)&cpi);
2644195534Sscottl
2645195534Sscottl	/* SCSI specific sanity checking */
2646195534Sscottl	if ((cpi.hba_inquiry & PI_TAG_ABLE) == 0
2647195534Sscottl	 || (INQ_DATA_TQ_ENABLED(inq_data)) == 0
2648195534Sscottl	 || (device->queue_flags & SCP_QUEUE_DQUE) != 0
2649195534Sscottl	 || (device->mintags == 0)) {
2650195534Sscottl		/*
2651195534Sscottl		 * Can't tag on hardware that doesn't support tags,
2652195534Sscottl		 * doesn't have it enabled, or has broken tag support.
2653195534Sscottl		 */
2654195534Sscottl		scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
2655195534Sscottl	}
2656195534Sscottl
2657195534Sscottl	if (async_update == FALSE) {
2658195534Sscottl		/*
2659195534Sscottl		 * Perform sanity checking against what the
2660195534Sscottl		 * controller and device can do.
2661195534Sscottl		 */
2662256843Smav		xpt_setup_ccb(&cur_cts.ccb_h, path, CAM_PRIORITY_NONE);
2663195534Sscottl		cur_cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
2664195534Sscottl		cur_cts.type = cts->type;
2665195534Sscottl		xpt_action((union ccb *)&cur_cts);
2666252382Sscottl		if (cam_ccb_status((union ccb *)&cur_cts) != CAM_REQ_CMP) {
2667195534Sscottl			return;
2668195534Sscottl		}
2669195534Sscottl		cur_scsi = &cur_cts.proto_specific.scsi;
2670195534Sscottl		if ((scsi->valid & CTS_SCSI_VALID_TQ) == 0) {
2671195534Sscottl			scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
2672195534Sscottl			scsi->flags |= cur_scsi->flags & CTS_SCSI_FLAGS_TAG_ENB;
2673195534Sscottl		}
2674195534Sscottl		if ((cur_scsi->valid & CTS_SCSI_VALID_TQ) == 0)
2675195534Sscottl			scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
2676195534Sscottl	}
2677195534Sscottl
2678195534Sscottl	/* SPI specific sanity checking */
2679195534Sscottl	if (cts->transport == XPORT_SPI && async_update == FALSE) {
2680195534Sscottl		u_int spi3caps;
2681195534Sscottl		struct ccb_trans_settings_spi *spi;
2682195534Sscottl		struct ccb_trans_settings_spi *cur_spi;
2683195534Sscottl
2684195534Sscottl		spi = &cts->xport_specific.spi;
2685195534Sscottl
2686195534Sscottl		cur_spi = &cur_cts.xport_specific.spi;
2687195534Sscottl
2688195534Sscottl		/* Fill in any gaps in what the user gave us */
2689195534Sscottl		if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0)
2690195534Sscottl			spi->sync_period = cur_spi->sync_period;
2691195534Sscottl		if ((cur_spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0)
2692195534Sscottl			spi->sync_period = 0;
2693195534Sscottl		if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0)
2694195534Sscottl			spi->sync_offset = cur_spi->sync_offset;
2695195534Sscottl		if ((cur_spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0)
2696195534Sscottl			spi->sync_offset = 0;
2697195534Sscottl		if ((spi->valid & CTS_SPI_VALID_PPR_OPTIONS) == 0)
2698195534Sscottl			spi->ppr_options = cur_spi->ppr_options;
2699195534Sscottl		if ((cur_spi->valid & CTS_SPI_VALID_PPR_OPTIONS) == 0)
2700195534Sscottl			spi->ppr_options = 0;
2701195534Sscottl		if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) == 0)
2702195534Sscottl			spi->bus_width = cur_spi->bus_width;
2703195534Sscottl		if ((cur_spi->valid & CTS_SPI_VALID_BUS_WIDTH) == 0)
2704195534Sscottl			spi->bus_width = 0;
2705195534Sscottl		if ((spi->valid & CTS_SPI_VALID_DISC) == 0) {
2706195534Sscottl			spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB;
2707195534Sscottl			spi->flags |= cur_spi->flags & CTS_SPI_FLAGS_DISC_ENB;
2708195534Sscottl		}
2709195534Sscottl		if ((cur_spi->valid & CTS_SPI_VALID_DISC) == 0)
2710195534Sscottl			spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB;
2711195534Sscottl		if (((device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0
2712195534Sscottl		  && (inq_data->flags & SID_Sync) == 0
2713195534Sscottl		  && cts->type == CTS_TYPE_CURRENT_SETTINGS)
2714195534Sscottl		 || ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0)) {
2715195534Sscottl			/* Force async */
2716195534Sscottl			spi->sync_period = 0;
2717195534Sscottl			spi->sync_offset = 0;
2718195534Sscottl		}
2719195534Sscottl
2720195534Sscottl		switch (spi->bus_width) {
2721195534Sscottl		case MSG_EXT_WDTR_BUS_32_BIT:
2722195534Sscottl			if (((device->flags & CAM_DEV_INQUIRY_DATA_VALID) == 0
2723195534Sscottl			  || (inq_data->flags & SID_WBus32) != 0
2724195534Sscottl			  || cts->type == CTS_TYPE_USER_SETTINGS)
2725195534Sscottl			 && (cpi.hba_inquiry & PI_WIDE_32) != 0)
2726195534Sscottl				break;
2727195534Sscottl			/* Fall Through to 16-bit */
2728195534Sscottl		case MSG_EXT_WDTR_BUS_16_BIT:
2729195534Sscottl			if (((device->flags & CAM_DEV_INQUIRY_DATA_VALID) == 0
2730195534Sscottl			  || (inq_data->flags & SID_WBus16) != 0
2731195534Sscottl			  || cts->type == CTS_TYPE_USER_SETTINGS)
2732195534Sscottl			 && (cpi.hba_inquiry & PI_WIDE_16) != 0) {
2733195534Sscottl				spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
2734195534Sscottl				break;
2735195534Sscottl			}
2736195534Sscottl			/* Fall Through to 8-bit */
2737195534Sscottl		default: /* New bus width?? */
2738195534Sscottl		case MSG_EXT_WDTR_BUS_8_BIT:
2739195534Sscottl			/* All targets can do this */
2740195534Sscottl			spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
2741195534Sscottl			break;
2742195534Sscottl		}
2743195534Sscottl
2744195534Sscottl		spi3caps = cpi.xport_specific.spi.ppr_options;
2745195534Sscottl		if ((device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0
2746195534Sscottl		 && cts->type == CTS_TYPE_CURRENT_SETTINGS)
2747195534Sscottl			spi3caps &= inq_data->spi3data;
2748195534Sscottl
2749195534Sscottl		if ((spi3caps & SID_SPI_CLOCK_DT) == 0)
2750195534Sscottl			spi->ppr_options &= ~MSG_EXT_PPR_DT_REQ;
2751195534Sscottl
2752195534Sscottl		if ((spi3caps & SID_SPI_IUS) == 0)
2753195534Sscottl			spi->ppr_options &= ~MSG_EXT_PPR_IU_REQ;
2754195534Sscottl
2755195534Sscottl		if ((spi3caps & SID_SPI_QAS) == 0)
2756195534Sscottl			spi->ppr_options &= ~MSG_EXT_PPR_QAS_REQ;
2757195534Sscottl
2758195534Sscottl		/* No SPI Transfer settings are allowed unless we are wide */
2759195534Sscottl		if (spi->bus_width == 0)
2760195534Sscottl			spi->ppr_options = 0;
2761195534Sscottl
2762195534Sscottl		if ((spi->valid & CTS_SPI_VALID_DISC)
2763195534Sscottl		 && ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) == 0)) {
2764195534Sscottl			/*
2765195534Sscottl			 * Can't tag queue without disconnection.
2766195534Sscottl			 */
2767195534Sscottl			scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
2768195534Sscottl			scsi->valid |= CTS_SCSI_VALID_TQ;
2769195534Sscottl		}
2770195534Sscottl
2771195534Sscottl		/*
2772195534Sscottl		 * If we are currently performing tagged transactions to
2773195534Sscottl		 * this device and want to change its negotiation parameters,
2774195534Sscottl		 * go non-tagged for a bit to give the controller a chance to
2775195534Sscottl		 * negotiate unhampered by tag messages.
2776195534Sscottl		 */
2777195534Sscottl		if (cts->type == CTS_TYPE_CURRENT_SETTINGS
2778195534Sscottl		 && (device->inq_flags & SID_CmdQue) != 0
2779195534Sscottl		 && (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0
2780195534Sscottl		 && (spi->flags & (CTS_SPI_VALID_SYNC_RATE|
2781195534Sscottl				   CTS_SPI_VALID_SYNC_OFFSET|
2782195534Sscottl				   CTS_SPI_VALID_BUS_WIDTH)) != 0)
2783256843Smav			scsi_toggle_tags(path);
2784195534Sscottl	}
2785195534Sscottl
2786195534Sscottl	if (cts->type == CTS_TYPE_CURRENT_SETTINGS
2787195534Sscottl	 && (scsi->valid & CTS_SCSI_VALID_TQ) != 0) {
2788195534Sscottl		int device_tagenb;
2789195534Sscottl
2790195534Sscottl		/*
2791195534Sscottl		 * If we are transitioning from tags to no-tags or
2792195534Sscottl		 * vice-versa, we need to carefully freeze and restart
2793195534Sscottl		 * the queue so that we don't overlap tagged and non-tagged
2794195534Sscottl		 * commands.  We also temporarily stop tags if there is
2795195534Sscottl		 * a change in transfer negotiation settings to allow
2796195534Sscottl		 * "tag-less" negotiation.
2797195534Sscottl		 */
2798195534Sscottl		if ((device->flags & CAM_DEV_TAG_AFTER_COUNT) != 0
2799195534Sscottl		 || (device->inq_flags & SID_CmdQue) != 0)
2800195534Sscottl			device_tagenb = TRUE;
2801195534Sscottl		else
2802195534Sscottl			device_tagenb = FALSE;
2803195534Sscottl
2804195534Sscottl		if (((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0
2805195534Sscottl		  && device_tagenb == FALSE)
2806195534Sscottl		 || ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) == 0
2807195534Sscottl		  && device_tagenb == TRUE)) {
2808195534Sscottl
2809195534Sscottl			if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) {
2810195534Sscottl				/*
2811195534Sscottl				 * Delay change to use tags until after a
2812195534Sscottl				 * few commands have gone to this device so
2813195534Sscottl				 * the controller has time to perform transfer
2814195534Sscottl				 * negotiations without tagged messages getting
2815195534Sscottl				 * in the way.
2816195534Sscottl				 */
2817195534Sscottl				device->tag_delay_count = CAM_TAG_DELAY_COUNT;
2818195534Sscottl				device->flags |= CAM_DEV_TAG_AFTER_COUNT;
2819195534Sscottl			} else {
2820256843Smav				xpt_stop_tags(path);
2821195534Sscottl			}
2822195534Sscottl		}
2823195534Sscottl	}
2824195534Sscottl	if (async_update == FALSE)
2825256843Smav		xpt_action_default((union ccb *)cts);
2826195534Sscottl}
2827195534Sscottl
2828195534Sscottlstatic void
2829195534Sscottlscsi_toggle_tags(struct cam_path *path)
2830195534Sscottl{
2831195534Sscottl	struct cam_ed *dev;
2832195534Sscottl
2833195534Sscottl	/*
2834195534Sscottl	 * Give controllers a chance to renegotiate
2835195534Sscottl	 * before starting tag operations.  We
2836195534Sscottl	 * "toggle" tagged queuing off then on
2837195534Sscottl	 * which causes the tag enable command delay
2838195534Sscottl	 * counter to come into effect.
2839195534Sscottl	 */
2840195534Sscottl	dev = path->device;
2841195534Sscottl	if ((dev->flags & CAM_DEV_TAG_AFTER_COUNT) != 0
2842195534Sscottl	 || ((dev->inq_flags & SID_CmdQue) != 0
2843195534Sscottl 	  && (dev->inq_flags & (SID_Sync|SID_WBus16|SID_WBus32)) != 0)) {
2844195534Sscottl		struct ccb_trans_settings cts;
2845195534Sscottl
2846203108Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
2847195534Sscottl		cts.protocol = PROTO_SCSI;
2848195534Sscottl		cts.protocol_version = PROTO_VERSION_UNSPECIFIED;
2849195534Sscottl		cts.transport = XPORT_UNSPECIFIED;
2850195534Sscottl		cts.transport_version = XPORT_VERSION_UNSPECIFIED;
2851195534Sscottl		cts.proto_specific.scsi.flags = 0;
2852195534Sscottl		cts.proto_specific.scsi.valid = CTS_SCSI_VALID_TQ;
2853256843Smav		scsi_set_transfer_settings(&cts, path,
2854195534Sscottl					  /*async_update*/TRUE);
2855195534Sscottl		cts.proto_specific.scsi.flags = CTS_SCSI_FLAGS_TAG_ENB;
2856256843Smav		scsi_set_transfer_settings(&cts, path,
2857195534Sscottl					  /*async_update*/TRUE);
2858195534Sscottl	}
2859195534Sscottl}
2860195534Sscottl
2861195534Sscottl/*
2862195534Sscottl * Handle any per-device event notifications that require action by the XPT.
2863195534Sscottl */
2864195534Sscottlstatic void
2865195534Sscottlscsi_dev_async(u_int32_t async_code, struct cam_eb *bus, struct cam_et *target,
2866195534Sscottl	      struct cam_ed *device, void *async_arg)
2867195534Sscottl{
2868195534Sscottl	cam_status status;
2869195534Sscottl	struct cam_path newpath;
2870195534Sscottl
2871195534Sscottl	/*
2872195534Sscottl	 * We only need to handle events for real devices.
2873195534Sscottl	 */
2874195534Sscottl	if (target->target_id == CAM_TARGET_WILDCARD
2875195534Sscottl	 || device->lun_id == CAM_LUN_WILDCARD)
2876195534Sscottl		return;
2877195534Sscottl
2878195534Sscottl	/*
2879195534Sscottl	 * We need our own path with wildcards expanded to
2880195534Sscottl	 * handle certain types of events.
2881195534Sscottl	 */
2882195534Sscottl	if ((async_code == AC_SENT_BDR)
2883195534Sscottl	 || (async_code == AC_BUS_RESET)
2884195534Sscottl	 || (async_code == AC_INQ_CHANGED))
2885195534Sscottl		status = xpt_compile_path(&newpath, NULL,
2886195534Sscottl					  bus->path_id,
2887195534Sscottl					  target->target_id,
2888195534Sscottl					  device->lun_id);
2889195534Sscottl	else
2890195534Sscottl		status = CAM_REQ_CMP_ERR;
2891195534Sscottl
2892195534Sscottl	if (status == CAM_REQ_CMP) {
2893195534Sscottl
2894195534Sscottl		/*
2895195534Sscottl		 * Allow transfer negotiation to occur in a
2896203108Smav		 * tag free environment and after settle delay.
2897195534Sscottl		 */
2898195534Sscottl		if (async_code == AC_SENT_BDR
2899203108Smav		 || async_code == AC_BUS_RESET) {
2900203108Smav			cam_freeze_devq(&newpath);
2901203108Smav			cam_release_devq(&newpath,
2902203108Smav				RELSIM_RELEASE_AFTER_TIMEOUT,
2903203108Smav				/*reduction*/0,
2904203108Smav				/*timeout*/scsi_delay,
2905203108Smav				/*getcount_only*/0);
2906195534Sscottl			scsi_toggle_tags(&newpath);
2907203108Smav		}
2908195534Sscottl
2909195534Sscottl		if (async_code == AC_INQ_CHANGED) {
2910195534Sscottl			/*
2911195534Sscottl			 * We've sent a start unit command, or
2912195534Sscottl			 * something similar to a device that
2913195534Sscottl			 * may have caused its inquiry data to
2914195534Sscottl			 * change. So we re-scan the device to
2915195534Sscottl			 * refresh the inquiry data for it.
2916195534Sscottl			 */
2917195534Sscottl			scsi_scan_lun(newpath.periph, &newpath,
2918195534Sscottl				     CAM_EXPECT_INQ_CHANGE, NULL);
2919195534Sscottl		}
2920195534Sscottl		xpt_release_path(&newpath);
2921198748Smav	} else if (async_code == AC_LOST_DEVICE &&
2922198748Smav	    (device->flags & CAM_DEV_UNCONFIGURED) == 0) {
2923195534Sscottl		device->flags |= CAM_DEV_UNCONFIGURED;
2924198748Smav		xpt_release_device(device);
2925195534Sscottl	} else if (async_code == AC_TRANSFER_NEG) {
2926195534Sscottl		struct ccb_trans_settings *settings;
2927256843Smav		struct cam_path path;
2928195534Sscottl
2929195534Sscottl		settings = (struct ccb_trans_settings *)async_arg;
2930256843Smav		xpt_compile_path(&path, NULL, bus->path_id, target->target_id,
2931256843Smav				 device->lun_id);
2932256843Smav		scsi_set_transfer_settings(settings, &path,
2933195534Sscottl					  /*async_update*/TRUE);
2934256843Smav		xpt_release_path(&path);
2935195534Sscottl	}
2936195534Sscottl}
2937195534Sscottl
2938204220Smavstatic void
2939204220Smavscsi_announce_periph(struct cam_periph *periph)
2940204220Smav{
2941204220Smav	struct	ccb_pathinq cpi;
2942204220Smav	struct	ccb_trans_settings cts;
2943204220Smav	struct	cam_path *path = periph->path;
2944204220Smav	u_int	speed;
2945204220Smav	u_int	freq;
2946204220Smav	u_int	mb;
2947204220Smav
2948256843Smav	cam_periph_assert(periph, MA_OWNED);
2949204220Smav
2950204220Smav	xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
2951204220Smav	cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
2952204220Smav	cts.type = CTS_TYPE_CURRENT_SETTINGS;
2953204220Smav	xpt_action((union ccb*)&cts);
2954252382Sscottl	if (cam_ccb_status((union ccb *)&cts) != CAM_REQ_CMP)
2955204220Smav		return;
2956204220Smav	/* Ask the SIM for its base transfer speed */
2957204220Smav	xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NORMAL);
2958204220Smav	cpi.ccb_h.func_code = XPT_PATH_INQ;
2959204220Smav	xpt_action((union ccb *)&cpi);
2960204220Smav	/* Report connection speed */
2961204220Smav	speed = cpi.base_transfer_speed;
2962204220Smav	freq = 0;
2963204220Smav	if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_SPI) {
2964204220Smav		struct	ccb_trans_settings_spi *spi =
2965204220Smav		    &cts.xport_specific.spi;
2966204220Smav
2967204220Smav		if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0
2968204220Smav		  && spi->sync_offset != 0) {
2969204220Smav			freq = scsi_calc_syncsrate(spi->sync_period);
2970204220Smav			speed = freq;
2971204220Smav		}
2972204220Smav		if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0)
2973204220Smav			speed *= (0x01 << spi->bus_width);
2974204220Smav	}
2975204220Smav	if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_FC) {
2976204220Smav		struct	ccb_trans_settings_fc *fc =
2977204220Smav		    &cts.xport_specific.fc;
2978204220Smav
2979204220Smav		if (fc->valid & CTS_FC_VALID_SPEED)
2980204220Smav			speed = fc->bitrate;
2981204220Smav	}
2982204220Smav	if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_SAS) {
2983204220Smav		struct	ccb_trans_settings_sas *sas =
2984204220Smav		    &cts.xport_specific.sas;
2985204220Smav
2986204220Smav		if (sas->valid & CTS_SAS_VALID_SPEED)
2987204220Smav			speed = sas->bitrate;
2988204220Smav	}
2989204220Smav	mb = speed / 1000;
2990204220Smav	if (mb > 0)
2991204220Smav		printf("%s%d: %d.%03dMB/s transfers",
2992204220Smav		       periph->periph_name, periph->unit_number,
2993204220Smav		       mb, speed % 1000);
2994204220Smav	else
2995204220Smav		printf("%s%d: %dKB/s transfers", periph->periph_name,
2996204220Smav		       periph->unit_number, speed);
2997204220Smav	/* Report additional information about SPI connections */
2998204220Smav	if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_SPI) {
2999204220Smav		struct	ccb_trans_settings_spi *spi;
3000204220Smav
3001204220Smav		spi = &cts.xport_specific.spi;
3002204220Smav		if (freq != 0) {
3003204220Smav			printf(" (%d.%03dMHz%s, offset %d", freq / 1000,
3004204220Smav			       freq % 1000,
3005204220Smav			       (spi->ppr_options & MSG_EXT_PPR_DT_REQ) != 0
3006204220Smav			     ? " DT" : "",
3007204220Smav			       spi->sync_offset);
3008204220Smav		}
3009204220Smav		if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0
3010204220Smav		 && spi->bus_width > 0) {
3011204220Smav			if (freq != 0) {
3012204220Smav				printf(", ");
3013204220Smav			} else {
3014204220Smav				printf(" (");
3015204220Smav			}
3016204220Smav			printf("%dbit)", 8 * (0x01 << spi->bus_width));
3017204220Smav		} else if (freq != 0) {
3018204220Smav			printf(")");
3019204220Smav		}
3020204220Smav	}
3021204220Smav	if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_FC) {
3022204220Smav		struct	ccb_trans_settings_fc *fc;
3023204220Smav
3024204220Smav		fc = &cts.xport_specific.fc;
3025204220Smav		if (fc->valid & CTS_FC_VALID_WWNN)
3026204220Smav			printf(" WWNN 0x%llx", (long long) fc->wwnn);
3027204220Smav		if (fc->valid & CTS_FC_VALID_WWPN)
3028204220Smav			printf(" WWPN 0x%llx", (long long) fc->wwpn);
3029204220Smav		if (fc->valid & CTS_FC_VALID_PORT)
3030204220Smav			printf(" PortID 0x%x", fc->port);
3031204220Smav	}
3032204220Smav	printf("\n");
3033204220Smav}
3034204220Smav
3035