1195534Sscottl/*-
2195534Sscottl * Copyright (c) 2009 Alexander Motin <mav@FreeBSD.org>
3195534Sscottl * All rights reserved.
4195534Sscottl *
5195534Sscottl * Redistribution and use in source and binary forms, with or without
6195534Sscottl * modification, are permitted provided that the following conditions
7195534Sscottl * are met:
8195534Sscottl * 1. Redistributions of source code must retain the above copyright
9195534Sscottl *    notice, this list of conditions and the following disclaimer,
10195534Sscottl *    without modification, immediately at the beginning of the file.
11195534Sscottl * 2. Redistributions in binary form must reproduce the above copyright
12195534Sscottl *    notice, this list of conditions and the following disclaimer in the
13195534Sscottl *    documentation and/or other materials provided with the distribution.
14195534Sscottl *
15195534Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16195534Sscottl * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17195534Sscottl * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18195534Sscottl * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19195534Sscottl * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20195534Sscottl * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21195534Sscottl * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22195534Sscottl * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23195534Sscottl * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24195534Sscottl * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25195534Sscottl */
26195534Sscottl
27195534Sscottl#include <sys/cdefs.h>
28195534Sscottl__FBSDID("$FreeBSD: stable/10/sys/cam/ata/ata_da.c 308081 2016-10-29 08:48:01Z mav $");
29195534Sscottl
30220454Smav#include "opt_ada.h"
31220454Smav
32195534Sscottl#include <sys/param.h>
33195534Sscottl
34195534Sscottl#ifdef _KERNEL
35195534Sscottl#include <sys/systm.h>
36195534Sscottl#include <sys/kernel.h>
37195534Sscottl#include <sys/bio.h>
38195534Sscottl#include <sys/sysctl.h>
39195534Sscottl#include <sys/taskqueue.h>
40195534Sscottl#include <sys/lock.h>
41195534Sscottl#include <sys/mutex.h>
42195534Sscottl#include <sys/conf.h>
43195534Sscottl#include <sys/devicestat.h>
44195534Sscottl#include <sys/eventhandler.h>
45195534Sscottl#include <sys/malloc.h>
46195534Sscottl#include <sys/cons.h>
47251792Smav#include <sys/proc.h>
48214279Sbrucec#include <sys/reboot.h>
49195534Sscottl#include <geom/geom_disk.h>
50195534Sscottl#endif /* _KERNEL */
51195534Sscottl
52195534Sscottl#ifndef _KERNEL
53195534Sscottl#include <stdio.h>
54195534Sscottl#include <string.h>
55195534Sscottl#endif /* _KERNEL */
56195534Sscottl
57195534Sscottl#include <cam/cam.h>
58195534Sscottl#include <cam/cam_ccb.h>
59195534Sscottl#include <cam/cam_periph.h>
60195534Sscottl#include <cam/cam_xpt_periph.h>
61195534Sscottl#include <cam/cam_sim.h>
62195534Sscottl
63195534Sscottl#include <cam/ata/ata_all.h>
64195534Sscottl
65208349Smarius#include <machine/md_var.h>	/* geometry translation */
66208349Smarius
67195534Sscottl#ifdef _KERNEL
68195534Sscottl
69195534Sscottl#define ATA_MAX_28BIT_LBA               268435455UL
70195534Sscottl
71195534Sscottltypedef enum {
72224497Smav	ADA_STATE_RAHEAD,
73220412Smav	ADA_STATE_WCACHE,
74198708Smav	ADA_STATE_NORMAL
75195534Sscottl} ada_state;
76195534Sscottl
77195534Sscottltypedef enum {
78249199Smarius	ADA_FLAG_CAN_48BIT	= 0x0002,
79249199Smarius	ADA_FLAG_CAN_FLUSHCACHE	= 0x0004,
80249199Smarius	ADA_FLAG_CAN_NCQ	= 0x0008,
81249199Smarius	ADA_FLAG_CAN_DMA	= 0x0010,
82249199Smarius	ADA_FLAG_NEED_OTAG	= 0x0020,
83260387Sscottl	ADA_FLAG_WAS_OTAG	= 0x0040,
84249199Smarius	ADA_FLAG_CAN_TRIM	= 0x0080,
85249199Smarius	ADA_FLAG_OPEN		= 0x0100,
86249199Smarius	ADA_FLAG_SCTX_INIT	= 0x0200,
87249199Smarius	ADA_FLAG_CAN_CFA        = 0x0400,
88249199Smarius	ADA_FLAG_CAN_POWERMGT   = 0x0800,
89253724Smav	ADA_FLAG_CAN_DMA48	= 0x1000,
90253724Smav	ADA_FLAG_DIRTY		= 0x2000
91195534Sscottl} ada_flags;
92195534Sscottl
93195534Sscottltypedef enum {
94222520Smav	ADA_Q_NONE		= 0x00,
95222520Smav	ADA_Q_4K		= 0x01,
96195534Sscottl} ada_quirks;
97195534Sscottl
98250792Ssmh#define ADA_Q_BIT_STRING	\
99250792Ssmh	"\020"			\
100250792Ssmh	"\0014K"
101250792Ssmh
102195534Sscottltypedef enum {
103224497Smav	ADA_CCB_RAHEAD		= 0x01,
104224497Smav	ADA_CCB_WCACHE		= 0x02,
105195534Sscottl	ADA_CCB_BUFFER_IO	= 0x03,
106195534Sscottl	ADA_CCB_DUMP		= 0x05,
107201139Smav	ADA_CCB_TRIM		= 0x06,
108195534Sscottl	ADA_CCB_TYPE_MASK	= 0x0F,
109195534Sscottl} ada_ccb_state;
110195534Sscottl
111195534Sscottl/* Offsets into our private area for storing information */
112195534Sscottl#define ccb_state	ppriv_field0
113195534Sscottl#define ccb_bp		ppriv_ptr1
114195534Sscottl
115195534Sscottlstruct disk_params {
116195534Sscottl	u_int8_t  heads;
117198897Smav	u_int8_t  secs_per_track;
118195534Sscottl	u_int32_t cylinders;
119198897Smav	u_int32_t secsize;	/* Number of bytes/logical sector */
120198897Smav	u_int64_t sectors;	/* Total number sectors */
121195534Sscottl};
122195534Sscottl
123222643Smav#define TRIM_MAX_BLOCKS	8
124249934Ssmh#define TRIM_MAX_RANGES	(TRIM_MAX_BLOCKS * ATA_DSM_BLK_RANGES)
125201139Smavstruct trim_request {
126249934Ssmh	uint8_t		data[TRIM_MAX_RANGES * ATA_DSM_RANGE_SIZE];
127260387Sscottl	TAILQ_HEAD(, bio) bps;
128201139Smav};
129201139Smav
130195534Sscottlstruct ada_softc {
131195534Sscottl	struct	 bio_queue_head bio_queue;
132201139Smav	struct	 bio_queue_head trim_queue;
133260387Sscottl	int	 outstanding_cmds;	/* Number of active commands */
134260387Sscottl	int	 refcount;		/* Active xpt_action() calls */
135195534Sscottl	ada_state state;
136260387Sscottl	ada_flags flags;
137195534Sscottl	ada_quirks quirks;
138248922Ssmh	int	 sort_io_queue;
139201139Smav	int	 trim_max_ranges;
140201139Smav	int	 trim_running;
141224497Smav	int	 read_ahead;
142220454Smav	int	 write_cache;
143220454Smav#ifdef ADA_TEST_FAILURE
144220454Smav	int      force_read_error;
145220454Smav	int      force_write_error;
146220454Smav	int      periodic_read_error;
147220454Smav	int      periodic_read_count;
148220454Smav#endif
149195534Sscottl	struct	 disk_params params;
150195534Sscottl	struct	 disk *disk;
151195534Sscottl	struct task		sysctl_task;
152195534Sscottl	struct sysctl_ctx_list	sysctl_ctx;
153195534Sscottl	struct sysctl_oid	*sysctl_tree;
154195534Sscottl	struct callout		sendordered_c;
155201139Smav	struct trim_request	trim_req;
156195534Sscottl};
157195534Sscottl
158195534Sscottlstruct ada_quirk_entry {
159195534Sscottl	struct scsi_inquiry_pattern inq_pat;
160195534Sscottl	ada_quirks quirks;
161195534Sscottl};
162195534Sscottl
163199178Smavstatic struct ada_quirk_entry ada_quirk_table[] =
164199178Smav{
165199178Smav	{
166222520Smav		/* Hitachi Advanced Format (4k) drives */
167222520Smav		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "Hitachi H??????????E3*", "*" },
168222520Smav		/*quirks*/ADA_Q_4K
169222520Smav	},
170222520Smav	{
171222520Smav		/* Samsung Advanced Format (4k) drives */
172228819Smav		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "SAMSUNG HD155UI*", "*" },
173228819Smav		/*quirks*/ADA_Q_4K
174228819Smav	},
175228819Smav	{
176228819Smav		/* Samsung Advanced Format (4k) drives */
177222520Smav		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "SAMSUNG HD204UI*", "*" },
178222520Smav		/*quirks*/ADA_Q_4K
179222520Smav	},
180222520Smav	{
181222520Smav		/* Seagate Barracuda Green Advanced Format (4k) drives */
182222520Smav		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "ST????DL*", "*" },
183222520Smav		/*quirks*/ADA_Q_4K
184222520Smav	},
185222520Smav	{
186228819Smav		/* Seagate Barracuda Advanced Format (4k) drives */
187228819Smav		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "ST???DM*", "*" },
188228819Smav		/*quirks*/ADA_Q_4K
189228819Smav	},
190228819Smav	{
191228819Smav		/* Seagate Barracuda Advanced Format (4k) drives */
192228819Smav		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "ST????DM*", "*" },
193228819Smav		/*quirks*/ADA_Q_4K
194228819Smav	},
195228819Smav	{
196222520Smav		/* Seagate Momentus Advanced Format (4k) drives */
197222520Smav		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9500423AS*", "*" },
198222520Smav		/*quirks*/ADA_Q_4K
199222520Smav	},
200222520Smav	{
201222520Smav		/* Seagate Momentus Advanced Format (4k) drives */
202222520Smav		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9500424AS*", "*" },
203222520Smav		/*quirks*/ADA_Q_4K
204222520Smav	},
205222520Smav	{
206222520Smav		/* Seagate Momentus Advanced Format (4k) drives */
207228819Smav		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9640423AS*", "*" },
208228819Smav		/*quirks*/ADA_Q_4K
209228819Smav	},
210228819Smav	{
211228819Smav		/* Seagate Momentus Advanced Format (4k) drives */
212228819Smav		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9640424AS*", "*" },
213228819Smav		/*quirks*/ADA_Q_4K
214228819Smav	},
215228819Smav	{
216228819Smav		/* Seagate Momentus Advanced Format (4k) drives */
217222520Smav		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9750420AS*", "*" },
218222520Smav		/*quirks*/ADA_Q_4K
219222520Smav	},
220222520Smav	{
221222520Smav		/* Seagate Momentus Advanced Format (4k) drives */
222222520Smav		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9750422AS*", "*" },
223222520Smav		/*quirks*/ADA_Q_4K
224222520Smav	},
225222520Smav	{
226228819Smav		/* Seagate Momentus Advanced Format (4k) drives */
227228819Smav		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9750423AS*", "*" },
228228819Smav		/*quirks*/ADA_Q_4K
229228819Smav	},
230228819Smav	{
231222520Smav		/* Seagate Momentus Thin Advanced Format (4k) drives */
232222520Smav		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "ST???LT*", "*" },
233222520Smav		/*quirks*/ADA_Q_4K
234222520Smav	},
235222520Smav	{
236288701Smav		/* WDC Caviar Red Advanced Format (4k) drives */
237288701Smav		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD????CX*", "*" },
238288701Smav		/*quirks*/ADA_Q_4K
239288701Smav	},
240288701Smav	{
241222520Smav		/* WDC Caviar Green Advanced Format (4k) drives */
242222520Smav		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD????RS*", "*" },
243222520Smav		/*quirks*/ADA_Q_4K
244222520Smav	},
245222520Smav	{
246288701Smav		/* WDC Caviar Green/Red Advanced Format (4k) drives */
247222520Smav		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD????RX*", "*" },
248222520Smav		/*quirks*/ADA_Q_4K
249222520Smav	},
250222520Smav	{
251288701Smav		/* WDC Caviar Red Advanced Format (4k) drives */
252288701Smav		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD??????CX*", "*" },
253288701Smav		/*quirks*/ADA_Q_4K
254288701Smav	},
255288701Smav	{
256288701Smav		/* WDC Caviar Black Advanced Format (4k) drives */
257288701Smav		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD??????EX*", "*" },
258288701Smav		/*quirks*/ADA_Q_4K
259288701Smav	},
260288701Smav	{
261222520Smav		/* WDC Caviar Green Advanced Format (4k) drives */
262222520Smav		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD??????RS*", "*" },
263222520Smav		/*quirks*/ADA_Q_4K
264222520Smav	},
265222520Smav	{
266222520Smav		/* WDC Caviar Green Advanced Format (4k) drives */
267222520Smav		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD??????RX*", "*" },
268222520Smav		/*quirks*/ADA_Q_4K
269222520Smav	},
270222520Smav	{
271222520Smav		/* WDC Scorpio Black Advanced Format (4k) drives */
272222520Smav		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD???PKT*", "*" },
273222520Smav		/*quirks*/ADA_Q_4K
274222520Smav	},
275222520Smav	{
276222520Smav		/* WDC Scorpio Black Advanced Format (4k) drives */
277222520Smav		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD?????PKT*", "*" },
278222520Smav		/*quirks*/ADA_Q_4K
279222520Smav	},
280222520Smav	{
281222520Smav		/* WDC Scorpio Blue Advanced Format (4k) drives */
282222520Smav		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD???PVT*", "*" },
283222520Smav		/*quirks*/ADA_Q_4K
284222520Smav	},
285222520Smav	{
286222520Smav		/* WDC Scorpio Blue Advanced Format (4k) drives */
287222520Smav		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD?????PVT*", "*" },
288222520Smav		/*quirks*/ADA_Q_4K
289222520Smav	},
290251061Ssmh	/* SSDs */
291222520Smav	{
292241784Seadler		/*
293241784Seadler		 * Corsair Force 2 SSDs
294241784Seadler		 * 4k optimised & trim only works in 4k requests + 4k aligned
295241784Seadler		 */
296241784Seadler		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "Corsair CSSD-F*", "*" },
297241784Seadler		/*quirks*/ADA_Q_4K
298241784Seadler	},
299241784Seadler	{
300241784Seadler		/*
301241784Seadler		 * Corsair Force 3 SSDs
302241784Seadler		 * 4k optimised & trim only works in 4k requests + 4k aligned
303241784Seadler		 */
304241784Seadler		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "Corsair Force 3*", "*" },
305241784Seadler		/*quirks*/ADA_Q_4K
306241784Seadler	},
307241784Seadler	{
308241784Seadler		/*
309260475Smav		 * Corsair Neutron GTX SSDs
310260475Smav		 * 4k optimised & trim only works in 4k requests + 4k aligned
311260475Smav		 */
312260475Smav		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "Corsair Neutron GTX*", "*" },
313260475Smav		/*quirks*/ADA_Q_4K
314260475Smav	},
315260475Smav	{
316260475Smav		/*
317270313Ssmh		 * Corsair Force GT & GS SSDs
318241784Seadler		 * 4k optimised & trim only works in 4k requests + 4k aligned
319241784Seadler		 */
320270313Ssmh		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "Corsair Force G*", "*" },
321241784Seadler		/*quirks*/ADA_Q_4K
322241784Seadler	},
323241784Seadler	{
324241784Seadler		/*
325251061Ssmh		 * Crucial M4 SSDs
326241784Seadler		 * 4k optimised & trim only works in 4k requests + 4k aligned
327241784Seadler		 */
328251061Ssmh		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "M4-CT???M4SSD2*", "*" },
329241784Seadler		/*quirks*/ADA_Q_4K
330241784Seadler	},
331241784Seadler	{
332241784Seadler		/*
333251061Ssmh		 * Crucial RealSSD C300 SSDs
334251061Ssmh		 * 4k optimised
335251061Ssmh		 */
336251061Ssmh		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "C300-CTFDDAC???MAG*",
337251061Ssmh		"*" }, /*quirks*/ADA_Q_4K
338251061Ssmh	},
339251061Ssmh	{
340251061Ssmh		/*
341251061Ssmh		 * Intel 320 Series SSDs
342241784Seadler		 * 4k optimised & trim only works in 4k requests + 4k aligned
343241784Seadler		 */
344251061Ssmh		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "INTEL SSDSA2CW*", "*" },
345241784Seadler		/*quirks*/ADA_Q_4K
346241784Seadler	},
347241784Seadler	{
348241784Seadler		/*
349251061Ssmh		 * Intel 330 Series SSDs
350241784Seadler		 * 4k optimised & trim only works in 4k requests + 4k aligned
351241784Seadler		 */
352251061Ssmh		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "INTEL SSDSC2CT*", "*" },
353241784Seadler		/*quirks*/ADA_Q_4K
354241784Seadler	},
355241784Seadler	{
356241784Seadler		/*
357251061Ssmh		 * Intel 510 Series SSDs
358251061Ssmh		 * 4k optimised & trim only works in 4k requests + 4k aligned
359241784Seadler		 */
360251061Ssmh		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "INTEL SSDSC2MH*", "*" },
361251061Ssmh		/*quirks*/ADA_Q_4K
362241784Seadler	},
363241784Seadler	{
364241784Seadler		/*
365251061Ssmh		 * Intel 520 Series SSDs
366251061Ssmh		 * 4k optimised & trim only works in 4k requests + 4k aligned
367241784Seadler		 */
368251061Ssmh		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "INTEL SSDSC2BW*", "*" },
369241784Seadler		/*quirks*/ADA_Q_4K
370241784Seadler	},
371241784Seadler	{
372241784Seadler		/*
373254329Ssmh		 * Intel X25-M Series SSDs
374254329Ssmh		 * 4k optimised & trim only works in 4k requests + 4k aligned
375254329Ssmh		 */
376254329Ssmh		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "INTEL SSDSA2M*", "*" },
377254329Ssmh		/*quirks*/ADA_Q_4K
378254329Ssmh	},
379254329Ssmh	{
380254329Ssmh		/*
381251061Ssmh		 * Kingston E100 Series SSDs
382250532Seadler		 * 4k optimised & trim only works in 4k requests + 4k aligned
383250532Seadler		 */
384251061Ssmh		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "KINGSTON SE100S3*", "*" },
385250532Seadler		/*quirks*/ADA_Q_4K
386250532Seadler	},
387250532Seadler	{
388250532Seadler		/*
389251061Ssmh		 * Kingston HyperX 3k SSDs
390241784Seadler		 * 4k optimised & trim only works in 4k requests + 4k aligned
391241784Seadler		 */
392251061Ssmh		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "KINGSTON SH103S3*", "*" },
393241784Seadler		/*quirks*/ADA_Q_4K
394241784Seadler	},
395241784Seadler	{
396241784Seadler		/*
397254329Ssmh		 * Marvell SSDs (entry taken from OpenSolaris)
398254329Ssmh		 * 4k optimised & trim only works in 4k requests + 4k aligned
399254329Ssmh		 */
400254329Ssmh		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "MARVELL SD88SA02*", "*" },
401254329Ssmh		/*quirks*/ADA_Q_4K
402254329Ssmh	},
403254329Ssmh	{
404254329Ssmh		/*
405254329Ssmh		 * OCZ Agility 2 SSDs
406254329Ssmh		 * 4k optimised & trim only works in 4k requests + 4k aligned
407254329Ssmh		 */
408254329Ssmh		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "OCZ-AGILITY2*", "*" },
409254329Ssmh		/*quirks*/ADA_Q_4K
410254329Ssmh	},
411254329Ssmh	{
412254329Ssmh		/*
413251061Ssmh		 * OCZ Agility 3 SSDs
414250532Seadler		 * 4k optimised & trim only works in 4k requests + 4k aligned
415250532Seadler		 */
416251061Ssmh		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "OCZ-AGILITY3*", "*" },
417250532Seadler		/*quirks*/ADA_Q_4K
418250532Seadler	},
419250532Seadler	{
420250532Seadler		/*
421241784Seadler		 * OCZ Deneva R Series SSDs
422241784Seadler		 * 4k optimised & trim only works in 4k requests + 4k aligned
423241784Seadler		 */
424241784Seadler		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "DENRSTE251M45*", "*" },
425241784Seadler		/*quirks*/ADA_Q_4K
426241784Seadler	},
427241784Seadler	{
428241784Seadler		/*
429251061Ssmh		 * OCZ Vertex 2 SSDs (inc pro series)
430241784Seadler		 * 4k optimised & trim only works in 4k requests + 4k aligned
431241784Seadler		 */
432251061Ssmh		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "OCZ?VERTEX2*", "*" },
433241784Seadler		/*quirks*/ADA_Q_4K
434241784Seadler	},
435241784Seadler	{
436251061Ssmh		/*
437251061Ssmh		 * OCZ Vertex 3 SSDs
438251061Ssmh		 * 4k optimised & trim only works in 4k requests + 4k aligned
439251061Ssmh		 */
440251061Ssmh		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "OCZ-VERTEX3*", "*" },
441251061Ssmh		/*quirks*/ADA_Q_4K
442251061Ssmh	},
443251061Ssmh	{
444251061Ssmh		/*
445253091Ssmh		 * OCZ Vertex 4 SSDs
446253091Ssmh		 * 4k optimised & trim only works in 4k requests + 4k aligned
447253091Ssmh		 */
448253091Ssmh		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "OCZ-VERTEX4*", "*" },
449253091Ssmh		/*quirks*/ADA_Q_4K
450253091Ssmh	},
451253091Ssmh	{
452253091Ssmh		/*
453251061Ssmh		 * Samsung 830 Series SSDs
454251061Ssmh		 * 4k optimised
455251061Ssmh		 */
456251061Ssmh		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "SAMSUNG SSD 830 Series*", "*" },
457251061Ssmh		/*quirks*/ADA_Q_4K
458251061Ssmh	},
459251061Ssmh	{
460251061Ssmh		/*
461270313Ssmh		 * Samsung 840 SSDs
462270313Ssmh		 * 4k optimised
463270313Ssmh		 */
464270313Ssmh		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "Samsung SSD 840*", "*" },
465270313Ssmh		/*quirks*/ADA_Q_4K
466270313Ssmh	},
467270313Ssmh	{
468270313Ssmh		/*
469274260Sgnn		 * Samsung 850 SSDs
470274260Sgnn		 * 4k optimised
471274260Sgnn		 */
472274260Sgnn		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "Samsung SSD 850*", "*" },
473274260Sgnn		/*quirks*/ADA_Q_4K
474274260Sgnn	},
475274260Sgnn	{
476274260Sgnn		/*
477297575Sdumbbell		 * Samsung 843T Series SSDs (MZ7WD*)
478297575Sdumbbell		 * Samsung PM851 Series SSDs (MZ7TE*)
479297575Sdumbbell		 * Samsung PM853T Series SSDs (MZ7GE*)
480297575Sdumbbell		 * Samsung SM863 Series SSDs (MZ7KM*)
481274260Sgnn		 * 4k optimised
482274260Sgnn		 */
483297575Sdumbbell		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "SAMSUNG MZ7*", "*" },
484274260Sgnn		/*quirks*/ADA_Q_4K
485274260Sgnn	},
486274260Sgnn	{
487274260Sgnn		/*
488251061Ssmh		 * SuperTalent TeraDrive CT SSDs
489251061Ssmh		 * 4k optimised & trim only works in 4k requests + 4k aligned
490251061Ssmh		 */
491251061Ssmh		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "FTM??CT25H*", "*" },
492251061Ssmh		/*quirks*/ADA_Q_4K
493251061Ssmh	},
494251061Ssmh	{
495251061Ssmh		/*
496251061Ssmh		 * XceedIOPS SATA SSDs
497251061Ssmh		 * 4k optimised
498251061Ssmh		 */
499251061Ssmh		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "SG9XCS2D*", "*" },
500251061Ssmh		/*quirks*/ADA_Q_4K
501251061Ssmh	},
502251061Ssmh	{
503199178Smav		/* Default */
504199178Smav		{
505199178Smav		  T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED,
506199178Smav		  /*vendor*/"*", /*product*/"*", /*revision*/"*"
507199178Smav		},
508199178Smav		/*quirks*/0
509199178Smav	},
510199178Smav};
511195534Sscottl
512195534Sscottlstatic	disk_strategy_t	adastrategy;
513195534Sscottlstatic	dumper_t	adadump;
514195534Sscottlstatic	periph_init_t	adainit;
515195534Sscottlstatic	void		adaasync(void *callback_arg, u_int32_t code,
516195534Sscottl				struct cam_path *path, void *arg);
517195534Sscottlstatic	void		adasysctlinit(void *context, int pending);
518195534Sscottlstatic	periph_ctor_t	adaregister;
519195534Sscottlstatic	periph_dtor_t	adacleanup;
520195534Sscottlstatic	periph_start_t	adastart;
521195534Sscottlstatic	periph_oninv_t	adaoninvalidate;
522195534Sscottlstatic	void		adadone(struct cam_periph *periph,
523195534Sscottl			       union ccb *done_ccb);
524195534Sscottlstatic  int		adaerror(union ccb *ccb, u_int32_t cam_flags,
525195534Sscottl				u_int32_t sense_flags);
526198897Smavstatic void		adagetparams(struct cam_periph *periph,
527195534Sscottl				struct ccb_getdev *cgd);
528195534Sscottlstatic timeout_t	adasendorderedtag;
529195534Sscottlstatic void		adashutdown(void *arg, int howto);
530220650Smavstatic void		adasuspend(void *arg);
531220650Smavstatic void		adaresume(void *arg);
532195534Sscottl
533221071Smav#ifndef	ADA_DEFAULT_LEGACY_ALIASES
534221071Smav#define	ADA_DEFAULT_LEGACY_ALIASES	1
535221071Smav#endif
536221071Smav
537195534Sscottl#ifndef ADA_DEFAULT_TIMEOUT
538195534Sscottl#define ADA_DEFAULT_TIMEOUT 30	/* Timeout in seconds */
539195534Sscottl#endif
540195534Sscottl
541195534Sscottl#ifndef	ADA_DEFAULT_RETRY
542195534Sscottl#define	ADA_DEFAULT_RETRY	4
543195534Sscottl#endif
544195534Sscottl
545195534Sscottl#ifndef	ADA_DEFAULT_SEND_ORDERED
546195534Sscottl#define	ADA_DEFAULT_SEND_ORDERED	1
547195534Sscottl#endif
548195534Sscottl
549214279Sbrucec#ifndef	ADA_DEFAULT_SPINDOWN_SHUTDOWN
550214279Sbrucec#define	ADA_DEFAULT_SPINDOWN_SHUTDOWN	1
551214279Sbrucec#endif
552214279Sbrucec
553220650Smav#ifndef	ADA_DEFAULT_SPINDOWN_SUSPEND
554220650Smav#define	ADA_DEFAULT_SPINDOWN_SUSPEND	1
555220650Smav#endif
556220650Smav
557224497Smav#ifndef	ADA_DEFAULT_READ_AHEAD
558224497Smav#define	ADA_DEFAULT_READ_AHEAD	1
559224497Smav#endif
560224497Smav
561220412Smav#ifndef	ADA_DEFAULT_WRITE_CACHE
562220412Smav#define	ADA_DEFAULT_WRITE_CACHE	1
563220412Smav#endif
564220412Smav
565224497Smav#define	ADA_RA	(softc->read_ahead >= 0 ? \
566224497Smav		 softc->read_ahead : ada_read_ahead)
567224497Smav#define	ADA_WC	(softc->write_cache >= 0 ? \
568224497Smav		 softc->write_cache : ada_write_cache)
569248922Ssmh#define	ADA_SIO	(softc->sort_io_queue >= 0 ? \
570248922Ssmh		 softc->sort_io_queue : cam_sort_io_queues)
571224497Smav
572208349Smarius/*
573208349Smarius * Most platforms map firmware geometry to actual, but some don't.  If
574208349Smarius * not overridden, default to nothing.
575208349Smarius */
576208349Smarius#ifndef ata_disk_firmware_geom_adjust
577208349Smarius#define	ata_disk_firmware_geom_adjust(disk)
578208349Smarius#endif
579195534Sscottl
580221071Smavstatic int ada_legacy_aliases = ADA_DEFAULT_LEGACY_ALIASES;
581195534Sscottlstatic int ada_retry_count = ADA_DEFAULT_RETRY;
582195534Sscottlstatic int ada_default_timeout = ADA_DEFAULT_TIMEOUT;
583195534Sscottlstatic int ada_send_ordered = ADA_DEFAULT_SEND_ORDERED;
584214279Sbrucecstatic int ada_spindown_shutdown = ADA_DEFAULT_SPINDOWN_SHUTDOWN;
585220650Smavstatic int ada_spindown_suspend = ADA_DEFAULT_SPINDOWN_SUSPEND;
586224497Smavstatic int ada_read_ahead = ADA_DEFAULT_READ_AHEAD;
587220412Smavstatic int ada_write_cache = ADA_DEFAULT_WRITE_CACHE;
588195534Sscottl
589227309Sedstatic SYSCTL_NODE(_kern_cam, OID_AUTO, ada, CTLFLAG_RD, 0,
590195534Sscottl            "CAM Direct Access Disk driver");
591221071SmavSYSCTL_INT(_kern_cam_ada, OID_AUTO, legacy_aliases, CTLFLAG_RW,
592221071Smav           &ada_legacy_aliases, 0, "Create legacy-like device aliases");
593221071SmavTUNABLE_INT("kern.cam.ada.legacy_aliases", &ada_legacy_aliases);
594195534SscottlSYSCTL_INT(_kern_cam_ada, OID_AUTO, retry_count, CTLFLAG_RW,
595195534Sscottl           &ada_retry_count, 0, "Normal I/O retry count");
596195534SscottlTUNABLE_INT("kern.cam.ada.retry_count", &ada_retry_count);
597195534SscottlSYSCTL_INT(_kern_cam_ada, OID_AUTO, default_timeout, CTLFLAG_RW,
598195534Sscottl           &ada_default_timeout, 0, "Normal I/O timeout (in seconds)");
599195534SscottlTUNABLE_INT("kern.cam.ada.default_timeout", &ada_default_timeout);
600238382SbruefferSYSCTL_INT(_kern_cam_ada, OID_AUTO, send_ordered, CTLFLAG_RW,
601195534Sscottl           &ada_send_ordered, 0, "Send Ordered Tags");
602238382SbruefferTUNABLE_INT("kern.cam.ada.send_ordered", &ada_send_ordered);
603214279SbrucecSYSCTL_INT(_kern_cam_ada, OID_AUTO, spindown_shutdown, CTLFLAG_RW,
604214279Sbrucec           &ada_spindown_shutdown, 0, "Spin down upon shutdown");
605214279SbrucecTUNABLE_INT("kern.cam.ada.spindown_shutdown", &ada_spindown_shutdown);
606220650SmavSYSCTL_INT(_kern_cam_ada, OID_AUTO, spindown_suspend, CTLFLAG_RW,
607220650Smav           &ada_spindown_suspend, 0, "Spin down upon suspend");
608220650SmavTUNABLE_INT("kern.cam.ada.spindown_suspend", &ada_spindown_suspend);
609224497SmavSYSCTL_INT(_kern_cam_ada, OID_AUTO, read_ahead, CTLFLAG_RW,
610224497Smav           &ada_read_ahead, 0, "Enable disk read-ahead");
611224497SmavTUNABLE_INT("kern.cam.ada.read_ahead", &ada_read_ahead);
612220412SmavSYSCTL_INT(_kern_cam_ada, OID_AUTO, write_cache, CTLFLAG_RW,
613220412Smav           &ada_write_cache, 0, "Enable disk write cache");
614220412SmavTUNABLE_INT("kern.cam.ada.write_cache", &ada_write_cache);
615195534Sscottl
616195534Sscottl/*
617195534Sscottl * ADA_ORDEREDTAG_INTERVAL determines how often, relative
618195534Sscottl * to the default timeout, we check to see whether an ordered
619195534Sscottl * tagged transaction is appropriate to prevent simple tag
620195534Sscottl * starvation.  Since we'd like to ensure that there is at least
621195534Sscottl * 1/2 of the timeout length left for a starved transaction to
622195534Sscottl * complete after we've sent an ordered tag, we must poll at least
623195534Sscottl * four times in every timeout period.  This takes care of the worst
624195534Sscottl * case where a starved transaction starts during an interval that
625195534Sscottl * meets the requirement "don't send an ordered tag" test so it takes
626195534Sscottl * us two intervals to determine that a tag must be sent.
627195534Sscottl */
628195534Sscottl#ifndef ADA_ORDEREDTAG_INTERVAL
629195534Sscottl#define ADA_ORDEREDTAG_INTERVAL 4
630195534Sscottl#endif
631195534Sscottl
632195534Sscottlstatic struct periph_driver adadriver =
633195534Sscottl{
634195534Sscottl	adainit, "ada",
635195534Sscottl	TAILQ_HEAD_INITIALIZER(adadriver.units), /* generation */ 0
636195534Sscottl};
637195534Sscottl
638195534SscottlPERIPHDRIVER_DECLARE(ada, adadriver);
639195534Sscottl
640195534Sscottlstatic int
641195534Sscottladaopen(struct disk *dp)
642195534Sscottl{
643195534Sscottl	struct cam_periph *periph;
644195534Sscottl	struct ada_softc *softc;
645195534Sscottl	int error;
646195534Sscottl
647195534Sscottl	periph = (struct cam_periph *)dp->d_drv1;
648195534Sscottl	if (cam_periph_acquire(periph) != CAM_REQ_CMP) {
649195534Sscottl		return(ENXIO);
650195534Sscottl	}
651195534Sscottl
652195534Sscottl	cam_periph_lock(periph);
653195534Sscottl	if ((error = cam_periph_hold(periph, PRIBIO|PCATCH)) != 0) {
654195534Sscottl		cam_periph_unlock(periph);
655195534Sscottl		cam_periph_release(periph);
656195534Sscottl		return (error);
657195534Sscottl	}
658195534Sscottl
659236602Smav	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE | CAM_DEBUG_PERIPH,
660236602Smav	    ("adaopen\n"));
661195534Sscottl
662249981Smav	softc = (struct ada_softc *)periph->softc;
663249981Smav	softc->flags |= ADA_FLAG_OPEN;
664195534Sscottl
665195534Sscottl	cam_periph_unhold(periph);
666195534Sscottl	cam_periph_unlock(periph);
667195534Sscottl	return (0);
668195534Sscottl}
669195534Sscottl
670195534Sscottlstatic int
671195534Sscottladaclose(struct disk *dp)
672195534Sscottl{
673195534Sscottl	struct	cam_periph *periph;
674195534Sscottl	struct	ada_softc *softc;
675195534Sscottl	union ccb *ccb;
676253724Smav	int error;
677195534Sscottl
678195534Sscottl	periph = (struct cam_periph *)dp->d_drv1;
679260387Sscottl	softc = (struct ada_softc *)periph->softc;
680195534Sscottl	cam_periph_lock(periph);
681195534Sscottl
682236602Smav	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE | CAM_DEBUG_PERIPH,
683236602Smav	    ("adaclose\n"));
684236602Smav
685195534Sscottl	/* We only sync the cache if the drive is capable of it. */
686253724Smav	if ((softc->flags & ADA_FLAG_DIRTY) != 0 &&
687253724Smav	    (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) != 0 &&
688260387Sscottl	    (periph->flags & CAM_PERIPH_INVALID) == 0 &&
689260387Sscottl	    cam_periph_hold(periph, PRIBIO) == 0) {
690195534Sscottl
691198382Smav		ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL);
692195534Sscottl		cam_fill_ataio(&ccb->ataio,
693195534Sscottl				    1,
694195534Sscottl				    adadone,
695195534Sscottl				    CAM_DIR_NONE,
696195534Sscottl				    0,
697195534Sscottl				    NULL,
698195534Sscottl				    0,
699195534Sscottl				    ada_default_timeout*1000);
700195534Sscottl
701195534Sscottl		if (softc->flags & ADA_FLAG_CAN_48BIT)
702195534Sscottl			ata_48bit_cmd(&ccb->ataio, ATA_FLUSHCACHE48, 0, 0, 0);
703195534Sscottl		else
704196659Smav			ata_28bit_cmd(&ccb->ataio, ATA_FLUSHCACHE, 0, 0, 0);
705253724Smav		error = cam_periph_runccb(ccb, adaerror, /*cam_flags*/0,
706198328Smav		    /*sense_flags*/0, softc->disk->d_devstat);
707195534Sscottl
708253724Smav		if (error != 0)
709195534Sscottl			xpt_print(periph->path, "Synchronize cache failed\n");
710308081Smav		softc->flags &= ~ADA_FLAG_DIRTY;
711195534Sscottl		xpt_release_ccb(ccb);
712260387Sscottl		cam_periph_unhold(periph);
713195534Sscottl	}
714195534Sscottl
715195534Sscottl	softc->flags &= ~ADA_FLAG_OPEN;
716260387Sscottl
717260387Sscottl	while (softc->refcount != 0)
718260387Sscottl		cam_periph_sleep(periph, &softc->refcount, PRIBIO, "adaclose", 1);
719195534Sscottl	cam_periph_unlock(periph);
720195534Sscottl	cam_periph_release(periph);
721195534Sscottl	return (0);
722195534Sscottl}
723195534Sscottl
724201139Smavstatic void
725201139Smavadaschedule(struct cam_periph *periph)
726201139Smav{
727201139Smav	struct ada_softc *softc = (struct ada_softc *)periph->softc;
728201139Smav
729249205Smav	if (softc->state != ADA_STATE_NORMAL)
730249205Smav		return;
731249205Smav
732224531Smav	/* Check if we have more work to do. */
733201139Smav	if (bioq_first(&softc->bio_queue) ||
734201139Smav	    (!softc->trim_running && bioq_first(&softc->trim_queue))) {
735260387Sscottl		xpt_schedule(periph, CAM_PRIORITY_NORMAL);
736201139Smav	}
737201139Smav}
738201139Smav
739195534Sscottl/*
740195534Sscottl * Actually translate the requested transfer into one the physical driver
741195534Sscottl * can understand.  The transfer is described by a buf and will include
742195534Sscottl * only one physical transfer.
743195534Sscottl */
744195534Sscottlstatic void
745195534Sscottladastrategy(struct bio *bp)
746195534Sscottl{
747195534Sscottl	struct cam_periph *periph;
748195534Sscottl	struct ada_softc *softc;
749195534Sscottl
750195534Sscottl	periph = (struct cam_periph *)bp->bio_disk->d_drv1;
751195534Sscottl	softc = (struct ada_softc *)periph->softc;
752195534Sscottl
753195534Sscottl	cam_periph_lock(periph);
754195534Sscottl
755236602Smav	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("adastrategy(%p)\n", bp));
756236602Smav
757195534Sscottl	/*
758195534Sscottl	 * If the device has been made invalid, error out
759195534Sscottl	 */
760249981Smav	if ((periph->flags & CAM_PERIPH_INVALID) != 0) {
761195534Sscottl		cam_periph_unlock(periph);
762195534Sscottl		biofinish(bp, NULL, ENXIO);
763195534Sscottl		return;
764195534Sscottl	}
765195534Sscottl
766195534Sscottl	/*
767195534Sscottl	 * Place it in the queue of disk activities for this disk
768195534Sscottl	 */
769268815Simp	if (bp->bio_cmd == BIO_DELETE) {
770268816Simp		bioq_disksort(&softc->trim_queue, bp);
771248922Ssmh	} else {
772248922Ssmh		if (ADA_SIO)
773248922Ssmh		    bioq_disksort(&softc->bio_queue, bp);
774248922Ssmh		else
775248922Ssmh		    bioq_insert_tail(&softc->bio_queue, bp);
776248922Ssmh	}
777195534Sscottl
778195534Sscottl	/*
779195534Sscottl	 * Schedule ourselves for performing the work.
780195534Sscottl	 */
781201139Smav	adaschedule(periph);
782195534Sscottl	cam_periph_unlock(periph);
783195534Sscottl
784195534Sscottl	return;
785195534Sscottl}
786195534Sscottl
787195534Sscottlstatic int
788195534Sscottladadump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t length)
789195534Sscottl{
790195534Sscottl	struct	    cam_periph *periph;
791195534Sscottl	struct	    ada_softc *softc;
792195534Sscottl	u_int	    secsize;
793195534Sscottl	union	    ccb ccb;
794195534Sscottl	struct	    disk *dp;
795195534Sscottl	uint64_t    lba;
796195534Sscottl	uint16_t    count;
797236814Smav	int	    error = 0;
798195534Sscottl
799195534Sscottl	dp = arg;
800195534Sscottl	periph = dp->d_drv1;
801195534Sscottl	softc = (struct ada_softc *)periph->softc;
802195534Sscottl	cam_periph_lock(periph);
803195534Sscottl	secsize = softc->params.secsize;
804195534Sscottl	lba = offset / secsize;
805195534Sscottl	count = length / secsize;
806195534Sscottl
807249981Smav	if ((periph->flags & CAM_PERIPH_INVALID) != 0) {
808195534Sscottl		cam_periph_unlock(periph);
809195534Sscottl		return (ENXIO);
810195534Sscottl	}
811195534Sscottl
812195534Sscottl	if (length > 0) {
813198382Smav		xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
814195534Sscottl		ccb.ccb_h.ccb_state = ADA_CCB_DUMP;
815195534Sscottl		cam_fill_ataio(&ccb.ataio,
816195534Sscottl		    0,
817195534Sscottl		    adadone,
818195534Sscottl		    CAM_DIR_OUT,
819195534Sscottl		    0,
820195534Sscottl		    (u_int8_t *) virtual,
821195534Sscottl		    length,
822195534Sscottl		    ada_default_timeout*1000);
823195534Sscottl		if ((softc->flags & ADA_FLAG_CAN_48BIT) &&
824195534Sscottl		    (lba + count >= ATA_MAX_28BIT_LBA ||
825195534Sscottl		    count >= 256)) {
826195534Sscottl			ata_48bit_cmd(&ccb.ataio, ATA_WRITE_DMA48,
827195534Sscottl			    0, lba, count);
828195534Sscottl		} else {
829196659Smav			ata_28bit_cmd(&ccb.ataio, ATA_WRITE_DMA,
830195534Sscottl			    0, lba, count);
831195534Sscottl		}
832195534Sscottl		xpt_polled_action(&ccb);
833195534Sscottl
834236814Smav		error = cam_periph_error(&ccb,
835236814Smav		    0, SF_NO_RECOVERY | SF_NO_RETRY, NULL);
836236814Smav		if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0)
837236814Smav			cam_release_devq(ccb.ccb_h.path, /*relsim_flags*/0,
838236814Smav			    /*reduction*/0, /*timeout*/0, /*getcount_only*/0);
839236814Smav		if (error != 0)
840195534Sscottl			printf("Aborting dump due to I/O error.\n");
841236814Smav
842195534Sscottl		cam_periph_unlock(periph);
843236814Smav		return (error);
844195534Sscottl	}
845195534Sscottl
846195534Sscottl	if (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) {
847198382Smav		xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
848195534Sscottl
849195534Sscottl		ccb.ccb_h.ccb_state = ADA_CCB_DUMP;
850195534Sscottl		cam_fill_ataio(&ccb.ataio,
851236814Smav				    0,
852195534Sscottl				    adadone,
853195534Sscottl				    CAM_DIR_NONE,
854195534Sscottl				    0,
855195534Sscottl				    NULL,
856195534Sscottl				    0,
857195534Sscottl				    ada_default_timeout*1000);
858195534Sscottl
859195534Sscottl		if (softc->flags & ADA_FLAG_CAN_48BIT)
860195534Sscottl			ata_48bit_cmd(&ccb.ataio, ATA_FLUSHCACHE48, 0, 0, 0);
861195534Sscottl		else
862196659Smav			ata_28bit_cmd(&ccb.ataio, ATA_FLUSHCACHE, 0, 0, 0);
863195534Sscottl		xpt_polled_action(&ccb);
864195534Sscottl
865236814Smav		error = cam_periph_error(&ccb,
866236814Smav		    0, SF_NO_RECOVERY | SF_NO_RETRY, NULL);
867236814Smav		if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0)
868236814Smav			cam_release_devq(ccb.ccb_h.path, /*relsim_flags*/0,
869236814Smav			    /*reduction*/0, /*timeout*/0, /*getcount_only*/0);
870236814Smav		if (error != 0)
871195534Sscottl			xpt_print(periph->path, "Synchronize cache failed\n");
872195534Sscottl	}
873195534Sscottl	cam_periph_unlock(periph);
874236814Smav	return (error);
875195534Sscottl}
876195534Sscottl
877195534Sscottlstatic void
878195534Sscottladainit(void)
879195534Sscottl{
880195534Sscottl	cam_status status;
881195534Sscottl
882195534Sscottl	/*
883195534Sscottl	 * Install a global async callback.  This callback will
884195534Sscottl	 * receive async callbacks like "new device found".
885195534Sscottl	 */
886195534Sscottl	status = xpt_register_async(AC_FOUND_DEVICE, adaasync, NULL, NULL);
887195534Sscottl
888195534Sscottl	if (status != CAM_REQ_CMP) {
889195534Sscottl		printf("ada: Failed to attach master async callback "
890195534Sscottl		       "due to status 0x%x!\n", status);
891195534Sscottl	} else if (ada_send_ordered) {
892195534Sscottl
893220650Smav		/* Register our event handlers */
894220650Smav		if ((EVENTHANDLER_REGISTER(power_suspend, adasuspend,
895220650Smav					   NULL, EVENTHANDLER_PRI_LAST)) == NULL)
896220650Smav		    printf("adainit: power event registration failed!\n");
897220650Smav		if ((EVENTHANDLER_REGISTER(power_resume, adaresume,
898220650Smav					   NULL, EVENTHANDLER_PRI_LAST)) == NULL)
899220650Smav		    printf("adainit: power event registration failed!\n");
900220650Smav		if ((EVENTHANDLER_REGISTER(shutdown_post_sync, adashutdown,
901195534Sscottl					   NULL, SHUTDOWN_PRI_DEFAULT)) == NULL)
902195534Sscottl		    printf("adainit: shutdown event registration failed!\n");
903195534Sscottl	}
904195534Sscottl}
905195534Sscottl
906249347Sken/*
907249347Sken * Callback from GEOM, called when it has finished cleaning up its
908249347Sken * resources.
909249347Sken */
910195534Sscottlstatic void
911249347Skenadadiskgonecb(struct disk *dp)
912249347Sken{
913249347Sken	struct cam_periph *periph;
914249347Sken
915249347Sken	periph = (struct cam_periph *)dp->d_drv1;
916249347Sken
917249347Sken	cam_periph_release(periph);
918249347Sken}
919249347Sken
920249347Skenstatic void
921195534Sscottladaoninvalidate(struct cam_periph *periph)
922195534Sscottl{
923195534Sscottl	struct ada_softc *softc;
924195534Sscottl
925195534Sscottl	softc = (struct ada_softc *)periph->softc;
926195534Sscottl
927195534Sscottl	/*
928195534Sscottl	 * De-register any async callbacks.
929195534Sscottl	 */
930195534Sscottl	xpt_register_async(0, adaasync, periph, periph->path);
931195534Sscottl
932195534Sscottl	/*
933195534Sscottl	 * Return all queued I/O with ENXIO.
934195534Sscottl	 * XXX Handle any transactions queued to the card
935195534Sscottl	 *     with XPT_ABORT_CCB.
936195534Sscottl	 */
937195534Sscottl	bioq_flush(&softc->bio_queue, NULL, ENXIO);
938201139Smav	bioq_flush(&softc->trim_queue, NULL, ENXIO);
939195534Sscottl
940195534Sscottl	disk_gone(softc->disk);
941195534Sscottl}
942195534Sscottl
943195534Sscottlstatic void
944195534Sscottladacleanup(struct cam_periph *periph)
945195534Sscottl{
946195534Sscottl	struct ada_softc *softc;
947195534Sscottl
948195534Sscottl	softc = (struct ada_softc *)periph->softc;
949195534Sscottl
950195534Sscottl	cam_periph_unlock(periph);
951195534Sscottl
952195534Sscottl	/*
953195534Sscottl	 * If we can't free the sysctl tree, oh well...
954195534Sscottl	 */
955195534Sscottl	if ((softc->flags & ADA_FLAG_SCTX_INIT) != 0
956195534Sscottl	    && sysctl_ctx_free(&softc->sysctl_ctx) != 0) {
957195534Sscottl		xpt_print(periph->path, "can't remove sysctl context\n");
958195534Sscottl	}
959195534Sscottl
960195534Sscottl	disk_destroy(softc->disk);
961195534Sscottl	callout_drain(&softc->sendordered_c);
962195534Sscottl	free(softc, M_DEVBUF);
963195534Sscottl	cam_periph_lock(periph);
964195534Sscottl}
965195534Sscottl
966195534Sscottlstatic void
967195534Sscottladaasync(void *callback_arg, u_int32_t code,
968195534Sscottl	struct cam_path *path, void *arg)
969195534Sscottl{
970236393Smav	struct ccb_getdev cgd;
971195534Sscottl	struct cam_periph *periph;
972220412Smav	struct ada_softc *softc;
973195534Sscottl
974195534Sscottl	periph = (struct cam_periph *)callback_arg;
975195534Sscottl	switch (code) {
976195534Sscottl	case AC_FOUND_DEVICE:
977195534Sscottl	{
978195534Sscottl		struct ccb_getdev *cgd;
979195534Sscottl		cam_status status;
980195534Sscottl
981195534Sscottl		cgd = (struct ccb_getdev *)arg;
982195534Sscottl		if (cgd == NULL)
983195534Sscottl			break;
984195534Sscottl
985195534Sscottl		if (cgd->protocol != PROTO_ATA)
986195534Sscottl			break;
987195534Sscottl
988195534Sscottl		/*
989195534Sscottl		 * Allocate a peripheral instance for
990195534Sscottl		 * this device and start the probe
991195534Sscottl		 * process.
992195534Sscottl		 */
993195534Sscottl		status = cam_periph_alloc(adaregister, adaoninvalidate,
994195534Sscottl					  adacleanup, adastart,
995195534Sscottl					  "ada", CAM_PERIPH_BIO,
996260387Sscottl					  path, adaasync,
997195534Sscottl					  AC_FOUND_DEVICE, cgd);
998195534Sscottl
999195534Sscottl		if (status != CAM_REQ_CMP
1000195534Sscottl		 && status != CAM_REQ_INPROG)
1001195534Sscottl			printf("adaasync: Unable to attach to new device "
1002195534Sscottl				"due to status 0x%x\n", status);
1003195534Sscottl		break;
1004195534Sscottl	}
1005236393Smav	case AC_GETDEV_CHANGED:
1006236393Smav	{
1007236393Smav		softc = (struct ada_softc *)periph->softc;
1008236393Smav		xpt_setup_ccb(&cgd.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
1009236393Smav		cgd.ccb_h.func_code = XPT_GDEV_TYPE;
1010236393Smav		xpt_action((union ccb *)&cgd);
1011236393Smav
1012236393Smav		if ((cgd.ident_data.capabilities1 & ATA_SUPPORT_DMA) &&
1013236393Smav		    (cgd.inq_flags & SID_DMA))
1014236393Smav			softc->flags |= ADA_FLAG_CAN_DMA;
1015236393Smav		else
1016236393Smav			softc->flags &= ~ADA_FLAG_CAN_DMA;
1017249199Smarius		if (cgd.ident_data.support.command2 & ATA_SUPPORT_ADDRESS48) {
1018249199Smarius			softc->flags |= ADA_FLAG_CAN_48BIT;
1019249199Smarius			if (cgd.inq_flags & SID_DMA48)
1020249199Smarius				softc->flags |= ADA_FLAG_CAN_DMA48;
1021249199Smarius			else
1022249199Smarius				softc->flags &= ~ADA_FLAG_CAN_DMA48;
1023249199Smarius		} else
1024249199Smarius			softc->flags &= ~(ADA_FLAG_CAN_48BIT |
1025249199Smarius			    ADA_FLAG_CAN_DMA48);
1026236393Smav		if ((cgd.ident_data.satacapabilities & ATA_SUPPORT_NCQ) &&
1027236393Smav		    (cgd.inq_flags & SID_DMA) && (cgd.inq_flags & SID_CmdQue))
1028236393Smav			softc->flags |= ADA_FLAG_CAN_NCQ;
1029236393Smav		else
1030236393Smav			softc->flags &= ~ADA_FLAG_CAN_NCQ;
1031236393Smav		if ((cgd.ident_data.support_dsm & ATA_SUPPORT_DSM_TRIM) &&
1032236393Smav		    (cgd.inq_flags & SID_DMA))
1033236393Smav			softc->flags |= ADA_FLAG_CAN_TRIM;
1034236393Smav		else
1035236393Smav			softc->flags &= ~ADA_FLAG_CAN_TRIM;
1036236393Smav
1037236393Smav		cam_periph_async(periph, code, path, arg);
1038236393Smav		break;
1039236393Smav	}
1040235897Smav	case AC_ADVINFO_CHANGED:
1041235897Smav	{
1042235897Smav		uintptr_t buftype;
1043235897Smav
1044235897Smav		buftype = (uintptr_t)arg;
1045235897Smav		if (buftype == CDAI_TYPE_PHYS_PATH) {
1046235897Smav			struct ada_softc *softc;
1047235897Smav
1048235897Smav			softc = periph->softc;
1049235897Smav			disk_attr_changed(softc->disk, "GEOM::physpath",
1050235897Smav					  M_NOWAIT);
1051235897Smav		}
1052235897Smav		break;
1053235897Smav	}
1054220412Smav	case AC_SENT_BDR:
1055220412Smav	case AC_BUS_RESET:
1056220412Smav	{
1057220412Smav		softc = (struct ada_softc *)periph->softc;
1058220412Smav		cam_periph_async(periph, code, path, arg);
1059220412Smav		if (softc->state != ADA_STATE_NORMAL)
1060220412Smav			break;
1061220454Smav		xpt_setup_ccb(&cgd.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
1062220412Smav		cgd.ccb_h.func_code = XPT_GDEV_TYPE;
1063220412Smav		xpt_action((union ccb *)&cgd);
1064224497Smav		if (ADA_RA >= 0 &&
1065224497Smav		    cgd.ident_data.support.command1 & ATA_SUPPORT_LOOKAHEAD)
1066224497Smav			softc->state = ADA_STATE_RAHEAD;
1067224497Smav		else if (ADA_WC >= 0 &&
1068224497Smav		    cgd.ident_data.support.command1 & ATA_SUPPORT_WRITECACHE)
1069224497Smav			softc->state = ADA_STATE_WCACHE;
1070224497Smav		else
1071224497Smav		    break;
1072260387Sscottl		if (cam_periph_acquire(periph) != CAM_REQ_CMP)
1073260387Sscottl			softc->state = ADA_STATE_NORMAL;
1074260387Sscottl		else
1075260387Sscottl			xpt_schedule(periph, CAM_PRIORITY_DEV);
1076220412Smav	}
1077195534Sscottl	default:
1078195534Sscottl		cam_periph_async(periph, code, path, arg);
1079195534Sscottl		break;
1080195534Sscottl	}
1081195534Sscottl}
1082195534Sscottl
1083195534Sscottlstatic void
1084195534Sscottladasysctlinit(void *context, int pending)
1085195534Sscottl{
1086195534Sscottl	struct cam_periph *periph;
1087195534Sscottl	struct ada_softc *softc;
1088195534Sscottl	char tmpstr[80], tmpstr2[80];
1089195534Sscottl
1090195534Sscottl	periph = (struct cam_periph *)context;
1091220454Smav
1092220454Smav	/* periph was held for us when this task was enqueued */
1093249981Smav	if ((periph->flags & CAM_PERIPH_INVALID) != 0) {
1094220454Smav		cam_periph_release(periph);
1095195534Sscottl		return;
1096220454Smav	}
1097195534Sscottl
1098195534Sscottl	softc = (struct ada_softc *)periph->softc;
1099195534Sscottl	snprintf(tmpstr, sizeof(tmpstr), "CAM ADA unit %d", periph->unit_number);
1100195534Sscottl	snprintf(tmpstr2, sizeof(tmpstr2), "%d", periph->unit_number);
1101195534Sscottl
1102195534Sscottl	sysctl_ctx_init(&softc->sysctl_ctx);
1103195534Sscottl	softc->flags |= ADA_FLAG_SCTX_INIT;
1104195534Sscottl	softc->sysctl_tree = SYSCTL_ADD_NODE(&softc->sysctl_ctx,
1105195534Sscottl		SYSCTL_STATIC_CHILDREN(_kern_cam_ada), OID_AUTO, tmpstr2,
1106195534Sscottl		CTLFLAG_RD, 0, tmpstr);
1107195534Sscottl	if (softc->sysctl_tree == NULL) {
1108195534Sscottl		printf("adasysctlinit: unable to allocate sysctl tree\n");
1109195534Sscottl		cam_periph_release(periph);
1110195534Sscottl		return;
1111195534Sscottl	}
1112195534Sscottl
1113220454Smav	SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree),
1114224497Smav		OID_AUTO, "read_ahead", CTLFLAG_RW | CTLFLAG_MPSAFE,
1115224497Smav		&softc->read_ahead, 0, "Enable disk read ahead.");
1116224497Smav	SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree),
1117220454Smav		OID_AUTO, "write_cache", CTLFLAG_RW | CTLFLAG_MPSAFE,
1118220454Smav		&softc->write_cache, 0, "Enable disk write cache.");
1119248922Ssmh	SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree),
1120248922Ssmh		OID_AUTO, "sort_io_queue", CTLFLAG_RW | CTLFLAG_MPSAFE,
1121248922Ssmh		&softc->sort_io_queue, 0,
1122248922Ssmh		"Sort IO queue to try and optimise disk access patterns");
1123220454Smav#ifdef ADA_TEST_FAILURE
1124220454Smav	/*
1125220454Smav	 * Add a 'door bell' sysctl which allows one to set it from userland
1126220454Smav	 * and cause something bad to happen.  For the moment, we only allow
1127220454Smav	 * whacking the next read or write.
1128220454Smav	 */
1129220454Smav	SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree),
1130220454Smav		OID_AUTO, "force_read_error", CTLFLAG_RW | CTLFLAG_MPSAFE,
1131220454Smav		&softc->force_read_error, 0,
1132220454Smav		"Force a read error for the next N reads.");
1133220454Smav	SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree),
1134220454Smav		OID_AUTO, "force_write_error", CTLFLAG_RW | CTLFLAG_MPSAFE,
1135220454Smav		&softc->force_write_error, 0,
1136220454Smav		"Force a write error for the next N writes.");
1137220454Smav	SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree),
1138220454Smav		OID_AUTO, "periodic_read_error", CTLFLAG_RW | CTLFLAG_MPSAFE,
1139220454Smav		&softc->periodic_read_error, 0,
1140220454Smav		"Force a read error every N reads (don't set too low).");
1141220454Smav#endif
1142195534Sscottl	cam_periph_release(periph);
1143195534Sscottl}
1144195534Sscottl
1145223089Sgibbsstatic int
1146223089Sgibbsadagetattr(struct bio *bp)
1147223089Sgibbs{
1148241485Smav	int ret;
1149223089Sgibbs	struct cam_periph *periph;
1150223089Sgibbs
1151223089Sgibbs	periph = (struct cam_periph *)bp->bio_disk->d_drv1;
1152241485Smav	cam_periph_lock(periph);
1153223089Sgibbs	ret = xpt_getattr(bp->bio_data, bp->bio_length, bp->bio_attribute,
1154223089Sgibbs	    periph->path);
1155241485Smav	cam_periph_unlock(periph);
1156223089Sgibbs	if (ret == 0)
1157223089Sgibbs		bp->bio_completed = bp->bio_length;
1158223089Sgibbs	return ret;
1159223089Sgibbs}
1160223089Sgibbs
1161195534Sscottlstatic cam_status
1162195534Sscottladaregister(struct cam_periph *periph, void *arg)
1163195534Sscottl{
1164195534Sscottl	struct ada_softc *softc;
1165195534Sscottl	struct ccb_pathinq cpi;
1166195534Sscottl	struct ccb_getdev *cgd;
1167221071Smav	char   announce_buf[80], buf1[32];
1168195534Sscottl	struct disk_params *dp;
1169195534Sscottl	caddr_t match;
1170195534Sscottl	u_int maxio;
1171222520Smav	int legacy_id, quirks;
1172195534Sscottl
1173195534Sscottl	cgd = (struct ccb_getdev *)arg;
1174195534Sscottl	if (cgd == NULL) {
1175195534Sscottl		printf("adaregister: no getdev CCB, can't register device\n");
1176195534Sscottl		return(CAM_REQ_CMP_ERR);
1177195534Sscottl	}
1178195534Sscottl
1179195534Sscottl	softc = (struct ada_softc *)malloc(sizeof(*softc), M_DEVBUF,
1180195534Sscottl	    M_NOWAIT|M_ZERO);
1181195534Sscottl
1182195534Sscottl	if (softc == NULL) {
1183195534Sscottl		printf("adaregister: Unable to probe new device. "
1184198328Smav		    "Unable to allocate softc\n");
1185195534Sscottl		return(CAM_REQ_CMP_ERR);
1186195534Sscottl	}
1187195534Sscottl
1188195534Sscottl	bioq_init(&softc->bio_queue);
1189201139Smav	bioq_init(&softc->trim_queue);
1190195534Sscottl
1191236393Smav	if ((cgd->ident_data.capabilities1 & ATA_SUPPORT_DMA) &&
1192220886Smav	    (cgd->inq_flags & SID_DMA))
1193198328Smav		softc->flags |= ADA_FLAG_CAN_DMA;
1194249199Smarius	if (cgd->ident_data.support.command2 & ATA_SUPPORT_ADDRESS48) {
1195195534Sscottl		softc->flags |= ADA_FLAG_CAN_48BIT;
1196249199Smarius		if (cgd->inq_flags & SID_DMA48)
1197249199Smarius			softc->flags |= ADA_FLAG_CAN_DMA48;
1198249199Smarius	}
1199195534Sscottl	if (cgd->ident_data.support.command2 & ATA_SUPPORT_FLUSHCACHE)
1200195534Sscottl		softc->flags |= ADA_FLAG_CAN_FLUSHCACHE;
1201214279Sbrucec	if (cgd->ident_data.support.command1 & ATA_SUPPORT_POWERMGT)
1202214279Sbrucec		softc->flags |= ADA_FLAG_CAN_POWERMGT;
1203236393Smav	if ((cgd->ident_data.satacapabilities & ATA_SUPPORT_NCQ) &&
1204220886Smav	    (cgd->inq_flags & SID_DMA) && (cgd->inq_flags & SID_CmdQue))
1205195534Sscottl		softc->flags |= ADA_FLAG_CAN_NCQ;
1206236393Smav	if ((cgd->ident_data.support_dsm & ATA_SUPPORT_DSM_TRIM) &&
1207236393Smav	    (cgd->inq_flags & SID_DMA)) {
1208201139Smav		softc->flags |= ADA_FLAG_CAN_TRIM;
1209201139Smav		softc->trim_max_ranges = TRIM_MAX_RANGES;
1210201139Smav		if (cgd->ident_data.max_dsm_blocks != 0) {
1211201139Smav			softc->trim_max_ranges =
1212249934Ssmh			    min(cgd->ident_data.max_dsm_blocks *
1213249934Ssmh				ATA_DSM_BLK_RANGES, softc->trim_max_ranges);
1214201139Smav		}
1215201139Smav	}
1216201139Smav	if (cgd->ident_data.support.command2 & ATA_SUPPORT_CFA)
1217201139Smav		softc->flags |= ADA_FLAG_CAN_CFA;
1218195534Sscottl
1219195534Sscottl	periph->softc = softc;
1220195534Sscottl
1221195534Sscottl	/*
1222195534Sscottl	 * See if this device has any quirks.
1223195534Sscottl	 */
1224199178Smav	match = cam_quirkmatch((caddr_t)&cgd->ident_data,
1225199178Smav			       (caddr_t)ada_quirk_table,
1226199178Smav			       sizeof(ada_quirk_table)/sizeof(*ada_quirk_table),
1227199178Smav			       sizeof(*ada_quirk_table), ata_identify_match);
1228195534Sscottl	if (match != NULL)
1229195534Sscottl		softc->quirks = ((struct ada_quirk_entry *)match)->quirks;
1230195534Sscottl	else
1231195534Sscottl		softc->quirks = ADA_Q_NONE;
1232195534Sscottl
1233195534Sscottl	bzero(&cpi, sizeof(cpi));
1234203108Smav	xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NONE);
1235195534Sscottl	cpi.ccb_h.func_code = XPT_PATH_INQ;
1236195534Sscottl	xpt_action((union ccb *)&cpi);
1237195534Sscottl
1238195534Sscottl	TASK_INIT(&softc->sysctl_task, 0, adasysctlinit, periph);
1239195534Sscottl
1240195534Sscottl	/*
1241195534Sscottl	 * Register this media as a disk
1242195534Sscottl	 */
1243220618Smav	(void)cam_periph_hold(periph, PRIBIO);
1244249106Smav	cam_periph_unlock(periph);
1245222520Smav	snprintf(announce_buf, sizeof(announce_buf),
1246222520Smav	    "kern.cam.ada.%d.quirks", periph->unit_number);
1247222520Smav	quirks = softc->quirks;
1248222520Smav	TUNABLE_INT_FETCH(announce_buf, &quirks);
1249222520Smav	softc->quirks = quirks;
1250224497Smav	softc->read_ahead = -1;
1251224497Smav	snprintf(announce_buf, sizeof(announce_buf),
1252224497Smav	    "kern.cam.ada.%d.read_ahead", periph->unit_number);
1253224497Smav	TUNABLE_INT_FETCH(announce_buf, &softc->read_ahead);
1254220618Smav	softc->write_cache = -1;
1255220618Smav	snprintf(announce_buf, sizeof(announce_buf),
1256220618Smav	    "kern.cam.ada.%d.write_cache", periph->unit_number);
1257220618Smav	TUNABLE_INT_FETCH(announce_buf, &softc->write_cache);
1258250033Ssmh	/* Disable queue sorting for non-rotational media by default. */
1259271238Ssmh	if (cgd->ident_data.media_rotation_rate == ATA_RATE_NON_ROTATING)
1260249941Ssmh		softc->sort_io_queue = 0;
1261249941Ssmh	else
1262249941Ssmh		softc->sort_io_queue = -1;
1263198897Smav	adagetparams(periph, cgd);
1264195534Sscottl	softc->disk = disk_alloc();
1265271238Ssmh	softc->disk->d_rotation_rate = cgd->ident_data.media_rotation_rate;
1266220644Smav	softc->disk->d_devstat = devstat_new_entry(periph->periph_name,
1267220644Smav			  periph->unit_number, softc->params.secsize,
1268220644Smav			  DEVSTAT_ALL_SUPPORTED,
1269220644Smav			  DEVSTAT_TYPE_DIRECT |
1270220644Smav			  XPORT_DEVSTAT_TYPE(cpi.transport),
1271220644Smav			  DEVSTAT_PRIORITY_DISK);
1272195534Sscottl	softc->disk->d_open = adaopen;
1273195534Sscottl	softc->disk->d_close = adaclose;
1274195534Sscottl	softc->disk->d_strategy = adastrategy;
1275223089Sgibbs	softc->disk->d_getattr = adagetattr;
1276195534Sscottl	softc->disk->d_dump = adadump;
1277249347Sken	softc->disk->d_gone = adadiskgonecb;
1278195534Sscottl	softc->disk->d_name = "ada";
1279195534Sscottl	softc->disk->d_drv1 = periph;
1280195534Sscottl	maxio = cpi.maxio;		/* Honor max I/O size of SIM */
1281195534Sscottl	if (maxio == 0)
1282195534Sscottl		maxio = DFLTPHYS;	/* traditional default */
1283195534Sscottl	else if (maxio > MAXPHYS)
1284195534Sscottl		maxio = MAXPHYS;	/* for safety */
1285201139Smav	if (softc->flags & ADA_FLAG_CAN_48BIT)
1286198897Smav		maxio = min(maxio, 65536 * softc->params.secsize);
1287195534Sscottl	else					/* 28bit ATA command limit */
1288198897Smav		maxio = min(maxio, 256 * softc->params.secsize);
1289195534Sscottl	softc->disk->d_maxsize = maxio;
1290195534Sscottl	softc->disk->d_unit = periph->unit_number;
1291260385Sscottl	softc->disk->d_flags = DISKFLAG_DIRECT_COMPLETION;
1292195534Sscottl	if (softc->flags & ADA_FLAG_CAN_FLUSHCACHE)
1293195534Sscottl		softc->disk->d_flags |= DISKFLAG_CANFLUSHCACHE;
1294249934Ssmh	if (softc->flags & ADA_FLAG_CAN_TRIM) {
1295201139Smav		softc->disk->d_flags |= DISKFLAG_CANDELETE;
1296249940Ssmh		softc->disk->d_delmaxsize = softc->params.secsize *
1297249940Ssmh					    ATA_DSM_RANGE_MAX *
1298249940Ssmh					    softc->trim_max_ranges;
1299249934Ssmh	} else if ((softc->flags & ADA_FLAG_CAN_CFA) &&
1300249934Ssmh	    !(softc->flags & ADA_FLAG_CAN_48BIT)) {
1301249934Ssmh		softc->disk->d_flags |= DISKFLAG_CANDELETE;
1302249940Ssmh		softc->disk->d_delmaxsize = 256 * softc->params.secsize;
1303249940Ssmh	} else
1304249940Ssmh		softc->disk->d_delmaxsize = maxio;
1305248519Skib	if ((cpi.hba_misc & PIM_UNMAPPED) != 0)
1306248519Skib		softc->disk->d_flags |= DISKFLAG_UNMAPPED_BIO;
1307219056Snwhitehorn	strlcpy(softc->disk->d_descr, cgd->ident_data.model,
1308219056Snwhitehorn	    MIN(sizeof(softc->disk->d_descr), sizeof(cgd->ident_data.model)));
1309241305Savg	strlcpy(softc->disk->d_ident, cgd->ident_data.serial,
1310241305Savg	    MIN(sizeof(softc->disk->d_ident), sizeof(cgd->ident_data.serial)));
1311210471Smav	softc->disk->d_hba_vendor = cpi.hba_vendor;
1312210471Smav	softc->disk->d_hba_device = cpi.hba_device;
1313210471Smav	softc->disk->d_hba_subvendor = cpi.hba_subvendor;
1314210471Smav	softc->disk->d_hba_subdevice = cpi.hba_subdevice;
1315195534Sscottl
1316195534Sscottl	softc->disk->d_sectorsize = softc->params.secsize;
1317198897Smav	softc->disk->d_mediasize = (off_t)softc->params.sectors *
1318198897Smav	    softc->params.secsize;
1319200969Smav	if (ata_physical_sector_size(&cgd->ident_data) !=
1320200969Smav	    softc->params.secsize) {
1321200969Smav		softc->disk->d_stripesize =
1322200969Smav		    ata_physical_sector_size(&cgd->ident_data);
1323200969Smav		softc->disk->d_stripeoffset = (softc->disk->d_stripesize -
1324200969Smav		    ata_logical_sector_offset(&cgd->ident_data)) %
1325200969Smav		    softc->disk->d_stripesize;
1326222520Smav	} else if (softc->quirks & ADA_Q_4K) {
1327222520Smav		softc->disk->d_stripesize = 4096;
1328222520Smav		softc->disk->d_stripeoffset = 0;
1329200969Smav	}
1330195534Sscottl	softc->disk->d_fwsectors = softc->params.secs_per_track;
1331195534Sscottl	softc->disk->d_fwheads = softc->params.heads;
1332208349Smarius	ata_disk_firmware_geom_adjust(softc->disk);
1333195534Sscottl
1334221071Smav	if (ada_legacy_aliases) {
1335221071Smav#ifdef ATA_STATIC_ID
1336221071Smav		legacy_id = xpt_path_legacy_ata_id(periph->path);
1337221071Smav#else
1338221071Smav		legacy_id = softc->disk->d_unit;
1339221071Smav#endif
1340221071Smav		if (legacy_id >= 0) {
1341221071Smav			snprintf(announce_buf, sizeof(announce_buf),
1342221071Smav			    "kern.devalias.%s%d",
1343221071Smav			    softc->disk->d_name, softc->disk->d_unit);
1344221071Smav			snprintf(buf1, sizeof(buf1),
1345221071Smav			    "ad%d", legacy_id);
1346221071Smav			setenv(announce_buf, buf1);
1347221071Smav		}
1348221071Smav	} else
1349221071Smav		legacy_id = -1;
1350249347Sken	/*
1351249347Sken	 * Acquire a reference to the periph before we register with GEOM.
1352249347Sken	 * We'll release this reference once GEOM calls us back (via
1353249347Sken	 * adadiskgonecb()) telling us that our provider has been freed.
1354249347Sken	 */
1355249347Sken	if (cam_periph_acquire(periph) != CAM_REQ_CMP) {
1356249347Sken		xpt_print(periph->path, "%s: lost periph during "
1357249347Sken			  "registration!\n", __func__);
1358249347Sken		cam_periph_lock(periph);
1359249347Sken		return (CAM_REQ_CMP_ERR);
1360249347Sken	}
1361195534Sscottl	disk_create(softc->disk, DISK_VERSION);
1362249106Smav	cam_periph_lock(periph);
1363220618Smav	cam_periph_unhold(periph);
1364195534Sscottl
1365195534Sscottl	dp = &softc->params;
1366195534Sscottl	snprintf(announce_buf, sizeof(announce_buf),
1367291497Smav	    "%juMB (%ju %u byte sectors)",
1368291497Smav	    ((uintmax_t)dp->secsize * dp->sectors) / (1024 * 1024),
1369291497Smav	    (uintmax_t)dp->sectors, dp->secsize);
1370195534Sscottl	xpt_announce_periph(periph, announce_buf);
1371250792Ssmh	xpt_announce_quirks(periph, softc->quirks, ADA_Q_BIT_STRING);
1372221071Smav	if (legacy_id >= 0)
1373221071Smav		printf("%s%d: Previously was known as ad%d\n",
1374221071Smav		       periph->periph_name, periph->unit_number, legacy_id);
1375220454Smav
1376195534Sscottl	/*
1377220454Smav	 * Create our sysctl variables, now that we know
1378220454Smav	 * we have successfully attached.
1379220454Smav	 */
1380260387Sscottl	if (cam_periph_acquire(periph) == CAM_REQ_CMP)
1381260387Sscottl		taskqueue_enqueue(taskqueue_thread, &softc->sysctl_task);
1382220454Smav
1383220454Smav	/*
1384195534Sscottl	 * Add async callbacks for bus reset and
1385195534Sscottl	 * bus device reset calls.  I don't bother
1386195534Sscottl	 * checking if this fails as, in most cases,
1387195534Sscottl	 * the system will function just fine without
1388195534Sscottl	 * them and the only alternative would be to
1389195534Sscottl	 * not attach the device on failure.
1390195534Sscottl	 */
1391235897Smav	xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE |
1392236393Smav	    AC_GETDEV_CHANGED | AC_ADVINFO_CHANGED,
1393236393Smav	    adaasync, periph, periph->path);
1394195534Sscottl
1395195534Sscottl	/*
1396195534Sscottl	 * Schedule a periodic event to occasionally send an
1397195534Sscottl	 * ordered tag to a device.
1398195534Sscottl	 */
1399260387Sscottl	callout_init_mtx(&softc->sendordered_c, cam_periph_mtx(periph), 0);
1400195534Sscottl	callout_reset(&softc->sendordered_c,
1401230921Smav	    (ada_default_timeout * hz) / ADA_ORDEREDTAG_INTERVAL,
1402195534Sscottl	    adasendorderedtag, softc);
1403195534Sscottl
1404224497Smav	if (ADA_RA >= 0 &&
1405224497Smav	    cgd->ident_data.support.command1 & ATA_SUPPORT_LOOKAHEAD) {
1406224497Smav		softc->state = ADA_STATE_RAHEAD;
1407224497Smav	} else if (ADA_WC >= 0 &&
1408220412Smav	    cgd->ident_data.support.command1 & ATA_SUPPORT_WRITECACHE) {
1409220412Smav		softc->state = ADA_STATE_WCACHE;
1410260387Sscottl	} else {
1411260387Sscottl		softc->state = ADA_STATE_NORMAL;
1412260387Sscottl		return(CAM_REQ_CMP);
1413260387Sscottl	}
1414260387Sscottl	if (cam_periph_acquire(periph) != CAM_REQ_CMP)
1415260387Sscottl		softc->state = ADA_STATE_NORMAL;
1416260387Sscottl	else
1417220412Smav		xpt_schedule(periph, CAM_PRIORITY_DEV);
1418195534Sscottl	return(CAM_REQ_CMP);
1419195534Sscottl}
1420195534Sscottl
1421195534Sscottlstatic void
1422268815Simpada_dsmtrim(struct ada_softc *softc, struct bio *bp, struct ccb_ataio *ataio)
1423268815Simp{
1424268815Simp	struct trim_request *req = &softc->trim_req;
1425268815Simp	uint64_t lastlba = (uint64_t)-1;
1426268815Simp	int c, lastcount = 0, off, ranges = 0;
1427268815Simp
1428268815Simp	bzero(req, sizeof(*req));
1429268815Simp	TAILQ_INIT(&req->bps);
1430268815Simp	do {
1431268815Simp		uint64_t lba = bp->bio_pblkno;
1432268815Simp		int count = bp->bio_bcount / softc->params.secsize;
1433268815Simp
1434268815Simp		bioq_remove(&softc->trim_queue, bp);
1435268815Simp
1436268815Simp		/* Try to extend the previous range. */
1437268815Simp		if (lba == lastlba) {
1438268815Simp			c = min(count, ATA_DSM_RANGE_MAX - lastcount);
1439268815Simp			lastcount += c;
1440268815Simp			off = (ranges - 1) * ATA_DSM_RANGE_SIZE;
1441268815Simp			req->data[off + 6] = lastcount & 0xff;
1442268815Simp			req->data[off + 7] =
1443268815Simp				(lastcount >> 8) & 0xff;
1444268815Simp			count -= c;
1445268815Simp			lba += c;
1446268815Simp		}
1447268815Simp
1448268815Simp		while (count > 0) {
1449268815Simp			c = min(count, ATA_DSM_RANGE_MAX);
1450268815Simp			off = ranges * ATA_DSM_RANGE_SIZE;
1451268815Simp			req->data[off + 0] = lba & 0xff;
1452268815Simp			req->data[off + 1] = (lba >> 8) & 0xff;
1453268815Simp			req->data[off + 2] = (lba >> 16) & 0xff;
1454268815Simp			req->data[off + 3] = (lba >> 24) & 0xff;
1455268815Simp			req->data[off + 4] = (lba >> 32) & 0xff;
1456268815Simp			req->data[off + 5] = (lba >> 40) & 0xff;
1457268815Simp			req->data[off + 6] = c & 0xff;
1458268815Simp			req->data[off + 7] = (c >> 8) & 0xff;
1459268815Simp			lba += c;
1460268815Simp			count -= c;
1461268815Simp			lastcount = c;
1462268815Simp			ranges++;
1463268815Simp			/*
1464268815Simp			 * Its the caller's responsibility to ensure the
1465268815Simp			 * request will fit so we don't need to check for
1466268815Simp			 * overrun here
1467268815Simp			 */
1468268815Simp		}
1469268815Simp		lastlba = lba;
1470268815Simp		TAILQ_INSERT_TAIL(&req->bps, bp, bio_queue);
1471268815Simp		bp = bioq_first(&softc->trim_queue);
1472268815Simp		if (bp == NULL ||
1473268815Simp		    bp->bio_bcount / softc->params.secsize >
1474268815Simp		    (softc->trim_max_ranges - ranges) * ATA_DSM_RANGE_MAX)
1475268815Simp			break;
1476268815Simp	} while (1);
1477268815Simp	cam_fill_ataio(ataio,
1478268815Simp	    ada_retry_count,
1479268815Simp	    adadone,
1480268815Simp	    CAM_DIR_OUT,
1481268815Simp	    0,
1482268815Simp	    req->data,
1483268815Simp	    ((ranges + ATA_DSM_BLK_RANGES - 1) /
1484268815Simp	    ATA_DSM_BLK_RANGES) * ATA_DSM_BLK_SIZE,
1485268815Simp	    ada_default_timeout * 1000);
1486268815Simp	ata_48bit_cmd(ataio, ATA_DATA_SET_MANAGEMENT,
1487268815Simp	    ATA_DSM_TRIM, 0, (ranges + ATA_DSM_BLK_RANGES -
1488268815Simp	    1) / ATA_DSM_BLK_RANGES);
1489268815Simp}
1490268815Simp
1491268815Simpstatic void
1492268815Simpada_cfaerase(struct ada_softc *softc, struct bio *bp, struct ccb_ataio *ataio)
1493268815Simp{
1494273814Ssmh	struct trim_request *req = &softc->trim_req;
1495268815Simp	uint64_t lba = bp->bio_pblkno;
1496268815Simp	uint16_t count = bp->bio_bcount / softc->params.secsize;
1497268815Simp
1498273814Ssmh	bzero(req, sizeof(*req));
1499273814Ssmh	TAILQ_INIT(&req->bps);
1500273814Ssmh	bioq_remove(&softc->trim_queue, bp);
1501273814Ssmh	TAILQ_INSERT_TAIL(&req->bps, bp, bio_queue);
1502273814Ssmh
1503268815Simp	cam_fill_ataio(ataio,
1504268815Simp	    ada_retry_count,
1505268815Simp	    adadone,
1506268815Simp	    CAM_DIR_NONE,
1507268815Simp	    0,
1508268815Simp	    NULL,
1509268815Simp	    0,
1510268815Simp	    ada_default_timeout*1000);
1511268815Simp
1512268815Simp	if (count >= 256)
1513268815Simp		count = 0;
1514268815Simp	ata_28bit_cmd(ataio, ATA_CFA_ERASE, 0, lba, count);
1515268815Simp}
1516268815Simp
1517268815Simpstatic void
1518195534Sscottladastart(struct cam_periph *periph, union ccb *start_ccb)
1519195534Sscottl{
1520198328Smav	struct ada_softc *softc = (struct ada_softc *)periph->softc;
1521198328Smav	struct ccb_ataio *ataio = &start_ccb->ataio;
1522195534Sscottl
1523236602Smav	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("adastart\n"));
1524236602Smav
1525195534Sscottl	switch (softc->state) {
1526195534Sscottl	case ADA_STATE_NORMAL:
1527195534Sscottl	{
1528195534Sscottl		struct bio *bp;
1529201139Smav		u_int8_t tag_code;
1530195534Sscottl
1531201139Smav		/* Run TRIM if not running yet. */
1532201139Smav		if (!softc->trim_running &&
1533201139Smav		    (bp = bioq_first(&softc->trim_queue)) != 0) {
1534268815Simp			if (softc->flags & ADA_FLAG_CAN_TRIM) {
1535268815Simp				ada_dsmtrim(softc, bp, ataio);
1536268815Simp			} else if ((softc->flags & ADA_FLAG_CAN_CFA) &&
1537268815Simp			    !(softc->flags & ADA_FLAG_CAN_48BIT)) {
1538268815Simp				ada_cfaerase(softc, bp, ataio);
1539268815Simp			} else {
1540286800Smav				/* This can happen if DMA was disabled. */
1541286800Smav				bioq_remove(&softc->trim_queue, bp);
1542287286Smav				biofinish(bp, NULL, EOPNOTSUPP);
1543286800Smav				xpt_release_ccb(start_ccb);
1544286800Smav				adaschedule(periph);
1545286800Smav				return;
1546268815Simp			}
1547201139Smav			softc->trim_running = 1;
1548201139Smav			start_ccb->ccb_h.ccb_state = ADA_CCB_TRIM;
1549260387Sscottl			start_ccb->ccb_h.flags |= CAM_UNLOCKED;
1550201139Smav			goto out;
1551201139Smav		}
1552201139Smav		/* Run regular command. */
1553201139Smav		bp = bioq_first(&softc->bio_queue);
1554201139Smav		if (bp == NULL) {
1555195534Sscottl			xpt_release_ccb(start_ccb);
1556201139Smav			break;
1557201139Smav		}
1558201139Smav		bioq_remove(&softc->bio_queue, bp);
1559201139Smav
1560212160Sgibbs		if ((bp->bio_flags & BIO_ORDERED) != 0
1561212160Sgibbs		 || (softc->flags & ADA_FLAG_NEED_OTAG) != 0) {
1562201139Smav			softc->flags &= ~ADA_FLAG_NEED_OTAG;
1563260387Sscottl			softc->flags |= ADA_FLAG_WAS_OTAG;
1564201139Smav			tag_code = 0;
1565195534Sscottl		} else {
1566201139Smav			tag_code = 1;
1567201139Smav		}
1568201139Smav		switch (bp->bio_cmd) {
1569253724Smav		case BIO_WRITE:
1570201139Smav		case BIO_READ:
1571201139Smav		{
1572201139Smav			uint64_t lba = bp->bio_pblkno;
1573201139Smav			uint16_t count = bp->bio_bcount / softc->params.secsize;
1574292348Sken			void *data_ptr;
1575292348Sken			int rw_op;
1576292348Sken
1577292348Sken			if (bp->bio_cmd == BIO_WRITE) {
1578292348Sken				softc->flags |= ADA_FLAG_DIRTY;
1579292348Sken				rw_op = CAM_DIR_OUT;
1580292348Sken			} else {
1581292348Sken				rw_op = CAM_DIR_IN;
1582292348Sken			}
1583292348Sken
1584292348Sken			data_ptr = bp->bio_data;
1585292348Sken			if ((bp->bio_flags & (BIO_UNMAPPED|BIO_VLIST)) != 0) {
1586292348Sken				rw_op |= CAM_DATA_BIO;
1587292348Sken				data_ptr = bp;
1588292348Sken			}
1589292348Sken
1590220454Smav#ifdef ADA_TEST_FAILURE
1591220454Smav			int fail = 0;
1592195534Sscottl
1593220454Smav			/*
1594220454Smav			 * Support the failure ioctls.  If the command is a
1595220454Smav			 * read, and there are pending forced read errors, or
1596220454Smav			 * if a write and pending write errors, then fail this
1597220454Smav			 * operation with EIO.  This is useful for testing
1598220454Smav			 * purposes.  Also, support having every Nth read fail.
1599220454Smav			 *
1600220454Smav			 * This is a rather blunt tool.
1601220454Smav			 */
1602220454Smav			if (bp->bio_cmd == BIO_READ) {
1603220454Smav				if (softc->force_read_error) {
1604220454Smav					softc->force_read_error--;
1605220454Smav					fail = 1;
1606220454Smav				}
1607220454Smav				if (softc->periodic_read_error > 0) {
1608220454Smav					if (++softc->periodic_read_count >=
1609220454Smav					    softc->periodic_read_error) {
1610220454Smav						softc->periodic_read_count = 0;
1611220454Smav						fail = 1;
1612220454Smav					}
1613220454Smav				}
1614220454Smav			} else {
1615220454Smav				if (softc->force_write_error) {
1616220454Smav					softc->force_write_error--;
1617220454Smav					fail = 1;
1618220454Smav				}
1619220454Smav			}
1620220454Smav			if (fail) {
1621287286Smav				biofinish(bp, NULL, EIO);
1622220454Smav				xpt_release_ccb(start_ccb);
1623220454Smav				adaschedule(periph);
1624220454Smav				return;
1625220454Smav			}
1626220454Smav#endif
1627248519Skib			KASSERT((bp->bio_flags & BIO_UNMAPPED) == 0 ||
1628248519Skib			    round_page(bp->bio_bcount + bp->bio_ma_offset) /
1629248519Skib			    PAGE_SIZE == bp->bio_ma_n,
1630248519Skib			    ("Short bio %p", bp));
1631201139Smav			cam_fill_ataio(ataio,
1632201139Smav			    ada_retry_count,
1633201139Smav			    adadone,
1634292348Sken			    rw_op,
1635201139Smav			    tag_code,
1636292348Sken			    data_ptr,
1637201139Smav			    bp->bio_bcount,
1638201139Smav			    ada_default_timeout*1000);
1639195534Sscottl
1640201139Smav			if ((softc->flags & ADA_FLAG_CAN_NCQ) && tag_code) {
1641201139Smav				if (bp->bio_cmd == BIO_READ) {
1642201139Smav					ata_ncq_cmd(ataio, ATA_READ_FPDMA_QUEUED,
1643201139Smav					    lba, count);
1644201139Smav				} else {
1645201139Smav					ata_ncq_cmd(ataio, ATA_WRITE_FPDMA_QUEUED,
1646201139Smav					    lba, count);
1647201139Smav				}
1648201139Smav			} else if ((softc->flags & ADA_FLAG_CAN_48BIT) &&
1649201139Smav			    (lba + count >= ATA_MAX_28BIT_LBA ||
1650201139Smav			    count > 256)) {
1651249199Smarius				if (softc->flags & ADA_FLAG_CAN_DMA48) {
1652195534Sscottl					if (bp->bio_cmd == BIO_READ) {
1653201139Smav						ata_48bit_cmd(ataio, ATA_READ_DMA48,
1654201139Smav						    0, lba, count);
1655195534Sscottl					} else {
1656201139Smav						ata_48bit_cmd(ataio, ATA_WRITE_DMA48,
1657201139Smav						    0, lba, count);
1658195534Sscottl					}
1659201139Smav				} else {
1660201139Smav					if (bp->bio_cmd == BIO_READ) {
1661201139Smav						ata_48bit_cmd(ataio, ATA_READ_MUL48,
1662201139Smav						    0, lba, count);
1663195534Sscottl					} else {
1664201139Smav						ata_48bit_cmd(ataio, ATA_WRITE_MUL48,
1665201139Smav						    0, lba, count);
1666195534Sscottl					}
1667201139Smav				}
1668201139Smav			} else {
1669201139Smav				if (count == 256)
1670201139Smav					count = 0;
1671201139Smav				if (softc->flags & ADA_FLAG_CAN_DMA) {
1672201139Smav					if (bp->bio_cmd == BIO_READ) {
1673201139Smav						ata_28bit_cmd(ataio, ATA_READ_DMA,
1674201139Smav						    0, lba, count);
1675201139Smav					} else {
1676201139Smav						ata_28bit_cmd(ataio, ATA_WRITE_DMA,
1677201139Smav						    0, lba, count);
1678201139Smav					}
1679195534Sscottl				} else {
1680201139Smav					if (bp->bio_cmd == BIO_READ) {
1681201139Smav						ata_28bit_cmd(ataio, ATA_READ_MUL,
1682201139Smav						    0, lba, count);
1683195534Sscottl					} else {
1684201139Smav						ata_28bit_cmd(ataio, ATA_WRITE_MUL,
1685201139Smav						    0, lba, count);
1686195534Sscottl					}
1687195534Sscottl				}
1688195534Sscottl			}
1689201139Smav			break;
1690201139Smav		}
1691201139Smav		case BIO_FLUSH:
1692201139Smav			cam_fill_ataio(ataio,
1693201139Smav			    1,
1694201139Smav			    adadone,
1695201139Smav			    CAM_DIR_NONE,
1696201139Smav			    0,
1697201139Smav			    NULL,
1698201139Smav			    0,
1699201139Smav			    ada_default_timeout*1000);
1700201139Smav
1701201139Smav			if (softc->flags & ADA_FLAG_CAN_48BIT)
1702201139Smav				ata_48bit_cmd(ataio, ATA_FLUSHCACHE48, 0, 0, 0);
1703201139Smav			else
1704201139Smav				ata_28bit_cmd(ataio, ATA_FLUSHCACHE, 0, 0, 0);
1705201139Smav			break;
1706195534Sscottl		}
1707201139Smav		start_ccb->ccb_h.ccb_state = ADA_CCB_BUFFER_IO;
1708260387Sscottl		start_ccb->ccb_h.flags |= CAM_UNLOCKED;
1709201139Smavout:
1710201139Smav		start_ccb->ccb_h.ccb_bp = bp;
1711201139Smav		softc->outstanding_cmds++;
1712260387Sscottl		softc->refcount++;
1713260387Sscottl		cam_periph_unlock(periph);
1714201139Smav		xpt_action(start_ccb);
1715260387Sscottl		cam_periph_lock(periph);
1716260387Sscottl		softc->refcount--;
1717201139Smav
1718201139Smav		/* May have more work to do, so ensure we stay scheduled */
1719201139Smav		adaschedule(periph);
1720195534Sscottl		break;
1721195534Sscottl	}
1722224497Smav	case ADA_STATE_RAHEAD:
1723220412Smav	case ADA_STATE_WCACHE:
1724220412Smav	{
1725220412Smav		cam_fill_ataio(ataio,
1726220412Smav		    1,
1727220412Smav		    adadone,
1728220412Smav		    CAM_DIR_NONE,
1729220412Smav		    0,
1730220412Smav		    NULL,
1731220412Smav		    0,
1732220412Smav		    ada_default_timeout*1000);
1733220412Smav
1734224497Smav		if (softc->state == ADA_STATE_RAHEAD) {
1735224497Smav			ata_28bit_cmd(ataio, ATA_SETFEATURES, ADA_RA ?
1736224497Smav			    ATA_SF_ENAB_RCACHE : ATA_SF_DIS_RCACHE, 0, 0);
1737224497Smav			start_ccb->ccb_h.ccb_state = ADA_CCB_RAHEAD;
1738224497Smav		} else {
1739224497Smav			ata_28bit_cmd(ataio, ATA_SETFEATURES, ADA_WC ?
1740224497Smav			    ATA_SF_ENAB_WCACHE : ATA_SF_DIS_WCACHE, 0, 0);
1741224497Smav			start_ccb->ccb_h.ccb_state = ADA_CCB_WCACHE;
1742224497Smav		}
1743249466Smav		start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE;
1744220412Smav		xpt_action(start_ccb);
1745220412Smav		break;
1746195534Sscottl	}
1747220412Smav	}
1748195534Sscottl}
1749195534Sscottl
1750195534Sscottlstatic void
1751195534Sscottladadone(struct cam_periph *periph, union ccb *done_ccb)
1752195534Sscottl{
1753195534Sscottl	struct ada_softc *softc;
1754195534Sscottl	struct ccb_ataio *ataio;
1755224497Smav	struct ccb_getdev *cgd;
1756249466Smav	struct cam_path *path;
1757253752Smav	int state;
1758195534Sscottl
1759195534Sscottl	softc = (struct ada_softc *)periph->softc;
1760195534Sscottl	ataio = &done_ccb->ataio;
1761249466Smav	path = done_ccb->ccb_h.path;
1762236602Smav
1763249466Smav	CAM_DEBUG(path, CAM_DEBUG_TRACE, ("adadone\n"));
1764236602Smav
1765253752Smav	state = ataio->ccb_h.ccb_state & ADA_CCB_TYPE_MASK;
1766253752Smav	switch (state) {
1767195534Sscottl	case ADA_CCB_BUFFER_IO:
1768201139Smav	case ADA_CCB_TRIM:
1769195534Sscottl	{
1770195534Sscottl		struct bio *bp;
1771253752Smav		int error;
1772195534Sscottl
1773260387Sscottl		cam_periph_lock(periph);
1774195534Sscottl		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
1775198328Smav			error = adaerror(done_ccb, 0, 0);
1776195534Sscottl			if (error == ERESTART) {
1777198328Smav				/* A retry was scheduled, so just return. */
1778260387Sscottl				cam_periph_unlock(periph);
1779195534Sscottl				return;
1780195534Sscottl			}
1781195534Sscottl			if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
1782249466Smav				cam_release_devq(path,
1783195534Sscottl						 /*relsim_flags*/0,
1784195534Sscottl						 /*reduction*/0,
1785195534Sscottl						 /*timeout*/0,
1786195534Sscottl						 /*getcount_only*/0);
1787195534Sscottl		} else {
1788195534Sscottl			if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
1789195534Sscottl				panic("REQ_CMP with QFRZN");
1790253752Smav			error = 0;
1791253752Smav		}
1792253752Smav		bp = (struct bio *)done_ccb->ccb_h.ccb_bp;
1793253752Smav		bp->bio_error = error;
1794253752Smav		if (error != 0) {
1795253752Smav			bp->bio_resid = bp->bio_bcount;
1796253752Smav			bp->bio_flags |= BIO_ERROR;
1797253752Smav		} else {
1798253752Smav			if (state == ADA_CCB_TRIM)
1799253752Smav				bp->bio_resid = 0;
1800253752Smav			else
1801253752Smav				bp->bio_resid = ataio->resid;
1802253752Smav			if (bp->bio_resid > 0)
1803195534Sscottl				bp->bio_flags |= BIO_ERROR;
1804195534Sscottl		}
1805195534Sscottl		softc->outstanding_cmds--;
1806195534Sscottl		if (softc->outstanding_cmds == 0)
1807260387Sscottl			softc->flags |= ADA_FLAG_WAS_OTAG;
1808260387Sscottl		xpt_release_ccb(done_ccb);
1809253752Smav		if (state == ADA_CCB_TRIM) {
1810260387Sscottl			TAILQ_HEAD(, bio) queue;
1811260387Sscottl			struct bio *bp1;
1812195534Sscottl
1813260387Sscottl			TAILQ_INIT(&queue);
1814260387Sscottl			TAILQ_CONCAT(&queue, &softc->trim_req.bps, bio_queue);
1815288694Smav			/*
1816288694Smav			 * Normally, the xpt_release_ccb() above would make sure
1817288694Smav			 * that when we have more work to do, that work would
1818288694Smav			 * get kicked off. However, we specifically keep
1819288694Smav			 * trim_running set to 0 before the call above to allow
1820288694Smav			 * other I/O to progress when many BIO_DELETE requests
1821288694Smav			 * are pushed down. We set trim_running to 0 and call
1822288694Smav			 * daschedule again so that we don't stall if there are
1823288694Smav			 * no other I/Os pending apart from BIO_DELETEs.
1824288694Smav			 */
1825260387Sscottl			softc->trim_running = 0;
1826260387Sscottl			adaschedule(periph);
1827260387Sscottl			cam_periph_unlock(periph);
1828260387Sscottl			while ((bp1 = TAILQ_FIRST(&queue)) != NULL) {
1829260387Sscottl				TAILQ_REMOVE(&queue, bp1, bio_queue);
1830260387Sscottl				bp1->bio_error = error;
1831260387Sscottl				if (error != 0) {
1832201139Smav					bp1->bio_flags |= BIO_ERROR;
1833253752Smav					bp1->bio_resid = bp1->bio_bcount;
1834253752Smav				} else
1835253752Smav					bp1->bio_resid = 0;
1836201139Smav				biodone(bp1);
1837201139Smav			}
1838260387Sscottl		} else {
1839260387Sscottl			cam_periph_unlock(periph);
1840201139Smav			biodone(bp);
1841260387Sscottl		}
1842260387Sscottl		return;
1843195534Sscottl	}
1844224497Smav	case ADA_CCB_RAHEAD:
1845224497Smav	{
1846224497Smav		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
1847224497Smav			if (adaerror(done_ccb, 0, 0) == ERESTART) {
1848249466Smavout:
1849249466Smav				/* Drop freeze taken due to CAM_DEV_QFREEZE */
1850249466Smav				cam_release_devq(path, 0, 0, 0, FALSE);
1851224497Smav				return;
1852224497Smav			} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
1853249466Smav				cam_release_devq(path,
1854224497Smav				    /*relsim_flags*/0,
1855224497Smav				    /*reduction*/0,
1856224497Smav				    /*timeout*/0,
1857224497Smav				    /*getcount_only*/0);
1858224497Smav			}
1859224497Smav		}
1860224497Smav
1861224497Smav		/*
1862224497Smav		 * Since our peripheral may be invalidated by an error
1863224497Smav		 * above or an external event, we must release our CCB
1864224497Smav		 * before releasing the reference on the peripheral.
1865224497Smav		 * The peripheral will only go away once the last reference
1866224497Smav		 * is removed, and we need it around for the CCB release
1867224497Smav		 * operation.
1868224497Smav		 */
1869224497Smav		cgd = (struct ccb_getdev *)done_ccb;
1870249466Smav		xpt_setup_ccb(&cgd->ccb_h, path, CAM_PRIORITY_NORMAL);
1871224497Smav		cgd->ccb_h.func_code = XPT_GDEV_TYPE;
1872224497Smav		xpt_action((union ccb *)cgd);
1873224497Smav		if (ADA_WC >= 0 &&
1874224497Smav		    cgd->ident_data.support.command1 & ATA_SUPPORT_WRITECACHE) {
1875224497Smav			softc->state = ADA_STATE_WCACHE;
1876224497Smav			xpt_release_ccb(done_ccb);
1877224497Smav			xpt_schedule(periph, CAM_PRIORITY_DEV);
1878249466Smav			goto out;
1879224497Smav		}
1880224497Smav		softc->state = ADA_STATE_NORMAL;
1881224497Smav		xpt_release_ccb(done_ccb);
1882249466Smav		/* Drop freeze taken due to CAM_DEV_QFREEZE */
1883249466Smav		cam_release_devq(path, 0, 0, 0, FALSE);
1884224497Smav		adaschedule(periph);
1885224497Smav		cam_periph_release_locked(periph);
1886224497Smav		return;
1887224497Smav	}
1888220412Smav	case ADA_CCB_WCACHE:
1889220412Smav	{
1890220412Smav		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
1891220412Smav			if (adaerror(done_ccb, 0, 0) == ERESTART) {
1892249466Smav				goto out;
1893220412Smav			} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
1894249466Smav				cam_release_devq(path,
1895220412Smav				    /*relsim_flags*/0,
1896220412Smav				    /*reduction*/0,
1897220412Smav				    /*timeout*/0,
1898220412Smav				    /*getcount_only*/0);
1899220412Smav			}
1900220412Smav		}
1901220412Smav
1902220412Smav		softc->state = ADA_STATE_NORMAL;
1903220412Smav		/*
1904220412Smav		 * Since our peripheral may be invalidated by an error
1905220412Smav		 * above or an external event, we must release our CCB
1906220412Smav		 * before releasing the reference on the peripheral.
1907220412Smav		 * The peripheral will only go away once the last reference
1908220412Smav		 * is removed, and we need it around for the CCB release
1909220412Smav		 * operation.
1910220412Smav		 */
1911220412Smav		xpt_release_ccb(done_ccb);
1912249466Smav		/* Drop freeze taken due to CAM_DEV_QFREEZE */
1913249466Smav		cam_release_devq(path, 0, 0, 0, FALSE);
1914220412Smav		adaschedule(periph);
1915220412Smav		cam_periph_release_locked(periph);
1916220412Smav		return;
1917220412Smav	}
1918195534Sscottl	case ADA_CCB_DUMP:
1919195534Sscottl		/* No-op.  We're polling */
1920195534Sscottl		return;
1921195534Sscottl	default:
1922195534Sscottl		break;
1923195534Sscottl	}
1924195534Sscottl	xpt_release_ccb(done_ccb);
1925195534Sscottl}
1926195534Sscottl
1927195534Sscottlstatic int
1928195534Sscottladaerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
1929195534Sscottl{
1930195534Sscottl
1931203385Smav	return(cam_periph_error(ccb, cam_flags, sense_flags, NULL));
1932195534Sscottl}
1933195534Sscottl
1934195534Sscottlstatic void
1935198897Smavadagetparams(struct cam_periph *periph, struct ccb_getdev *cgd)
1936195534Sscottl{
1937195534Sscottl	struct ada_softc *softc = (struct ada_softc *)periph->softc;
1938195534Sscottl	struct disk_params *dp = &softc->params;
1939195534Sscottl	u_int64_t lbasize48;
1940195534Sscottl	u_int32_t lbasize;
1941195534Sscottl
1942198897Smav	dp->secsize = ata_logical_sector_size(&cgd->ident_data);
1943195534Sscottl	if ((cgd->ident_data.atavalid & ATA_FLAG_54_58) &&
1944195534Sscottl		cgd->ident_data.current_heads && cgd->ident_data.current_sectors) {
1945195534Sscottl		dp->heads = cgd->ident_data.current_heads;
1946195534Sscottl		dp->secs_per_track = cgd->ident_data.current_sectors;
1947195534Sscottl		dp->cylinders = cgd->ident_data.cylinders;
1948195534Sscottl		dp->sectors = (u_int32_t)cgd->ident_data.current_size_1 |
1949195534Sscottl			  ((u_int32_t)cgd->ident_data.current_size_2 << 16);
1950195534Sscottl	} else {
1951195534Sscottl		dp->heads = cgd->ident_data.heads;
1952195534Sscottl		dp->secs_per_track = cgd->ident_data.sectors;
1953195534Sscottl		dp->cylinders = cgd->ident_data.cylinders;
1954195534Sscottl		dp->sectors = cgd->ident_data.cylinders * dp->heads * dp->secs_per_track;
1955195534Sscottl	}
1956195534Sscottl	lbasize = (u_int32_t)cgd->ident_data.lba_size_1 |
1957195534Sscottl		  ((u_int32_t)cgd->ident_data.lba_size_2 << 16);
1958195534Sscottl
1959195534Sscottl	/* use the 28bit LBA size if valid or bigger than the CHS mapping */
1960195534Sscottl	if (cgd->ident_data.cylinders == 16383 || dp->sectors < lbasize)
1961195534Sscottl		dp->sectors = lbasize;
1962195534Sscottl
1963195534Sscottl	/* use the 48bit LBA size if valid */
1964195534Sscottl	lbasize48 = ((u_int64_t)cgd->ident_data.lba_size48_1) |
1965195534Sscottl		    ((u_int64_t)cgd->ident_data.lba_size48_2 << 16) |
1966195534Sscottl		    ((u_int64_t)cgd->ident_data.lba_size48_3 << 32) |
1967195534Sscottl		    ((u_int64_t)cgd->ident_data.lba_size48_4 << 48);
1968195534Sscottl	if ((cgd->ident_data.support.command2 & ATA_SUPPORT_ADDRESS48) &&
1969195534Sscottl	    lbasize48 > ATA_MAX_28BIT_LBA)
1970195534Sscottl		dp->sectors = lbasize48;
1971195534Sscottl}
1972195534Sscottl
1973195534Sscottlstatic void
1974195534Sscottladasendorderedtag(void *arg)
1975195534Sscottl{
1976195534Sscottl	struct ada_softc *softc = arg;
1977195534Sscottl
1978195534Sscottl	if (ada_send_ordered) {
1979260387Sscottl		if (softc->outstanding_cmds > 0) {
1980260387Sscottl			if ((softc->flags & ADA_FLAG_WAS_OTAG) == 0)
1981260387Sscottl				softc->flags |= ADA_FLAG_NEED_OTAG;
1982260387Sscottl			softc->flags &= ~ADA_FLAG_WAS_OTAG;
1983195534Sscottl		}
1984195534Sscottl	}
1985195534Sscottl	/* Queue us up again */
1986195534Sscottl	callout_reset(&softc->sendordered_c,
1987230921Smav	    (ada_default_timeout * hz) / ADA_ORDEREDTAG_INTERVAL,
1988195534Sscottl	    adasendorderedtag, softc);
1989195534Sscottl}
1990195534Sscottl
1991195534Sscottl/*
1992195534Sscottl * Step through all ADA peripheral drivers, and if the device is still open,
1993195534Sscottl * sync the disk cache to physical media.
1994195534Sscottl */
1995195534Sscottlstatic void
1996220650Smavadaflush(void)
1997195534Sscottl{
1998195534Sscottl	struct cam_periph *periph;
1999195534Sscottl	struct ada_softc *softc;
2000248872Smav	union ccb *ccb;
2001236814Smav	int error;
2002195534Sscottl
2003248868Smav	CAM_PERIPH_FOREACH(periph, &adadriver) {
2004251792Smav		softc = (struct ada_softc *)periph->softc;
2005251792Smav		if (SCHEDULER_STOPPED()) {
2006251792Smav			/* If we paniced with the lock held, do not recurse. */
2007251792Smav			if (!cam_periph_owned(periph) &&
2008251792Smav			    (softc->flags & ADA_FLAG_OPEN)) {
2009251792Smav				adadump(softc->disk, NULL, 0, 0, 0);
2010251792Smav			}
2011200180Smav			continue;
2012251792Smav		}
2013195534Sscottl		cam_periph_lock(periph);
2014195534Sscottl		/*
2015195534Sscottl		 * We only sync the cache if the drive is still open, and
2016195534Sscottl		 * if the drive is capable of it..
2017195534Sscottl		 */
2018195534Sscottl		if (((softc->flags & ADA_FLAG_OPEN) == 0) ||
2019195534Sscottl		    (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) == 0) {
2020195534Sscottl			cam_periph_unlock(periph);
2021195534Sscottl			continue;
2022195534Sscottl		}
2023195534Sscottl
2024248872Smav		ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL);
2025248872Smav		cam_fill_ataio(&ccb->ataio,
2026236814Smav				    0,
2027195534Sscottl				    adadone,
2028195534Sscottl				    CAM_DIR_NONE,
2029195534Sscottl				    0,
2030195534Sscottl				    NULL,
2031195534Sscottl				    0,
2032195534Sscottl				    ada_default_timeout*1000);
2033195534Sscottl		if (softc->flags & ADA_FLAG_CAN_48BIT)
2034248872Smav			ata_48bit_cmd(&ccb->ataio, ATA_FLUSHCACHE48, 0, 0, 0);
2035195534Sscottl		else
2036248872Smav			ata_28bit_cmd(&ccb->ataio, ATA_FLUSHCACHE, 0, 0, 0);
2037195534Sscottl
2038248872Smav		error = cam_periph_runccb(ccb, adaerror, /*cam_flags*/0,
2039248872Smav		    /*sense_flags*/ SF_NO_RECOVERY | SF_NO_RETRY,
2040248872Smav		    softc->disk->d_devstat);
2041236814Smav		if (error != 0)
2042195534Sscottl			xpt_print(periph->path, "Synchronize cache failed\n");
2043249048Smav		xpt_release_ccb(ccb);
2044195534Sscottl		cam_periph_unlock(periph);
2045195534Sscottl	}
2046220650Smav}
2047214279Sbrucec
2048220650Smavstatic void
2049220650Smavadaspindown(uint8_t cmd, int flags)
2050220650Smav{
2051220650Smav	struct cam_periph *periph;
2052220650Smav	struct ada_softc *softc;
2053248872Smav	union ccb *ccb;
2054236814Smav	int error;
2055214279Sbrucec
2056248868Smav	CAM_PERIPH_FOREACH(periph, &adadriver) {
2057214279Sbrucec		/* If we paniced with lock held - not recurse here. */
2058214279Sbrucec		if (cam_periph_owned(periph))
2059214279Sbrucec			continue;
2060214279Sbrucec		cam_periph_lock(periph);
2061214279Sbrucec		softc = (struct ada_softc *)periph->softc;
2062214279Sbrucec		/*
2063214279Sbrucec		 * We only spin-down the drive if it is capable of it..
2064214279Sbrucec		 */
2065214279Sbrucec		if ((softc->flags & ADA_FLAG_CAN_POWERMGT) == 0) {
2066214279Sbrucec			cam_periph_unlock(periph);
2067214279Sbrucec			continue;
2068214279Sbrucec		}
2069214279Sbrucec
2070214279Sbrucec		if (bootverbose)
2071214279Sbrucec			xpt_print(periph->path, "spin-down\n");
2072214279Sbrucec
2073248872Smav		ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL);
2074248872Smav		cam_fill_ataio(&ccb->ataio,
2075236814Smav				    0,
2076214279Sbrucec				    adadone,
2077220650Smav				    CAM_DIR_NONE | flags,
2078214279Sbrucec				    0,
2079214279Sbrucec				    NULL,
2080214279Sbrucec				    0,
2081214279Sbrucec				    ada_default_timeout*1000);
2082248872Smav		ata_28bit_cmd(&ccb->ataio, cmd, 0, 0, 0);
2083214279Sbrucec
2084248872Smav		error = cam_periph_runccb(ccb, adaerror, /*cam_flags*/0,
2085248872Smav		    /*sense_flags*/ SF_NO_RECOVERY | SF_NO_RETRY,
2086248872Smav		    softc->disk->d_devstat);
2087236814Smav		if (error != 0)
2088214279Sbrucec			xpt_print(periph->path, "Spin-down disk failed\n");
2089249048Smav		xpt_release_ccb(ccb);
2090214279Sbrucec		cam_periph_unlock(periph);
2091214279Sbrucec	}
2092195534Sscottl}
2093195534Sscottl
2094220650Smavstatic void
2095220650Smavadashutdown(void *arg, int howto)
2096220650Smav{
2097220650Smav
2098220650Smav	adaflush();
2099220650Smav	if (ada_spindown_shutdown != 0 &&
2100220650Smav	    (howto & (RB_HALT | RB_POWEROFF)) != 0)
2101220650Smav		adaspindown(ATA_STANDBY_IMMEDIATE, 0);
2102220650Smav}
2103220650Smav
2104220650Smavstatic void
2105220650Smavadasuspend(void *arg)
2106220650Smav{
2107220650Smav
2108220650Smav	adaflush();
2109220650Smav	if (ada_spindown_suspend != 0)
2110220650Smav		adaspindown(ATA_SLEEP, CAM_DEV_QFREEZE);
2111220650Smav}
2112220650Smav
2113220650Smavstatic void
2114220650Smavadaresume(void *arg)
2115220650Smav{
2116220650Smav	struct cam_periph *periph;
2117220650Smav	struct ada_softc *softc;
2118220650Smav
2119220650Smav	if (ada_spindown_suspend == 0)
2120220650Smav		return;
2121220650Smav
2122248868Smav	CAM_PERIPH_FOREACH(periph, &adadriver) {
2123220650Smav		cam_periph_lock(periph);
2124220650Smav		softc = (struct ada_softc *)periph->softc;
2125220650Smav		/*
2126220650Smav		 * We only spin-down the drive if it is capable of it..
2127220650Smav		 */
2128220650Smav		if ((softc->flags & ADA_FLAG_CAN_POWERMGT) == 0) {
2129220650Smav			cam_periph_unlock(periph);
2130220650Smav			continue;
2131220650Smav		}
2132220650Smav
2133220650Smav		if (bootverbose)
2134220650Smav			xpt_print(periph->path, "resume\n");
2135220650Smav
2136220650Smav		/*
2137220650Smav		 * Drop freeze taken due to CAM_DEV_QFREEZE flag set on
2138220650Smav		 * sleep request.
2139220650Smav		 */
2140220650Smav		cam_release_devq(periph->path,
2141220650Smav			 /*relsim_flags*/0,
2142220650Smav			 /*openings*/0,
2143220650Smav			 /*timeout*/0,
2144220650Smav			 /*getcount_only*/0);
2145220650Smav
2146220650Smav		cam_periph_unlock(periph);
2147220650Smav	}
2148220650Smav}
2149220650Smav
2150195534Sscottl#endif /* _KERNEL */
2151