152c9ce25SScott Long /*- 252c9ce25SScott Long * Copyright (c) 2009 Alexander Motin <mav@FreeBSD.org> 352c9ce25SScott Long * All rights reserved. 452c9ce25SScott Long * 552c9ce25SScott Long * Redistribution and use in source and binary forms, with or without 652c9ce25SScott Long * modification, are permitted provided that the following conditions 752c9ce25SScott Long * are met: 852c9ce25SScott Long * 1. Redistributions of source code must retain the above copyright 952c9ce25SScott Long * notice, this list of conditions and the following disclaimer, 1052c9ce25SScott Long * without modification, immediately at the beginning of the file. 1152c9ce25SScott Long * 2. Redistributions in binary form must reproduce the above copyright 1252c9ce25SScott Long * notice, this list of conditions and the following disclaimer in the 1352c9ce25SScott Long * documentation and/or other materials provided with the distribution. 1452c9ce25SScott Long * 1552c9ce25SScott Long * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1652c9ce25SScott Long * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1752c9ce25SScott Long * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1852c9ce25SScott Long * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1952c9ce25SScott Long * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2052c9ce25SScott Long * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2152c9ce25SScott Long * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2252c9ce25SScott Long * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2352c9ce25SScott Long * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2452c9ce25SScott Long * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2552c9ce25SScott Long */ 2652c9ce25SScott Long 2752c9ce25SScott Long #include <sys/cdefs.h> 2852c9ce25SScott Long __FBSDID("$FreeBSD$"); 2952c9ce25SScott Long 30e3a6d3a4SAlexander Motin #include "opt_ada.h" 31e3a6d3a4SAlexander Motin 3252c9ce25SScott Long #include <sys/param.h> 3352c9ce25SScott Long 3452c9ce25SScott Long #ifdef _KERNEL 3552c9ce25SScott Long #include <sys/systm.h> 3652c9ce25SScott Long #include <sys/kernel.h> 3752c9ce25SScott Long #include <sys/bio.h> 3852c9ce25SScott Long #include <sys/sysctl.h> 3952c9ce25SScott Long #include <sys/taskqueue.h> 4052c9ce25SScott Long #include <sys/lock.h> 4152c9ce25SScott Long #include <sys/mutex.h> 4252c9ce25SScott Long #include <sys/conf.h> 4352c9ce25SScott Long #include <sys/devicestat.h> 4452c9ce25SScott Long #include <sys/eventhandler.h> 4552c9ce25SScott Long #include <sys/malloc.h> 4652c9ce25SScott Long #include <sys/cons.h> 47fd104c15SRebecca Cran #include <sys/reboot.h> 4852c9ce25SScott Long #include <geom/geom_disk.h> 4952c9ce25SScott Long #endif /* _KERNEL */ 5052c9ce25SScott Long 5152c9ce25SScott Long #ifndef _KERNEL 5252c9ce25SScott Long #include <stdio.h> 5352c9ce25SScott Long #include <string.h> 5452c9ce25SScott Long #endif /* _KERNEL */ 5552c9ce25SScott Long 5652c9ce25SScott Long #include <cam/cam.h> 5752c9ce25SScott Long #include <cam/cam_ccb.h> 5852c9ce25SScott Long #include <cam/cam_periph.h> 5952c9ce25SScott Long #include <cam/cam_xpt_periph.h> 6052c9ce25SScott Long #include <cam/cam_sim.h> 6152c9ce25SScott Long 6252c9ce25SScott Long #include <cam/ata/ata_all.h> 6352c9ce25SScott Long 644461491bSMarius Strobl #include <machine/md_var.h> /* geometry translation */ 654461491bSMarius Strobl 6652c9ce25SScott Long #ifdef _KERNEL 6752c9ce25SScott Long 6852c9ce25SScott Long #define ATA_MAX_28BIT_LBA 268435455UL 6952c9ce25SScott Long 7052c9ce25SScott Long typedef enum { 711ed6aaf9SAlexander Motin ADA_STATE_RAHEAD, 72f513d14cSAlexander Motin ADA_STATE_WCACHE, 731e637ba6SAlexander Motin ADA_STATE_NORMAL 7452c9ce25SScott Long } ada_state; 7552c9ce25SScott Long 7652c9ce25SScott Long typedef enum { 772e1eb332SMarius Strobl ADA_FLAG_CAN_48BIT = 0x0002, 782e1eb332SMarius Strobl ADA_FLAG_CAN_FLUSHCACHE = 0x0004, 792e1eb332SMarius Strobl ADA_FLAG_CAN_NCQ = 0x0008, 802e1eb332SMarius Strobl ADA_FLAG_CAN_DMA = 0x0010, 812e1eb332SMarius Strobl ADA_FLAG_NEED_OTAG = 0x0020, 822e1eb332SMarius Strobl ADA_FLAG_WENT_IDLE = 0x0040, 832e1eb332SMarius Strobl ADA_FLAG_CAN_TRIM = 0x0080, 842e1eb332SMarius Strobl ADA_FLAG_OPEN = 0x0100, 852e1eb332SMarius Strobl ADA_FLAG_SCTX_INIT = 0x0200, 862e1eb332SMarius Strobl ADA_FLAG_CAN_CFA = 0x0400, 872e1eb332SMarius Strobl ADA_FLAG_CAN_POWERMGT = 0x0800, 882e1eb332SMarius Strobl ADA_FLAG_CAN_DMA48 = 0x1000 8952c9ce25SScott Long } ada_flags; 9052c9ce25SScott Long 9152c9ce25SScott Long typedef enum { 92d3a460d3SAlexander Motin ADA_Q_NONE = 0x00, 93d3a460d3SAlexander Motin ADA_Q_4K = 0x01, 9452c9ce25SScott Long } ada_quirks; 9552c9ce25SScott Long 96*6fb5c84eSSteven Hartland #define ADA_Q_BIT_STRING \ 97*6fb5c84eSSteven Hartland "\020" \ 98*6fb5c84eSSteven Hartland "\0014K" 99*6fb5c84eSSteven Hartland 10052c9ce25SScott Long typedef enum { 1011ed6aaf9SAlexander Motin ADA_CCB_RAHEAD = 0x01, 1021ed6aaf9SAlexander Motin ADA_CCB_WCACHE = 0x02, 10352c9ce25SScott Long ADA_CCB_BUFFER_IO = 0x03, 10452c9ce25SScott Long ADA_CCB_WAITING = 0x04, 10552c9ce25SScott Long ADA_CCB_DUMP = 0x05, 1061c80ec0aSAlexander Motin ADA_CCB_TRIM = 0x06, 10752c9ce25SScott Long ADA_CCB_TYPE_MASK = 0x0F, 10852c9ce25SScott Long } ada_ccb_state; 10952c9ce25SScott Long 11052c9ce25SScott Long /* Offsets into our private area for storing information */ 11152c9ce25SScott Long #define ccb_state ppriv_field0 11252c9ce25SScott Long #define ccb_bp ppriv_ptr1 11352c9ce25SScott Long 11452c9ce25SScott Long struct disk_params { 11552c9ce25SScott Long u_int8_t heads; 11652c9ce25SScott Long u_int8_t secs_per_track; 117c1bd46c2SAlexander Motin u_int32_t cylinders; 118c1bd46c2SAlexander Motin u_int32_t secsize; /* Number of bytes/logical sector */ 119c1bd46c2SAlexander Motin u_int64_t sectors; /* Total number sectors */ 12052c9ce25SScott Long }; 12152c9ce25SScott Long 1221524677aSAlexander Motin #define TRIM_MAX_BLOCKS 8 123c213c551SSteven Hartland #define TRIM_MAX_RANGES (TRIM_MAX_BLOCKS * ATA_DSM_BLK_RANGES) 1241524677aSAlexander Motin #define TRIM_MAX_BIOS (TRIM_MAX_RANGES * 4) 1251c80ec0aSAlexander Motin struct trim_request { 126c213c551SSteven Hartland uint8_t data[TRIM_MAX_RANGES * ATA_DSM_RANGE_SIZE]; 12737ddbd16SAlexander Motin struct bio *bps[TRIM_MAX_BIOS]; 1281c80ec0aSAlexander Motin }; 1291c80ec0aSAlexander Motin 13052c9ce25SScott Long struct ada_softc { 13152c9ce25SScott Long struct bio_queue_head bio_queue; 1321c80ec0aSAlexander Motin struct bio_queue_head trim_queue; 13352c9ce25SScott Long ada_state state; 13452c9ce25SScott Long ada_flags flags; 13552c9ce25SScott Long ada_quirks quirks; 1365f83aee5SSteven Hartland int sort_io_queue; 13752c9ce25SScott Long int ordered_tag_count; 13852c9ce25SScott Long int outstanding_cmds; 1391c80ec0aSAlexander Motin int trim_max_ranges; 1401c80ec0aSAlexander Motin int trim_running; 1411ed6aaf9SAlexander Motin int read_ahead; 142e3a6d3a4SAlexander Motin int write_cache; 143e3a6d3a4SAlexander Motin #ifdef ADA_TEST_FAILURE 144e3a6d3a4SAlexander Motin int force_read_error; 145e3a6d3a4SAlexander Motin int force_write_error; 146e3a6d3a4SAlexander Motin int periodic_read_error; 147e3a6d3a4SAlexander Motin int periodic_read_count; 148e3a6d3a4SAlexander Motin #endif 14952c9ce25SScott Long struct disk_params params; 15052c9ce25SScott Long struct disk *disk; 15152c9ce25SScott Long struct task sysctl_task; 15252c9ce25SScott Long struct sysctl_ctx_list sysctl_ctx; 15352c9ce25SScott Long struct sysctl_oid *sysctl_tree; 15452c9ce25SScott Long struct callout sendordered_c; 1551c80ec0aSAlexander Motin struct trim_request trim_req; 15652c9ce25SScott Long }; 15752c9ce25SScott Long 15852c9ce25SScott Long struct ada_quirk_entry { 15952c9ce25SScott Long struct scsi_inquiry_pattern inq_pat; 16052c9ce25SScott Long ada_quirks quirks; 16152c9ce25SScott Long }; 16252c9ce25SScott Long 16330a4094fSAlexander Motin static struct ada_quirk_entry ada_quirk_table[] = 16430a4094fSAlexander Motin { 16530a4094fSAlexander Motin { 166d3a460d3SAlexander Motin /* Hitachi Advanced Format (4k) drives */ 167d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "Hitachi H??????????E3*", "*" }, 168d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 169d3a460d3SAlexander Motin }, 170d3a460d3SAlexander Motin { 171d3a460d3SAlexander Motin /* Samsung Advanced Format (4k) drives */ 172643d1826SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "SAMSUNG HD155UI*", "*" }, 173643d1826SAlexander Motin /*quirks*/ADA_Q_4K 174643d1826SAlexander Motin }, 175643d1826SAlexander Motin { 176643d1826SAlexander Motin /* Samsung Advanced Format (4k) drives */ 177d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "SAMSUNG HD204UI*", "*" }, 178d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 179d3a460d3SAlexander Motin }, 180d3a460d3SAlexander Motin { 181d3a460d3SAlexander Motin /* Seagate Barracuda Green Advanced Format (4k) drives */ 182d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST????DL*", "*" }, 183d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 184d3a460d3SAlexander Motin }, 185d3a460d3SAlexander Motin { 186643d1826SAlexander Motin /* Seagate Barracuda Advanced Format (4k) drives */ 187643d1826SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST???DM*", "*" }, 188643d1826SAlexander Motin /*quirks*/ADA_Q_4K 189643d1826SAlexander Motin }, 190643d1826SAlexander Motin { 191643d1826SAlexander Motin /* Seagate Barracuda Advanced Format (4k) drives */ 192643d1826SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST????DM*", "*" }, 193643d1826SAlexander Motin /*quirks*/ADA_Q_4K 194643d1826SAlexander Motin }, 195643d1826SAlexander Motin { 196d3a460d3SAlexander Motin /* Seagate Momentus Advanced Format (4k) drives */ 197d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9500423AS*", "*" }, 198d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 199d3a460d3SAlexander Motin }, 200d3a460d3SAlexander Motin { 201d3a460d3SAlexander Motin /* Seagate Momentus Advanced Format (4k) drives */ 202d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9500424AS*", "*" }, 203d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 204d3a460d3SAlexander Motin }, 205d3a460d3SAlexander Motin { 206d3a460d3SAlexander Motin /* Seagate Momentus Advanced Format (4k) drives */ 207643d1826SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9640423AS*", "*" }, 208643d1826SAlexander Motin /*quirks*/ADA_Q_4K 209643d1826SAlexander Motin }, 210643d1826SAlexander Motin { 211643d1826SAlexander Motin /* Seagate Momentus Advanced Format (4k) drives */ 212643d1826SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9640424AS*", "*" }, 213643d1826SAlexander Motin /*quirks*/ADA_Q_4K 214643d1826SAlexander Motin }, 215643d1826SAlexander Motin { 216643d1826SAlexander Motin /* Seagate Momentus Advanced Format (4k) drives */ 217d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9750420AS*", "*" }, 218d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 219d3a460d3SAlexander Motin }, 220d3a460d3SAlexander Motin { 221d3a460d3SAlexander Motin /* Seagate Momentus Advanced Format (4k) drives */ 222d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9750422AS*", "*" }, 223d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 224d3a460d3SAlexander Motin }, 225d3a460d3SAlexander Motin { 226643d1826SAlexander Motin /* Seagate Momentus Advanced Format (4k) drives */ 227643d1826SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9750423AS*", "*" }, 228643d1826SAlexander Motin /*quirks*/ADA_Q_4K 229643d1826SAlexander Motin }, 230643d1826SAlexander Motin { 231d3a460d3SAlexander Motin /* Seagate Momentus Thin Advanced Format (4k) drives */ 232d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST???LT*", "*" }, 233d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 234d3a460d3SAlexander Motin }, 235d3a460d3SAlexander Motin { 236d3a460d3SAlexander Motin /* WDC Caviar Green Advanced Format (4k) drives */ 237d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD????RS*", "*" }, 238d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 239d3a460d3SAlexander Motin }, 240d3a460d3SAlexander Motin { 241d3a460d3SAlexander Motin /* WDC Caviar Green Advanced Format (4k) drives */ 242d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD????RX*", "*" }, 243d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 244d3a460d3SAlexander Motin }, 245d3a460d3SAlexander Motin { 246d3a460d3SAlexander Motin /* WDC Caviar Green Advanced Format (4k) drives */ 247d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD??????RS*", "*" }, 248d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 249d3a460d3SAlexander Motin }, 250d3a460d3SAlexander Motin { 251d3a460d3SAlexander Motin /* WDC Caviar Green Advanced Format (4k) drives */ 252d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD??????RX*", "*" }, 253d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 254d3a460d3SAlexander Motin }, 255d3a460d3SAlexander Motin { 256d3a460d3SAlexander Motin /* WDC Scorpio Black Advanced Format (4k) drives */ 257d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD???PKT*", "*" }, 258d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 259d3a460d3SAlexander Motin }, 260d3a460d3SAlexander Motin { 261d3a460d3SAlexander Motin /* WDC Scorpio Black Advanced Format (4k) drives */ 262d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD?????PKT*", "*" }, 263d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 264d3a460d3SAlexander Motin }, 265d3a460d3SAlexander Motin { 266d3a460d3SAlexander Motin /* WDC Scorpio Blue Advanced Format (4k) drives */ 267d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD???PVT*", "*" }, 268d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 269d3a460d3SAlexander Motin }, 270d3a460d3SAlexander Motin { 271d3a460d3SAlexander Motin /* WDC Scorpio Blue Advanced Format (4k) drives */ 272d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD?????PVT*", "*" }, 273d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 274d3a460d3SAlexander Motin }, 275d3a460d3SAlexander Motin { 2769d3334e1SEitan Adler /* 2779d3334e1SEitan Adler * Corsair Force 2 SSDs 2789d3334e1SEitan Adler * 4k optimised & trim only works in 4k requests + 4k aligned 2799d3334e1SEitan Adler * Submitted by: Steven Hartland <steven.hartland@multiplay.co.uk> 2809d3334e1SEitan Adler * PR: 169974 2819d3334e1SEitan Adler */ 2829d3334e1SEitan Adler { T_DIRECT, SIP_MEDIA_FIXED, "*", "Corsair CSSD-F*", "*" }, 2839d3334e1SEitan Adler /*quirks*/ADA_Q_4K 2849d3334e1SEitan Adler }, 2859d3334e1SEitan Adler { 2869d3334e1SEitan Adler /* 2879d3334e1SEitan Adler * Corsair Force 3 SSDs 2889d3334e1SEitan Adler * 4k optimised & trim only works in 4k requests + 4k aligned 2899d3334e1SEitan Adler * Submitted by: Steven Hartland <steven.hartland@multiplay.co.uk> 2909d3334e1SEitan Adler * PR: 169974 2919d3334e1SEitan Adler */ 2929d3334e1SEitan Adler { T_DIRECT, SIP_MEDIA_FIXED, "*", "Corsair Force 3*", "*" }, 2939d3334e1SEitan Adler /*quirks*/ADA_Q_4K 2949d3334e1SEitan Adler }, 2959d3334e1SEitan Adler { 2969d3334e1SEitan Adler /* 2979d3334e1SEitan Adler * OCZ Agility 3 SSDs 2989d3334e1SEitan Adler * 4k optimised & trim only works in 4k requests + 4k aligned 2999d3334e1SEitan Adler * Submitted by: Steven Hartland <steven.hartland@multiplay.co.uk> 3009d3334e1SEitan Adler * PR: 169974 3019d3334e1SEitan Adler */ 3029d3334e1SEitan Adler { T_DIRECT, SIP_MEDIA_FIXED, "*", "OCZ-AGILITY3*", "*" }, 3039d3334e1SEitan Adler /*quirks*/ADA_Q_4K 3049d3334e1SEitan Adler }, 3059d3334e1SEitan Adler { 3069d3334e1SEitan Adler /* 3079d3334e1SEitan Adler * OCZ Vertex 2 SSDs (inc pro series) 3089d3334e1SEitan Adler * 4k optimised & trim only works in 4k requests + 4k aligned 3099d3334e1SEitan Adler * Submitted by: Steven Hartland <steven.hartland@multiplay.co.uk> 3109d3334e1SEitan Adler * PR: 169974 3119d3334e1SEitan Adler */ 3129d3334e1SEitan Adler { T_DIRECT, SIP_MEDIA_FIXED, "*", "OCZ?VERTEX2*", "*" }, 3139d3334e1SEitan Adler /*quirks*/ADA_Q_4K 3149d3334e1SEitan Adler }, 3159d3334e1SEitan Adler { 3169d3334e1SEitan Adler /* 3179d3334e1SEitan Adler * OCZ Vertex 3 SSDs 3189d3334e1SEitan Adler * 4k optimised & trim only works in 4k requests + 4k aligned 3199d3334e1SEitan Adler * Submitted by: Steven Hartland <steven.hartland@multiplay.co.uk> 3209d3334e1SEitan Adler * PR: 169974 3219d3334e1SEitan Adler */ 3229d3334e1SEitan Adler { T_DIRECT, SIP_MEDIA_FIXED, "*", "OCZ-VERTEX3*", "*" }, 3239d3334e1SEitan Adler /*quirks*/ADA_Q_4K 3249d3334e1SEitan Adler }, 3259d3334e1SEitan Adler { 3269d3334e1SEitan Adler /* 3279d3334e1SEitan Adler * SuperTalent TeraDrive CT SSDs 3289d3334e1SEitan Adler * 4k optimised & trim only works in 4k requests + 4k aligned 3299d3334e1SEitan Adler * Submitted by: Steven Hartland <steven.hartland@multiplay.co.uk> 3309d3334e1SEitan Adler * PR: 169974 3319d3334e1SEitan Adler */ 3329d3334e1SEitan Adler { T_DIRECT, SIP_MEDIA_FIXED, "*", "FTM??CT25H*", "*" }, 3339d3334e1SEitan Adler /*quirks*/ADA_Q_4K 3349d3334e1SEitan Adler }, 3359d3334e1SEitan Adler { 3369d3334e1SEitan Adler /* 3379d3334e1SEitan Adler * Crucial RealSSD C300 SSDs 3389d3334e1SEitan Adler * 4k optimised 3399d3334e1SEitan Adler * Submitted by: Steven Hartland <steven.hartland@multiplay.co.uk> 3409d3334e1SEitan Adler * PR: 169974 3419d3334e1SEitan Adler */ 3429d3334e1SEitan Adler { T_DIRECT, SIP_MEDIA_FIXED, "*", "C300-CTFDDAC???MAG*", 3439d3334e1SEitan Adler "*" }, /*quirks*/ADA_Q_4K 3449d3334e1SEitan Adler }, 3459d3334e1SEitan Adler { 3469d3334e1SEitan Adler /* 3479d3334e1SEitan Adler * XceedIOPS SATA SSDs 3489d3334e1SEitan Adler * 4k optimised 3499d3334e1SEitan Adler * Submitted by: Steven Hartland <steven.hartland@multiplay.co.uk> 3509d3334e1SEitan Adler * PR: 169974 3519d3334e1SEitan Adler */ 3529d3334e1SEitan Adler { T_DIRECT, SIP_MEDIA_FIXED, "*", "SG9XCS2D*", "*" }, 3539d3334e1SEitan Adler /*quirks*/ADA_Q_4K 3549d3334e1SEitan Adler }, 3559d3334e1SEitan Adler { 3569d3334e1SEitan Adler /* 357883db1c1SEitan Adler * Intel 320 Series SSDs 358883db1c1SEitan Adler * 4k optimised & trim only works in 4k requests + 4k aligned 359883db1c1SEitan Adler */ 360883db1c1SEitan Adler { T_DIRECT, SIP_MEDIA_FIXED, "*", "INTEL SSDSA2CW*", "*" }, 361883db1c1SEitan Adler /*quirks*/ADA_Q_4K 362883db1c1SEitan Adler }, 363883db1c1SEitan Adler { 364883db1c1SEitan Adler /* 3659d3334e1SEitan Adler * Intel 330 Series SSDs 3669d3334e1SEitan Adler * 4k optimised & trim only works in 4k requests + 4k aligned 3679d3334e1SEitan Adler * Submitted by: Steven Hartland <steven.hartland@multiplay.co.uk> 3689d3334e1SEitan Adler * PR: 169974 3699d3334e1SEitan Adler */ 3709d3334e1SEitan Adler { T_DIRECT, SIP_MEDIA_FIXED, "*", "INTEL SSDSC2ct*", "*" }, 3719d3334e1SEitan Adler /*quirks*/ADA_Q_4K 3729d3334e1SEitan Adler }, 3739d3334e1SEitan Adler { 3749d3334e1SEitan Adler /* 375883db1c1SEitan Adler * Intel 510 Series SSDs 376883db1c1SEitan Adler * 4k optimised & trim only works in 4k requests + 4k aligned 377883db1c1SEitan Adler */ 378883db1c1SEitan Adler { T_DIRECT, SIP_MEDIA_FIXED, "*", "INTEL SSDSC2MH*", "*" }, 379883db1c1SEitan Adler /*quirks*/ADA_Q_4K 380883db1c1SEitan Adler }, 381883db1c1SEitan Adler { 382883db1c1SEitan Adler /* 3839d3334e1SEitan Adler * OCZ Deneva R Series SSDs 3849d3334e1SEitan Adler * 4k optimised & trim only works in 4k requests + 4k aligned 3859d3334e1SEitan Adler * Submitted by: Steven Hartland <steven.hartland@multiplay.co.uk> 3869d3334e1SEitan Adler * PR: 169974 3879d3334e1SEitan Adler */ 3889d3334e1SEitan Adler { T_DIRECT, SIP_MEDIA_FIXED, "*", "DENRSTE251M45*", "*" }, 3899d3334e1SEitan Adler /*quirks*/ADA_Q_4K 3909d3334e1SEitan Adler }, 3919d3334e1SEitan Adler { 3929d3334e1SEitan Adler /* 3939d3334e1SEitan Adler * Kingston HyperX 3k SSDs 3949d3334e1SEitan Adler * 4k optimised & trim only works in 4k requests + 4k aligned 3959d3334e1SEitan Adler * Submitted by: Steven Hartland <steven.hartland@multiplay.co.uk> 3969d3334e1SEitan Adler * PR: 169974 3979d3334e1SEitan Adler */ 3989d3334e1SEitan Adler { T_DIRECT, SIP_MEDIA_FIXED, "*", "KINGSTON SH103S3*", "*" }, 3999d3334e1SEitan Adler /*quirks*/ADA_Q_4K 4009d3334e1SEitan Adler }, 4019d3334e1SEitan Adler { 40230a4094fSAlexander Motin /* Default */ 40330a4094fSAlexander Motin { 40430a4094fSAlexander Motin T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED, 40530a4094fSAlexander Motin /*vendor*/"*", /*product*/"*", /*revision*/"*" 40630a4094fSAlexander Motin }, 40730a4094fSAlexander Motin /*quirks*/0 40830a4094fSAlexander Motin }, 40930a4094fSAlexander Motin }; 41052c9ce25SScott Long 41152c9ce25SScott Long static disk_strategy_t adastrategy; 41252c9ce25SScott Long static dumper_t adadump; 41352c9ce25SScott Long static periph_init_t adainit; 41452c9ce25SScott Long static void adaasync(void *callback_arg, u_int32_t code, 41552c9ce25SScott Long struct cam_path *path, void *arg); 41652c9ce25SScott Long static void adasysctlinit(void *context, int pending); 41752c9ce25SScott Long static periph_ctor_t adaregister; 41852c9ce25SScott Long static periph_dtor_t adacleanup; 41952c9ce25SScott Long static periph_start_t adastart; 42052c9ce25SScott Long static periph_oninv_t adaoninvalidate; 42152c9ce25SScott Long static void adadone(struct cam_periph *periph, 42252c9ce25SScott Long union ccb *done_ccb); 42352c9ce25SScott Long static int adaerror(union ccb *ccb, u_int32_t cam_flags, 42452c9ce25SScott Long u_int32_t sense_flags); 425c1bd46c2SAlexander Motin static void adagetparams(struct cam_periph *periph, 42652c9ce25SScott Long struct ccb_getdev *cgd); 42752c9ce25SScott Long static timeout_t adasendorderedtag; 42852c9ce25SScott Long static void adashutdown(void *arg, int howto); 429c3d0d168SAlexander Motin static void adasuspend(void *arg); 430c3d0d168SAlexander Motin static void adaresume(void *arg); 43152c9ce25SScott Long 4320d307e09SAlexander Motin #ifndef ADA_DEFAULT_LEGACY_ALIASES 4330d307e09SAlexander Motin #define ADA_DEFAULT_LEGACY_ALIASES 1 4340d307e09SAlexander Motin #endif 4350d307e09SAlexander Motin 43652c9ce25SScott Long #ifndef ADA_DEFAULT_TIMEOUT 43752c9ce25SScott Long #define ADA_DEFAULT_TIMEOUT 30 /* Timeout in seconds */ 43852c9ce25SScott Long #endif 43952c9ce25SScott Long 44052c9ce25SScott Long #ifndef ADA_DEFAULT_RETRY 44152c9ce25SScott Long #define ADA_DEFAULT_RETRY 4 44252c9ce25SScott Long #endif 44352c9ce25SScott Long 44452c9ce25SScott Long #ifndef ADA_DEFAULT_SEND_ORDERED 44552c9ce25SScott Long #define ADA_DEFAULT_SEND_ORDERED 1 44652c9ce25SScott Long #endif 44752c9ce25SScott Long 448fd104c15SRebecca Cran #ifndef ADA_DEFAULT_SPINDOWN_SHUTDOWN 449fd104c15SRebecca Cran #define ADA_DEFAULT_SPINDOWN_SHUTDOWN 1 450fd104c15SRebecca Cran #endif 451fd104c15SRebecca Cran 452c3d0d168SAlexander Motin #ifndef ADA_DEFAULT_SPINDOWN_SUSPEND 453c3d0d168SAlexander Motin #define ADA_DEFAULT_SPINDOWN_SUSPEND 1 454c3d0d168SAlexander Motin #endif 455c3d0d168SAlexander Motin 4561ed6aaf9SAlexander Motin #ifndef ADA_DEFAULT_READ_AHEAD 4571ed6aaf9SAlexander Motin #define ADA_DEFAULT_READ_AHEAD 1 4581ed6aaf9SAlexander Motin #endif 4591ed6aaf9SAlexander Motin 460f513d14cSAlexander Motin #ifndef ADA_DEFAULT_WRITE_CACHE 461f513d14cSAlexander Motin #define ADA_DEFAULT_WRITE_CACHE 1 462f513d14cSAlexander Motin #endif 463f513d14cSAlexander Motin 4641ed6aaf9SAlexander Motin #define ADA_RA (softc->read_ahead >= 0 ? \ 4651ed6aaf9SAlexander Motin softc->read_ahead : ada_read_ahead) 4661ed6aaf9SAlexander Motin #define ADA_WC (softc->write_cache >= 0 ? \ 4671ed6aaf9SAlexander Motin softc->write_cache : ada_write_cache) 4685f83aee5SSteven Hartland #define ADA_SIO (softc->sort_io_queue >= 0 ? \ 4695f83aee5SSteven Hartland softc->sort_io_queue : cam_sort_io_queues) 4701ed6aaf9SAlexander Motin 4714461491bSMarius Strobl /* 4724461491bSMarius Strobl * Most platforms map firmware geometry to actual, but some don't. If 4734461491bSMarius Strobl * not overridden, default to nothing. 4744461491bSMarius Strobl */ 4754461491bSMarius Strobl #ifndef ata_disk_firmware_geom_adjust 4764461491bSMarius Strobl #define ata_disk_firmware_geom_adjust(disk) 4774461491bSMarius Strobl #endif 47852c9ce25SScott Long 4790d307e09SAlexander Motin static int ada_legacy_aliases = ADA_DEFAULT_LEGACY_ALIASES; 48052c9ce25SScott Long static int ada_retry_count = ADA_DEFAULT_RETRY; 48152c9ce25SScott Long static int ada_default_timeout = ADA_DEFAULT_TIMEOUT; 48252c9ce25SScott Long static int ada_send_ordered = ADA_DEFAULT_SEND_ORDERED; 483fd104c15SRebecca Cran static int ada_spindown_shutdown = ADA_DEFAULT_SPINDOWN_SHUTDOWN; 484c3d0d168SAlexander Motin static int ada_spindown_suspend = ADA_DEFAULT_SPINDOWN_SUSPEND; 4851ed6aaf9SAlexander Motin static int ada_read_ahead = ADA_DEFAULT_READ_AHEAD; 486f513d14cSAlexander Motin static int ada_write_cache = ADA_DEFAULT_WRITE_CACHE; 48752c9ce25SScott Long 4886472ac3dSEd Schouten static SYSCTL_NODE(_kern_cam, OID_AUTO, ada, CTLFLAG_RD, 0, 48952c9ce25SScott Long "CAM Direct Access Disk driver"); 4900d307e09SAlexander Motin SYSCTL_INT(_kern_cam_ada, OID_AUTO, legacy_aliases, CTLFLAG_RW, 4910d307e09SAlexander Motin &ada_legacy_aliases, 0, "Create legacy-like device aliases"); 4920d307e09SAlexander Motin TUNABLE_INT("kern.cam.ada.legacy_aliases", &ada_legacy_aliases); 49352c9ce25SScott Long SYSCTL_INT(_kern_cam_ada, OID_AUTO, retry_count, CTLFLAG_RW, 49452c9ce25SScott Long &ada_retry_count, 0, "Normal I/O retry count"); 49552c9ce25SScott Long TUNABLE_INT("kern.cam.ada.retry_count", &ada_retry_count); 49652c9ce25SScott Long SYSCTL_INT(_kern_cam_ada, OID_AUTO, default_timeout, CTLFLAG_RW, 49752c9ce25SScott Long &ada_default_timeout, 0, "Normal I/O timeout (in seconds)"); 49852c9ce25SScott Long TUNABLE_INT("kern.cam.ada.default_timeout", &ada_default_timeout); 499af010905SChristian Brueffer SYSCTL_INT(_kern_cam_ada, OID_AUTO, send_ordered, CTLFLAG_RW, 50052c9ce25SScott Long &ada_send_ordered, 0, "Send Ordered Tags"); 501af010905SChristian Brueffer TUNABLE_INT("kern.cam.ada.send_ordered", &ada_send_ordered); 502fd104c15SRebecca Cran SYSCTL_INT(_kern_cam_ada, OID_AUTO, spindown_shutdown, CTLFLAG_RW, 503fd104c15SRebecca Cran &ada_spindown_shutdown, 0, "Spin down upon shutdown"); 504fd104c15SRebecca Cran TUNABLE_INT("kern.cam.ada.spindown_shutdown", &ada_spindown_shutdown); 505c3d0d168SAlexander Motin SYSCTL_INT(_kern_cam_ada, OID_AUTO, spindown_suspend, CTLFLAG_RW, 506c3d0d168SAlexander Motin &ada_spindown_suspend, 0, "Spin down upon suspend"); 507c3d0d168SAlexander Motin TUNABLE_INT("kern.cam.ada.spindown_suspend", &ada_spindown_suspend); 5081ed6aaf9SAlexander Motin SYSCTL_INT(_kern_cam_ada, OID_AUTO, read_ahead, CTLFLAG_RW, 5091ed6aaf9SAlexander Motin &ada_read_ahead, 0, "Enable disk read-ahead"); 5101ed6aaf9SAlexander Motin TUNABLE_INT("kern.cam.ada.read_ahead", &ada_read_ahead); 511f513d14cSAlexander Motin SYSCTL_INT(_kern_cam_ada, OID_AUTO, write_cache, CTLFLAG_RW, 512f513d14cSAlexander Motin &ada_write_cache, 0, "Enable disk write cache"); 513f513d14cSAlexander Motin TUNABLE_INT("kern.cam.ada.write_cache", &ada_write_cache); 51452c9ce25SScott Long 51552c9ce25SScott Long /* 51652c9ce25SScott Long * ADA_ORDEREDTAG_INTERVAL determines how often, relative 51752c9ce25SScott Long * to the default timeout, we check to see whether an ordered 51852c9ce25SScott Long * tagged transaction is appropriate to prevent simple tag 51952c9ce25SScott Long * starvation. Since we'd like to ensure that there is at least 52052c9ce25SScott Long * 1/2 of the timeout length left for a starved transaction to 52152c9ce25SScott Long * complete after we've sent an ordered tag, we must poll at least 52252c9ce25SScott Long * four times in every timeout period. This takes care of the worst 52352c9ce25SScott Long * case where a starved transaction starts during an interval that 52452c9ce25SScott Long * meets the requirement "don't send an ordered tag" test so it takes 52552c9ce25SScott Long * us two intervals to determine that a tag must be sent. 52652c9ce25SScott Long */ 52752c9ce25SScott Long #ifndef ADA_ORDEREDTAG_INTERVAL 52852c9ce25SScott Long #define ADA_ORDEREDTAG_INTERVAL 4 52952c9ce25SScott Long #endif 53052c9ce25SScott Long 53152c9ce25SScott Long static struct periph_driver adadriver = 53252c9ce25SScott Long { 53352c9ce25SScott Long adainit, "ada", 53452c9ce25SScott Long TAILQ_HEAD_INITIALIZER(adadriver.units), /* generation */ 0 53552c9ce25SScott Long }; 53652c9ce25SScott Long 53752c9ce25SScott Long PERIPHDRIVER_DECLARE(ada, adadriver); 53852c9ce25SScott Long 539d745c852SEd Schouten static MALLOC_DEFINE(M_ATADA, "ata_da", "ata_da buffers"); 54052c9ce25SScott Long 54152c9ce25SScott Long static int 54252c9ce25SScott Long adaopen(struct disk *dp) 54352c9ce25SScott Long { 54452c9ce25SScott Long struct cam_periph *periph; 54552c9ce25SScott Long struct ada_softc *softc; 54652c9ce25SScott Long int error; 54752c9ce25SScott Long 54852c9ce25SScott Long periph = (struct cam_periph *)dp->d_drv1; 54952c9ce25SScott Long if (cam_periph_acquire(periph) != CAM_REQ_CMP) { 55052c9ce25SScott Long return(ENXIO); 55152c9ce25SScott Long } 55252c9ce25SScott Long 55352c9ce25SScott Long cam_periph_lock(periph); 55452c9ce25SScott Long if ((error = cam_periph_hold(periph, PRIBIO|PCATCH)) != 0) { 55552c9ce25SScott Long cam_periph_unlock(periph); 55652c9ce25SScott Long cam_periph_release(periph); 55752c9ce25SScott Long return (error); 55852c9ce25SScott Long } 55952c9ce25SScott Long 560fddde2b8SAlexander Motin CAM_DEBUG(periph->path, CAM_DEBUG_TRACE | CAM_DEBUG_PERIPH, 561fddde2b8SAlexander Motin ("adaopen\n")); 56252c9ce25SScott Long 5637338ef1aSAlexander Motin softc = (struct ada_softc *)periph->softc; 5647338ef1aSAlexander Motin softc->flags |= ADA_FLAG_OPEN; 56552c9ce25SScott Long 56652c9ce25SScott Long cam_periph_unhold(periph); 56752c9ce25SScott Long cam_periph_unlock(periph); 56852c9ce25SScott Long return (0); 56952c9ce25SScott Long } 57052c9ce25SScott Long 57152c9ce25SScott Long static int 57252c9ce25SScott Long adaclose(struct disk *dp) 57352c9ce25SScott Long { 57452c9ce25SScott Long struct cam_periph *periph; 57552c9ce25SScott Long struct ada_softc *softc; 57652c9ce25SScott Long union ccb *ccb; 57752c9ce25SScott Long 57852c9ce25SScott Long periph = (struct cam_periph *)dp->d_drv1; 57952c9ce25SScott Long cam_periph_lock(periph); 5806f487924SAlexander Motin if (cam_periph_hold(periph, PRIBIO) != 0) { 58152c9ce25SScott Long cam_periph_unlock(periph); 58252c9ce25SScott Long cam_periph_release(periph); 5836f487924SAlexander Motin return (0); 58452c9ce25SScott Long } 58552c9ce25SScott Long 58652c9ce25SScott Long softc = (struct ada_softc *)periph->softc; 587fddde2b8SAlexander Motin 588fddde2b8SAlexander Motin CAM_DEBUG(periph->path, CAM_DEBUG_TRACE | CAM_DEBUG_PERIPH, 589fddde2b8SAlexander Motin ("adaclose\n")); 590fddde2b8SAlexander Motin 59152c9ce25SScott Long /* We only sync the cache if the drive is capable of it. */ 592c36bb43cSAlexander Motin if ((softc->flags & ADA_FLAG_CAN_FLUSHCACHE) != 0 && 5937338ef1aSAlexander Motin (periph->flags & CAM_PERIPH_INVALID) == 0) { 59452c9ce25SScott Long 595bbfa4aa1SAlexander Motin ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 59652c9ce25SScott Long cam_fill_ataio(&ccb->ataio, 59752c9ce25SScott Long 1, 59852c9ce25SScott Long adadone, 59952c9ce25SScott Long CAM_DIR_NONE, 60052c9ce25SScott Long 0, 60152c9ce25SScott Long NULL, 60252c9ce25SScott Long 0, 60352c9ce25SScott Long ada_default_timeout*1000); 60452c9ce25SScott Long 60552c9ce25SScott Long if (softc->flags & ADA_FLAG_CAN_48BIT) 60652c9ce25SScott Long ata_48bit_cmd(&ccb->ataio, ATA_FLUSHCACHE48, 0, 0, 0); 60752c9ce25SScott Long else 6087606b445SAlexander Motin ata_28bit_cmd(&ccb->ataio, ATA_FLUSHCACHE, 0, 0, 0); 6097642883fSAlexander Motin cam_periph_runccb(ccb, adaerror, /*cam_flags*/0, 61046f118feSAlexander Motin /*sense_flags*/0, softc->disk->d_devstat); 61152c9ce25SScott Long 61252c9ce25SScott Long if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) 61352c9ce25SScott Long xpt_print(periph->path, "Synchronize cache failed\n"); 61452c9ce25SScott Long xpt_release_ccb(ccb); 61552c9ce25SScott Long } 61652c9ce25SScott Long 61752c9ce25SScott Long softc->flags &= ~ADA_FLAG_OPEN; 61852c9ce25SScott Long cam_periph_unhold(periph); 61952c9ce25SScott Long cam_periph_unlock(periph); 62052c9ce25SScott Long cam_periph_release(periph); 62152c9ce25SScott Long return (0); 62252c9ce25SScott Long } 62352c9ce25SScott Long 6241c80ec0aSAlexander Motin static void 6251c80ec0aSAlexander Motin adaschedule(struct cam_periph *periph) 6261c80ec0aSAlexander Motin { 6271c80ec0aSAlexander Motin struct ada_softc *softc = (struct ada_softc *)periph->softc; 62810a6c358SAlexander Motin uint32_t prio; 6291c80ec0aSAlexander Motin 6306bf435dcSAlexander Motin if (softc->state != ADA_STATE_NORMAL) 6316bf435dcSAlexander Motin return; 6326bf435dcSAlexander Motin 63310a6c358SAlexander Motin /* Check if cam_periph_getccb() was called. */ 63410a6c358SAlexander Motin prio = periph->immediate_priority; 63510a6c358SAlexander Motin 63610a6c358SAlexander Motin /* Check if we have more work to do. */ 6371c80ec0aSAlexander Motin if (bioq_first(&softc->bio_queue) || 6381c80ec0aSAlexander Motin (!softc->trim_running && bioq_first(&softc->trim_queue))) { 63910a6c358SAlexander Motin prio = CAM_PRIORITY_NORMAL; 6401c80ec0aSAlexander Motin } 64110a6c358SAlexander Motin 64210a6c358SAlexander Motin /* Schedule CCB if any of above is true. */ 64310a6c358SAlexander Motin if (prio != CAM_PRIORITY_NONE) 64410a6c358SAlexander Motin xpt_schedule(periph, prio); 6451c80ec0aSAlexander Motin } 6461c80ec0aSAlexander Motin 64752c9ce25SScott Long /* 64852c9ce25SScott Long * Actually translate the requested transfer into one the physical driver 64952c9ce25SScott Long * can understand. The transfer is described by a buf and will include 65052c9ce25SScott Long * only one physical transfer. 65152c9ce25SScott Long */ 65252c9ce25SScott Long static void 65352c9ce25SScott Long adastrategy(struct bio *bp) 65452c9ce25SScott Long { 65552c9ce25SScott Long struct cam_periph *periph; 65652c9ce25SScott Long struct ada_softc *softc; 65752c9ce25SScott Long 65852c9ce25SScott Long periph = (struct cam_periph *)bp->bio_disk->d_drv1; 65952c9ce25SScott Long softc = (struct ada_softc *)periph->softc; 66052c9ce25SScott Long 66152c9ce25SScott Long cam_periph_lock(periph); 66252c9ce25SScott Long 663fddde2b8SAlexander Motin CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("adastrategy(%p)\n", bp)); 664fddde2b8SAlexander Motin 66552c9ce25SScott Long /* 66652c9ce25SScott Long * If the device has been made invalid, error out 66752c9ce25SScott Long */ 6687338ef1aSAlexander Motin if ((periph->flags & CAM_PERIPH_INVALID) != 0) { 66952c9ce25SScott Long cam_periph_unlock(periph); 67052c9ce25SScott Long biofinish(bp, NULL, ENXIO); 67152c9ce25SScott Long return; 67252c9ce25SScott Long } 67352c9ce25SScott Long 67452c9ce25SScott Long /* 67552c9ce25SScott Long * Place it in the queue of disk activities for this disk 67652c9ce25SScott Long */ 6771c80ec0aSAlexander Motin if (bp->bio_cmd == BIO_DELETE && 6785f83aee5SSteven Hartland (softc->flags & ADA_FLAG_CAN_TRIM)) { 6795f83aee5SSteven Hartland if (ADA_SIO) 6801c80ec0aSAlexander Motin bioq_disksort(&softc->trim_queue, bp); 6811c80ec0aSAlexander Motin else 6825f83aee5SSteven Hartland bioq_insert_tail(&softc->trim_queue, bp); 6835f83aee5SSteven Hartland } else { 6845f83aee5SSteven Hartland if (ADA_SIO) 68552c9ce25SScott Long bioq_disksort(&softc->bio_queue, bp); 6865f83aee5SSteven Hartland else 6875f83aee5SSteven Hartland bioq_insert_tail(&softc->bio_queue, bp); 6885f83aee5SSteven Hartland } 68952c9ce25SScott Long 69052c9ce25SScott Long /* 69152c9ce25SScott Long * Schedule ourselves for performing the work. 69252c9ce25SScott Long */ 6931c80ec0aSAlexander Motin adaschedule(periph); 69452c9ce25SScott Long cam_periph_unlock(periph); 69552c9ce25SScott Long 69652c9ce25SScott Long return; 69752c9ce25SScott Long } 69852c9ce25SScott Long 69952c9ce25SScott Long static int 70052c9ce25SScott Long adadump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t length) 70152c9ce25SScott Long { 70252c9ce25SScott Long struct cam_periph *periph; 70352c9ce25SScott Long struct ada_softc *softc; 70452c9ce25SScott Long u_int secsize; 70552c9ce25SScott Long union ccb ccb; 70652c9ce25SScott Long struct disk *dp; 70752c9ce25SScott Long uint64_t lba; 70852c9ce25SScott Long uint16_t count; 7090191d9b3SAlexander Motin int error = 0; 71052c9ce25SScott Long 71152c9ce25SScott Long dp = arg; 71252c9ce25SScott Long periph = dp->d_drv1; 71352c9ce25SScott Long softc = (struct ada_softc *)periph->softc; 71452c9ce25SScott Long cam_periph_lock(periph); 71552c9ce25SScott Long secsize = softc->params.secsize; 71652c9ce25SScott Long lba = offset / secsize; 71752c9ce25SScott Long count = length / secsize; 71852c9ce25SScott Long 7197338ef1aSAlexander Motin if ((periph->flags & CAM_PERIPH_INVALID) != 0) { 72052c9ce25SScott Long cam_periph_unlock(periph); 72152c9ce25SScott Long return (ENXIO); 72252c9ce25SScott Long } 72352c9ce25SScott Long 72452c9ce25SScott Long if (length > 0) { 725bbfa4aa1SAlexander Motin xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 72652c9ce25SScott Long ccb.ccb_h.ccb_state = ADA_CCB_DUMP; 72752c9ce25SScott Long cam_fill_ataio(&ccb.ataio, 72852c9ce25SScott Long 0, 72952c9ce25SScott Long adadone, 73052c9ce25SScott Long CAM_DIR_OUT, 73152c9ce25SScott Long 0, 73252c9ce25SScott Long (u_int8_t *) virtual, 73352c9ce25SScott Long length, 73452c9ce25SScott Long ada_default_timeout*1000); 73552c9ce25SScott Long if ((softc->flags & ADA_FLAG_CAN_48BIT) && 73652c9ce25SScott Long (lba + count >= ATA_MAX_28BIT_LBA || 73752c9ce25SScott Long count >= 256)) { 73852c9ce25SScott Long ata_48bit_cmd(&ccb.ataio, ATA_WRITE_DMA48, 73952c9ce25SScott Long 0, lba, count); 74052c9ce25SScott Long } else { 7417606b445SAlexander Motin ata_28bit_cmd(&ccb.ataio, ATA_WRITE_DMA, 74252c9ce25SScott Long 0, lba, count); 74352c9ce25SScott Long } 74452c9ce25SScott Long xpt_polled_action(&ccb); 74552c9ce25SScott Long 7460191d9b3SAlexander Motin error = cam_periph_error(&ccb, 7470191d9b3SAlexander Motin 0, SF_NO_RECOVERY | SF_NO_RETRY, NULL); 7480191d9b3SAlexander Motin if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0) 7490191d9b3SAlexander Motin cam_release_devq(ccb.ccb_h.path, /*relsim_flags*/0, 7500191d9b3SAlexander Motin /*reduction*/0, /*timeout*/0, /*getcount_only*/0); 7510191d9b3SAlexander Motin if (error != 0) 75252c9ce25SScott Long printf("Aborting dump due to I/O error.\n"); 7530191d9b3SAlexander Motin 75452c9ce25SScott Long cam_periph_unlock(periph); 7550191d9b3SAlexander Motin return (error); 75652c9ce25SScott Long } 75752c9ce25SScott Long 75852c9ce25SScott Long if (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) { 759bbfa4aa1SAlexander Motin xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 76052c9ce25SScott Long 76152c9ce25SScott Long ccb.ccb_h.ccb_state = ADA_CCB_DUMP; 76252c9ce25SScott Long cam_fill_ataio(&ccb.ataio, 7630191d9b3SAlexander Motin 0, 76452c9ce25SScott Long adadone, 76552c9ce25SScott Long CAM_DIR_NONE, 76652c9ce25SScott Long 0, 76752c9ce25SScott Long NULL, 76852c9ce25SScott Long 0, 76952c9ce25SScott Long ada_default_timeout*1000); 77052c9ce25SScott Long 77152c9ce25SScott Long if (softc->flags & ADA_FLAG_CAN_48BIT) 77252c9ce25SScott Long ata_48bit_cmd(&ccb.ataio, ATA_FLUSHCACHE48, 0, 0, 0); 77352c9ce25SScott Long else 7747606b445SAlexander Motin ata_28bit_cmd(&ccb.ataio, ATA_FLUSHCACHE, 0, 0, 0); 77552c9ce25SScott Long xpt_polled_action(&ccb); 77652c9ce25SScott Long 7770191d9b3SAlexander Motin error = cam_periph_error(&ccb, 7780191d9b3SAlexander Motin 0, SF_NO_RECOVERY | SF_NO_RETRY, NULL); 77952c9ce25SScott Long if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0) 7800191d9b3SAlexander Motin cam_release_devq(ccb.ccb_h.path, /*relsim_flags*/0, 7810191d9b3SAlexander Motin /*reduction*/0, /*timeout*/0, /*getcount_only*/0); 7820191d9b3SAlexander Motin if (error != 0) 7830191d9b3SAlexander Motin xpt_print(periph->path, "Synchronize cache failed\n"); 78452c9ce25SScott Long } 78552c9ce25SScott Long cam_periph_unlock(periph); 7860191d9b3SAlexander Motin return (error); 78752c9ce25SScott Long } 78852c9ce25SScott Long 78952c9ce25SScott Long static void 79052c9ce25SScott Long adainit(void) 79152c9ce25SScott Long { 79252c9ce25SScott Long cam_status status; 79352c9ce25SScott Long 79452c9ce25SScott Long /* 79552c9ce25SScott Long * Install a global async callback. This callback will 79652c9ce25SScott Long * receive async callbacks like "new device found". 79752c9ce25SScott Long */ 79852c9ce25SScott Long status = xpt_register_async(AC_FOUND_DEVICE, adaasync, NULL, NULL); 79952c9ce25SScott Long 80052c9ce25SScott Long if (status != CAM_REQ_CMP) { 80152c9ce25SScott Long printf("ada: Failed to attach master async callback " 80252c9ce25SScott Long "due to status 0x%x!\n", status); 80352c9ce25SScott Long } else if (ada_send_ordered) { 80452c9ce25SScott Long 805c3d0d168SAlexander Motin /* Register our event handlers */ 806c3d0d168SAlexander Motin if ((EVENTHANDLER_REGISTER(power_suspend, adasuspend, 807c3d0d168SAlexander Motin NULL, EVENTHANDLER_PRI_LAST)) == NULL) 808c3d0d168SAlexander Motin printf("adainit: power event registration failed!\n"); 809c3d0d168SAlexander Motin if ((EVENTHANDLER_REGISTER(power_resume, adaresume, 810c3d0d168SAlexander Motin NULL, EVENTHANDLER_PRI_LAST)) == NULL) 811c3d0d168SAlexander Motin printf("adainit: power event registration failed!\n"); 81252c9ce25SScott Long if ((EVENTHANDLER_REGISTER(shutdown_post_sync, adashutdown, 81352c9ce25SScott Long NULL, SHUTDOWN_PRI_DEFAULT)) == NULL) 81452c9ce25SScott Long printf("adainit: shutdown event registration failed!\n"); 81552c9ce25SScott Long } 81652c9ce25SScott Long } 81752c9ce25SScott Long 8180ba1e4d0SKenneth D. Merry /* 8190ba1e4d0SKenneth D. Merry * Callback from GEOM, called when it has finished cleaning up its 8200ba1e4d0SKenneth D. Merry * resources. 8210ba1e4d0SKenneth D. Merry */ 8220ba1e4d0SKenneth D. Merry static void 8230ba1e4d0SKenneth D. Merry adadiskgonecb(struct disk *dp) 8240ba1e4d0SKenneth D. Merry { 8250ba1e4d0SKenneth D. Merry struct cam_periph *periph; 8260ba1e4d0SKenneth D. Merry 8270ba1e4d0SKenneth D. Merry periph = (struct cam_periph *)dp->d_drv1; 8280ba1e4d0SKenneth D. Merry 8290ba1e4d0SKenneth D. Merry cam_periph_release(periph); 8300ba1e4d0SKenneth D. Merry } 8310ba1e4d0SKenneth D. Merry 83252c9ce25SScott Long static void 83352c9ce25SScott Long adaoninvalidate(struct cam_periph *periph) 83452c9ce25SScott Long { 83552c9ce25SScott Long struct ada_softc *softc; 83652c9ce25SScott Long 83752c9ce25SScott Long softc = (struct ada_softc *)periph->softc; 83852c9ce25SScott Long 83952c9ce25SScott Long /* 84052c9ce25SScott Long * De-register any async callbacks. 84152c9ce25SScott Long */ 84252c9ce25SScott Long xpt_register_async(0, adaasync, periph, periph->path); 84352c9ce25SScott Long 84452c9ce25SScott Long /* 84552c9ce25SScott Long * Return all queued I/O with ENXIO. 84652c9ce25SScott Long * XXX Handle any transactions queued to the card 84752c9ce25SScott Long * with XPT_ABORT_CCB. 84852c9ce25SScott Long */ 84952c9ce25SScott Long bioq_flush(&softc->bio_queue, NULL, ENXIO); 8501c80ec0aSAlexander Motin bioq_flush(&softc->trim_queue, NULL, ENXIO); 85152c9ce25SScott Long 85252c9ce25SScott Long disk_gone(softc->disk); 85352c9ce25SScott Long xpt_print(periph->path, "lost device\n"); 85452c9ce25SScott Long } 85552c9ce25SScott Long 85652c9ce25SScott Long static void 85752c9ce25SScott Long adacleanup(struct cam_periph *periph) 85852c9ce25SScott Long { 85952c9ce25SScott Long struct ada_softc *softc; 86052c9ce25SScott Long 86152c9ce25SScott Long softc = (struct ada_softc *)periph->softc; 86252c9ce25SScott Long 86352c9ce25SScott Long xpt_print(periph->path, "removing device entry\n"); 86452c9ce25SScott Long cam_periph_unlock(periph); 86552c9ce25SScott Long 86652c9ce25SScott Long /* 86752c9ce25SScott Long * If we can't free the sysctl tree, oh well... 86852c9ce25SScott Long */ 86952c9ce25SScott Long if ((softc->flags & ADA_FLAG_SCTX_INIT) != 0 87052c9ce25SScott Long && sysctl_ctx_free(&softc->sysctl_ctx) != 0) { 87152c9ce25SScott Long xpt_print(periph->path, "can't remove sysctl context\n"); 87252c9ce25SScott Long } 87352c9ce25SScott Long 87452c9ce25SScott Long disk_destroy(softc->disk); 87552c9ce25SScott Long callout_drain(&softc->sendordered_c); 87652c9ce25SScott Long free(softc, M_DEVBUF); 87752c9ce25SScott Long cam_periph_lock(periph); 87852c9ce25SScott Long } 87952c9ce25SScott Long 88052c9ce25SScott Long static void 88152c9ce25SScott Long adaasync(void *callback_arg, u_int32_t code, 88252c9ce25SScott Long struct cam_path *path, void *arg) 88352c9ce25SScott Long { 884581b2e78SAlexander Motin struct ccb_getdev cgd; 88552c9ce25SScott Long struct cam_periph *periph; 886f513d14cSAlexander Motin struct ada_softc *softc; 88752c9ce25SScott Long 88852c9ce25SScott Long periph = (struct cam_periph *)callback_arg; 88952c9ce25SScott Long switch (code) { 89052c9ce25SScott Long case AC_FOUND_DEVICE: 89152c9ce25SScott Long { 89252c9ce25SScott Long struct ccb_getdev *cgd; 89352c9ce25SScott Long cam_status status; 89452c9ce25SScott Long 89552c9ce25SScott Long cgd = (struct ccb_getdev *)arg; 89652c9ce25SScott Long if (cgd == NULL) 89752c9ce25SScott Long break; 89852c9ce25SScott Long 89952c9ce25SScott Long if (cgd->protocol != PROTO_ATA) 90052c9ce25SScott Long break; 90152c9ce25SScott Long 90252c9ce25SScott Long /* 90352c9ce25SScott Long * Allocate a peripheral instance for 90452c9ce25SScott Long * this device and start the probe 90552c9ce25SScott Long * process. 90652c9ce25SScott Long */ 90752c9ce25SScott Long status = cam_periph_alloc(adaregister, adaoninvalidate, 90852c9ce25SScott Long adacleanup, adastart, 90952c9ce25SScott Long "ada", CAM_PERIPH_BIO, 91052c9ce25SScott Long cgd->ccb_h.path, adaasync, 91152c9ce25SScott Long AC_FOUND_DEVICE, cgd); 91252c9ce25SScott Long 91352c9ce25SScott Long if (status != CAM_REQ_CMP 91452c9ce25SScott Long && status != CAM_REQ_INPROG) 91552c9ce25SScott Long printf("adaasync: Unable to attach to new device " 91652c9ce25SScott Long "due to status 0x%x\n", status); 91752c9ce25SScott Long break; 91852c9ce25SScott Long } 919581b2e78SAlexander Motin case AC_GETDEV_CHANGED: 920581b2e78SAlexander Motin { 921581b2e78SAlexander Motin softc = (struct ada_softc *)periph->softc; 922581b2e78SAlexander Motin xpt_setup_ccb(&cgd.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 923581b2e78SAlexander Motin cgd.ccb_h.func_code = XPT_GDEV_TYPE; 924581b2e78SAlexander Motin xpt_action((union ccb *)&cgd); 925581b2e78SAlexander Motin 926581b2e78SAlexander Motin if ((cgd.ident_data.capabilities1 & ATA_SUPPORT_DMA) && 927581b2e78SAlexander Motin (cgd.inq_flags & SID_DMA)) 928581b2e78SAlexander Motin softc->flags |= ADA_FLAG_CAN_DMA; 929581b2e78SAlexander Motin else 930581b2e78SAlexander Motin softc->flags &= ~ADA_FLAG_CAN_DMA; 9312e1eb332SMarius Strobl if (cgd.ident_data.support.command2 & ATA_SUPPORT_ADDRESS48) { 9322e1eb332SMarius Strobl softc->flags |= ADA_FLAG_CAN_48BIT; 9332e1eb332SMarius Strobl if (cgd.inq_flags & SID_DMA48) 9342e1eb332SMarius Strobl softc->flags |= ADA_FLAG_CAN_DMA48; 9352e1eb332SMarius Strobl else 9362e1eb332SMarius Strobl softc->flags &= ~ADA_FLAG_CAN_DMA48; 9372e1eb332SMarius Strobl } else 9382e1eb332SMarius Strobl softc->flags &= ~(ADA_FLAG_CAN_48BIT | 9392e1eb332SMarius Strobl ADA_FLAG_CAN_DMA48); 940581b2e78SAlexander Motin if ((cgd.ident_data.satacapabilities & ATA_SUPPORT_NCQ) && 941581b2e78SAlexander Motin (cgd.inq_flags & SID_DMA) && (cgd.inq_flags & SID_CmdQue)) 942581b2e78SAlexander Motin softc->flags |= ADA_FLAG_CAN_NCQ; 943581b2e78SAlexander Motin else 944581b2e78SAlexander Motin softc->flags &= ~ADA_FLAG_CAN_NCQ; 945581b2e78SAlexander Motin if ((cgd.ident_data.support_dsm & ATA_SUPPORT_DSM_TRIM) && 946581b2e78SAlexander Motin (cgd.inq_flags & SID_DMA)) 947581b2e78SAlexander Motin softc->flags |= ADA_FLAG_CAN_TRIM; 948581b2e78SAlexander Motin else 949581b2e78SAlexander Motin softc->flags &= ~ADA_FLAG_CAN_TRIM; 950581b2e78SAlexander Motin 951581b2e78SAlexander Motin cam_periph_async(periph, code, path, arg); 952581b2e78SAlexander Motin break; 953581b2e78SAlexander Motin } 9543089bb2eSAlexander Motin case AC_ADVINFO_CHANGED: 9553089bb2eSAlexander Motin { 9563089bb2eSAlexander Motin uintptr_t buftype; 9573089bb2eSAlexander Motin 9583089bb2eSAlexander Motin buftype = (uintptr_t)arg; 9593089bb2eSAlexander Motin if (buftype == CDAI_TYPE_PHYS_PATH) { 9603089bb2eSAlexander Motin struct ada_softc *softc; 9613089bb2eSAlexander Motin 9623089bb2eSAlexander Motin softc = periph->softc; 9633089bb2eSAlexander Motin disk_attr_changed(softc->disk, "GEOM::physpath", 9643089bb2eSAlexander Motin M_NOWAIT); 9653089bb2eSAlexander Motin } 9663089bb2eSAlexander Motin break; 9673089bb2eSAlexander Motin } 968f513d14cSAlexander Motin case AC_SENT_BDR: 969f513d14cSAlexander Motin case AC_BUS_RESET: 970f513d14cSAlexander Motin { 971f513d14cSAlexander Motin softc = (struct ada_softc *)periph->softc; 972f513d14cSAlexander Motin cam_periph_async(periph, code, path, arg); 973f513d14cSAlexander Motin if (softc->state != ADA_STATE_NORMAL) 974f513d14cSAlexander Motin break; 975e3a6d3a4SAlexander Motin xpt_setup_ccb(&cgd.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 976f513d14cSAlexander Motin cgd.ccb_h.func_code = XPT_GDEV_TYPE; 977f513d14cSAlexander Motin xpt_action((union ccb *)&cgd); 9781ed6aaf9SAlexander Motin if (ADA_RA >= 0 && 9791ed6aaf9SAlexander Motin cgd.ident_data.support.command1 & ATA_SUPPORT_LOOKAHEAD) 9801ed6aaf9SAlexander Motin softc->state = ADA_STATE_RAHEAD; 9811ed6aaf9SAlexander Motin else if (ADA_WC >= 0 && 9821ed6aaf9SAlexander Motin cgd.ident_data.support.command1 & ATA_SUPPORT_WRITECACHE) 983f513d14cSAlexander Motin softc->state = ADA_STATE_WCACHE; 9841ed6aaf9SAlexander Motin else 9851ed6aaf9SAlexander Motin break; 986f513d14cSAlexander Motin cam_periph_acquire(periph); 987f513d14cSAlexander Motin xpt_schedule(periph, CAM_PRIORITY_DEV); 988f513d14cSAlexander Motin } 98952c9ce25SScott Long default: 99052c9ce25SScott Long cam_periph_async(periph, code, path, arg); 99152c9ce25SScott Long break; 99252c9ce25SScott Long } 99352c9ce25SScott Long } 99452c9ce25SScott Long 99552c9ce25SScott Long static void 99652c9ce25SScott Long adasysctlinit(void *context, int pending) 99752c9ce25SScott Long { 99852c9ce25SScott Long struct cam_periph *periph; 99952c9ce25SScott Long struct ada_softc *softc; 100052c9ce25SScott Long char tmpstr[80], tmpstr2[80]; 100152c9ce25SScott Long 100252c9ce25SScott Long periph = (struct cam_periph *)context; 1003e3a6d3a4SAlexander Motin 1004e3a6d3a4SAlexander Motin /* periph was held for us when this task was enqueued */ 10057338ef1aSAlexander Motin if ((periph->flags & CAM_PERIPH_INVALID) != 0) { 1006e3a6d3a4SAlexander Motin cam_periph_release(periph); 100752c9ce25SScott Long return; 1008e3a6d3a4SAlexander Motin } 100952c9ce25SScott Long 101052c9ce25SScott Long softc = (struct ada_softc *)periph->softc; 101152c9ce25SScott Long snprintf(tmpstr, sizeof(tmpstr), "CAM ADA unit %d", periph->unit_number); 101252c9ce25SScott Long snprintf(tmpstr2, sizeof(tmpstr2), "%d", periph->unit_number); 101352c9ce25SScott Long 101452c9ce25SScott Long sysctl_ctx_init(&softc->sysctl_ctx); 101552c9ce25SScott Long softc->flags |= ADA_FLAG_SCTX_INIT; 101652c9ce25SScott Long softc->sysctl_tree = SYSCTL_ADD_NODE(&softc->sysctl_ctx, 101752c9ce25SScott Long SYSCTL_STATIC_CHILDREN(_kern_cam_ada), OID_AUTO, tmpstr2, 101852c9ce25SScott Long CTLFLAG_RD, 0, tmpstr); 101952c9ce25SScott Long if (softc->sysctl_tree == NULL) { 102052c9ce25SScott Long printf("adasysctlinit: unable to allocate sysctl tree\n"); 102152c9ce25SScott Long cam_periph_release(periph); 102252c9ce25SScott Long return; 102352c9ce25SScott Long } 102452c9ce25SScott Long 1025e3a6d3a4SAlexander Motin SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 10261ed6aaf9SAlexander Motin OID_AUTO, "read_ahead", CTLFLAG_RW | CTLFLAG_MPSAFE, 10271ed6aaf9SAlexander Motin &softc->read_ahead, 0, "Enable disk read ahead."); 10281ed6aaf9SAlexander Motin SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 1029e3a6d3a4SAlexander Motin OID_AUTO, "write_cache", CTLFLAG_RW | CTLFLAG_MPSAFE, 1030e3a6d3a4SAlexander Motin &softc->write_cache, 0, "Enable disk write cache."); 10315f83aee5SSteven Hartland SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 10325f83aee5SSteven Hartland OID_AUTO, "sort_io_queue", CTLFLAG_RW | CTLFLAG_MPSAFE, 10335f83aee5SSteven Hartland &softc->sort_io_queue, 0, 10345f83aee5SSteven Hartland "Sort IO queue to try and optimise disk access patterns"); 1035e3a6d3a4SAlexander Motin #ifdef ADA_TEST_FAILURE 1036e3a6d3a4SAlexander Motin /* 1037e3a6d3a4SAlexander Motin * Add a 'door bell' sysctl which allows one to set it from userland 1038e3a6d3a4SAlexander Motin * and cause something bad to happen. For the moment, we only allow 1039e3a6d3a4SAlexander Motin * whacking the next read or write. 1040e3a6d3a4SAlexander Motin */ 1041e3a6d3a4SAlexander Motin SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 1042e3a6d3a4SAlexander Motin OID_AUTO, "force_read_error", CTLFLAG_RW | CTLFLAG_MPSAFE, 1043e3a6d3a4SAlexander Motin &softc->force_read_error, 0, 1044e3a6d3a4SAlexander Motin "Force a read error for the next N reads."); 1045e3a6d3a4SAlexander Motin SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 1046e3a6d3a4SAlexander Motin OID_AUTO, "force_write_error", CTLFLAG_RW | CTLFLAG_MPSAFE, 1047e3a6d3a4SAlexander Motin &softc->force_write_error, 0, 1048e3a6d3a4SAlexander Motin "Force a write error for the next N writes."); 1049e3a6d3a4SAlexander Motin SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 1050e3a6d3a4SAlexander Motin OID_AUTO, "periodic_read_error", CTLFLAG_RW | CTLFLAG_MPSAFE, 1051e3a6d3a4SAlexander Motin &softc->periodic_read_error, 0, 1052e3a6d3a4SAlexander Motin "Force a read error every N reads (don't set too low)."); 1053e3a6d3a4SAlexander Motin #endif 105452c9ce25SScott Long cam_periph_release(periph); 105552c9ce25SScott Long } 105652c9ce25SScott Long 1057416494d7SJustin T. Gibbs static int 1058416494d7SJustin T. Gibbs adagetattr(struct bio *bp) 1059416494d7SJustin T. Gibbs { 10606884b662SAlexander Motin int ret; 1061416494d7SJustin T. Gibbs struct cam_periph *periph; 1062416494d7SJustin T. Gibbs 1063416494d7SJustin T. Gibbs periph = (struct cam_periph *)bp->bio_disk->d_drv1; 10646884b662SAlexander Motin cam_periph_lock(periph); 1065416494d7SJustin T. Gibbs ret = xpt_getattr(bp->bio_data, bp->bio_length, bp->bio_attribute, 1066416494d7SJustin T. Gibbs periph->path); 10676884b662SAlexander Motin cam_periph_unlock(periph); 1068416494d7SJustin T. Gibbs if (ret == 0) 1069416494d7SJustin T. Gibbs bp->bio_completed = bp->bio_length; 1070416494d7SJustin T. Gibbs return ret; 1071416494d7SJustin T. Gibbs } 1072416494d7SJustin T. Gibbs 107352c9ce25SScott Long static cam_status 107452c9ce25SScott Long adaregister(struct cam_periph *periph, void *arg) 107552c9ce25SScott Long { 107652c9ce25SScott Long struct ada_softc *softc; 107752c9ce25SScott Long struct ccb_pathinq cpi; 107852c9ce25SScott Long struct ccb_getdev *cgd; 10790d307e09SAlexander Motin char announce_buf[80], buf1[32]; 108052c9ce25SScott Long struct disk_params *dp; 108152c9ce25SScott Long caddr_t match; 108252c9ce25SScott Long u_int maxio; 1083d3a460d3SAlexander Motin int legacy_id, quirks; 108452c9ce25SScott Long 108552c9ce25SScott Long cgd = (struct ccb_getdev *)arg; 108652c9ce25SScott Long if (cgd == NULL) { 108752c9ce25SScott Long printf("adaregister: no getdev CCB, can't register device\n"); 108852c9ce25SScott Long return(CAM_REQ_CMP_ERR); 108952c9ce25SScott Long } 109052c9ce25SScott Long 109152c9ce25SScott Long softc = (struct ada_softc *)malloc(sizeof(*softc), M_DEVBUF, 109252c9ce25SScott Long M_NOWAIT|M_ZERO); 109352c9ce25SScott Long 109452c9ce25SScott Long if (softc == NULL) { 109552c9ce25SScott Long printf("adaregister: Unable to probe new device. " 109652c9ce25SScott Long "Unable to allocate softc\n"); 109752c9ce25SScott Long return(CAM_REQ_CMP_ERR); 109852c9ce25SScott Long } 109952c9ce25SScott Long 110052c9ce25SScott Long bioq_init(&softc->bio_queue); 11011c80ec0aSAlexander Motin bioq_init(&softc->trim_queue); 110252c9ce25SScott Long 1103581b2e78SAlexander Motin if ((cgd->ident_data.capabilities1 & ATA_SUPPORT_DMA) && 1104cf2b9a5fSAlexander Motin (cgd->inq_flags & SID_DMA)) 110546f118feSAlexander Motin softc->flags |= ADA_FLAG_CAN_DMA; 11062e1eb332SMarius Strobl if (cgd->ident_data.support.command2 & ATA_SUPPORT_ADDRESS48) { 110752c9ce25SScott Long softc->flags |= ADA_FLAG_CAN_48BIT; 11082e1eb332SMarius Strobl if (cgd->inq_flags & SID_DMA48) 11092e1eb332SMarius Strobl softc->flags |= ADA_FLAG_CAN_DMA48; 11102e1eb332SMarius Strobl } 111152c9ce25SScott Long if (cgd->ident_data.support.command2 & ATA_SUPPORT_FLUSHCACHE) 111252c9ce25SScott Long softc->flags |= ADA_FLAG_CAN_FLUSHCACHE; 1113fd104c15SRebecca Cran if (cgd->ident_data.support.command1 & ATA_SUPPORT_POWERMGT) 1114fd104c15SRebecca Cran softc->flags |= ADA_FLAG_CAN_POWERMGT; 1115581b2e78SAlexander Motin if ((cgd->ident_data.satacapabilities & ATA_SUPPORT_NCQ) && 1116cf2b9a5fSAlexander Motin (cgd->inq_flags & SID_DMA) && (cgd->inq_flags & SID_CmdQue)) 111752c9ce25SScott Long softc->flags |= ADA_FLAG_CAN_NCQ; 1118581b2e78SAlexander Motin if ((cgd->ident_data.support_dsm & ATA_SUPPORT_DSM_TRIM) && 1119581b2e78SAlexander Motin (cgd->inq_flags & SID_DMA)) { 11201c80ec0aSAlexander Motin softc->flags |= ADA_FLAG_CAN_TRIM; 11211c80ec0aSAlexander Motin softc->trim_max_ranges = TRIM_MAX_RANGES; 11221c80ec0aSAlexander Motin if (cgd->ident_data.max_dsm_blocks != 0) { 11231c80ec0aSAlexander Motin softc->trim_max_ranges = 1124c213c551SSteven Hartland min(cgd->ident_data.max_dsm_blocks * 1125c213c551SSteven Hartland ATA_DSM_BLK_RANGES, softc->trim_max_ranges); 11261c80ec0aSAlexander Motin } 11271c80ec0aSAlexander Motin } 11281c80ec0aSAlexander Motin if (cgd->ident_data.support.command2 & ATA_SUPPORT_CFA) 11291c80ec0aSAlexander Motin softc->flags |= ADA_FLAG_CAN_CFA; 113052c9ce25SScott Long 113152c9ce25SScott Long periph->softc = softc; 113252c9ce25SScott Long 113352c9ce25SScott Long /* 113452c9ce25SScott Long * See if this device has any quirks. 113552c9ce25SScott Long */ 113630a4094fSAlexander Motin match = cam_quirkmatch((caddr_t)&cgd->ident_data, 113730a4094fSAlexander Motin (caddr_t)ada_quirk_table, 113830a4094fSAlexander Motin sizeof(ada_quirk_table)/sizeof(*ada_quirk_table), 113930a4094fSAlexander Motin sizeof(*ada_quirk_table), ata_identify_match); 114052c9ce25SScott Long if (match != NULL) 114152c9ce25SScott Long softc->quirks = ((struct ada_quirk_entry *)match)->quirks; 114252c9ce25SScott Long else 114352c9ce25SScott Long softc->quirks = ADA_Q_NONE; 114452c9ce25SScott Long 114552c9ce25SScott Long bzero(&cpi, sizeof(cpi)); 114683c5d981SAlexander Motin xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NONE); 114752c9ce25SScott Long cpi.ccb_h.func_code = XPT_PATH_INQ; 114852c9ce25SScott Long xpt_action((union ccb *)&cpi); 114952c9ce25SScott Long 115052c9ce25SScott Long TASK_INIT(&softc->sysctl_task, 0, adasysctlinit, periph); 115152c9ce25SScott Long 115252c9ce25SScott Long /* 115352c9ce25SScott Long * Register this media as a disk 115452c9ce25SScott Long */ 1155781338b6SAlexander Motin (void)cam_periph_hold(periph, PRIBIO); 1156edec59d9SAlexander Motin cam_periph_unlock(periph); 1157d3a460d3SAlexander Motin snprintf(announce_buf, sizeof(announce_buf), 1158d3a460d3SAlexander Motin "kern.cam.ada.%d.quirks", periph->unit_number); 1159d3a460d3SAlexander Motin quirks = softc->quirks; 1160d3a460d3SAlexander Motin TUNABLE_INT_FETCH(announce_buf, &quirks); 1161d3a460d3SAlexander Motin softc->quirks = quirks; 11621ed6aaf9SAlexander Motin softc->read_ahead = -1; 11631ed6aaf9SAlexander Motin snprintf(announce_buf, sizeof(announce_buf), 11641ed6aaf9SAlexander Motin "kern.cam.ada.%d.read_ahead", periph->unit_number); 11651ed6aaf9SAlexander Motin TUNABLE_INT_FETCH(announce_buf, &softc->read_ahead); 1166781338b6SAlexander Motin softc->write_cache = -1; 1167781338b6SAlexander Motin snprintf(announce_buf, sizeof(announce_buf), 1168781338b6SAlexander Motin "kern.cam.ada.%d.write_cache", periph->unit_number); 1169781338b6SAlexander Motin TUNABLE_INT_FETCH(announce_buf, &softc->write_cache); 117062cc3a63SSteven Hartland /* Disable queue sorting for non-rotational media by default. */ 117190edda31SSteven Hartland if (cgd->ident_data.media_rotation_rate == 1) 117290edda31SSteven Hartland softc->sort_io_queue = 0; 117390edda31SSteven Hartland else 11745f83aee5SSteven Hartland softc->sort_io_queue = -1; 1175c1bd46c2SAlexander Motin adagetparams(periph, cgd); 117652c9ce25SScott Long softc->disk = disk_alloc(); 1177b8b6b5d3SAlexander Motin softc->disk->d_devstat = devstat_new_entry(periph->periph_name, 1178b8b6b5d3SAlexander Motin periph->unit_number, softc->params.secsize, 1179b8b6b5d3SAlexander Motin DEVSTAT_ALL_SUPPORTED, 1180b8b6b5d3SAlexander Motin DEVSTAT_TYPE_DIRECT | 1181b8b6b5d3SAlexander Motin XPORT_DEVSTAT_TYPE(cpi.transport), 1182b8b6b5d3SAlexander Motin DEVSTAT_PRIORITY_DISK); 118352c9ce25SScott Long softc->disk->d_open = adaopen; 118452c9ce25SScott Long softc->disk->d_close = adaclose; 118552c9ce25SScott Long softc->disk->d_strategy = adastrategy; 1186416494d7SJustin T. Gibbs softc->disk->d_getattr = adagetattr; 118752c9ce25SScott Long softc->disk->d_dump = adadump; 11880ba1e4d0SKenneth D. Merry softc->disk->d_gone = adadiskgonecb; 118952c9ce25SScott Long softc->disk->d_name = "ada"; 119052c9ce25SScott Long softc->disk->d_drv1 = periph; 119152c9ce25SScott Long maxio = cpi.maxio; /* Honor max I/O size of SIM */ 119252c9ce25SScott Long if (maxio == 0) 119352c9ce25SScott Long maxio = DFLTPHYS; /* traditional default */ 119452c9ce25SScott Long else if (maxio > MAXPHYS) 119552c9ce25SScott Long maxio = MAXPHYS; /* for safety */ 11961c80ec0aSAlexander Motin if (softc->flags & ADA_FLAG_CAN_48BIT) 1197c1bd46c2SAlexander Motin maxio = min(maxio, 65536 * softc->params.secsize); 119852c9ce25SScott Long else /* 28bit ATA command limit */ 1199c1bd46c2SAlexander Motin maxio = min(maxio, 256 * softc->params.secsize); 120052c9ce25SScott Long softc->disk->d_maxsize = maxio; 120152c9ce25SScott Long softc->disk->d_unit = periph->unit_number; 120252c9ce25SScott Long softc->disk->d_flags = 0; 120352c9ce25SScott Long if (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) 120452c9ce25SScott Long softc->disk->d_flags |= DISKFLAG_CANFLUSHCACHE; 1205c213c551SSteven Hartland if (softc->flags & ADA_FLAG_CAN_TRIM) { 12061c80ec0aSAlexander Motin softc->disk->d_flags |= DISKFLAG_CANDELETE; 12079fe9ba5bSSteven Hartland softc->disk->d_delmaxsize = softc->params.secsize * 12089fe9ba5bSSteven Hartland ATA_DSM_RANGE_MAX * 12099fe9ba5bSSteven Hartland softc->trim_max_ranges; 1210c213c551SSteven Hartland } else if ((softc->flags & ADA_FLAG_CAN_CFA) && 1211c213c551SSteven Hartland !(softc->flags & ADA_FLAG_CAN_48BIT)) { 1212c213c551SSteven Hartland softc->disk->d_flags |= DISKFLAG_CANDELETE; 12139fe9ba5bSSteven Hartland softc->disk->d_delmaxsize = 256 * softc->params.secsize; 12149fe9ba5bSSteven Hartland } else 12159fe9ba5bSSteven Hartland softc->disk->d_delmaxsize = maxio; 1216abc1e60eSKonstantin Belousov if ((cpi.hba_misc & PIM_UNMAPPED) != 0) 1217abc1e60eSKonstantin Belousov softc->disk->d_flags |= DISKFLAG_UNMAPPED_BIO; 121865cb6238SNathan Whitehorn strlcpy(softc->disk->d_descr, cgd->ident_data.model, 121965cb6238SNathan Whitehorn MIN(sizeof(softc->disk->d_descr), sizeof(cgd->ident_data.model))); 1220d50aaa6dSAndriy Gapon strlcpy(softc->disk->d_ident, cgd->ident_data.serial, 1221d50aaa6dSAndriy Gapon MIN(sizeof(softc->disk->d_ident), sizeof(cgd->ident_data.serial))); 12228edcf694SAlexander Motin softc->disk->d_hba_vendor = cpi.hba_vendor; 12238edcf694SAlexander Motin softc->disk->d_hba_device = cpi.hba_device; 12248edcf694SAlexander Motin softc->disk->d_hba_subvendor = cpi.hba_subvendor; 12258edcf694SAlexander Motin softc->disk->d_hba_subdevice = cpi.hba_subdevice; 122652c9ce25SScott Long 122752c9ce25SScott Long softc->disk->d_sectorsize = softc->params.secsize; 1228c1bd46c2SAlexander Motin softc->disk->d_mediasize = (off_t)softc->params.sectors * 1229c1bd46c2SAlexander Motin softc->params.secsize; 1230ce8332d4SAlexander Motin if (ata_physical_sector_size(&cgd->ident_data) != 1231ce8332d4SAlexander Motin softc->params.secsize) { 1232ce8332d4SAlexander Motin softc->disk->d_stripesize = 1233ce8332d4SAlexander Motin ata_physical_sector_size(&cgd->ident_data); 1234ce8332d4SAlexander Motin softc->disk->d_stripeoffset = (softc->disk->d_stripesize - 1235ce8332d4SAlexander Motin ata_logical_sector_offset(&cgd->ident_data)) % 1236ce8332d4SAlexander Motin softc->disk->d_stripesize; 1237d3a460d3SAlexander Motin } else if (softc->quirks & ADA_Q_4K) { 1238d3a460d3SAlexander Motin softc->disk->d_stripesize = 4096; 1239d3a460d3SAlexander Motin softc->disk->d_stripeoffset = 0; 1240ce8332d4SAlexander Motin } 124152c9ce25SScott Long softc->disk->d_fwsectors = softc->params.secs_per_track; 124252c9ce25SScott Long softc->disk->d_fwheads = softc->params.heads; 12434461491bSMarius Strobl ata_disk_firmware_geom_adjust(softc->disk); 124452c9ce25SScott Long 12450d307e09SAlexander Motin if (ada_legacy_aliases) { 12460d307e09SAlexander Motin #ifdef ATA_STATIC_ID 12470d307e09SAlexander Motin legacy_id = xpt_path_legacy_ata_id(periph->path); 12480d307e09SAlexander Motin #else 12490d307e09SAlexander Motin legacy_id = softc->disk->d_unit; 12500d307e09SAlexander Motin #endif 12510d307e09SAlexander Motin if (legacy_id >= 0) { 12520d307e09SAlexander Motin snprintf(announce_buf, sizeof(announce_buf), 12530d307e09SAlexander Motin "kern.devalias.%s%d", 12540d307e09SAlexander Motin softc->disk->d_name, softc->disk->d_unit); 12550d307e09SAlexander Motin snprintf(buf1, sizeof(buf1), 12560d307e09SAlexander Motin "ad%d", legacy_id); 12570d307e09SAlexander Motin setenv(announce_buf, buf1); 12580d307e09SAlexander Motin } 12590d307e09SAlexander Motin } else 12600d307e09SAlexander Motin legacy_id = -1; 12610ba1e4d0SKenneth D. Merry /* 12620ba1e4d0SKenneth D. Merry * Acquire a reference to the periph before we register with GEOM. 12630ba1e4d0SKenneth D. Merry * We'll release this reference once GEOM calls us back (via 12640ba1e4d0SKenneth D. Merry * adadiskgonecb()) telling us that our provider has been freed. 12650ba1e4d0SKenneth D. Merry */ 12660ba1e4d0SKenneth D. Merry if (cam_periph_acquire(periph) != CAM_REQ_CMP) { 12670ba1e4d0SKenneth D. Merry xpt_print(periph->path, "%s: lost periph during " 12680ba1e4d0SKenneth D. Merry "registration!\n", __func__); 12690ba1e4d0SKenneth D. Merry cam_periph_lock(periph); 12700ba1e4d0SKenneth D. Merry return (CAM_REQ_CMP_ERR); 12710ba1e4d0SKenneth D. Merry } 127252c9ce25SScott Long disk_create(softc->disk, DISK_VERSION); 1273edec59d9SAlexander Motin cam_periph_lock(periph); 1274781338b6SAlexander Motin cam_periph_unhold(periph); 127552c9ce25SScott Long 127652c9ce25SScott Long dp = &softc->params; 127752c9ce25SScott Long snprintf(announce_buf, sizeof(announce_buf), 127852c9ce25SScott Long "%juMB (%ju %u byte sectors: %dH %dS/T %dC)", 127952c9ce25SScott Long (uintmax_t)(((uintmax_t)dp->secsize * 128052c9ce25SScott Long dp->sectors) / (1024*1024)), 128152c9ce25SScott Long (uintmax_t)dp->sectors, 128252c9ce25SScott Long dp->secsize, dp->heads, 128352c9ce25SScott Long dp->secs_per_track, dp->cylinders); 128452c9ce25SScott Long xpt_announce_periph(periph, announce_buf); 1285*6fb5c84eSSteven Hartland xpt_announce_quirks(periph, softc->quirks, ADA_Q_BIT_STRING); 12860d307e09SAlexander Motin if (legacy_id >= 0) 12870d307e09SAlexander Motin printf("%s%d: Previously was known as ad%d\n", 12880d307e09SAlexander Motin periph->periph_name, periph->unit_number, legacy_id); 1289e3a6d3a4SAlexander Motin 1290e3a6d3a4SAlexander Motin /* 1291e3a6d3a4SAlexander Motin * Create our sysctl variables, now that we know 1292e3a6d3a4SAlexander Motin * we have successfully attached. 1293e3a6d3a4SAlexander Motin */ 1294e3a6d3a4SAlexander Motin cam_periph_acquire(periph); 1295e3a6d3a4SAlexander Motin taskqueue_enqueue(taskqueue_thread, &softc->sysctl_task); 1296e3a6d3a4SAlexander Motin 129752c9ce25SScott Long /* 129852c9ce25SScott Long * Add async callbacks for bus reset and 129952c9ce25SScott Long * bus device reset calls. I don't bother 130052c9ce25SScott Long * checking if this fails as, in most cases, 130152c9ce25SScott Long * the system will function just fine without 130252c9ce25SScott Long * them and the only alternative would be to 130352c9ce25SScott Long * not attach the device on failure. 130452c9ce25SScott Long */ 13053089bb2eSAlexander Motin xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE | 1306581b2e78SAlexander Motin AC_GETDEV_CHANGED | AC_ADVINFO_CHANGED, 1307581b2e78SAlexander Motin adaasync, periph, periph->path); 130852c9ce25SScott Long 130952c9ce25SScott Long /* 131052c9ce25SScott Long * Schedule a periodic event to occasionally send an 131152c9ce25SScott Long * ordered tag to a device. 131252c9ce25SScott Long */ 131352c9ce25SScott Long callout_init_mtx(&softc->sendordered_c, periph->sim->mtx, 0); 131452c9ce25SScott Long callout_reset(&softc->sendordered_c, 131547bb9643SAlexander Motin (ada_default_timeout * hz) / ADA_ORDEREDTAG_INTERVAL, 131652c9ce25SScott Long adasendorderedtag, softc); 131752c9ce25SScott Long 13181ed6aaf9SAlexander Motin if (ADA_RA >= 0 && 13191ed6aaf9SAlexander Motin cgd->ident_data.support.command1 & ATA_SUPPORT_LOOKAHEAD) { 13201ed6aaf9SAlexander Motin softc->state = ADA_STATE_RAHEAD; 13211ed6aaf9SAlexander Motin cam_periph_acquire(periph); 13221ed6aaf9SAlexander Motin xpt_schedule(periph, CAM_PRIORITY_DEV); 13231ed6aaf9SAlexander Motin } else if (ADA_WC >= 0 && 1324f513d14cSAlexander Motin cgd->ident_data.support.command1 & ATA_SUPPORT_WRITECACHE) { 1325f513d14cSAlexander Motin softc->state = ADA_STATE_WCACHE; 1326f513d14cSAlexander Motin cam_periph_acquire(periph); 1327f513d14cSAlexander Motin xpt_schedule(periph, CAM_PRIORITY_DEV); 1328f513d14cSAlexander Motin } else 1329f513d14cSAlexander Motin softc->state = ADA_STATE_NORMAL; 1330f513d14cSAlexander Motin 133152c9ce25SScott Long return(CAM_REQ_CMP); 133252c9ce25SScott Long } 133352c9ce25SScott Long 133452c9ce25SScott Long static void 133552c9ce25SScott Long adastart(struct cam_periph *periph, union ccb *start_ccb) 133652c9ce25SScott Long { 133746f118feSAlexander Motin struct ada_softc *softc = (struct ada_softc *)periph->softc; 133846f118feSAlexander Motin struct ccb_ataio *ataio = &start_ccb->ataio; 133952c9ce25SScott Long 1340fddde2b8SAlexander Motin CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("adastart\n")); 1341fddde2b8SAlexander Motin 134252c9ce25SScott Long switch (softc->state) { 134352c9ce25SScott Long case ADA_STATE_NORMAL: 134452c9ce25SScott Long { 134552c9ce25SScott Long struct bio *bp; 13461c80ec0aSAlexander Motin u_int8_t tag_code; 134752c9ce25SScott Long 13481c80ec0aSAlexander Motin /* Execute immediate CCB if waiting. */ 134952c9ce25SScott Long if (periph->immediate_priority <= periph->pinfo.priority) { 1350fddde2b8SAlexander Motin CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 135152c9ce25SScott Long ("queuing for immediate ccb\n")); 135252c9ce25SScott Long start_ccb->ccb_h.ccb_state = ADA_CCB_WAITING; 135352c9ce25SScott Long SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, 135452c9ce25SScott Long periph_links.sle); 135552c9ce25SScott Long periph->immediate_priority = CAM_PRIORITY_NONE; 135652c9ce25SScott Long wakeup(&periph->ccb_list); 13571c80ec0aSAlexander Motin /* Have more work to do, so ensure we stay scheduled */ 13581c80ec0aSAlexander Motin adaschedule(periph); 13591c80ec0aSAlexander Motin break; 13601c80ec0aSAlexander Motin } 13611c80ec0aSAlexander Motin /* Run TRIM if not running yet. */ 13621c80ec0aSAlexander Motin if (!softc->trim_running && 13631c80ec0aSAlexander Motin (bp = bioq_first(&softc->trim_queue)) != 0) { 13641c80ec0aSAlexander Motin struct trim_request *req = &softc->trim_req; 13651c80ec0aSAlexander Motin struct bio *bp1; 136637ddbd16SAlexander Motin uint64_t lastlba = (uint64_t)-1; 136737ddbd16SAlexander Motin int bps = 0, c, lastcount = 0, off, ranges = 0; 136852c9ce25SScott Long 13691c80ec0aSAlexander Motin softc->trim_running = 1; 13701c80ec0aSAlexander Motin bzero(req, sizeof(*req)); 13711c80ec0aSAlexander Motin bp1 = bp; 13721c80ec0aSAlexander Motin do { 13731c80ec0aSAlexander Motin uint64_t lba = bp1->bio_pblkno; 13741c80ec0aSAlexander Motin int count = bp1->bio_bcount / 13751c80ec0aSAlexander Motin softc->params.secsize; 13761c80ec0aSAlexander Motin 13771c80ec0aSAlexander Motin bioq_remove(&softc->trim_queue, bp1); 13781c80ec0aSAlexander Motin 137937ddbd16SAlexander Motin /* Try to extend the previous range. */ 138037ddbd16SAlexander Motin if (lba == lastlba) { 1381c213c551SSteven Hartland c = min(count, ATA_DSM_RANGE_MAX - lastcount); 138237ddbd16SAlexander Motin lastcount += c; 1383c213c551SSteven Hartland off = (ranges - 1) * ATA_DSM_RANGE_SIZE; 138437ddbd16SAlexander Motin req->data[off + 6] = lastcount & 0xff; 138537ddbd16SAlexander Motin req->data[off + 7] = 138637ddbd16SAlexander Motin (lastcount >> 8) & 0xff; 138737ddbd16SAlexander Motin count -= c; 138837ddbd16SAlexander Motin lba += c; 138937ddbd16SAlexander Motin } 139037ddbd16SAlexander Motin 139137ddbd16SAlexander Motin while (count > 0) { 1392c213c551SSteven Hartland c = min(count, ATA_DSM_RANGE_MAX); 1393c213c551SSteven Hartland off = ranges * ATA_DSM_RANGE_SIZE; 13941c80ec0aSAlexander Motin req->data[off + 0] = lba & 0xff; 13951c80ec0aSAlexander Motin req->data[off + 1] = (lba >> 8) & 0xff; 13961c80ec0aSAlexander Motin req->data[off + 2] = (lba >> 16) & 0xff; 13971c80ec0aSAlexander Motin req->data[off + 3] = (lba >> 24) & 0xff; 13981c80ec0aSAlexander Motin req->data[off + 4] = (lba >> 32) & 0xff; 13991c80ec0aSAlexander Motin req->data[off + 5] = (lba >> 40) & 0xff; 14001c80ec0aSAlexander Motin req->data[off + 6] = c & 0xff; 14011c80ec0aSAlexander Motin req->data[off + 7] = (c >> 8) & 0xff; 14021c80ec0aSAlexander Motin lba += c; 14031c80ec0aSAlexander Motin count -= c; 140437ddbd16SAlexander Motin lastcount = c; 14051c80ec0aSAlexander Motin ranges++; 1406c213c551SSteven Hartland /* 1407c213c551SSteven Hartland * Its the caller's responsibility to ensure the 1408c213c551SSteven Hartland * request will fit so we don't need to check for 1409c213c551SSteven Hartland * overrun here 1410c213c551SSteven Hartland */ 14111c80ec0aSAlexander Motin } 141237ddbd16SAlexander Motin lastlba = lba; 14131c80ec0aSAlexander Motin req->bps[bps++] = bp1; 14141c80ec0aSAlexander Motin bp1 = bioq_first(&softc->trim_queue); 141537ddbd16SAlexander Motin if (bps >= TRIM_MAX_BIOS || 141637ddbd16SAlexander Motin bp1 == NULL || 14171c80ec0aSAlexander Motin bp1->bio_bcount / softc->params.secsize > 1418c213c551SSteven Hartland (softc->trim_max_ranges - ranges) * 1419c213c551SSteven Hartland ATA_DSM_RANGE_MAX) 14201c80ec0aSAlexander Motin break; 14211c80ec0aSAlexander Motin } while (1); 14221c80ec0aSAlexander Motin cam_fill_ataio(ataio, 14231c80ec0aSAlexander Motin ada_retry_count, 14241c80ec0aSAlexander Motin adadone, 14251c80ec0aSAlexander Motin CAM_DIR_OUT, 14261c80ec0aSAlexander Motin 0, 14271c80ec0aSAlexander Motin req->data, 1428c213c551SSteven Hartland ((ranges + ATA_DSM_BLK_RANGES - 1) / 1429c213c551SSteven Hartland ATA_DSM_BLK_RANGES) * ATA_DSM_BLK_SIZE, 14301c80ec0aSAlexander Motin ada_default_timeout * 1000); 14311c80ec0aSAlexander Motin ata_48bit_cmd(ataio, ATA_DATA_SET_MANAGEMENT, 1432c213c551SSteven Hartland ATA_DSM_TRIM, 0, (ranges + ATA_DSM_BLK_RANGES - 1433c213c551SSteven Hartland 1) / ATA_DSM_BLK_RANGES); 14341c80ec0aSAlexander Motin start_ccb->ccb_h.ccb_state = ADA_CCB_TRIM; 14351c80ec0aSAlexander Motin goto out; 14361c80ec0aSAlexander Motin } 14371c80ec0aSAlexander Motin /* Run regular command. */ 14381c80ec0aSAlexander Motin bp = bioq_first(&softc->bio_queue); 14391c80ec0aSAlexander Motin if (bp == NULL) { 14401c80ec0aSAlexander Motin xpt_release_ccb(start_ccb); 14411c80ec0aSAlexander Motin break; 14421c80ec0aSAlexander Motin } 144352c9ce25SScott Long bioq_remove(&softc->bio_queue, bp); 144452c9ce25SScott Long 1445f03f7a0cSJustin T. Gibbs if ((bp->bio_flags & BIO_ORDERED) != 0 1446f03f7a0cSJustin T. Gibbs || (softc->flags & ADA_FLAG_NEED_OTAG) != 0) { 144752c9ce25SScott Long softc->flags &= ~ADA_FLAG_NEED_OTAG; 144852c9ce25SScott Long softc->ordered_tag_count++; 144946f118feSAlexander Motin tag_code = 0; 145052c9ce25SScott Long } else { 145146f118feSAlexander Motin tag_code = 1; 145252c9ce25SScott Long } 145352c9ce25SScott Long switch (bp->bio_cmd) { 145452c9ce25SScott Long case BIO_READ: 145552c9ce25SScott Long case BIO_WRITE: 145652c9ce25SScott Long { 145752c9ce25SScott Long uint64_t lba = bp->bio_pblkno; 145852c9ce25SScott Long uint16_t count = bp->bio_bcount / softc->params.secsize; 1459e3a6d3a4SAlexander Motin #ifdef ADA_TEST_FAILURE 1460e3a6d3a4SAlexander Motin int fail = 0; 146152c9ce25SScott Long 1462e3a6d3a4SAlexander Motin /* 1463e3a6d3a4SAlexander Motin * Support the failure ioctls. If the command is a 1464e3a6d3a4SAlexander Motin * read, and there are pending forced read errors, or 1465e3a6d3a4SAlexander Motin * if a write and pending write errors, then fail this 1466e3a6d3a4SAlexander Motin * operation with EIO. This is useful for testing 1467e3a6d3a4SAlexander Motin * purposes. Also, support having every Nth read fail. 1468e3a6d3a4SAlexander Motin * 1469e3a6d3a4SAlexander Motin * This is a rather blunt tool. 1470e3a6d3a4SAlexander Motin */ 1471e3a6d3a4SAlexander Motin if (bp->bio_cmd == BIO_READ) { 1472e3a6d3a4SAlexander Motin if (softc->force_read_error) { 1473e3a6d3a4SAlexander Motin softc->force_read_error--; 1474e3a6d3a4SAlexander Motin fail = 1; 1475e3a6d3a4SAlexander Motin } 1476e3a6d3a4SAlexander Motin if (softc->periodic_read_error > 0) { 1477e3a6d3a4SAlexander Motin if (++softc->periodic_read_count >= 1478e3a6d3a4SAlexander Motin softc->periodic_read_error) { 1479e3a6d3a4SAlexander Motin softc->periodic_read_count = 0; 1480e3a6d3a4SAlexander Motin fail = 1; 1481e3a6d3a4SAlexander Motin } 1482e3a6d3a4SAlexander Motin } 1483e3a6d3a4SAlexander Motin } else { 1484e3a6d3a4SAlexander Motin if (softc->force_write_error) { 1485e3a6d3a4SAlexander Motin softc->force_write_error--; 1486e3a6d3a4SAlexander Motin fail = 1; 1487e3a6d3a4SAlexander Motin } 1488e3a6d3a4SAlexander Motin } 1489e3a6d3a4SAlexander Motin if (fail) { 1490e3a6d3a4SAlexander Motin bp->bio_error = EIO; 1491e3a6d3a4SAlexander Motin bp->bio_flags |= BIO_ERROR; 1492e3a6d3a4SAlexander Motin biodone(bp); 1493e3a6d3a4SAlexander Motin xpt_release_ccb(start_ccb); 1494e3a6d3a4SAlexander Motin adaschedule(periph); 1495e3a6d3a4SAlexander Motin return; 1496e3a6d3a4SAlexander Motin } 1497e3a6d3a4SAlexander Motin #endif 1498abc1e60eSKonstantin Belousov KASSERT((bp->bio_flags & BIO_UNMAPPED) == 0 || 1499abc1e60eSKonstantin Belousov round_page(bp->bio_bcount + bp->bio_ma_offset) / 1500abc1e60eSKonstantin Belousov PAGE_SIZE == bp->bio_ma_n, 1501abc1e60eSKonstantin Belousov ("Short bio %p", bp)); 150252c9ce25SScott Long cam_fill_ataio(ataio, 150352c9ce25SScott Long ada_retry_count, 150452c9ce25SScott Long adadone, 1505abc1e60eSKonstantin Belousov (bp->bio_cmd == BIO_READ ? CAM_DIR_IN : 1506abc1e60eSKonstantin Belousov CAM_DIR_OUT) | ((bp->bio_flags & BIO_UNMAPPED) 1507abc1e60eSKonstantin Belousov != 0 ? CAM_DATA_BIO : 0), 150852c9ce25SScott Long tag_code, 1509abc1e60eSKonstantin Belousov ((bp->bio_flags & BIO_UNMAPPED) != 0) ? (void *)bp : 151052c9ce25SScott Long bp->bio_data, 151152c9ce25SScott Long bp->bio_bcount, 151252c9ce25SScott Long ada_default_timeout*1000); 151352c9ce25SScott Long 151446f118feSAlexander Motin if ((softc->flags & ADA_FLAG_CAN_NCQ) && tag_code) { 151552c9ce25SScott Long if (bp->bio_cmd == BIO_READ) { 151652c9ce25SScott Long ata_ncq_cmd(ataio, ATA_READ_FPDMA_QUEUED, 151752c9ce25SScott Long lba, count); 151852c9ce25SScott Long } else { 151952c9ce25SScott Long ata_ncq_cmd(ataio, ATA_WRITE_FPDMA_QUEUED, 152052c9ce25SScott Long lba, count); 152152c9ce25SScott Long } 152252c9ce25SScott Long } else if ((softc->flags & ADA_FLAG_CAN_48BIT) && 152352c9ce25SScott Long (lba + count >= ATA_MAX_28BIT_LBA || 152446f118feSAlexander Motin count > 256)) { 15252e1eb332SMarius Strobl if (softc->flags & ADA_FLAG_CAN_DMA48) { 152652c9ce25SScott Long if (bp->bio_cmd == BIO_READ) { 152752c9ce25SScott Long ata_48bit_cmd(ataio, ATA_READ_DMA48, 152852c9ce25SScott Long 0, lba, count); 152952c9ce25SScott Long } else { 153052c9ce25SScott Long ata_48bit_cmd(ataio, ATA_WRITE_DMA48, 153152c9ce25SScott Long 0, lba, count); 153252c9ce25SScott Long } 153352c9ce25SScott Long } else { 153452c9ce25SScott Long if (bp->bio_cmd == BIO_READ) { 153546f118feSAlexander Motin ata_48bit_cmd(ataio, ATA_READ_MUL48, 153646f118feSAlexander Motin 0, lba, count); 153746f118feSAlexander Motin } else { 153846f118feSAlexander Motin ata_48bit_cmd(ataio, ATA_WRITE_MUL48, 153946f118feSAlexander Motin 0, lba, count); 154046f118feSAlexander Motin } 154146f118feSAlexander Motin } 154246f118feSAlexander Motin } else { 154346f118feSAlexander Motin if (count == 256) 154446f118feSAlexander Motin count = 0; 154546f118feSAlexander Motin if (softc->flags & ADA_FLAG_CAN_DMA) { 154646f118feSAlexander Motin if (bp->bio_cmd == BIO_READ) { 15477606b445SAlexander Motin ata_28bit_cmd(ataio, ATA_READ_DMA, 154852c9ce25SScott Long 0, lba, count); 154952c9ce25SScott Long } else { 15507606b445SAlexander Motin ata_28bit_cmd(ataio, ATA_WRITE_DMA, 155152c9ce25SScott Long 0, lba, count); 155252c9ce25SScott Long } 155346f118feSAlexander Motin } else { 155446f118feSAlexander Motin if (bp->bio_cmd == BIO_READ) { 155546f118feSAlexander Motin ata_28bit_cmd(ataio, ATA_READ_MUL, 155646f118feSAlexander Motin 0, lba, count); 155746f118feSAlexander Motin } else { 155846f118feSAlexander Motin ata_28bit_cmd(ataio, ATA_WRITE_MUL, 155946f118feSAlexander Motin 0, lba, count); 156046f118feSAlexander Motin } 156146f118feSAlexander Motin } 156252c9ce25SScott Long } 156352c9ce25SScott Long break; 15641c80ec0aSAlexander Motin } 15651c80ec0aSAlexander Motin case BIO_DELETE: 15661c80ec0aSAlexander Motin { 15671c80ec0aSAlexander Motin uint64_t lba = bp->bio_pblkno; 15681c80ec0aSAlexander Motin uint16_t count = bp->bio_bcount / softc->params.secsize; 15691c80ec0aSAlexander Motin 15701c80ec0aSAlexander Motin cam_fill_ataio(ataio, 15711c80ec0aSAlexander Motin ada_retry_count, 15721c80ec0aSAlexander Motin adadone, 15731c80ec0aSAlexander Motin CAM_DIR_NONE, 15741c80ec0aSAlexander Motin 0, 15751c80ec0aSAlexander Motin NULL, 15761c80ec0aSAlexander Motin 0, 15771c80ec0aSAlexander Motin ada_default_timeout*1000); 15781c80ec0aSAlexander Motin 15791c80ec0aSAlexander Motin if (count >= 256) 15801c80ec0aSAlexander Motin count = 0; 15811c80ec0aSAlexander Motin ata_28bit_cmd(ataio, ATA_CFA_ERASE, 0, lba, count); 15821c80ec0aSAlexander Motin break; 15831c80ec0aSAlexander Motin } 158452c9ce25SScott Long case BIO_FLUSH: 158552c9ce25SScott Long cam_fill_ataio(ataio, 158652c9ce25SScott Long 1, 158752c9ce25SScott Long adadone, 158852c9ce25SScott Long CAM_DIR_NONE, 158946f118feSAlexander Motin 0, 159052c9ce25SScott Long NULL, 159152c9ce25SScott Long 0, 159252c9ce25SScott Long ada_default_timeout*1000); 159352c9ce25SScott Long 159452c9ce25SScott Long if (softc->flags & ADA_FLAG_CAN_48BIT) 159552c9ce25SScott Long ata_48bit_cmd(ataio, ATA_FLUSHCACHE48, 0, 0, 0); 159652c9ce25SScott Long else 15977606b445SAlexander Motin ata_28bit_cmd(ataio, ATA_FLUSHCACHE, 0, 0, 0); 159852c9ce25SScott Long break; 159952c9ce25SScott Long } 160052c9ce25SScott Long start_ccb->ccb_h.ccb_state = ADA_CCB_BUFFER_IO; 16011c80ec0aSAlexander Motin out: 160252c9ce25SScott Long start_ccb->ccb_h.ccb_bp = bp; 1603c1bd46c2SAlexander Motin softc->outstanding_cmds++; 160452c9ce25SScott Long xpt_action(start_ccb); 160552c9ce25SScott Long 16061c80ec0aSAlexander Motin /* May have more work to do, so ensure we stay scheduled */ 16071c80ec0aSAlexander Motin adaschedule(periph); 160852c9ce25SScott Long break; 160952c9ce25SScott Long } 16101ed6aaf9SAlexander Motin case ADA_STATE_RAHEAD: 1611f513d14cSAlexander Motin case ADA_STATE_WCACHE: 1612f513d14cSAlexander Motin { 16137338ef1aSAlexander Motin if ((periph->flags & CAM_PERIPH_INVALID) != 0) { 16141ed6aaf9SAlexander Motin softc->state = ADA_STATE_NORMAL; 16151ed6aaf9SAlexander Motin xpt_release_ccb(start_ccb); 16161ed6aaf9SAlexander Motin cam_periph_release_locked(periph); 16171ed6aaf9SAlexander Motin return; 16181ed6aaf9SAlexander Motin } 16191ed6aaf9SAlexander Motin 1620f513d14cSAlexander Motin cam_fill_ataio(ataio, 1621f513d14cSAlexander Motin 1, 1622f513d14cSAlexander Motin adadone, 1623f513d14cSAlexander Motin CAM_DIR_NONE, 1624f513d14cSAlexander Motin 0, 1625f513d14cSAlexander Motin NULL, 1626f513d14cSAlexander Motin 0, 1627f513d14cSAlexander Motin ada_default_timeout*1000); 1628f513d14cSAlexander Motin 16291ed6aaf9SAlexander Motin if (softc->state == ADA_STATE_RAHEAD) { 16301ed6aaf9SAlexander Motin ata_28bit_cmd(ataio, ATA_SETFEATURES, ADA_RA ? 16311ed6aaf9SAlexander Motin ATA_SF_ENAB_RCACHE : ATA_SF_DIS_RCACHE, 0, 0); 16321ed6aaf9SAlexander Motin start_ccb->ccb_h.ccb_state = ADA_CCB_RAHEAD; 16331ed6aaf9SAlexander Motin } else { 16341ed6aaf9SAlexander Motin ata_28bit_cmd(ataio, ATA_SETFEATURES, ADA_WC ? 1635f513d14cSAlexander Motin ATA_SF_ENAB_WCACHE : ATA_SF_DIS_WCACHE, 0, 0); 1636f513d14cSAlexander Motin start_ccb->ccb_h.ccb_state = ADA_CCB_WCACHE; 16371ed6aaf9SAlexander Motin } 1638cccf4220SAlexander Motin start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE; 1639f513d14cSAlexander Motin xpt_action(start_ccb); 1640f513d14cSAlexander Motin break; 1641f513d14cSAlexander Motin } 164252c9ce25SScott Long } 164352c9ce25SScott Long } 164452c9ce25SScott Long 164552c9ce25SScott Long static void 164652c9ce25SScott Long adadone(struct cam_periph *periph, union ccb *done_ccb) 164752c9ce25SScott Long { 164852c9ce25SScott Long struct ada_softc *softc; 164952c9ce25SScott Long struct ccb_ataio *ataio; 16501ed6aaf9SAlexander Motin struct ccb_getdev *cgd; 1651cccf4220SAlexander Motin struct cam_path *path; 165252c9ce25SScott Long 165352c9ce25SScott Long softc = (struct ada_softc *)periph->softc; 165452c9ce25SScott Long ataio = &done_ccb->ataio; 1655cccf4220SAlexander Motin path = done_ccb->ccb_h.path; 1656fddde2b8SAlexander Motin 1657cccf4220SAlexander Motin CAM_DEBUG(path, CAM_DEBUG_TRACE, ("adadone\n")); 1658fddde2b8SAlexander Motin 165952c9ce25SScott Long switch (ataio->ccb_h.ccb_state & ADA_CCB_TYPE_MASK) { 166052c9ce25SScott Long case ADA_CCB_BUFFER_IO: 16611c80ec0aSAlexander Motin case ADA_CCB_TRIM: 166252c9ce25SScott Long { 166352c9ce25SScott Long struct bio *bp; 166452c9ce25SScott Long 166552c9ce25SScott Long bp = (struct bio *)done_ccb->ccb_h.ccb_bp; 166652c9ce25SScott Long if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 166752c9ce25SScott Long int error; 166852c9ce25SScott Long 166946f118feSAlexander Motin error = adaerror(done_ccb, 0, 0); 167052c9ce25SScott Long if (error == ERESTART) { 167146f118feSAlexander Motin /* A retry was scheduled, so just return. */ 167252c9ce25SScott Long return; 167352c9ce25SScott Long } 167452c9ce25SScott Long if (error != 0) { 167552c9ce25SScott Long bp->bio_error = error; 167652c9ce25SScott Long bp->bio_resid = bp->bio_bcount; 167752c9ce25SScott Long bp->bio_flags |= BIO_ERROR; 167852c9ce25SScott Long } else { 167952c9ce25SScott Long bp->bio_resid = ataio->resid; 168052c9ce25SScott Long bp->bio_error = 0; 168152c9ce25SScott Long if (bp->bio_resid != 0) 168252c9ce25SScott Long bp->bio_flags |= BIO_ERROR; 168352c9ce25SScott Long } 168452c9ce25SScott Long if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 1685cccf4220SAlexander Motin cam_release_devq(path, 168652c9ce25SScott Long /*relsim_flags*/0, 168752c9ce25SScott Long /*reduction*/0, 168852c9ce25SScott Long /*timeout*/0, 168952c9ce25SScott Long /*getcount_only*/0); 169052c9ce25SScott Long } else { 169152c9ce25SScott Long if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 169252c9ce25SScott Long panic("REQ_CMP with QFRZN"); 169352c9ce25SScott Long bp->bio_resid = ataio->resid; 169452c9ce25SScott Long if (ataio->resid > 0) 169552c9ce25SScott Long bp->bio_flags |= BIO_ERROR; 169652c9ce25SScott Long } 169752c9ce25SScott Long softc->outstanding_cmds--; 169852c9ce25SScott Long if (softc->outstanding_cmds == 0) 169952c9ce25SScott Long softc->flags |= ADA_FLAG_WENT_IDLE; 17001c80ec0aSAlexander Motin if ((ataio->ccb_h.ccb_state & ADA_CCB_TYPE_MASK) == 17011c80ec0aSAlexander Motin ADA_CCB_TRIM) { 17021c80ec0aSAlexander Motin struct trim_request *req = 17031c80ec0aSAlexander Motin (struct trim_request *)ataio->data_ptr; 17041c80ec0aSAlexander Motin int i; 170552c9ce25SScott Long 170637ddbd16SAlexander Motin for (i = 1; i < TRIM_MAX_BIOS && req->bps[i]; i++) { 17071c80ec0aSAlexander Motin struct bio *bp1 = req->bps[i]; 17081c80ec0aSAlexander Motin 17091c80ec0aSAlexander Motin bp1->bio_resid = bp->bio_resid; 17101c80ec0aSAlexander Motin bp1->bio_error = bp->bio_error; 17111c80ec0aSAlexander Motin if (bp->bio_flags & BIO_ERROR) 17121c80ec0aSAlexander Motin bp1->bio_flags |= BIO_ERROR; 17131c80ec0aSAlexander Motin biodone(bp1); 17141c80ec0aSAlexander Motin } 17151c80ec0aSAlexander Motin softc->trim_running = 0; 17161c80ec0aSAlexander Motin biodone(bp); 17171c80ec0aSAlexander Motin adaschedule(periph); 17181c80ec0aSAlexander Motin } else 171952c9ce25SScott Long biodone(bp); 172052c9ce25SScott Long break; 172152c9ce25SScott Long } 17221ed6aaf9SAlexander Motin case ADA_CCB_RAHEAD: 17231ed6aaf9SAlexander Motin { 17241ed6aaf9SAlexander Motin if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 17251ed6aaf9SAlexander Motin if (adaerror(done_ccb, 0, 0) == ERESTART) { 1726cccf4220SAlexander Motin out: 1727cccf4220SAlexander Motin /* Drop freeze taken due to CAM_DEV_QFREEZE */ 1728cccf4220SAlexander Motin cam_release_devq(path, 0, 0, 0, FALSE); 17291ed6aaf9SAlexander Motin return; 17301ed6aaf9SAlexander Motin } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 1731cccf4220SAlexander Motin cam_release_devq(path, 17321ed6aaf9SAlexander Motin /*relsim_flags*/0, 17331ed6aaf9SAlexander Motin /*reduction*/0, 17341ed6aaf9SAlexander Motin /*timeout*/0, 17351ed6aaf9SAlexander Motin /*getcount_only*/0); 17361ed6aaf9SAlexander Motin } 17371ed6aaf9SAlexander Motin } 17381ed6aaf9SAlexander Motin 17391ed6aaf9SAlexander Motin /* 17401ed6aaf9SAlexander Motin * Since our peripheral may be invalidated by an error 17411ed6aaf9SAlexander Motin * above or an external event, we must release our CCB 17421ed6aaf9SAlexander Motin * before releasing the reference on the peripheral. 17431ed6aaf9SAlexander Motin * The peripheral will only go away once the last reference 17441ed6aaf9SAlexander Motin * is removed, and we need it around for the CCB release 17451ed6aaf9SAlexander Motin * operation. 17461ed6aaf9SAlexander Motin */ 17471ed6aaf9SAlexander Motin cgd = (struct ccb_getdev *)done_ccb; 1748cccf4220SAlexander Motin xpt_setup_ccb(&cgd->ccb_h, path, CAM_PRIORITY_NORMAL); 17491ed6aaf9SAlexander Motin cgd->ccb_h.func_code = XPT_GDEV_TYPE; 17501ed6aaf9SAlexander Motin xpt_action((union ccb *)cgd); 17511ed6aaf9SAlexander Motin if (ADA_WC >= 0 && 17521ed6aaf9SAlexander Motin cgd->ident_data.support.command1 & ATA_SUPPORT_WRITECACHE) { 17531ed6aaf9SAlexander Motin softc->state = ADA_STATE_WCACHE; 17541ed6aaf9SAlexander Motin xpt_release_ccb(done_ccb); 17551ed6aaf9SAlexander Motin xpt_schedule(periph, CAM_PRIORITY_DEV); 1756cccf4220SAlexander Motin goto out; 17571ed6aaf9SAlexander Motin } 17581ed6aaf9SAlexander Motin softc->state = ADA_STATE_NORMAL; 17591ed6aaf9SAlexander Motin xpt_release_ccb(done_ccb); 1760cccf4220SAlexander Motin /* Drop freeze taken due to CAM_DEV_QFREEZE */ 1761cccf4220SAlexander Motin cam_release_devq(path, 0, 0, 0, FALSE); 17621ed6aaf9SAlexander Motin adaschedule(periph); 17631ed6aaf9SAlexander Motin cam_periph_release_locked(periph); 17641ed6aaf9SAlexander Motin return; 17651ed6aaf9SAlexander Motin } 1766f513d14cSAlexander Motin case ADA_CCB_WCACHE: 1767f513d14cSAlexander Motin { 1768f513d14cSAlexander Motin if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 1769f513d14cSAlexander Motin if (adaerror(done_ccb, 0, 0) == ERESTART) { 1770cccf4220SAlexander Motin goto out; 1771f513d14cSAlexander Motin } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 1772cccf4220SAlexander Motin cam_release_devq(path, 1773f513d14cSAlexander Motin /*relsim_flags*/0, 1774f513d14cSAlexander Motin /*reduction*/0, 1775f513d14cSAlexander Motin /*timeout*/0, 1776f513d14cSAlexander Motin /*getcount_only*/0); 1777f513d14cSAlexander Motin } 1778f513d14cSAlexander Motin } 1779f513d14cSAlexander Motin 1780f513d14cSAlexander Motin softc->state = ADA_STATE_NORMAL; 1781f513d14cSAlexander Motin /* 1782f513d14cSAlexander Motin * Since our peripheral may be invalidated by an error 1783f513d14cSAlexander Motin * above or an external event, we must release our CCB 1784f513d14cSAlexander Motin * before releasing the reference on the peripheral. 1785f513d14cSAlexander Motin * The peripheral will only go away once the last reference 1786f513d14cSAlexander Motin * is removed, and we need it around for the CCB release 1787f513d14cSAlexander Motin * operation. 1788f513d14cSAlexander Motin */ 1789f513d14cSAlexander Motin xpt_release_ccb(done_ccb); 1790cccf4220SAlexander Motin /* Drop freeze taken due to CAM_DEV_QFREEZE */ 1791cccf4220SAlexander Motin cam_release_devq(path, 0, 0, 0, FALSE); 1792f513d14cSAlexander Motin adaschedule(periph); 1793f513d14cSAlexander Motin cam_periph_release_locked(periph); 1794f513d14cSAlexander Motin return; 1795f513d14cSAlexander Motin } 179652c9ce25SScott Long case ADA_CCB_WAITING: 179752c9ce25SScott Long { 179852c9ce25SScott Long /* Caller will release the CCB */ 179952c9ce25SScott Long wakeup(&done_ccb->ccb_h.cbfcnp); 180052c9ce25SScott Long return; 180152c9ce25SScott Long } 180252c9ce25SScott Long case ADA_CCB_DUMP: 180352c9ce25SScott Long /* No-op. We're polling */ 180452c9ce25SScott Long return; 180552c9ce25SScott Long default: 180652c9ce25SScott Long break; 180752c9ce25SScott Long } 180852c9ce25SScott Long xpt_release_ccb(done_ccb); 180952c9ce25SScott Long } 181052c9ce25SScott Long 181152c9ce25SScott Long static int 181252c9ce25SScott Long adaerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) 181352c9ce25SScott Long { 181452c9ce25SScott Long 1815a9b8edb1SAlexander Motin return(cam_periph_error(ccb, cam_flags, sense_flags, NULL)); 181652c9ce25SScott Long } 181752c9ce25SScott Long 181852c9ce25SScott Long static void 1819c1bd46c2SAlexander Motin adagetparams(struct cam_periph *periph, struct ccb_getdev *cgd) 182052c9ce25SScott Long { 182152c9ce25SScott Long struct ada_softc *softc = (struct ada_softc *)periph->softc; 182252c9ce25SScott Long struct disk_params *dp = &softc->params; 182352c9ce25SScott Long u_int64_t lbasize48; 182452c9ce25SScott Long u_int32_t lbasize; 182552c9ce25SScott Long 1826c1bd46c2SAlexander Motin dp->secsize = ata_logical_sector_size(&cgd->ident_data); 182752c9ce25SScott Long if ((cgd->ident_data.atavalid & ATA_FLAG_54_58) && 182852c9ce25SScott Long cgd->ident_data.current_heads && cgd->ident_data.current_sectors) { 182952c9ce25SScott Long dp->heads = cgd->ident_data.current_heads; 183052c9ce25SScott Long dp->secs_per_track = cgd->ident_data.current_sectors; 183152c9ce25SScott Long dp->cylinders = cgd->ident_data.cylinders; 183252c9ce25SScott Long dp->sectors = (u_int32_t)cgd->ident_data.current_size_1 | 183352c9ce25SScott Long ((u_int32_t)cgd->ident_data.current_size_2 << 16); 183452c9ce25SScott Long } else { 183552c9ce25SScott Long dp->heads = cgd->ident_data.heads; 183652c9ce25SScott Long dp->secs_per_track = cgd->ident_data.sectors; 183752c9ce25SScott Long dp->cylinders = cgd->ident_data.cylinders; 183852c9ce25SScott Long dp->sectors = cgd->ident_data.cylinders * dp->heads * dp->secs_per_track; 183952c9ce25SScott Long } 184052c9ce25SScott Long lbasize = (u_int32_t)cgd->ident_data.lba_size_1 | 184152c9ce25SScott Long ((u_int32_t)cgd->ident_data.lba_size_2 << 16); 184252c9ce25SScott Long 184352c9ce25SScott Long /* use the 28bit LBA size if valid or bigger than the CHS mapping */ 184452c9ce25SScott Long if (cgd->ident_data.cylinders == 16383 || dp->sectors < lbasize) 184552c9ce25SScott Long dp->sectors = lbasize; 184652c9ce25SScott Long 184752c9ce25SScott Long /* use the 48bit LBA size if valid */ 184852c9ce25SScott Long lbasize48 = ((u_int64_t)cgd->ident_data.lba_size48_1) | 184952c9ce25SScott Long ((u_int64_t)cgd->ident_data.lba_size48_2 << 16) | 185052c9ce25SScott Long ((u_int64_t)cgd->ident_data.lba_size48_3 << 32) | 185152c9ce25SScott Long ((u_int64_t)cgd->ident_data.lba_size48_4 << 48); 185252c9ce25SScott Long if ((cgd->ident_data.support.command2 & ATA_SUPPORT_ADDRESS48) && 185352c9ce25SScott Long lbasize48 > ATA_MAX_28BIT_LBA) 185452c9ce25SScott Long dp->sectors = lbasize48; 185552c9ce25SScott Long } 185652c9ce25SScott Long 185752c9ce25SScott Long static void 185852c9ce25SScott Long adasendorderedtag(void *arg) 185952c9ce25SScott Long { 186052c9ce25SScott Long struct ada_softc *softc = arg; 186152c9ce25SScott Long 186252c9ce25SScott Long if (ada_send_ordered) { 186352c9ce25SScott Long if ((softc->ordered_tag_count == 0) 186452c9ce25SScott Long && ((softc->flags & ADA_FLAG_WENT_IDLE) == 0)) { 186552c9ce25SScott Long softc->flags |= ADA_FLAG_NEED_OTAG; 186652c9ce25SScott Long } 186752c9ce25SScott Long if (softc->outstanding_cmds > 0) 186852c9ce25SScott Long softc->flags &= ~ADA_FLAG_WENT_IDLE; 186952c9ce25SScott Long 187052c9ce25SScott Long softc->ordered_tag_count = 0; 187152c9ce25SScott Long } 187252c9ce25SScott Long /* Queue us up again */ 187352c9ce25SScott Long callout_reset(&softc->sendordered_c, 187447bb9643SAlexander Motin (ada_default_timeout * hz) / ADA_ORDEREDTAG_INTERVAL, 187552c9ce25SScott Long adasendorderedtag, softc); 187652c9ce25SScott Long } 187752c9ce25SScott Long 187852c9ce25SScott Long /* 187952c9ce25SScott Long * Step through all ADA peripheral drivers, and if the device is still open, 188052c9ce25SScott Long * sync the disk cache to physical media. 188152c9ce25SScott Long */ 188252c9ce25SScott Long static void 1883c3d0d168SAlexander Motin adaflush(void) 188452c9ce25SScott Long { 188552c9ce25SScott Long struct cam_periph *periph; 188652c9ce25SScott Long struct ada_softc *softc; 188709cfadbeSAlexander Motin union ccb *ccb; 18880191d9b3SAlexander Motin int error; 188952c9ce25SScott Long 1890f371c9e2SAlexander Motin CAM_PERIPH_FOREACH(periph, &adadriver) { 189121cc8587SAlexander Motin /* If we paniced with lock held - not recurse here. */ 189221cc8587SAlexander Motin if (cam_periph_owned(periph)) 189321cc8587SAlexander Motin continue; 189452c9ce25SScott Long cam_periph_lock(periph); 189552c9ce25SScott Long softc = (struct ada_softc *)periph->softc; 189652c9ce25SScott Long /* 189752c9ce25SScott Long * We only sync the cache if the drive is still open, and 189852c9ce25SScott Long * if the drive is capable of it.. 189952c9ce25SScott Long */ 190052c9ce25SScott Long if (((softc->flags & ADA_FLAG_OPEN) == 0) || 190152c9ce25SScott Long (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) == 0) { 190252c9ce25SScott Long cam_periph_unlock(periph); 190352c9ce25SScott Long continue; 190452c9ce25SScott Long } 190552c9ce25SScott Long 190609cfadbeSAlexander Motin ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 190709cfadbeSAlexander Motin cam_fill_ataio(&ccb->ataio, 19080191d9b3SAlexander Motin 0, 190952c9ce25SScott Long adadone, 191052c9ce25SScott Long CAM_DIR_NONE, 191152c9ce25SScott Long 0, 191252c9ce25SScott Long NULL, 191352c9ce25SScott Long 0, 191452c9ce25SScott Long ada_default_timeout*1000); 191552c9ce25SScott Long if (softc->flags & ADA_FLAG_CAN_48BIT) 191609cfadbeSAlexander Motin ata_48bit_cmd(&ccb->ataio, ATA_FLUSHCACHE48, 0, 0, 0); 191752c9ce25SScott Long else 191809cfadbeSAlexander Motin ata_28bit_cmd(&ccb->ataio, ATA_FLUSHCACHE, 0, 0, 0); 191952c9ce25SScott Long 192009cfadbeSAlexander Motin error = cam_periph_runccb(ccb, adaerror, /*cam_flags*/0, 192109cfadbeSAlexander Motin /*sense_flags*/ SF_NO_RECOVERY | SF_NO_RETRY, 192209cfadbeSAlexander Motin softc->disk->d_devstat); 19230191d9b3SAlexander Motin if (error != 0) 19240191d9b3SAlexander Motin xpt_print(periph->path, "Synchronize cache failed\n"); 1925d6794b70SAlexander Motin xpt_release_ccb(ccb); 192652c9ce25SScott Long cam_periph_unlock(periph); 192752c9ce25SScott Long } 1928c3d0d168SAlexander Motin } 1929fd104c15SRebecca Cran 1930c3d0d168SAlexander Motin static void 1931c3d0d168SAlexander Motin adaspindown(uint8_t cmd, int flags) 1932c3d0d168SAlexander Motin { 1933c3d0d168SAlexander Motin struct cam_periph *periph; 1934c3d0d168SAlexander Motin struct ada_softc *softc; 193509cfadbeSAlexander Motin union ccb *ccb; 19360191d9b3SAlexander Motin int error; 1937fd104c15SRebecca Cran 1938f371c9e2SAlexander Motin CAM_PERIPH_FOREACH(periph, &adadriver) { 1939fd104c15SRebecca Cran /* If we paniced with lock held - not recurse here. */ 1940fd104c15SRebecca Cran if (cam_periph_owned(periph)) 1941fd104c15SRebecca Cran continue; 1942fd104c15SRebecca Cran cam_periph_lock(periph); 1943fd104c15SRebecca Cran softc = (struct ada_softc *)periph->softc; 1944fd104c15SRebecca Cran /* 1945fd104c15SRebecca Cran * We only spin-down the drive if it is capable of it.. 1946fd104c15SRebecca Cran */ 1947fd104c15SRebecca Cran if ((softc->flags & ADA_FLAG_CAN_POWERMGT) == 0) { 1948fd104c15SRebecca Cran cam_periph_unlock(periph); 1949fd104c15SRebecca Cran continue; 1950fd104c15SRebecca Cran } 1951fd104c15SRebecca Cran 1952fd104c15SRebecca Cran if (bootverbose) 1953fd104c15SRebecca Cran xpt_print(periph->path, "spin-down\n"); 1954fd104c15SRebecca Cran 195509cfadbeSAlexander Motin ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 195609cfadbeSAlexander Motin cam_fill_ataio(&ccb->ataio, 19570191d9b3SAlexander Motin 0, 1958fd104c15SRebecca Cran adadone, 1959c3d0d168SAlexander Motin CAM_DIR_NONE | flags, 1960fd104c15SRebecca Cran 0, 1961fd104c15SRebecca Cran NULL, 1962fd104c15SRebecca Cran 0, 1963fd104c15SRebecca Cran ada_default_timeout*1000); 196409cfadbeSAlexander Motin ata_28bit_cmd(&ccb->ataio, cmd, 0, 0, 0); 1965fd104c15SRebecca Cran 196609cfadbeSAlexander Motin error = cam_periph_runccb(ccb, adaerror, /*cam_flags*/0, 196709cfadbeSAlexander Motin /*sense_flags*/ SF_NO_RECOVERY | SF_NO_RETRY, 196809cfadbeSAlexander Motin softc->disk->d_devstat); 19690191d9b3SAlexander Motin if (error != 0) 19700191d9b3SAlexander Motin xpt_print(periph->path, "Spin-down disk failed\n"); 1971d6794b70SAlexander Motin xpt_release_ccb(ccb); 1972fd104c15SRebecca Cran cam_periph_unlock(periph); 1973fd104c15SRebecca Cran } 197452c9ce25SScott Long } 197552c9ce25SScott Long 1976c3d0d168SAlexander Motin static void 1977c3d0d168SAlexander Motin adashutdown(void *arg, int howto) 1978c3d0d168SAlexander Motin { 1979c3d0d168SAlexander Motin 1980c3d0d168SAlexander Motin adaflush(); 1981c3d0d168SAlexander Motin if (ada_spindown_shutdown != 0 && 1982c3d0d168SAlexander Motin (howto & (RB_HALT | RB_POWEROFF)) != 0) 1983c3d0d168SAlexander Motin adaspindown(ATA_STANDBY_IMMEDIATE, 0); 1984c3d0d168SAlexander Motin } 1985c3d0d168SAlexander Motin 1986c3d0d168SAlexander Motin static void 1987c3d0d168SAlexander Motin adasuspend(void *arg) 1988c3d0d168SAlexander Motin { 1989c3d0d168SAlexander Motin 1990c3d0d168SAlexander Motin adaflush(); 1991c3d0d168SAlexander Motin if (ada_spindown_suspend != 0) 1992c3d0d168SAlexander Motin adaspindown(ATA_SLEEP, CAM_DEV_QFREEZE); 1993c3d0d168SAlexander Motin } 1994c3d0d168SAlexander Motin 1995c3d0d168SAlexander Motin static void 1996c3d0d168SAlexander Motin adaresume(void *arg) 1997c3d0d168SAlexander Motin { 1998c3d0d168SAlexander Motin struct cam_periph *periph; 1999c3d0d168SAlexander Motin struct ada_softc *softc; 2000c3d0d168SAlexander Motin 2001c3d0d168SAlexander Motin if (ada_spindown_suspend == 0) 2002c3d0d168SAlexander Motin return; 2003c3d0d168SAlexander Motin 2004f371c9e2SAlexander Motin CAM_PERIPH_FOREACH(periph, &adadriver) { 2005c3d0d168SAlexander Motin cam_periph_lock(periph); 2006c3d0d168SAlexander Motin softc = (struct ada_softc *)periph->softc; 2007c3d0d168SAlexander Motin /* 2008c3d0d168SAlexander Motin * We only spin-down the drive if it is capable of it.. 2009c3d0d168SAlexander Motin */ 2010c3d0d168SAlexander Motin if ((softc->flags & ADA_FLAG_CAN_POWERMGT) == 0) { 2011c3d0d168SAlexander Motin cam_periph_unlock(periph); 2012c3d0d168SAlexander Motin continue; 2013c3d0d168SAlexander Motin } 2014c3d0d168SAlexander Motin 2015c3d0d168SAlexander Motin if (bootverbose) 2016c3d0d168SAlexander Motin xpt_print(periph->path, "resume\n"); 2017c3d0d168SAlexander Motin 2018c3d0d168SAlexander Motin /* 2019c3d0d168SAlexander Motin * Drop freeze taken due to CAM_DEV_QFREEZE flag set on 2020c3d0d168SAlexander Motin * sleep request. 2021c3d0d168SAlexander Motin */ 2022c3d0d168SAlexander Motin cam_release_devq(periph->path, 2023c3d0d168SAlexander Motin /*relsim_flags*/0, 2024c3d0d168SAlexander Motin /*openings*/0, 2025c3d0d168SAlexander Motin /*timeout*/0, 2026c3d0d168SAlexander Motin /*getcount_only*/0); 2027c3d0d168SAlexander Motin 2028c3d0d168SAlexander Motin cam_periph_unlock(periph); 2029c3d0d168SAlexander Motin } 2030c3d0d168SAlexander Motin } 2031c3d0d168SAlexander Motin 203252c9ce25SScott Long #endif /* _KERNEL */ 2033