ata_da.c revision 256216
178828Sobrien/*-
278828Sobrien * Copyright (c) 2009 Alexander Motin <mav@FreeBSD.org>
3218822Sdim * All rights reserved.
433965Sjdp *
533965Sjdp * Redistribution and use in source and binary forms, with or without
6218822Sdim * modification, are permitted provided that the following conditions
733965Sjdp * are met:
8218822Sdim * 1. Redistributions of source code must retain the above copyright
9218822Sdim *    notice, this list of conditions and the following disclaimer,
10218822Sdim *    without modification, immediately at the beginning of the file.
11218822Sdim * 2. Redistributions in binary form must reproduce the above copyright
1233965Sjdp *    notice, this list of conditions and the following disclaimer in the
13218822Sdim *    documentation and/or other materials provided with the distribution.
14218822Sdim *
15218822Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16218822Sdim * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1733965Sjdp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18218822Sdim * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19218822Sdim * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20218822Sdim * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2133965Sjdp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2233965Sjdp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2333965Sjdp * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2433965Sjdp * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2533965Sjdp */
2633965Sjdp
2733965Sjdp#include <sys/cdefs.h>
2833965Sjdp__FBSDID("$FreeBSD: stable/9/sys/cam/ata/ata_da.c 256216 2013-10-09 18:58:28Z mav $");
29218822Sdim
3033965Sjdp#include "opt_ada.h"
3133965Sjdp#include "opt_ata.h"
32130561Sobrien
3333965Sjdp#include <sys/param.h>
3433965Sjdp
3533965Sjdp#ifdef _KERNEL
3677298Sobrien#include <sys/systm.h>
3733965Sjdp#include <sys/kernel.h>
3833965Sjdp#include <sys/bio.h>
3933965Sjdp#include <sys/sysctl.h>
4033965Sjdp#include <sys/taskqueue.h>
4160484Sobrien#include <sys/lock.h>
4233965Sjdp#include <sys/mutex.h>
4333965Sjdp#include <sys/conf.h>
4433965Sjdp#include <sys/devicestat.h>
4533965Sjdp#include <sys/eventhandler.h>
4633965Sjdp#include <sys/malloc.h>
4733965Sjdp#include <sys/cons.h>
4833965Sjdp#include <sys/proc.h>
49218822Sdim#include <sys/reboot.h>
5033965Sjdp#include <geom/geom_disk.h>
51130561Sobrien#endif /* _KERNEL */
52130561Sobrien
5333965Sjdp#ifndef _KERNEL
54130561Sobrien#include <stdio.h>
55130561Sobrien#include <string.h>
56130561Sobrien#endif /* _KERNEL */
5760484Sobrien
5833965Sjdp#include <cam/cam.h>
5933965Sjdp#include <cam/cam_ccb.h>
6033965Sjdp#include <cam/cam_periph.h>
6133965Sjdp#include <cam/cam_xpt_periph.h>
6233965Sjdp#include <cam/cam_sim.h>
6333965Sjdp
6433965Sjdp#include <cam/ata/ata_all.h>
6533965Sjdp
6633965Sjdp#include <machine/md_var.h>	/* geometry translation */
67104834Sobrien
68104834Sobrien#ifdef _KERNEL
69104834Sobrien
70104834Sobrien#define ATA_MAX_28BIT_LBA               268435455UL
71104834Sobrien
72104834Sobrientypedef enum {
7333965Sjdp	ADA_STATE_RAHEAD,
7460484Sobrien	ADA_STATE_WCACHE,
7560484Sobrien	ADA_STATE_NORMAL
7689857Sobrien} ada_state;
7760484Sobrien
7833965Sjdptypedef enum {
7933965Sjdp	ADA_FLAG_CAN_48BIT	= 0x0002,
8033965Sjdp	ADA_FLAG_CAN_FLUSHCACHE	= 0x0004,
8133965Sjdp	ADA_FLAG_CAN_NCQ	= 0x0008,
82130561Sobrien	ADA_FLAG_CAN_DMA	= 0x0010,
83130561Sobrien	ADA_FLAG_NEED_OTAG	= 0x0020,
8433965Sjdp	ADA_FLAG_WENT_IDLE	= 0x0040,
8533965Sjdp	ADA_FLAG_CAN_TRIM	= 0x0080,
8633965Sjdp	ADA_FLAG_OPEN		= 0x0100,
8733965Sjdp	ADA_FLAG_SCTX_INIT	= 0x0200,
8833965Sjdp	ADA_FLAG_CAN_CFA        = 0x0400,
8933965Sjdp	ADA_FLAG_CAN_POWERMGT   = 0x0800,
9033965Sjdp	ADA_FLAG_CAN_DMA48	= 0x1000,
9133965Sjdp	ADA_FLAG_DIRTY		= 0x2000
9233965Sjdp} ada_flags;
9333965Sjdp
9433965Sjdptypedef enum {
95218822Sdim	ADA_Q_NONE		= 0x00,
96104834Sobrien	ADA_Q_4K		= 0x01,
9760484Sobrien} ada_quirks;
9889857Sobrien
9933965Sjdp#define ADA_Q_BIT_STRING	\
10060484Sobrien	"\020"			\
10160484Sobrien	"\0014K"
10260484Sobrien
103130561Sobrientypedef enum {
10433965Sjdp	ADA_CCB_RAHEAD		= 0x01,
10533965Sjdp	ADA_CCB_WCACHE		= 0x02,
10633965Sjdp	ADA_CCB_BUFFER_IO	= 0x03,
10733965Sjdp	ADA_CCB_WAITING		= 0x04,
10833965Sjdp	ADA_CCB_DUMP		= 0x05,
10933965Sjdp	ADA_CCB_TRIM		= 0x06,
11033965Sjdp	ADA_CCB_TYPE_MASK	= 0x0F,
111130561Sobrien} ada_ccb_state;
11233965Sjdp
11333965Sjdp/* Offsets into our private area for storing information */
11433965Sjdp#define ccb_state	ppriv_field0
11533965Sjdp#define ccb_bp		ppriv_ptr1
11633965Sjdp
11733965Sjdpstruct disk_params {
11833965Sjdp	u_int8_t  heads;
11933965Sjdp	u_int8_t  secs_per_track;
12033965Sjdp	u_int32_t cylinders;
12133965Sjdp	u_int32_t secsize;	/* Number of bytes/logical sector */
12233965Sjdp	u_int64_t sectors;	/* Total number sectors */
12333965Sjdp};
12433965Sjdp
12533965Sjdp#define TRIM_MAX_BLOCKS	8
126130561Sobrien#define TRIM_MAX_RANGES	(TRIM_MAX_BLOCKS * ATA_DSM_BLK_RANGES)
12733965Sjdp#define TRIM_MAX_BIOS	(TRIM_MAX_RANGES * 4)
12838889Sjdpstruct trim_request {
129218822Sdim	uint8_t		data[TRIM_MAX_RANGES * ATA_DSM_RANGE_SIZE];
130218822Sdim	struct bio	*bps[TRIM_MAX_BIOS];
13133965Sjdp};
13233965Sjdp
13389857Sobrienstruct ada_softc {
134218822Sdim	struct	 bio_queue_head bio_queue;
13533965Sjdp	struct	 bio_queue_head trim_queue;
136218822Sdim	ada_state state;
13733965Sjdp	ada_flags flags;
138218822Sdim	ada_quirks quirks;
13933965Sjdp	int	 sort_io_queue;
140218822Sdim	int	 ordered_tag_count;
14133965Sjdp	int	 outstanding_cmds;
14233965Sjdp	int	 trim_max_ranges;
14333965Sjdp	int	 trim_running;
144218822Sdim	int	 read_ahead;
145218822Sdim	int	 write_cache;
14633965Sjdp#ifdef ADA_TEST_FAILURE
14760484Sobrien	int      force_read_error;
14833965Sjdp	int      force_write_error;
14933965Sjdp	int      periodic_read_error;
15033965Sjdp	int      periodic_read_count;
15138889Sjdp#endif
152218822Sdim	struct	 disk_params params;
15360484Sobrien	struct	 disk *disk;
154218822Sdim	struct task		sysctl_task;
15533965Sjdp	struct sysctl_ctx_list	sysctl_ctx;
15633965Sjdp	struct sysctl_oid	*sysctl_tree;
15733965Sjdp	struct callout		sendordered_c;
158218822Sdim	struct trim_request	trim_req;
15933965Sjdp};
16033965Sjdp
16133965Sjdpstruct ada_quirk_entry {
162130561Sobrien	struct scsi_inquiry_pattern inq_pat;
16333965Sjdp	ada_quirks quirks;
16433965Sjdp};
16533965Sjdp
166218822Sdimstatic struct ada_quirk_entry ada_quirk_table[] =
16733965Sjdp{
16833965Sjdp	{
16933965Sjdp		/* Hitachi Advanced Format (4k) drives */
17033965Sjdp		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "Hitachi H??????????E3*", "*" },
17133965Sjdp		/*quirks*/ADA_Q_4K
17233965Sjdp	},
17333965Sjdp	{
17433965Sjdp		/* Samsung Advanced Format (4k) drives */
17533965Sjdp		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "SAMSUNG HD155UI*", "*" },
17633965Sjdp		/*quirks*/ADA_Q_4K
17733965Sjdp	},
17833965Sjdp	{
17933965Sjdp		/* Samsung Advanced Format (4k) drives */
18033965Sjdp		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "SAMSUNG HD204UI*", "*" },
181104834Sobrien		/*quirks*/ADA_Q_4K
18233965Sjdp	},
183130561Sobrien	{
18433965Sjdp		/* Seagate Barracuda Green Advanced Format (4k) drives */
18533965Sjdp		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "ST????DL*", "*" },
18633965Sjdp		/*quirks*/ADA_Q_4K
18760484Sobrien	},
18833965Sjdp	{
18933965Sjdp		/* Seagate Barracuda Advanced Format (4k) drives */
19033965Sjdp		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "ST???DM*", "*" },
19133965Sjdp		/*quirks*/ADA_Q_4K
19233965Sjdp	},
19333965Sjdp	{
19433965Sjdp		/* Seagate Barracuda Advanced Format (4k) drives */
19533965Sjdp		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "ST????DM*", "*" },
19633965Sjdp		/*quirks*/ADA_Q_4K
19733965Sjdp	},
19833965Sjdp	{
19933965Sjdp		/* Seagate Momentus Advanced Format (4k) drives */
20033965Sjdp		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9500423AS*", "*" },
20133965Sjdp		/*quirks*/ADA_Q_4K
20233965Sjdp	},
203130561Sobrien	{
20433965Sjdp		/* Seagate Momentus Advanced Format (4k) drives */
20533965Sjdp		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9500424AS*", "*" },
20660484Sobrien		/*quirks*/ADA_Q_4K
20733965Sjdp	},
20833965Sjdp	{
20933965Sjdp		/* Seagate Momentus Advanced Format (4k) drives */
21033965Sjdp		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9640423AS*", "*" },
21133965Sjdp		/*quirks*/ADA_Q_4K
212130561Sobrien	},
21333965Sjdp	{
21433965Sjdp		/* Seagate Momentus Advanced Format (4k) drives */
21533965Sjdp		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9640424AS*", "*" },
21633965Sjdp		/*quirks*/ADA_Q_4K
217130561Sobrien	},
21833965Sjdp	{
21933965Sjdp		/* Seagate Momentus Advanced Format (4k) drives */
22033965Sjdp		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9750420AS*", "*" },
22133965Sjdp		/*quirks*/ADA_Q_4K
22233965Sjdp	},
22333965Sjdp	{
22433965Sjdp		/* Seagate Momentus Advanced Format (4k) drives */
22533965Sjdp		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9750422AS*", "*" },
22633965Sjdp		/*quirks*/ADA_Q_4K
22733965Sjdp	},
22833965Sjdp	{
22933965Sjdp		/* Seagate Momentus Advanced Format (4k) drives */
23033965Sjdp		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9750423AS*", "*" },
23133965Sjdp		/*quirks*/ADA_Q_4K
23233965Sjdp	},
23333965Sjdp	{
23433965Sjdp		/* Seagate Momentus Thin Advanced Format (4k) drives */
23533965Sjdp		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "ST???LT*", "*" },
23633965Sjdp		/*quirks*/ADA_Q_4K
237130561Sobrien	},
238130561Sobrien	{
23933965Sjdp		/* WDC Caviar Green Advanced Format (4k) drives */
24033965Sjdp		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD????RS*", "*" },
24133965Sjdp		/*quirks*/ADA_Q_4K
242104834Sobrien	},
24333965Sjdp	{
24433965Sjdp		/* WDC Caviar Green Advanced Format (4k) drives */
245104834Sobrien		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD????RX*", "*" },
246104834Sobrien		/*quirks*/ADA_Q_4K
24733965Sjdp	},
24833965Sjdp	{
24933965Sjdp		/* WDC Caviar Green Advanced Format (4k) drives */
25089857Sobrien		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD??????RS*", "*" },
25189857Sobrien		/*quirks*/ADA_Q_4K
25289857Sobrien	},
25333965Sjdp	{
254130561Sobrien		/* WDC Caviar Green Advanced Format (4k) drives */
25533965Sjdp		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD??????RX*", "*" },
25633965Sjdp		/*quirks*/ADA_Q_4K
25733965Sjdp	},
25833965Sjdp	{
25933965Sjdp		/* WDC Scorpio Black Advanced Format (4k) drives */
26033965Sjdp		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD???PKT*", "*" },
26133965Sjdp		/*quirks*/ADA_Q_4K
26233965Sjdp	},
26333965Sjdp	{
26433965Sjdp		/* WDC Scorpio Black Advanced Format (4k) drives */
26533965Sjdp		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD?????PKT*", "*" },
26633965Sjdp		/*quirks*/ADA_Q_4K
26733965Sjdp	},
26833965Sjdp	{
26933965Sjdp		/* WDC Scorpio Blue Advanced Format (4k) drives */
27033965Sjdp		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD???PVT*", "*" },
27133965Sjdp		/*quirks*/ADA_Q_4K
27233965Sjdp	},
27333965Sjdp	{
27433965Sjdp		/* WDC Scorpio Blue Advanced Format (4k) drives */
27533965Sjdp		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD?????PVT*", "*" },
27633965Sjdp		/*quirks*/ADA_Q_4K
27733965Sjdp	},
27833965Sjdp	/* SSDs */
27933965Sjdp	{
28033965Sjdp		/*
28133965Sjdp		 * Corsair Force 2 SSDs
28233965Sjdp		 * 4k optimised & trim only works in 4k requests + 4k aligned
283218822Sdim		 */
28433965Sjdp		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "Corsair CSSD-F*", "*" },
285218822Sdim		/*quirks*/ADA_Q_4K
286218822Sdim	},
287218822Sdim	{
288218822Sdim		/*
289218822Sdim		 * Corsair Force 3 SSDs
29033965Sjdp		 * 4k optimised & trim only works in 4k requests + 4k aligned
29133965Sjdp		 */
292218822Sdim		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "Corsair Force 3*", "*" },
29360484Sobrien		/*quirks*/ADA_Q_4K
294218822Sdim	},
29533965Sjdp	{
29633965Sjdp		/*
29733965Sjdp		 * Corsair Force GT SSDs
29833965Sjdp		 * 4k optimised & trim only works in 4k requests + 4k aligned
299218822Sdim		 */
300218822Sdim		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "Corsair Force GT*", "*" },
301218822Sdim		/*quirks*/ADA_Q_4K
30233965Sjdp	},
30333965Sjdp	{
30433965Sjdp		/*
305218822Sdim		 * Crucial M4 SSDs
30633965Sjdp		 * 4k optimised & trim only works in 4k requests + 4k aligned
30733965Sjdp		 */
30833965Sjdp		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "M4-CT???M4SSD2*", "*" },
30933965Sjdp		/*quirks*/ADA_Q_4K
31033965Sjdp	},
31133965Sjdp	{
31233965Sjdp		/*
31333965Sjdp		 * Crucial RealSSD C300 SSDs
31433965Sjdp		 * 4k optimised
31533965Sjdp		 */
31633965Sjdp		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "C300-CTFDDAC???MAG*",
31733965Sjdp		"*" }, /*quirks*/ADA_Q_4K
31833965Sjdp	},
31933965Sjdp	{
32033965Sjdp		/*
32133965Sjdp		 * Intel 320 Series SSDs
32233965Sjdp		 * 4k optimised & trim only works in 4k requests + 4k aligned
32333965Sjdp		 */
324130561Sobrien		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "INTEL SSDSA2CW*", "*" },
32533965Sjdp		/*quirks*/ADA_Q_4K
32633965Sjdp	},
32733965Sjdp	{
32833965Sjdp		/*
32933965Sjdp		 * Intel 330 Series SSDs
33033965Sjdp		 * 4k optimised & trim only works in 4k requests + 4k aligned
33133965Sjdp		 */
33233965Sjdp		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "INTEL SSDSC2CT*", "*" },
333130561Sobrien		/*quirks*/ADA_Q_4K
33433965Sjdp	},
335130561Sobrien	{
33689857Sobrien		/*
337130561Sobrien		 * Intel 510 Series SSDs
33833965Sjdp		 * 4k optimised & trim only works in 4k requests + 4k aligned
33933965Sjdp		 */
34033965Sjdp		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "INTEL SSDSC2MH*", "*" },
34133965Sjdp		/*quirks*/ADA_Q_4K
34233965Sjdp	},
34333965Sjdp	{
34433965Sjdp		/*
345130561Sobrien		 * Intel 520 Series SSDs
34689857Sobrien		 * 4k optimised & trim only works in 4k requests + 4k aligned
34789857Sobrien		 */
34889857Sobrien		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "INTEL SSDSC2BW*", "*" },
34933965Sjdp		/*quirks*/ADA_Q_4K
35033965Sjdp	},
35133965Sjdp	{
35233965Sjdp		/*
35360484Sobrien		 * Kingston E100 Series SSDs
35433965Sjdp		 * 4k optimised & trim only works in 4k requests + 4k aligned
35533965Sjdp		 */
35633965Sjdp		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "KINGSTON SE100S3*", "*" },
35733965Sjdp		/*quirks*/ADA_Q_4K
35833965Sjdp	},
35933965Sjdp	{
36033965Sjdp		/*
36133965Sjdp		 * Kingston HyperX 3k SSDs
36233965Sjdp		 * 4k optimised & trim only works in 4k requests + 4k aligned
36333965Sjdp		 */
36433965Sjdp		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "KINGSTON SH103S3*", "*" },
36533965Sjdp		/*quirks*/ADA_Q_4K
36633965Sjdp	},
36733965Sjdp	{
36833965Sjdp		/*
36933965Sjdp		 * OCZ Agility 3 SSDs
37033965Sjdp		 * 4k optimised & trim only works in 4k requests + 4k aligned
37133965Sjdp		 */
37233965Sjdp		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "OCZ-AGILITY3*", "*" },
37333965Sjdp		/*quirks*/ADA_Q_4K
37433965Sjdp	},
375218822Sdim	{
376218822Sdim		/*
377218822Sdim		 * OCZ Deneva R Series SSDs
378218822Sdim		 * 4k optimised & trim only works in 4k requests + 4k aligned
379218822Sdim		 */
380218822Sdim		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "DENRSTE251M45*", "*" },
381218822Sdim		/*quirks*/ADA_Q_4K
382218822Sdim	},
383218822Sdim	{
384218822Sdim		/*
385218822Sdim		 * OCZ Vertex 2 SSDs (inc pro series)
386218822Sdim		 * 4k optimised & trim only works in 4k requests + 4k aligned
38733965Sjdp		 */
38833965Sjdp		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "OCZ?VERTEX2*", "*" },
38933965Sjdp		/*quirks*/ADA_Q_4K
39033965Sjdp	},
39133965Sjdp	{
39233965Sjdp		/*
39333965Sjdp		 * OCZ Vertex 3 SSDs
39433965Sjdp		 * 4k optimised & trim only works in 4k requests + 4k aligned
39533965Sjdp		 */
39633965Sjdp		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "OCZ-VERTEX3*", "*" },
39733965Sjdp		/*quirks*/ADA_Q_4K
39833965Sjdp	},
39933965Sjdp	{
40033965Sjdp		/*
401130561Sobrien		 * OCZ Vertex 4 SSDs
40233965Sjdp		 * 4k optimised & trim only works in 4k requests + 4k aligned
403130561Sobrien		 */
404130561Sobrien		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "OCZ-VERTEX4*", "*" },
405130561Sobrien		/*quirks*/ADA_Q_4K
40633965Sjdp	},
40733965Sjdp	{
40833965Sjdp		/*
40933965Sjdp		 * Samsung 830 Series SSDs
41060484Sobrien		 * 4k optimised
41133965Sjdp		 */
41260484Sobrien		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "SAMSUNG SSD 830 Series*", "*" },
41360484Sobrien		/*quirks*/ADA_Q_4K
41460484Sobrien	},
41533965Sjdp	{
41660484Sobrien		/*
41760484Sobrien		 * SuperTalent TeraDrive CT SSDs
41860484Sobrien		 * 4k optimised & trim only works in 4k requests + 4k aligned
41933965Sjdp		 */
42060484Sobrien		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "FTM??CT25H*", "*" },
42160484Sobrien		/*quirks*/ADA_Q_4K
42260484Sobrien	},
42333965Sjdp	{
42433965Sjdp		/*
42560484Sobrien		 * XceedIOPS SATA SSDs
42660484Sobrien		 * 4k optimised
42733965Sjdp		 */
42860484Sobrien		{ T_DIRECT, SIP_MEDIA_FIXED, "*", "SG9XCS2D*", "*" },
429218822Sdim		/*quirks*/ADA_Q_4K
43060484Sobrien	},
43133965Sjdp	{
43260484Sobrien		/* Default */
43333965Sjdp		{
43460484Sobrien		  T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED,
435218822Sdim		  /*vendor*/"*", /*product*/"*", /*revision*/"*"
43660484Sobrien		},
43733965Sjdp		/*quirks*/0
438218822Sdim	},
43933965Sjdp};
44060484Sobrien
441218822Sdimstatic	disk_strategy_t	adastrategy;
44260484Sobrienstatic	dumper_t	adadump;
44333965Sjdpstatic	periph_init_t	adainit;
444218822Sdimstatic	void		adaasync(void *callback_arg, u_int32_t code,
44533965Sjdp				struct cam_path *path, void *arg);
446218822Sdimstatic	void		adasysctlinit(void *context, int pending);
447218822Sdimstatic	periph_ctor_t	adaregister;
448218822Sdimstatic	periph_dtor_t	adacleanup;
449218822Sdimstatic	periph_start_t	adastart;
450218822Sdimstatic	periph_oninv_t	adaoninvalidate;
451218822Sdimstatic	void		adadone(struct cam_periph *periph,
452218822Sdim			       union ccb *done_ccb);
453218822Sdimstatic  int		adaerror(union ccb *ccb, u_int32_t cam_flags,
454218822Sdim				u_int32_t sense_flags);
455218822Sdimstatic void		adagetparams(struct cam_periph *periph,
456218822Sdim				struct ccb_getdev *cgd);
457218822Sdimstatic timeout_t	adasendorderedtag;
458218822Sdimstatic void		adashutdown(void *arg, int howto);
459218822Sdimstatic void		adasuspend(void *arg);
460218822Sdimstatic void		adaresume(void *arg);
461218822Sdim
462218822Sdim#ifndef	ADA_DEFAULT_LEGACY_ALIASES
463218822Sdim#ifdef ATA_CAM
464218822Sdim#define	ADA_DEFAULT_LEGACY_ALIASES	1
465218822Sdim#else
466218822Sdim#define	ADA_DEFAULT_LEGACY_ALIASES	0
467218822Sdim#endif
468218822Sdim#endif
469218822Sdim
470218822Sdim#ifndef ADA_DEFAULT_TIMEOUT
471218822Sdim#define ADA_DEFAULT_TIMEOUT 30	/* Timeout in seconds */
472218822Sdim#endif
473218822Sdim
474218822Sdim#ifndef	ADA_DEFAULT_RETRY
475218822Sdim#define	ADA_DEFAULT_RETRY	4
47660484Sobrien#endif
477218822Sdim
47860484Sobrien#ifndef	ADA_DEFAULT_SEND_ORDERED
47933965Sjdp#define	ADA_DEFAULT_SEND_ORDERED	1
48060484Sobrien#endif
48160484Sobrien
48260484Sobrien#ifndef	ADA_DEFAULT_SPINDOWN_SHUTDOWN
48360484Sobrien#define	ADA_DEFAULT_SPINDOWN_SHUTDOWN	1
48460484Sobrien#endif
48560484Sobrien
48660484Sobrien#ifndef	ADA_DEFAULT_SPINDOWN_SUSPEND
48760484Sobrien#define	ADA_DEFAULT_SPINDOWN_SUSPEND	1
48860484Sobrien#endif
489130561Sobrien
49060484Sobrien#ifndef	ADA_DEFAULT_READ_AHEAD
49160484Sobrien#define	ADA_DEFAULT_READ_AHEAD	1
49260484Sobrien#endif
49360484Sobrien
49460484Sobrien#ifndef	ADA_DEFAULT_WRITE_CACHE
49560484Sobrien#define	ADA_DEFAULT_WRITE_CACHE	1
49660484Sobrien#endif
49760484Sobrien
49860484Sobrien#define	ADA_RA	(softc->read_ahead >= 0 ? \
49960484Sobrien		 softc->read_ahead : ada_read_ahead)
50060484Sobrien#define	ADA_WC	(softc->write_cache >= 0 ? \
50160484Sobrien		 softc->write_cache : ada_write_cache)
50260484Sobrien#define	ADA_SIO	(softc->sort_io_queue >= 0 ? \
50389857Sobrien		 softc->sort_io_queue : cam_sort_io_queues)
50460484Sobrien
50589857Sobrien/*
50689857Sobrien * Most platforms map firmware geometry to actual, but some don't.  If
50789857Sobrien * not overridden, default to nothing.
50889857Sobrien */
50989857Sobrien#ifndef ata_disk_firmware_geom_adjust
51060484Sobrien#define	ata_disk_firmware_geom_adjust(disk)
51189857Sobrien#endif
51289857Sobrien
51360484Sobrienstatic int ada_legacy_aliases = ADA_DEFAULT_LEGACY_ALIASES;
51489857Sobrienstatic int ada_retry_count = ADA_DEFAULT_RETRY;
51589857Sobrienstatic int ada_default_timeout = ADA_DEFAULT_TIMEOUT;
51689857Sobrienstatic int ada_send_ordered = ADA_DEFAULT_SEND_ORDERED;
51789857Sobrienstatic int ada_spindown_shutdown = ADA_DEFAULT_SPINDOWN_SHUTDOWN;
51889857Sobrienstatic int ada_spindown_suspend = ADA_DEFAULT_SPINDOWN_SUSPEND;
51960484Sobrienstatic int ada_read_ahead = ADA_DEFAULT_READ_AHEAD;
52060484Sobrienstatic int ada_write_cache = ADA_DEFAULT_WRITE_CACHE;
52160484Sobrien
52260484Sobrienstatic SYSCTL_NODE(_kern_cam, OID_AUTO, ada, CTLFLAG_RD, 0,
52360484Sobrien            "CAM Direct Access Disk driver");
52460484SobrienSYSCTL_INT(_kern_cam_ada, OID_AUTO, legacy_aliases, CTLFLAG_RW,
52589857Sobrien           &ada_legacy_aliases, 0, "Create legacy-like device aliases");
52689857SobrienTUNABLE_INT("kern.cam.ada.legacy_aliases", &ada_legacy_aliases);
52789857SobrienSYSCTL_INT(_kern_cam_ada, OID_AUTO, retry_count, CTLFLAG_RW,
528218822Sdim           &ada_retry_count, 0, "Normal I/O retry count");
52989857SobrienTUNABLE_INT("kern.cam.ada.retry_count", &ada_retry_count);
53060484SobrienSYSCTL_INT(_kern_cam_ada, OID_AUTO, default_timeout, CTLFLAG_RW,
53189857Sobrien           &ada_default_timeout, 0, "Normal I/O timeout (in seconds)");
53260484SobrienTUNABLE_INT("kern.cam.ada.default_timeout", &ada_default_timeout);
53389857SobrienSYSCTL_INT(_kern_cam_ada, OID_AUTO, send_ordered, CTLFLAG_RW,
53460484Sobrien           &ada_send_ordered, 0, "Send Ordered Tags");
53589857SobrienTUNABLE_INT("kern.cam.ada.send_ordered", &ada_send_ordered);
53660484SobrienSYSCTL_INT(_kern_cam_ada, OID_AUTO, spindown_shutdown, CTLFLAG_RW,
53789857Sobrien           &ada_spindown_shutdown, 0, "Spin down upon shutdown");
53860484SobrienTUNABLE_INT("kern.cam.ada.spindown_shutdown", &ada_spindown_shutdown);
53933965SjdpSYSCTL_INT(_kern_cam_ada, OID_AUTO, spindown_suspend, CTLFLAG_RW,
54033965Sjdp           &ada_spindown_suspend, 0, "Spin down upon suspend");
54160484SobrienTUNABLE_INT("kern.cam.ada.spindown_suspend", &ada_spindown_suspend);
54260484SobrienSYSCTL_INT(_kern_cam_ada, OID_AUTO, read_ahead, CTLFLAG_RW,
54360484Sobrien           &ada_read_ahead, 0, "Enable disk read-ahead");
544130561SobrienTUNABLE_INT("kern.cam.ada.read_ahead", &ada_read_ahead);
54560484SobrienSYSCTL_INT(_kern_cam_ada, OID_AUTO, write_cache, CTLFLAG_RW,
546130561Sobrien           &ada_write_cache, 0, "Enable disk write cache");
54760484SobrienTUNABLE_INT("kern.cam.ada.write_cache", &ada_write_cache);
54860484Sobrien
54933965Sjdp/*
55033965Sjdp * ADA_ORDEREDTAG_INTERVAL determines how often, relative
55133965Sjdp * to the default timeout, we check to see whether an ordered
55233965Sjdp * tagged transaction is appropriate to prevent simple tag
553130561Sobrien * starvation.  Since we'd like to ensure that there is at least
55433965Sjdp * 1/2 of the timeout length left for a starved transaction to
55533965Sjdp * complete after we've sent an ordered tag, we must poll at least
55633965Sjdp * four times in every timeout period.  This takes care of the worst
55733965Sjdp * case where a starved transaction starts during an interval that
558130561Sobrien * meets the requirement "don't send an ordered tag" test so it takes
559130561Sobrien * us two intervals to determine that a tag must be sent.
56033965Sjdp */
561218822Sdim#ifndef ADA_ORDEREDTAG_INTERVAL
56260484Sobrien#define ADA_ORDEREDTAG_INTERVAL 4
563130561Sobrien#endif
56460484Sobrien
56560484Sobrienstatic struct periph_driver adadriver =
56633965Sjdp{
56733965Sjdp	adainit, "ada",
56833965Sjdp	TAILQ_HEAD_INITIALIZER(adadriver.units), /* generation */ 0
569104834Sobrien};
57033965Sjdp
571130561SobrienPERIPHDRIVER_DECLARE(ada, adadriver);
572104834Sobrien
57333965Sjdpstatic MALLOC_DEFINE(M_ATADA, "ata_da", "ata_da buffers");
574104834Sobrien
57533965Sjdpstatic int
576218822Sdimadaopen(struct disk *dp)
577218822Sdim{
578218822Sdim	struct cam_periph *periph;
57933965Sjdp	struct ada_softc *softc;
58033965Sjdp	int error;
58133965Sjdp
58233965Sjdp	periph = (struct cam_periph *)dp->d_drv1;
58333965Sjdp	if (cam_periph_acquire(periph) != CAM_REQ_CMP) {
58433965Sjdp		return(ENXIO);
585130561Sobrien	}
58633965Sjdp
58733965Sjdp	cam_periph_lock(periph);
58833965Sjdp	if ((error = cam_periph_hold(periph, PRIBIO|PCATCH)) != 0) {
58933965Sjdp		cam_periph_unlock(periph);
59033965Sjdp		cam_periph_release(periph);
59133965Sjdp		return (error);
59233965Sjdp	}
59333965Sjdp
59438889Sjdp	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE | CAM_DEBUG_PERIPH,
59538889Sjdp	    ("adaopen\n"));
59633965Sjdp
59733965Sjdp	softc = (struct ada_softc *)periph->softc;
59833965Sjdp	softc->flags |= ADA_FLAG_OPEN;
59933965Sjdp
60033965Sjdp	cam_periph_unhold(periph);
60133965Sjdp	cam_periph_unlock(periph);
60233965Sjdp	return (0);
60333965Sjdp}
604104834Sobrien
605104834Sobrienstatic int
60633965Sjdpadaclose(struct disk *dp)
607218822Sdim{
60833965Sjdp	struct	cam_periph *periph;
60933965Sjdp	struct	ada_softc *softc;
61033965Sjdp	union ccb *ccb;
611104834Sobrien	int error;
612104834Sobrien
613104834Sobrien	periph = (struct cam_periph *)dp->d_drv1;
614104834Sobrien	cam_periph_lock(periph);
615104834Sobrien	if (cam_periph_hold(periph, PRIBIO) != 0) {
61633965Sjdp		cam_periph_unlock(periph);
61733965Sjdp		cam_periph_release(periph);
61833965Sjdp		return (0);
61933965Sjdp	}
62033965Sjdp
62133965Sjdp	softc = (struct ada_softc *)periph->softc;
62233965Sjdp
62333965Sjdp	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE | CAM_DEBUG_PERIPH,
62433965Sjdp	    ("adaclose\n"));
62533965Sjdp
62633965Sjdp	/* We only sync the cache if the drive is capable of it. */
62733965Sjdp	if ((softc->flags & ADA_FLAG_DIRTY) != 0 &&
62833965Sjdp	    (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) != 0 &&
62933965Sjdp	    (periph->flags & CAM_PERIPH_INVALID) == 0) {
63033965Sjdp
63133965Sjdp		ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL);
63233965Sjdp		cam_fill_ataio(&ccb->ataio,
63333965Sjdp				    1,
63433965Sjdp				    adadone,
63533965Sjdp				    CAM_DIR_NONE,
63633965Sjdp				    0,
63733965Sjdp				    NULL,
63833965Sjdp				    0,
63933965Sjdp				    ada_default_timeout*1000);
64033965Sjdp
64133965Sjdp		if (softc->flags & ADA_FLAG_CAN_48BIT)
64233965Sjdp			ata_48bit_cmd(&ccb->ataio, ATA_FLUSHCACHE48, 0, 0, 0);
64333965Sjdp		else
64433965Sjdp			ata_28bit_cmd(&ccb->ataio, ATA_FLUSHCACHE, 0, 0, 0);
64533965Sjdp		error = cam_periph_runccb(ccb, adaerror, /*cam_flags*/0,
64633965Sjdp		    /*sense_flags*/0, softc->disk->d_devstat);
64733965Sjdp
64833965Sjdp		if (error != 0)
64933965Sjdp			xpt_print(periph->path, "Synchronize cache failed\n");
65033965Sjdp		else
65133965Sjdp			softc->flags &= ~ADA_FLAG_DIRTY;
65233965Sjdp		xpt_release_ccb(ccb);
65333965Sjdp	}
65433965Sjdp
65533965Sjdp	softc->flags &= ~ADA_FLAG_OPEN;
656218822Sdim	cam_periph_unhold(periph);
65733965Sjdp	cam_periph_unlock(periph);
658218822Sdim	cam_periph_release(periph);
659218822Sdim	return (0);
660218822Sdim}
661218822Sdim
66233965Sjdpstatic void
66333965Sjdpadaschedule(struct cam_periph *periph)
66433965Sjdp{
66533965Sjdp	struct ada_softc *softc = (struct ada_softc *)periph->softc;
66633965Sjdp	uint32_t prio;
66733965Sjdp
66833965Sjdp	if (softc->state != ADA_STATE_NORMAL)
66933965Sjdp		return;
67033965Sjdp
67133965Sjdp	/* Check if cam_periph_getccb() was called. */
67233965Sjdp	prio = periph->immediate_priority;
67333965Sjdp
67433965Sjdp	/* Check if we have more work to do. */
67533965Sjdp	if (bioq_first(&softc->bio_queue) ||
67633965Sjdp	    (!softc->trim_running && bioq_first(&softc->trim_queue))) {
67733965Sjdp		prio = CAM_PRIORITY_NORMAL;
67833965Sjdp	}
67933965Sjdp
680107492Sobrien	/* Schedule CCB if any of above is true. */
681130561Sobrien	if (prio != CAM_PRIORITY_NONE)
68233965Sjdp		xpt_schedule(periph, prio);
68333965Sjdp}
684107492Sobrien
68577298Sobrien/*
68677298Sobrien * Actually translate the requested transfer into one the physical driver
68777298Sobrien * can understand.  The transfer is described by a buf and will include
68833965Sjdp * only one physical transfer.
689218822Sdim */
690218822Sdimstatic void
691218822Sdimadastrategy(struct bio *bp)
692218822Sdim{
69338889Sjdp	struct cam_periph *periph;
69438889Sjdp	struct ada_softc *softc;
69538889Sjdp
69633965Sjdp	periph = (struct cam_periph *)bp->bio_disk->d_drv1;
697218822Sdim	softc = (struct ada_softc *)periph->softc;
698218822Sdim
69933965Sjdp	cam_periph_lock(periph);
70060484Sobrien
70133965Sjdp	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("adastrategy(%p)\n", bp));
70233965Sjdp
70360484Sobrien	/*
70460484Sobrien	 * If the device has been made invalid, error out
70560484Sobrien	 */
70633965Sjdp	if ((periph->flags & CAM_PERIPH_INVALID) != 0) {
70733965Sjdp		cam_periph_unlock(periph);
70860484Sobrien		biofinish(bp, NULL, ENXIO);
70960484Sobrien		return;
71060484Sobrien	}
71160484Sobrien
71260484Sobrien	/*
71360484Sobrien	 * Place it in the queue of disk activities for this disk
71460484Sobrien	 */
71560484Sobrien	if (bp->bio_cmd == BIO_DELETE &&
71660484Sobrien	    (softc->flags & ADA_FLAG_CAN_TRIM)) {
71760484Sobrien		if (ADA_SIO)
71860484Sobrien		    bioq_disksort(&softc->trim_queue, bp);
71960484Sobrien		else
72033965Sjdp		    bioq_insert_tail(&softc->trim_queue, bp);
72133965Sjdp	} else {
72233965Sjdp		if (ADA_SIO)
72333965Sjdp		    bioq_disksort(&softc->bio_queue, bp);
72433965Sjdp		else
72533965Sjdp		    bioq_insert_tail(&softc->bio_queue, bp);
72633965Sjdp	}
72733965Sjdp
72833965Sjdp	/*
72933965Sjdp	 * Schedule ourselves for performing the work.
73033965Sjdp	 */
73133965Sjdp	adaschedule(periph);
73233965Sjdp	cam_periph_unlock(periph);
73333965Sjdp
73433965Sjdp	return;
73533965Sjdp}
73633965Sjdp
73733965Sjdpstatic int
73833965Sjdpadadump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t length)
73933965Sjdp{
74033965Sjdp	struct	    cam_periph *periph;
74133965Sjdp	struct	    ada_softc *softc;
74233965Sjdp	u_int	    secsize;
74333965Sjdp	union	    ccb ccb;
74433965Sjdp	struct	    disk *dp;
74533965Sjdp	uint64_t    lba;
74633965Sjdp	uint16_t    count;
74733965Sjdp	int	    error = 0;
74833965Sjdp
749130561Sobrien	dp = arg;
75033965Sjdp	periph = dp->d_drv1;
751130561Sobrien	softc = (struct ada_softc *)periph->softc;
75233965Sjdp	cam_periph_lock(periph);
753130561Sobrien	secsize = softc->params.secsize;
75433965Sjdp	lba = offset / secsize;
75533965Sjdp	count = length / secsize;
75633965Sjdp
75733965Sjdp	if ((periph->flags & CAM_PERIPH_INVALID) != 0) {
75833965Sjdp		cam_periph_unlock(periph);
75933965Sjdp		return (ENXIO);
76033965Sjdp	}
76133965Sjdp
76233965Sjdp	if (length > 0) {
76333965Sjdp		xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
76433965Sjdp		ccb.ccb_h.ccb_state = ADA_CCB_DUMP;
76533965Sjdp		cam_fill_ataio(&ccb.ataio,
76633965Sjdp		    0,
76733965Sjdp		    adadone,
76833965Sjdp		    CAM_DIR_OUT,
76933965Sjdp		    0,
77033965Sjdp		    (u_int8_t *) virtual,
77133965Sjdp		    length,
77233965Sjdp		    ada_default_timeout*1000);
77333965Sjdp		if ((softc->flags & ADA_FLAG_CAN_48BIT) &&
77433965Sjdp		    (lba + count >= ATA_MAX_28BIT_LBA ||
77533965Sjdp		    count >= 256)) {
77633965Sjdp			ata_48bit_cmd(&ccb.ataio, ATA_WRITE_DMA48,
77733965Sjdp			    0, lba, count);
77833965Sjdp		} else {
779218822Sdim			ata_28bit_cmd(&ccb.ataio, ATA_WRITE_DMA,
78033965Sjdp			    0, lba, count);
781218822Sdim		}
78233965Sjdp		xpt_polled_action(&ccb);
78333965Sjdp
78433965Sjdp		error = cam_periph_error(&ccb,
78533965Sjdp		    0, SF_NO_RECOVERY | SF_NO_RETRY, NULL);
786218822Sdim		if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0)
78733965Sjdp			cam_release_devq(ccb.ccb_h.path, /*relsim_flags*/0,
78833965Sjdp			    /*reduction*/0, /*timeout*/0, /*getcount_only*/0);
78933965Sjdp		if (error != 0)
790218822Sdim			printf("Aborting dump due to I/O error.\n");
79133965Sjdp
792218822Sdim		cam_periph_unlock(periph);
79333965Sjdp		return (error);
79433965Sjdp	}
79533965Sjdp
796218822Sdim	if (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) {
79733965Sjdp		xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
79833965Sjdp
799218822Sdim		ccb.ccb_h.ccb_state = ADA_CCB_DUMP;
80033965Sjdp		cam_fill_ataio(&ccb.ataio,
801218822Sdim				    0,
80233965Sjdp				    adadone,
803218822Sdim				    CAM_DIR_NONE,
80433965Sjdp				    0,
805218822Sdim				    NULL,
80633965Sjdp				    0,
807218822Sdim				    ada_default_timeout*1000);
80833965Sjdp
809218822Sdim		if (softc->flags & ADA_FLAG_CAN_48BIT)
81033965Sjdp			ata_48bit_cmd(&ccb.ataio, ATA_FLUSHCACHE48, 0, 0, 0);
811218822Sdim		else
81233965Sjdp			ata_28bit_cmd(&ccb.ataio, ATA_FLUSHCACHE, 0, 0, 0);
813218822Sdim		xpt_polled_action(&ccb);
81433965Sjdp
815218822Sdim		error = cam_periph_error(&ccb,
81633965Sjdp		    0, SF_NO_RECOVERY | SF_NO_RETRY, NULL);
817218822Sdim		if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0)
81833965Sjdp			cam_release_devq(ccb.ccb_h.path, /*relsim_flags*/0,
819218822Sdim			    /*reduction*/0, /*timeout*/0, /*getcount_only*/0);
82033965Sjdp		if (error != 0)
821218822Sdim			xpt_print(periph->path, "Synchronize cache failed\n");
82233965Sjdp	}
823218822Sdim	cam_periph_unlock(periph);
82433965Sjdp	return (error);
825218822Sdim}
82633965Sjdp
827218822Sdimstatic void
82833965Sjdpadainit(void)
829218822Sdim{
83033965Sjdp	cam_status status;
831218822Sdim
83233965Sjdp	/*
833218822Sdim	 * Install a global async callback.  This callback will
83433965Sjdp	 * receive async callbacks like "new device found".
835218822Sdim	 */
83633965Sjdp	status = xpt_register_async(AC_FOUND_DEVICE, adaasync, NULL, NULL);
837218822Sdim
83833965Sjdp	if (status != CAM_REQ_CMP) {
839104834Sobrien		printf("ada: Failed to attach master async callback "
84033965Sjdp		       "due to status 0x%x!\n", status);
841218822Sdim	} else if (ada_send_ordered) {
84233965Sjdp
843218822Sdim		/* Register our event handlers */
844218822Sdim		if ((EVENTHANDLER_REGISTER(power_suspend, adasuspend,
84533965Sjdp					   NULL, EVENTHANDLER_PRI_LAST)) == NULL)
846218822Sdim		    printf("adainit: power event registration failed!\n");
84733965Sjdp		if ((EVENTHANDLER_REGISTER(power_resume, adaresume,
848218822Sdim					   NULL, EVENTHANDLER_PRI_LAST)) == NULL)
84933965Sjdp		    printf("adainit: power event registration failed!\n");
850218822Sdim		if ((EVENTHANDLER_REGISTER(shutdown_post_sync, adashutdown,
851218822Sdim					   NULL, SHUTDOWN_PRI_DEFAULT)) == NULL)
852218822Sdim		    printf("adainit: shutdown event registration failed!\n");
85333965Sjdp	}
854218822Sdim}
85533965Sjdp
856218822Sdim/*
857130561Sobrien * Callback from GEOM, called when it has finished cleaning up its
858218822Sdim * resources.
859104834Sobrien */
860104834Sobrienstatic void
861218822Sdimadadiskgonecb(struct disk *dp)
862218822Sdim{
863104834Sobrien	struct cam_periph *periph;
864218822Sdim
865218822Sdim	periph = (struct cam_periph *)dp->d_drv1;
866218822Sdim
867218822Sdim	cam_periph_release(periph);
868218822Sdim}
869218822Sdim
870218822Sdimstatic void
871218822Sdimadaoninvalidate(struct cam_periph *periph)
872218822Sdim{
873218822Sdim	struct ada_softc *softc;
87433965Sjdp
875218822Sdim	softc = (struct ada_softc *)periph->softc;
87633965Sjdp
877218822Sdim	/*
87860484Sobrien	 * De-register any async callbacks.
87960484Sobrien	 */
88060484Sobrien	xpt_register_async(0, adaasync, periph, periph->path);
88160484Sobrien
88260484Sobrien	/*
88360484Sobrien	 * Return all queued I/O with ENXIO.
884218822Sdim	 * XXX Handle any transactions queued to the card
885218822Sdim	 *     with XPT_ABORT_CCB.
886218822Sdim	 */
887218822Sdim	bioq_flush(&softc->bio_queue, NULL, ENXIO);
88833965Sjdp	bioq_flush(&softc->trim_queue, NULL, ENXIO);
88933965Sjdp
89033965Sjdp	disk_gone(softc->disk);
89160484Sobrien	xpt_print(periph->path, "lost device\n");
89260484Sobrien}
893104834Sobrien
89460484Sobrienstatic void
89560484Sobrienadacleanup(struct cam_periph *periph)
89633965Sjdp{
89733965Sjdp	struct ada_softc *softc;
89833965Sjdp
89933965Sjdp	softc = (struct ada_softc *)periph->softc;
90033965Sjdp
901218822Sdim	xpt_print(periph->path, "removing device entry\n");
902218822Sdim	cam_periph_unlock(periph);
903218822Sdim
904218822Sdim	/*
905218822Sdim	 * If we can't free the sysctl tree, oh well...
906130561Sobrien	 */
907130561Sobrien	if ((softc->flags & ADA_FLAG_SCTX_INIT) != 0
908130561Sobrien	    && sysctl_ctx_free(&softc->sysctl_ctx) != 0) {
909130561Sobrien		xpt_print(periph->path, "can't remove sysctl context\n");
910130561Sobrien	}
911218822Sdim
912218822Sdim	disk_destroy(softc->disk);
913218822Sdim	callout_drain(&softc->sendordered_c);
914218822Sdim	free(softc, M_DEVBUF);
915218822Sdim	cam_periph_lock(periph);
916218822Sdim}
917218822Sdim
91833965Sjdpstatic void
919130561Sobrienadaasync(void *callback_arg, u_int32_t code,
920130561Sobrien	struct cam_path *path, void *arg)
921218822Sdim{
922130561Sobrien	struct ccb_getdev cgd;
923218822Sdim	struct cam_periph *periph;
92433965Sjdp	struct ada_softc *softc;
92533965Sjdp
92633965Sjdp	periph = (struct cam_periph *)callback_arg;
92733965Sjdp	switch (code) {
928218822Sdim	case AC_FOUND_DEVICE:
92933965Sjdp	{
930130561Sobrien		struct ccb_getdev *cgd;
93133965Sjdp		cam_status status;
93260484Sobrien
93333965Sjdp		cgd = (struct ccb_getdev *)arg;
93433965Sjdp		if (cgd == NULL)
935218822Sdim			break;
93633965Sjdp
93733965Sjdp		if (cgd->protocol != PROTO_ATA)
938107492Sobrien			break;
93933965Sjdp
94033965Sjdp		/*
941130561Sobrien		 * Allocate a peripheral instance for
94233965Sjdp		 * this device and start the probe
943130561Sobrien		 * process.
94433965Sjdp		 */
945130561Sobrien		status = cam_periph_alloc(adaregister, adaoninvalidate,
94633965Sjdp					  adacleanup, adastart,
94733965Sjdp					  "ada", CAM_PERIPH_BIO,
94833965Sjdp					  cgd->ccb_h.path, adaasync,
94933965Sjdp					  AC_FOUND_DEVICE, cgd);
95060484Sobrien
95133965Sjdp		if (status != CAM_REQ_CMP
95233965Sjdp		 && status != CAM_REQ_INPROG)
953104834Sobrien			printf("adaasync: Unable to attach to new device "
954130561Sobrien				"due to status 0x%x\n", status);
95533965Sjdp		break;
95633965Sjdp	}
95733965Sjdp	case AC_GETDEV_CHANGED:
95833965Sjdp	{
95933965Sjdp		softc = (struct ada_softc *)periph->softc;
96033965Sjdp		xpt_setup_ccb(&cgd.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
96133965Sjdp		cgd.ccb_h.func_code = XPT_GDEV_TYPE;
96233965Sjdp		xpt_action((union ccb *)&cgd);
96333965Sjdp
96433965Sjdp		if ((cgd.ident_data.capabilities1 & ATA_SUPPORT_DMA) &&
96533965Sjdp		    (cgd.inq_flags & SID_DMA))
96633965Sjdp			softc->flags |= ADA_FLAG_CAN_DMA;
96733965Sjdp		else
96833965Sjdp			softc->flags &= ~ADA_FLAG_CAN_DMA;
96933965Sjdp		if (cgd.ident_data.support.command2 & ATA_SUPPORT_ADDRESS48) {
97033965Sjdp			softc->flags |= ADA_FLAG_CAN_48BIT;
97133965Sjdp			if (cgd.inq_flags & SID_DMA48)
972218822Sdim				softc->flags |= ADA_FLAG_CAN_DMA48;
973218822Sdim			else
974218822Sdim				softc->flags &= ~ADA_FLAG_CAN_DMA48;
975218822Sdim		} else
97633965Sjdp			softc->flags &= ~(ADA_FLAG_CAN_48BIT |
97733965Sjdp			    ADA_FLAG_CAN_DMA48);
97833965Sjdp		if ((cgd.ident_data.satacapabilities & ATA_SUPPORT_NCQ) &&
97933965Sjdp		    (cgd.inq_flags & SID_DMA) && (cgd.inq_flags & SID_CmdQue))
98033965Sjdp			softc->flags |= ADA_FLAG_CAN_NCQ;
98138889Sjdp		else
98233965Sjdp			softc->flags &= ~ADA_FLAG_CAN_NCQ;
98333965Sjdp		if ((cgd.ident_data.support_dsm & ATA_SUPPORT_DSM_TRIM) &&
98433965Sjdp		    (cgd.inq_flags & SID_DMA))
98533965Sjdp			softc->flags |= ADA_FLAG_CAN_TRIM;
98633965Sjdp		else
98733965Sjdp			softc->flags &= ~ADA_FLAG_CAN_TRIM;
98833965Sjdp
98933965Sjdp		cam_periph_async(periph, code, path, arg);
99033965Sjdp		break;
99133965Sjdp	}
99233965Sjdp	case AC_ADVINFO_CHANGED:
99333965Sjdp	{
99433965Sjdp		uintptr_t buftype;
99533965Sjdp
99633965Sjdp		buftype = (uintptr_t)arg;
99733965Sjdp		if (buftype == CDAI_TYPE_PHYS_PATH) {
99833965Sjdp			struct ada_softc *softc;
99933965Sjdp
100033965Sjdp			softc = periph->softc;
100133965Sjdp			disk_attr_changed(softc->disk, "GEOM::physpath",
100233965Sjdp					  M_NOWAIT);
100333965Sjdp		}
100433965Sjdp		break;
100533965Sjdp	}
100633965Sjdp	case AC_SENT_BDR:
100733965Sjdp	case AC_BUS_RESET:
100833965Sjdp	{
100933965Sjdp		softc = (struct ada_softc *)periph->softc;
101033965Sjdp		cam_periph_async(periph, code, path, arg);
1011130561Sobrien		if (softc->state != ADA_STATE_NORMAL)
101233965Sjdp			break;
101333965Sjdp		xpt_setup_ccb(&cgd.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
101433965Sjdp		cgd.ccb_h.func_code = XPT_GDEV_TYPE;
101533965Sjdp		xpt_action((union ccb *)&cgd);
101633965Sjdp		if (ADA_RA >= 0 &&
101733965Sjdp		    cgd.ident_data.support.command1 & ATA_SUPPORT_LOOKAHEAD)
101833965Sjdp			softc->state = ADA_STATE_RAHEAD;
101933965Sjdp		else if (ADA_WC >= 0 &&
102033965Sjdp		    cgd.ident_data.support.command1 & ATA_SUPPORT_WRITECACHE)
102133965Sjdp			softc->state = ADA_STATE_WCACHE;
102233965Sjdp		else
102333965Sjdp		    break;
102433965Sjdp		cam_periph_acquire(periph);
102533965Sjdp		xpt_schedule(periph, CAM_PRIORITY_DEV);
1026130561Sobrien	}
102733965Sjdp	default:
102833965Sjdp		cam_periph_async(periph, code, path, arg);
102933965Sjdp		break;
103033965Sjdp	}
103133965Sjdp}
103233965Sjdp
103333965Sjdpstatic void
103433965Sjdpadasysctlinit(void *context, int pending)
103533965Sjdp{
103633965Sjdp	struct cam_periph *periph;
103733965Sjdp	struct ada_softc *softc;
103833965Sjdp	char tmpstr[80], tmpstr2[80];
103933965Sjdp
104033965Sjdp	periph = (struct cam_periph *)context;
104133965Sjdp
104233965Sjdp	/* periph was held for us when this task was enqueued */
104333965Sjdp	if ((periph->flags & CAM_PERIPH_INVALID) != 0) {
104433965Sjdp		cam_periph_release(periph);
104533965Sjdp		return;
104633965Sjdp	}
104733965Sjdp
104833965Sjdp	softc = (struct ada_softc *)periph->softc;
104933965Sjdp	snprintf(tmpstr, sizeof(tmpstr), "CAM ADA unit %d", periph->unit_number);
105033965Sjdp	snprintf(tmpstr2, sizeof(tmpstr2), "%d", periph->unit_number);
105133965Sjdp
105233965Sjdp	sysctl_ctx_init(&softc->sysctl_ctx);
105333965Sjdp	softc->flags |= ADA_FLAG_SCTX_INIT;
105433965Sjdp	softc->sysctl_tree = SYSCTL_ADD_NODE(&softc->sysctl_ctx,
105533965Sjdp		SYSCTL_STATIC_CHILDREN(_kern_cam_ada), OID_AUTO, tmpstr2,
105633965Sjdp		CTLFLAG_RD, 0, tmpstr);
105733965Sjdp	if (softc->sysctl_tree == NULL) {
105833965Sjdp		printf("adasysctlinit: unable to allocate sysctl tree\n");
105933965Sjdp		cam_periph_release(periph);
106033965Sjdp		return;
106133965Sjdp	}
106233965Sjdp
106333965Sjdp	SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree),
106433965Sjdp		OID_AUTO, "read_ahead", CTLFLAG_RW | CTLFLAG_MPSAFE,
106533965Sjdp		&softc->read_ahead, 0, "Enable disk read ahead.");
106633965Sjdp	SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree),
106733965Sjdp		OID_AUTO, "write_cache", CTLFLAG_RW | CTLFLAG_MPSAFE,
106833965Sjdp		&softc->write_cache, 0, "Enable disk write cache.");
106933965Sjdp	SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree),
107033965Sjdp		OID_AUTO, "sort_io_queue", CTLFLAG_RW | CTLFLAG_MPSAFE,
107133965Sjdp		&softc->sort_io_queue, 0,
107233965Sjdp		"Sort IO queue to try and optimise disk access patterns");
107333965Sjdp#ifdef ADA_TEST_FAILURE
107433965Sjdp	/*
107533965Sjdp	 * Add a 'door bell' sysctl which allows one to set it from userland
107633965Sjdp	 * and cause something bad to happen.  For the moment, we only allow
107733965Sjdp	 * whacking the next read or write.
107833965Sjdp	 */
107933965Sjdp	SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree),
108033965Sjdp		OID_AUTO, "force_read_error", CTLFLAG_RW | CTLFLAG_MPSAFE,
108133965Sjdp		&softc->force_read_error, 0,
108233965Sjdp		"Force a read error for the next N reads.");
1083130561Sobrien	SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree),
108433965Sjdp		OID_AUTO, "force_write_error", CTLFLAG_RW | CTLFLAG_MPSAFE,
108533965Sjdp		&softc->force_write_error, 0,
108633965Sjdp		"Force a write error for the next N writes.");
108733965Sjdp	SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree),
108833965Sjdp		OID_AUTO, "periodic_read_error", CTLFLAG_RW | CTLFLAG_MPSAFE,
108933965Sjdp		&softc->periodic_read_error, 0,
109033965Sjdp		"Force a read error every N reads (don't set too low).");
109133965Sjdp#endif
109233965Sjdp	cam_periph_release(periph);
109333965Sjdp}
109433965Sjdp
1095130561Sobrienstatic int
1096130561Sobrienadagetattr(struct bio *bp)
1097130561Sobrien{
1098130561Sobrien	int ret;
1099130561Sobrien	struct cam_periph *periph;
1100130561Sobrien
1101130561Sobrien	periph = (struct cam_periph *)bp->bio_disk->d_drv1;
1102130561Sobrien	cam_periph_lock(periph);
1103130561Sobrien	ret = xpt_getattr(bp->bio_data, bp->bio_length, bp->bio_attribute,
1104130561Sobrien	    periph->path);
1105130561Sobrien	cam_periph_unlock(periph);
1106130561Sobrien	if (ret == 0)
1107130561Sobrien		bp->bio_completed = bp->bio_length;
1108130561Sobrien	return ret;
110933965Sjdp}
111033965Sjdp
111133965Sjdpstatic cam_status
111233965Sjdpadaregister(struct cam_periph *periph, void *arg)
111333965Sjdp{
111433965Sjdp	struct ada_softc *softc;
111533965Sjdp	struct ccb_pathinq cpi;
111633965Sjdp	struct ccb_getdev *cgd;
111733965Sjdp	char   announce_buf[80], buf1[32];
111833965Sjdp	struct disk_params *dp;
111933965Sjdp	caddr_t match;
112033965Sjdp	u_int maxio;
112133965Sjdp	int legacy_id, quirks;
1122130561Sobrien
112333965Sjdp	cgd = (struct ccb_getdev *)arg;
1124130561Sobrien	if (cgd == NULL) {
112533965Sjdp		printf("adaregister: no getdev CCB, can't register device\n");
112633965Sjdp		return(CAM_REQ_CMP_ERR);
112733965Sjdp	}
112860484Sobrien
112933965Sjdp	softc = (struct ada_softc *)malloc(sizeof(*softc), M_DEVBUF,
113033965Sjdp	    M_NOWAIT|M_ZERO);
113133965Sjdp
113233965Sjdp	if (softc == NULL) {
113333965Sjdp		printf("adaregister: Unable to probe new device. "
113433965Sjdp		    "Unable to allocate softc\n");
113533965Sjdp		return(CAM_REQ_CMP_ERR);
113633965Sjdp	}
113733965Sjdp
113833965Sjdp	bioq_init(&softc->bio_queue);
113933965Sjdp	bioq_init(&softc->trim_queue);
114033965Sjdp
114133965Sjdp	if ((cgd->ident_data.capabilities1 & ATA_SUPPORT_DMA) &&
114233965Sjdp	    (cgd->inq_flags & SID_DMA))
114333965Sjdp		softc->flags |= ADA_FLAG_CAN_DMA;
114433965Sjdp	if (cgd->ident_data.support.command2 & ATA_SUPPORT_ADDRESS48) {
114533965Sjdp		softc->flags |= ADA_FLAG_CAN_48BIT;
114633965Sjdp		if (cgd->inq_flags & SID_DMA48)
114733965Sjdp			softc->flags |= ADA_FLAG_CAN_DMA48;
1148218822Sdim	}
1149218822Sdim	if (cgd->ident_data.support.command2 & ATA_SUPPORT_FLUSHCACHE)
1150218822Sdim		softc->flags |= ADA_FLAG_CAN_FLUSHCACHE;
1151218822Sdim	if (cgd->ident_data.support.command1 & ATA_SUPPORT_POWERMGT)
1152218822Sdim		softc->flags |= ADA_FLAG_CAN_POWERMGT;
1153218822Sdim	if ((cgd->ident_data.satacapabilities & ATA_SUPPORT_NCQ) &&
1154218822Sdim	    (cgd->inq_flags & SID_DMA) && (cgd->inq_flags & SID_CmdQue))
1155218822Sdim		softc->flags |= ADA_FLAG_CAN_NCQ;
1156218822Sdim	if ((cgd->ident_data.support_dsm & ATA_SUPPORT_DSM_TRIM) &&
1157218822Sdim	    (cgd->inq_flags & SID_DMA)) {
1158218822Sdim		softc->flags |= ADA_FLAG_CAN_TRIM;
1159218822Sdim		softc->trim_max_ranges = TRIM_MAX_RANGES;
1160218822Sdim		if (cgd->ident_data.max_dsm_blocks != 0) {
1161218822Sdim			softc->trim_max_ranges =
1162218822Sdim			    min(cgd->ident_data.max_dsm_blocks *
1163218822Sdim				ATA_DSM_BLK_RANGES, softc->trim_max_ranges);
1164218822Sdim		}
1165218822Sdim	}
1166218822Sdim	if (cgd->ident_data.support.command2 & ATA_SUPPORT_CFA)
1167218822Sdim		softc->flags |= ADA_FLAG_CAN_CFA;
1168218822Sdim
1169218822Sdim	periph->softc = softc;
1170218822Sdim
1171218822Sdim	/*
1172218822Sdim	 * See if this device has any quirks.
1173218822Sdim	 */
1174218822Sdim	match = cam_quirkmatch((caddr_t)&cgd->ident_data,
1175218822Sdim			       (caddr_t)ada_quirk_table,
117633965Sjdp			       sizeof(ada_quirk_table)/sizeof(*ada_quirk_table),
117733965Sjdp			       sizeof(*ada_quirk_table), ata_identify_match);
117833965Sjdp	if (match != NULL)
117933965Sjdp		softc->quirks = ((struct ada_quirk_entry *)match)->quirks;
118033965Sjdp	else
118160484Sobrien		softc->quirks = ADA_Q_NONE;
118233965Sjdp
118333965Sjdp	bzero(&cpi, sizeof(cpi));
118433965Sjdp	xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NONE);
118533965Sjdp	cpi.ccb_h.func_code = XPT_PATH_INQ;
118633965Sjdp	xpt_action((union ccb *)&cpi);
118733965Sjdp
118833965Sjdp	TASK_INIT(&softc->sysctl_task, 0, adasysctlinit, periph);
118933965Sjdp
119033965Sjdp	/*
119133965Sjdp	 * Register this media as a disk
119233965Sjdp	 */
119333965Sjdp	(void)cam_periph_hold(periph, PRIBIO);
119433965Sjdp	cam_periph_unlock(periph);
119533965Sjdp	snprintf(announce_buf, sizeof(announce_buf),
119638889Sjdp	    "kern.cam.ada.%d.quirks", periph->unit_number);
119733965Sjdp	quirks = softc->quirks;
119833965Sjdp	TUNABLE_INT_FETCH(announce_buf, &quirks);
119933965Sjdp	softc->quirks = quirks;
120033965Sjdp	softc->read_ahead = -1;
120133965Sjdp	snprintf(announce_buf, sizeof(announce_buf),
120233965Sjdp	    "kern.cam.ada.%d.read_ahead", periph->unit_number);
120333965Sjdp	TUNABLE_INT_FETCH(announce_buf, &softc->read_ahead);
120433965Sjdp	softc->write_cache = -1;
120533965Sjdp	snprintf(announce_buf, sizeof(announce_buf),
120633965Sjdp	    "kern.cam.ada.%d.write_cache", periph->unit_number);
120733965Sjdp	TUNABLE_INT_FETCH(announce_buf, &softc->write_cache);
120889857Sobrien	/* Disable queue sorting for non-rotational media by default. */
120933965Sjdp	if (cgd->ident_data.media_rotation_rate == 1)
121089857Sobrien		softc->sort_io_queue = 0;
121189857Sobrien	else
121289857Sobrien		softc->sort_io_queue = -1;
121389857Sobrien	adagetparams(periph, cgd);
121433965Sjdp	softc->disk = disk_alloc();
121533965Sjdp	softc->disk->d_devstat = devstat_new_entry(periph->periph_name,
121633965Sjdp			  periph->unit_number, softc->params.secsize,
121733965Sjdp			  DEVSTAT_ALL_SUPPORTED,
121833965Sjdp			  DEVSTAT_TYPE_DIRECT |
121933965Sjdp			  XPORT_DEVSTAT_TYPE(cpi.transport),
122033965Sjdp			  DEVSTAT_PRIORITY_DISK);
122133965Sjdp	softc->disk->d_open = adaopen;
122233965Sjdp	softc->disk->d_close = adaclose;
122333965Sjdp	softc->disk->d_strategy = adastrategy;
122433965Sjdp	softc->disk->d_getattr = adagetattr;
122533965Sjdp	softc->disk->d_dump = adadump;
122633965Sjdp	softc->disk->d_gone = adadiskgonecb;
122733965Sjdp	softc->disk->d_name = "ada";
122833965Sjdp	softc->disk->d_drv1 = periph;
122933965Sjdp	maxio = cpi.maxio;		/* Honor max I/O size of SIM */
123033965Sjdp	if (maxio == 0)
123133965Sjdp		maxio = DFLTPHYS;	/* traditional default */
123233965Sjdp	else if (maxio > MAXPHYS)
123333965Sjdp		maxio = MAXPHYS;	/* for safety */
123433965Sjdp	if (softc->flags & ADA_FLAG_CAN_48BIT)
123533965Sjdp		maxio = min(maxio, 65536 * softc->params.secsize);
123633965Sjdp	else					/* 28bit ATA command limit */
123733965Sjdp		maxio = min(maxio, 256 * softc->params.secsize);
123833965Sjdp	softc->disk->d_maxsize = maxio;
123933965Sjdp	softc->disk->d_unit = periph->unit_number;
124033965Sjdp	softc->disk->d_flags = 0;
124133965Sjdp	if (softc->flags & ADA_FLAG_CAN_FLUSHCACHE)
124233965Sjdp		softc->disk->d_flags |= DISKFLAG_CANFLUSHCACHE;
124333965Sjdp	if (softc->flags & ADA_FLAG_CAN_TRIM) {
124433965Sjdp		softc->disk->d_flags |= DISKFLAG_CANDELETE;
124533965Sjdp		softc->disk->d_delmaxsize = softc->params.secsize *
124633965Sjdp					    ATA_DSM_RANGE_MAX *
124733965Sjdp					    softc->trim_max_ranges;
124833965Sjdp	} else if ((softc->flags & ADA_FLAG_CAN_CFA) &&
124933965Sjdp	    !(softc->flags & ADA_FLAG_CAN_48BIT)) {
125033965Sjdp		softc->disk->d_flags |= DISKFLAG_CANDELETE;
125133965Sjdp		softc->disk->d_delmaxsize = 256 * softc->params.secsize;
125233965Sjdp	} else
125333965Sjdp		softc->disk->d_delmaxsize = maxio;
125433965Sjdp	if ((cpi.hba_misc & PIM_UNMAPPED) != 0)
125533965Sjdp		softc->disk->d_flags |= DISKFLAG_UNMAPPED_BIO;
125633965Sjdp	strlcpy(softc->disk->d_descr, cgd->ident_data.model,
125733965Sjdp	    MIN(sizeof(softc->disk->d_descr), sizeof(cgd->ident_data.model)));
125833965Sjdp	strlcpy(softc->disk->d_ident, cgd->ident_data.serial,
1259218822Sdim	    MIN(sizeof(softc->disk->d_ident), sizeof(cgd->ident_data.serial)));
126033965Sjdp	softc->disk->d_hba_vendor = cpi.hba_vendor;
1261218822Sdim	softc->disk->d_hba_device = cpi.hba_device;
1262218822Sdim	softc->disk->d_hba_subvendor = cpi.hba_subvendor;
1263218822Sdim	softc->disk->d_hba_subdevice = cpi.hba_subdevice;
1264218822Sdim
126533965Sjdp	softc->disk->d_sectorsize = softc->params.secsize;
126633965Sjdp	softc->disk->d_mediasize = (off_t)softc->params.sectors *
1267218822Sdim	    softc->params.secsize;
126833965Sjdp	if (ata_physical_sector_size(&cgd->ident_data) !=
1269218822Sdim	    softc->params.secsize) {
1270218822Sdim		softc->disk->d_stripesize =
1271218822Sdim		    ata_physical_sector_size(&cgd->ident_data);
1272218822Sdim		softc->disk->d_stripeoffset = (softc->disk->d_stripesize -
1273130561Sobrien		    ata_logical_sector_offset(&cgd->ident_data)) %
1274130561Sobrien		    softc->disk->d_stripesize;
1275130561Sobrien	} else if (softc->quirks & ADA_Q_4K) {
1276130561Sobrien		softc->disk->d_stripesize = 4096;
1277130561Sobrien		softc->disk->d_stripeoffset = 0;
1278130561Sobrien	}
1279130561Sobrien	softc->disk->d_fwsectors = softc->params.secs_per_track;
1280218822Sdim	softc->disk->d_fwheads = softc->params.heads;
1281218822Sdim	ata_disk_firmware_geom_adjust(softc->disk);
1282218822Sdim
1283130561Sobrien	if (ada_legacy_aliases) {
1284130561Sobrien#ifdef ATA_STATIC_ID
1285130561Sobrien		legacy_id = xpt_path_legacy_ata_id(periph->path);
128660484Sobrien#else
128760484Sobrien		legacy_id = softc->disk->d_unit;
128860484Sobrien#endif
128960484Sobrien		if (legacy_id >= 0) {
129060484Sobrien			snprintf(announce_buf, sizeof(announce_buf),
1291130561Sobrien			    "kern.devalias.%s%d",
129260484Sobrien			    softc->disk->d_name, softc->disk->d_unit);
129377298Sobrien			snprintf(buf1, sizeof(buf1),
129460484Sobrien			    "ad%d", legacy_id);
129560484Sobrien			setenv(announce_buf, buf1);
1296218822Sdim		}
1297218822Sdim	} else
1298218822Sdim		legacy_id = -1;
1299218822Sdim	/*
1300218822Sdim	 * Acquire a reference to the periph before we register with GEOM.
1301218822Sdim	 * We'll release this reference once GEOM calls us back (via
1302218822Sdim	 * adadiskgonecb()) telling us that our provider has been freed.
1303218822Sdim	 */
1304218822Sdim	if (cam_periph_acquire(periph) != CAM_REQ_CMP) {
1305218822Sdim		xpt_print(periph->path, "%s: lost periph during "
1306218822Sdim			  "registration!\n", __func__);
1307218822Sdim		cam_periph_lock(periph);
1308218822Sdim		return (CAM_REQ_CMP_ERR);
1309218822Sdim	}
1310218822Sdim	disk_create(softc->disk, DISK_VERSION);
1311218822Sdim	cam_periph_lock(periph);
1312218822Sdim	cam_periph_unhold(periph);
1313218822Sdim
1314218822Sdim	dp = &softc->params;
1315218822Sdim	snprintf(announce_buf, sizeof(announce_buf),
1316218822Sdim		"%juMB (%ju %u byte sectors: %dH %dS/T %dC)",
1317218822Sdim		(uintmax_t)(((uintmax_t)dp->secsize *
1318218822Sdim		dp->sectors) / (1024*1024)),
1319218822Sdim		(uintmax_t)dp->sectors,
132033965Sjdp		dp->secsize, dp->heads,
132133965Sjdp		dp->secs_per_track, dp->cylinders);
1322130561Sobrien	xpt_announce_periph(periph, announce_buf);
1323130561Sobrien	xpt_announce_quirks(periph, softc->quirks, ADA_Q_BIT_STRING);
1324130561Sobrien	if (legacy_id >= 0)
1325130561Sobrien		printf("%s%d: Previously was known as ad%d\n",
1326130561Sobrien		       periph->periph_name, periph->unit_number, legacy_id);
132733965Sjdp
132833965Sjdp	/*
1329130561Sobrien	 * Create our sysctl variables, now that we know
133033965Sjdp	 * we have successfully attached.
1331130561Sobrien	 */
133233965Sjdp	cam_periph_acquire(periph);
133360484Sobrien	taskqueue_enqueue(taskqueue_thread, &softc->sysctl_task);
133433965Sjdp
133533965Sjdp	/*
133633965Sjdp	 * Add async callbacks for bus reset and
133733965Sjdp	 * bus device reset calls.  I don't bother
133833965Sjdp	 * checking if this fails as, in most cases,
133933965Sjdp	 * the system will function just fine without
1340	 * them and the only alternative would be to
1341	 * not attach the device on failure.
1342	 */
1343	xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE |
1344	    AC_GETDEV_CHANGED | AC_ADVINFO_CHANGED,
1345	    adaasync, periph, periph->path);
1346
1347	/*
1348	 * Schedule a periodic event to occasionally send an
1349	 * ordered tag to a device.
1350	 */
1351	callout_init_mtx(&softc->sendordered_c, periph->sim->mtx, 0);
1352	callout_reset(&softc->sendordered_c,
1353	    (ada_default_timeout * hz) / ADA_ORDEREDTAG_INTERVAL,
1354	    adasendorderedtag, softc);
1355
1356	if (ADA_RA >= 0 &&
1357	    cgd->ident_data.support.command1 & ATA_SUPPORT_LOOKAHEAD) {
1358		softc->state = ADA_STATE_RAHEAD;
1359		cam_periph_acquire(periph);
1360		xpt_schedule(periph, CAM_PRIORITY_DEV);
1361	} else if (ADA_WC >= 0 &&
1362	    cgd->ident_data.support.command1 & ATA_SUPPORT_WRITECACHE) {
1363		softc->state = ADA_STATE_WCACHE;
1364		cam_periph_acquire(periph);
1365		xpt_schedule(periph, CAM_PRIORITY_DEV);
1366	} else
1367		softc->state = ADA_STATE_NORMAL;
1368
1369	return(CAM_REQ_CMP);
1370}
1371
1372static void
1373adastart(struct cam_periph *periph, union ccb *start_ccb)
1374{
1375	struct ada_softc *softc = (struct ada_softc *)periph->softc;
1376	struct ccb_ataio *ataio = &start_ccb->ataio;
1377
1378	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("adastart\n"));
1379
1380	switch (softc->state) {
1381	case ADA_STATE_NORMAL:
1382	{
1383		struct bio *bp;
1384		u_int8_t tag_code;
1385
1386		/* Execute immediate CCB if waiting. */
1387		if (periph->immediate_priority <= periph->pinfo.priority) {
1388			CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
1389					("queuing for immediate ccb\n"));
1390			start_ccb->ccb_h.ccb_state = ADA_CCB_WAITING;
1391			SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
1392					  periph_links.sle);
1393			periph->immediate_priority = CAM_PRIORITY_NONE;
1394			wakeup(&periph->ccb_list);
1395			/* Have more work to do, so ensure we stay scheduled */
1396			adaschedule(periph);
1397			break;
1398		}
1399		/* Run TRIM if not running yet. */
1400		if (!softc->trim_running &&
1401		    (bp = bioq_first(&softc->trim_queue)) != 0) {
1402			struct trim_request *req = &softc->trim_req;
1403			struct bio *bp1;
1404			uint64_t lastlba = (uint64_t)-1;
1405			int bps = 0, c, lastcount = 0, off, ranges = 0;
1406
1407			softc->trim_running = 1;
1408			bzero(req, sizeof(*req));
1409			bp1 = bp;
1410			do {
1411				uint64_t lba = bp1->bio_pblkno;
1412				int count = bp1->bio_bcount /
1413				    softc->params.secsize;
1414
1415				bioq_remove(&softc->trim_queue, bp1);
1416
1417				/* Try to extend the previous range. */
1418				if (lba == lastlba) {
1419					c = min(count, ATA_DSM_RANGE_MAX - lastcount);
1420					lastcount += c;
1421					off = (ranges - 1) * ATA_DSM_RANGE_SIZE;
1422					req->data[off + 6] = lastcount & 0xff;
1423					req->data[off + 7] =
1424					    (lastcount >> 8) & 0xff;
1425					count -= c;
1426					lba += c;
1427				}
1428
1429				while (count > 0) {
1430					c = min(count, ATA_DSM_RANGE_MAX);
1431					off = ranges * ATA_DSM_RANGE_SIZE;
1432					req->data[off + 0] = lba & 0xff;
1433					req->data[off + 1] = (lba >> 8) & 0xff;
1434					req->data[off + 2] = (lba >> 16) & 0xff;
1435					req->data[off + 3] = (lba >> 24) & 0xff;
1436					req->data[off + 4] = (lba >> 32) & 0xff;
1437					req->data[off + 5] = (lba >> 40) & 0xff;
1438					req->data[off + 6] = c & 0xff;
1439					req->data[off + 7] = (c >> 8) & 0xff;
1440					lba += c;
1441					count -= c;
1442					lastcount = c;
1443					ranges++;
1444					/*
1445					 * Its the caller's responsibility to ensure the
1446					 * request will fit so we don't need to check for
1447					 * overrun here
1448					 */
1449				}
1450				lastlba = lba;
1451				req->bps[bps++] = bp1;
1452				bp1 = bioq_first(&softc->trim_queue);
1453				if (bps >= TRIM_MAX_BIOS ||
1454				    bp1 == NULL ||
1455				    bp1->bio_bcount / softc->params.secsize >
1456				    (softc->trim_max_ranges - ranges) *
1457				    ATA_DSM_RANGE_MAX)
1458					break;
1459			} while (1);
1460			cam_fill_ataio(ataio,
1461			    ada_retry_count,
1462			    adadone,
1463			    CAM_DIR_OUT,
1464			    0,
1465			    req->data,
1466			    ((ranges + ATA_DSM_BLK_RANGES - 1) /
1467			        ATA_DSM_BLK_RANGES) * ATA_DSM_BLK_SIZE,
1468			    ada_default_timeout * 1000);
1469			ata_48bit_cmd(ataio, ATA_DATA_SET_MANAGEMENT,
1470			    ATA_DSM_TRIM, 0, (ranges + ATA_DSM_BLK_RANGES -
1471			    1) / ATA_DSM_BLK_RANGES);
1472			start_ccb->ccb_h.ccb_state = ADA_CCB_TRIM;
1473			goto out;
1474		}
1475		/* Run regular command. */
1476		bp = bioq_first(&softc->bio_queue);
1477		if (bp == NULL) {
1478			xpt_release_ccb(start_ccb);
1479			break;
1480		}
1481		bioq_remove(&softc->bio_queue, bp);
1482
1483		if ((bp->bio_flags & BIO_ORDERED) != 0
1484		 || (softc->flags & ADA_FLAG_NEED_OTAG) != 0) {
1485			softc->flags &= ~ADA_FLAG_NEED_OTAG;
1486			softc->ordered_tag_count++;
1487			tag_code = 0;
1488		} else {
1489			tag_code = 1;
1490		}
1491		switch (bp->bio_cmd) {
1492		case BIO_WRITE:
1493			softc->flags |= ADA_FLAG_DIRTY;
1494			/* FALLTHROUGH */
1495		case BIO_READ:
1496		{
1497			uint64_t lba = bp->bio_pblkno;
1498			uint16_t count = bp->bio_bcount / softc->params.secsize;
1499#ifdef ADA_TEST_FAILURE
1500			int fail = 0;
1501
1502			/*
1503			 * Support the failure ioctls.  If the command is a
1504			 * read, and there are pending forced read errors, or
1505			 * if a write and pending write errors, then fail this
1506			 * operation with EIO.  This is useful for testing
1507			 * purposes.  Also, support having every Nth read fail.
1508			 *
1509			 * This is a rather blunt tool.
1510			 */
1511			if (bp->bio_cmd == BIO_READ) {
1512				if (softc->force_read_error) {
1513					softc->force_read_error--;
1514					fail = 1;
1515				}
1516				if (softc->periodic_read_error > 0) {
1517					if (++softc->periodic_read_count >=
1518					    softc->periodic_read_error) {
1519						softc->periodic_read_count = 0;
1520						fail = 1;
1521					}
1522				}
1523			} else {
1524				if (softc->force_write_error) {
1525					softc->force_write_error--;
1526					fail = 1;
1527				}
1528			}
1529			if (fail) {
1530				bp->bio_error = EIO;
1531				bp->bio_flags |= BIO_ERROR;
1532				biodone(bp);
1533				xpt_release_ccb(start_ccb);
1534				adaschedule(periph);
1535				return;
1536			}
1537#endif
1538			KASSERT((bp->bio_flags & BIO_UNMAPPED) == 0 ||
1539			    round_page(bp->bio_bcount + bp->bio_ma_offset) /
1540			    PAGE_SIZE == bp->bio_ma_n,
1541			    ("Short bio %p", bp));
1542			cam_fill_ataio(ataio,
1543			    ada_retry_count,
1544			    adadone,
1545			    (bp->bio_cmd == BIO_READ ? CAM_DIR_IN :
1546				CAM_DIR_OUT) | ((bp->bio_flags & BIO_UNMAPPED)
1547				!= 0 ? CAM_DATA_BIO : 0),
1548			    tag_code,
1549			    ((bp->bio_flags & BIO_UNMAPPED) != 0) ? (void *)bp :
1550				bp->bio_data,
1551			    bp->bio_bcount,
1552			    ada_default_timeout*1000);
1553
1554			if ((softc->flags & ADA_FLAG_CAN_NCQ) && tag_code) {
1555				if (bp->bio_cmd == BIO_READ) {
1556					ata_ncq_cmd(ataio, ATA_READ_FPDMA_QUEUED,
1557					    lba, count);
1558				} else {
1559					ata_ncq_cmd(ataio, ATA_WRITE_FPDMA_QUEUED,
1560					    lba, count);
1561				}
1562			} else if ((softc->flags & ADA_FLAG_CAN_48BIT) &&
1563			    (lba + count >= ATA_MAX_28BIT_LBA ||
1564			    count > 256)) {
1565				if (softc->flags & ADA_FLAG_CAN_DMA48) {
1566					if (bp->bio_cmd == BIO_READ) {
1567						ata_48bit_cmd(ataio, ATA_READ_DMA48,
1568						    0, lba, count);
1569					} else {
1570						ata_48bit_cmd(ataio, ATA_WRITE_DMA48,
1571						    0, lba, count);
1572					}
1573				} else {
1574					if (bp->bio_cmd == BIO_READ) {
1575						ata_48bit_cmd(ataio, ATA_READ_MUL48,
1576						    0, lba, count);
1577					} else {
1578						ata_48bit_cmd(ataio, ATA_WRITE_MUL48,
1579						    0, lba, count);
1580					}
1581				}
1582			} else {
1583				if (count == 256)
1584					count = 0;
1585				if (softc->flags & ADA_FLAG_CAN_DMA) {
1586					if (bp->bio_cmd == BIO_READ) {
1587						ata_28bit_cmd(ataio, ATA_READ_DMA,
1588						    0, lba, count);
1589					} else {
1590						ata_28bit_cmd(ataio, ATA_WRITE_DMA,
1591						    0, lba, count);
1592					}
1593				} else {
1594					if (bp->bio_cmd == BIO_READ) {
1595						ata_28bit_cmd(ataio, ATA_READ_MUL,
1596						    0, lba, count);
1597					} else {
1598						ata_28bit_cmd(ataio, ATA_WRITE_MUL,
1599						    0, lba, count);
1600					}
1601				}
1602			}
1603			break;
1604		}
1605		case BIO_DELETE:
1606		{
1607			uint64_t lba = bp->bio_pblkno;
1608			uint16_t count = bp->bio_bcount / softc->params.secsize;
1609
1610			cam_fill_ataio(ataio,
1611			    ada_retry_count,
1612			    adadone,
1613			    CAM_DIR_NONE,
1614			    0,
1615			    NULL,
1616			    0,
1617			    ada_default_timeout*1000);
1618
1619			if (count >= 256)
1620				count = 0;
1621			ata_28bit_cmd(ataio, ATA_CFA_ERASE, 0, lba, count);
1622			break;
1623		}
1624		case BIO_FLUSH:
1625			cam_fill_ataio(ataio,
1626			    1,
1627			    adadone,
1628			    CAM_DIR_NONE,
1629			    0,
1630			    NULL,
1631			    0,
1632			    ada_default_timeout*1000);
1633
1634			if (softc->flags & ADA_FLAG_CAN_48BIT)
1635				ata_48bit_cmd(ataio, ATA_FLUSHCACHE48, 0, 0, 0);
1636			else
1637				ata_28bit_cmd(ataio, ATA_FLUSHCACHE, 0, 0, 0);
1638			break;
1639		}
1640		start_ccb->ccb_h.ccb_state = ADA_CCB_BUFFER_IO;
1641out:
1642		start_ccb->ccb_h.ccb_bp = bp;
1643		softc->outstanding_cmds++;
1644		xpt_action(start_ccb);
1645
1646		/* May have more work to do, so ensure we stay scheduled */
1647		adaschedule(periph);
1648		break;
1649	}
1650	case ADA_STATE_RAHEAD:
1651	case ADA_STATE_WCACHE:
1652	{
1653		if ((periph->flags & CAM_PERIPH_INVALID) != 0) {
1654			softc->state = ADA_STATE_NORMAL;
1655			xpt_release_ccb(start_ccb);
1656			adaschedule(periph);
1657			cam_periph_release_locked(periph);
1658			return;
1659		}
1660
1661		cam_fill_ataio(ataio,
1662		    1,
1663		    adadone,
1664		    CAM_DIR_NONE,
1665		    0,
1666		    NULL,
1667		    0,
1668		    ada_default_timeout*1000);
1669
1670		if (softc->state == ADA_STATE_RAHEAD) {
1671			ata_28bit_cmd(ataio, ATA_SETFEATURES, ADA_RA ?
1672			    ATA_SF_ENAB_RCACHE : ATA_SF_DIS_RCACHE, 0, 0);
1673			start_ccb->ccb_h.ccb_state = ADA_CCB_RAHEAD;
1674		} else {
1675			ata_28bit_cmd(ataio, ATA_SETFEATURES, ADA_WC ?
1676			    ATA_SF_ENAB_WCACHE : ATA_SF_DIS_WCACHE, 0, 0);
1677			start_ccb->ccb_h.ccb_state = ADA_CCB_WCACHE;
1678		}
1679		start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE;
1680		xpt_action(start_ccb);
1681		break;
1682	}
1683	}
1684}
1685
1686static void
1687adadone(struct cam_periph *periph, union ccb *done_ccb)
1688{
1689	struct ada_softc *softc;
1690	struct ccb_ataio *ataio;
1691	struct ccb_getdev *cgd;
1692	struct cam_path *path;
1693	int state;
1694
1695	softc = (struct ada_softc *)periph->softc;
1696	ataio = &done_ccb->ataio;
1697	path = done_ccb->ccb_h.path;
1698
1699	CAM_DEBUG(path, CAM_DEBUG_TRACE, ("adadone\n"));
1700
1701	state = ataio->ccb_h.ccb_state & ADA_CCB_TYPE_MASK;
1702	switch (state) {
1703	case ADA_CCB_BUFFER_IO:
1704	case ADA_CCB_TRIM:
1705	{
1706		struct bio *bp;
1707		int error;
1708
1709		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
1710			error = adaerror(done_ccb, 0, 0);
1711			if (error == ERESTART) {
1712				/* A retry was scheduled, so just return. */
1713				return;
1714			}
1715			if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
1716				cam_release_devq(path,
1717						 /*relsim_flags*/0,
1718						 /*reduction*/0,
1719						 /*timeout*/0,
1720						 /*getcount_only*/0);
1721		} else {
1722			if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
1723				panic("REQ_CMP with QFRZN");
1724			error = 0;
1725		}
1726		bp = (struct bio *)done_ccb->ccb_h.ccb_bp;
1727		bp->bio_error = error;
1728		if (error != 0) {
1729			bp->bio_resid = bp->bio_bcount;
1730			bp->bio_flags |= BIO_ERROR;
1731		} else {
1732			if (state == ADA_CCB_TRIM)
1733				bp->bio_resid = 0;
1734			else
1735				bp->bio_resid = ataio->resid;
1736			if (bp->bio_resid > 0)
1737				bp->bio_flags |= BIO_ERROR;
1738		}
1739		softc->outstanding_cmds--;
1740		if (softc->outstanding_cmds == 0)
1741			softc->flags |= ADA_FLAG_WENT_IDLE;
1742		if (state == ADA_CCB_TRIM) {
1743			struct trim_request *req =
1744			    (struct trim_request *)ataio->data_ptr;
1745			int i;
1746
1747			for (i = 1; i < TRIM_MAX_BIOS && req->bps[i]; i++) {
1748				struct bio *bp1 = req->bps[i];
1749
1750				bp1->bio_error = bp->bio_error;
1751				if (bp->bio_flags & BIO_ERROR) {
1752					bp1->bio_flags |= BIO_ERROR;
1753					bp1->bio_resid = bp1->bio_bcount;
1754				} else
1755					bp1->bio_resid = 0;
1756				biodone(bp1);
1757			}
1758			softc->trim_running = 0;
1759			biodone(bp);
1760			adaschedule(periph);
1761		} else
1762			biodone(bp);
1763		break;
1764	}
1765	case ADA_CCB_RAHEAD:
1766	{
1767		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
1768			if (adaerror(done_ccb, 0, 0) == ERESTART) {
1769out:
1770				/* Drop freeze taken due to CAM_DEV_QFREEZE */
1771				cam_release_devq(path, 0, 0, 0, FALSE);
1772				return;
1773			} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
1774				cam_release_devq(path,
1775				    /*relsim_flags*/0,
1776				    /*reduction*/0,
1777				    /*timeout*/0,
1778				    /*getcount_only*/0);
1779			}
1780		}
1781
1782		/*
1783		 * Since our peripheral may be invalidated by an error
1784		 * above or an external event, we must release our CCB
1785		 * before releasing the reference on the peripheral.
1786		 * The peripheral will only go away once the last reference
1787		 * is removed, and we need it around for the CCB release
1788		 * operation.
1789		 */
1790		cgd = (struct ccb_getdev *)done_ccb;
1791		xpt_setup_ccb(&cgd->ccb_h, path, CAM_PRIORITY_NORMAL);
1792		cgd->ccb_h.func_code = XPT_GDEV_TYPE;
1793		xpt_action((union ccb *)cgd);
1794		if (ADA_WC >= 0 &&
1795		    cgd->ident_data.support.command1 & ATA_SUPPORT_WRITECACHE) {
1796			softc->state = ADA_STATE_WCACHE;
1797			xpt_release_ccb(done_ccb);
1798			xpt_schedule(periph, CAM_PRIORITY_DEV);
1799			goto out;
1800		}
1801		softc->state = ADA_STATE_NORMAL;
1802		xpt_release_ccb(done_ccb);
1803		/* Drop freeze taken due to CAM_DEV_QFREEZE */
1804		cam_release_devq(path, 0, 0, 0, FALSE);
1805		adaschedule(periph);
1806		cam_periph_release_locked(periph);
1807		return;
1808	}
1809	case ADA_CCB_WCACHE:
1810	{
1811		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
1812			if (adaerror(done_ccb, 0, 0) == ERESTART) {
1813				goto out;
1814			} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
1815				cam_release_devq(path,
1816				    /*relsim_flags*/0,
1817				    /*reduction*/0,
1818				    /*timeout*/0,
1819				    /*getcount_only*/0);
1820			}
1821		}
1822
1823		softc->state = ADA_STATE_NORMAL;
1824		/*
1825		 * Since our peripheral may be invalidated by an error
1826		 * above or an external event, we must release our CCB
1827		 * before releasing the reference on the peripheral.
1828		 * The peripheral will only go away once the last reference
1829		 * is removed, and we need it around for the CCB release
1830		 * operation.
1831		 */
1832		xpt_release_ccb(done_ccb);
1833		/* Drop freeze taken due to CAM_DEV_QFREEZE */
1834		cam_release_devq(path, 0, 0, 0, FALSE);
1835		adaschedule(periph);
1836		cam_periph_release_locked(periph);
1837		return;
1838	}
1839	case ADA_CCB_WAITING:
1840	{
1841		/* Caller will release the CCB */
1842		wakeup(&done_ccb->ccb_h.cbfcnp);
1843		return;
1844	}
1845	case ADA_CCB_DUMP:
1846		/* No-op.  We're polling */
1847		return;
1848	default:
1849		break;
1850	}
1851	xpt_release_ccb(done_ccb);
1852}
1853
1854static int
1855adaerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
1856{
1857
1858	return(cam_periph_error(ccb, cam_flags, sense_flags, NULL));
1859}
1860
1861static void
1862adagetparams(struct cam_periph *periph, struct ccb_getdev *cgd)
1863{
1864	struct ada_softc *softc = (struct ada_softc *)periph->softc;
1865	struct disk_params *dp = &softc->params;
1866	u_int64_t lbasize48;
1867	u_int32_t lbasize;
1868
1869	dp->secsize = ata_logical_sector_size(&cgd->ident_data);
1870	if ((cgd->ident_data.atavalid & ATA_FLAG_54_58) &&
1871		cgd->ident_data.current_heads && cgd->ident_data.current_sectors) {
1872		dp->heads = cgd->ident_data.current_heads;
1873		dp->secs_per_track = cgd->ident_data.current_sectors;
1874		dp->cylinders = cgd->ident_data.cylinders;
1875		dp->sectors = (u_int32_t)cgd->ident_data.current_size_1 |
1876			  ((u_int32_t)cgd->ident_data.current_size_2 << 16);
1877	} else {
1878		dp->heads = cgd->ident_data.heads;
1879		dp->secs_per_track = cgd->ident_data.sectors;
1880		dp->cylinders = cgd->ident_data.cylinders;
1881		dp->sectors = cgd->ident_data.cylinders * dp->heads * dp->secs_per_track;
1882	}
1883	lbasize = (u_int32_t)cgd->ident_data.lba_size_1 |
1884		  ((u_int32_t)cgd->ident_data.lba_size_2 << 16);
1885
1886	/* use the 28bit LBA size if valid or bigger than the CHS mapping */
1887	if (cgd->ident_data.cylinders == 16383 || dp->sectors < lbasize)
1888		dp->sectors = lbasize;
1889
1890	/* use the 48bit LBA size if valid */
1891	lbasize48 = ((u_int64_t)cgd->ident_data.lba_size48_1) |
1892		    ((u_int64_t)cgd->ident_data.lba_size48_2 << 16) |
1893		    ((u_int64_t)cgd->ident_data.lba_size48_3 << 32) |
1894		    ((u_int64_t)cgd->ident_data.lba_size48_4 << 48);
1895	if ((cgd->ident_data.support.command2 & ATA_SUPPORT_ADDRESS48) &&
1896	    lbasize48 > ATA_MAX_28BIT_LBA)
1897		dp->sectors = lbasize48;
1898}
1899
1900static void
1901adasendorderedtag(void *arg)
1902{
1903	struct ada_softc *softc = arg;
1904
1905	if (ada_send_ordered) {
1906		if ((softc->ordered_tag_count == 0)
1907		 && ((softc->flags & ADA_FLAG_WENT_IDLE) == 0)) {
1908			softc->flags |= ADA_FLAG_NEED_OTAG;
1909		}
1910		if (softc->outstanding_cmds > 0)
1911			softc->flags &= ~ADA_FLAG_WENT_IDLE;
1912
1913		softc->ordered_tag_count = 0;
1914	}
1915	/* Queue us up again */
1916	callout_reset(&softc->sendordered_c,
1917	    (ada_default_timeout * hz) / ADA_ORDEREDTAG_INTERVAL,
1918	    adasendorderedtag, softc);
1919}
1920
1921/*
1922 * Step through all ADA peripheral drivers, and if the device is still open,
1923 * sync the disk cache to physical media.
1924 */
1925static void
1926adaflush(void)
1927{
1928	struct cam_periph *periph;
1929	struct ada_softc *softc;
1930	union ccb *ccb;
1931	int error;
1932
1933	CAM_PERIPH_FOREACH(periph, &adadriver) {
1934		softc = (struct ada_softc *)periph->softc;
1935		if (SCHEDULER_STOPPED()) {
1936			/* If we paniced with the lock held, do not recurse. */
1937			if (!cam_periph_owned(periph) &&
1938			    (softc->flags & ADA_FLAG_OPEN)) {
1939				adadump(softc->disk, NULL, 0, 0, 0);
1940			}
1941			continue;
1942		}
1943		cam_periph_lock(periph);
1944		/*
1945		 * We only sync the cache if the drive is still open, and
1946		 * if the drive is capable of it..
1947		 */
1948		if (((softc->flags & ADA_FLAG_OPEN) == 0) ||
1949		    (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) == 0) {
1950			cam_periph_unlock(periph);
1951			continue;
1952		}
1953
1954		ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL);
1955		cam_fill_ataio(&ccb->ataio,
1956				    0,
1957				    adadone,
1958				    CAM_DIR_NONE,
1959				    0,
1960				    NULL,
1961				    0,
1962				    ada_default_timeout*1000);
1963		if (softc->flags & ADA_FLAG_CAN_48BIT)
1964			ata_48bit_cmd(&ccb->ataio, ATA_FLUSHCACHE48, 0, 0, 0);
1965		else
1966			ata_28bit_cmd(&ccb->ataio, ATA_FLUSHCACHE, 0, 0, 0);
1967
1968		error = cam_periph_runccb(ccb, adaerror, /*cam_flags*/0,
1969		    /*sense_flags*/ SF_NO_RECOVERY | SF_NO_RETRY,
1970		    softc->disk->d_devstat);
1971		if (error != 0)
1972			xpt_print(periph->path, "Synchronize cache failed\n");
1973		xpt_release_ccb(ccb);
1974		cam_periph_unlock(periph);
1975	}
1976}
1977
1978static void
1979adaspindown(uint8_t cmd, int flags)
1980{
1981	struct cam_periph *periph;
1982	struct ada_softc *softc;
1983	union ccb *ccb;
1984	int error;
1985
1986	CAM_PERIPH_FOREACH(periph, &adadriver) {
1987		/* If we paniced with lock held - not recurse here. */
1988		if (cam_periph_owned(periph))
1989			continue;
1990		cam_periph_lock(periph);
1991		softc = (struct ada_softc *)periph->softc;
1992		/*
1993		 * We only spin-down the drive if it is capable of it..
1994		 */
1995		if ((softc->flags & ADA_FLAG_CAN_POWERMGT) == 0) {
1996			cam_periph_unlock(periph);
1997			continue;
1998		}
1999
2000		if (bootverbose)
2001			xpt_print(periph->path, "spin-down\n");
2002
2003		ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL);
2004		cam_fill_ataio(&ccb->ataio,
2005				    0,
2006				    adadone,
2007				    CAM_DIR_NONE | flags,
2008				    0,
2009				    NULL,
2010				    0,
2011				    ada_default_timeout*1000);
2012		ata_28bit_cmd(&ccb->ataio, cmd, 0, 0, 0);
2013
2014		error = cam_periph_runccb(ccb, adaerror, /*cam_flags*/0,
2015		    /*sense_flags*/ SF_NO_RECOVERY | SF_NO_RETRY,
2016		    softc->disk->d_devstat);
2017		if (error != 0)
2018			xpt_print(periph->path, "Spin-down disk failed\n");
2019		xpt_release_ccb(ccb);
2020		cam_periph_unlock(periph);
2021	}
2022}
2023
2024static void
2025adashutdown(void *arg, int howto)
2026{
2027
2028	adaflush();
2029	if (ada_spindown_shutdown != 0 &&
2030	    (howto & (RB_HALT | RB_POWEROFF)) != 0)
2031		adaspindown(ATA_STANDBY_IMMEDIATE, 0);
2032}
2033
2034static void
2035adasuspend(void *arg)
2036{
2037
2038	adaflush();
2039	if (ada_spindown_suspend != 0)
2040		adaspindown(ATA_SLEEP, CAM_DEV_QFREEZE);
2041}
2042
2043static void
2044adaresume(void *arg)
2045{
2046	struct cam_periph *periph;
2047	struct ada_softc *softc;
2048
2049	if (ada_spindown_suspend == 0)
2050		return;
2051
2052	CAM_PERIPH_FOREACH(periph, &adadriver) {
2053		cam_periph_lock(periph);
2054		softc = (struct ada_softc *)periph->softc;
2055		/*
2056		 * We only spin-down the drive if it is capable of it..
2057		 */
2058		if ((softc->flags & ADA_FLAG_CAN_POWERMGT) == 0) {
2059			cam_periph_unlock(periph);
2060			continue;
2061		}
2062
2063		if (bootverbose)
2064			xpt_print(periph->path, "resume\n");
2065
2066		/*
2067		 * Drop freeze taken due to CAM_DEV_QFREEZE flag set on
2068		 * sleep request.
2069		 */
2070		cam_release_devq(periph->path,
2071			 /*relsim_flags*/0,
2072			 /*openings*/0,
2073			 /*timeout*/0,
2074			 /*getcount_only*/0);
2075
2076		cam_periph_unlock(periph);
2077	}
2078}
2079
2080#endif /* _KERNEL */
2081