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" 310d307e09SAlexander Motin #include "opt_ata.h" 32e3a6d3a4SAlexander Motin 3352c9ce25SScott Long #include <sys/param.h> 3452c9ce25SScott Long 3552c9ce25SScott Long #ifdef _KERNEL 3652c9ce25SScott Long #include <sys/systm.h> 3752c9ce25SScott Long #include <sys/kernel.h> 3852c9ce25SScott Long #include <sys/bio.h> 3952c9ce25SScott Long #include <sys/sysctl.h> 4052c9ce25SScott Long #include <sys/taskqueue.h> 4152c9ce25SScott Long #include <sys/lock.h> 4252c9ce25SScott Long #include <sys/mutex.h> 4352c9ce25SScott Long #include <sys/conf.h> 4452c9ce25SScott Long #include <sys/devicestat.h> 4552c9ce25SScott Long #include <sys/eventhandler.h> 4652c9ce25SScott Long #include <sys/malloc.h> 4752c9ce25SScott Long #include <sys/cons.h> 48fd104c15SRebecca Cran #include <sys/reboot.h> 4952c9ce25SScott Long #include <geom/geom_disk.h> 5052c9ce25SScott Long #endif /* _KERNEL */ 5152c9ce25SScott Long 5252c9ce25SScott Long #ifndef _KERNEL 5352c9ce25SScott Long #include <stdio.h> 5452c9ce25SScott Long #include <string.h> 5552c9ce25SScott Long #endif /* _KERNEL */ 5652c9ce25SScott Long 5752c9ce25SScott Long #include <cam/cam.h> 5852c9ce25SScott Long #include <cam/cam_ccb.h> 5952c9ce25SScott Long #include <cam/cam_periph.h> 6052c9ce25SScott Long #include <cam/cam_xpt_periph.h> 6152c9ce25SScott Long #include <cam/cam_sim.h> 6252c9ce25SScott Long 6352c9ce25SScott Long #include <cam/ata/ata_all.h> 6452c9ce25SScott Long 654461491bSMarius Strobl #include <machine/md_var.h> /* geometry translation */ 664461491bSMarius Strobl 6752c9ce25SScott Long #ifdef _KERNEL 6852c9ce25SScott Long 6952c9ce25SScott Long #define ATA_MAX_28BIT_LBA 268435455UL 7052c9ce25SScott Long 7152c9ce25SScott Long typedef enum { 721ed6aaf9SAlexander Motin ADA_STATE_RAHEAD, 73f513d14cSAlexander Motin ADA_STATE_WCACHE, 741e637ba6SAlexander Motin ADA_STATE_NORMAL 7552c9ce25SScott Long } ada_state; 7652c9ce25SScott Long 7752c9ce25SScott Long typedef enum { 78*2e1eb332SMarius Strobl ADA_FLAG_PACK_INVALID = 0x0001, 79*2e1eb332SMarius Strobl ADA_FLAG_CAN_48BIT = 0x0002, 80*2e1eb332SMarius Strobl ADA_FLAG_CAN_FLUSHCACHE = 0x0004, 81*2e1eb332SMarius Strobl ADA_FLAG_CAN_NCQ = 0x0008, 82*2e1eb332SMarius Strobl ADA_FLAG_CAN_DMA = 0x0010, 83*2e1eb332SMarius Strobl ADA_FLAG_NEED_OTAG = 0x0020, 84*2e1eb332SMarius Strobl ADA_FLAG_WENT_IDLE = 0x0040, 85*2e1eb332SMarius Strobl ADA_FLAG_CAN_TRIM = 0x0080, 86*2e1eb332SMarius Strobl ADA_FLAG_OPEN = 0x0100, 87*2e1eb332SMarius Strobl ADA_FLAG_SCTX_INIT = 0x0200, 88*2e1eb332SMarius Strobl ADA_FLAG_CAN_CFA = 0x0400, 89*2e1eb332SMarius Strobl ADA_FLAG_CAN_POWERMGT = 0x0800, 90*2e1eb332SMarius Strobl ADA_FLAG_CAN_DMA48 = 0x1000 9152c9ce25SScott Long } ada_flags; 9252c9ce25SScott Long 9352c9ce25SScott Long typedef enum { 94d3a460d3SAlexander Motin ADA_Q_NONE = 0x00, 95d3a460d3SAlexander Motin ADA_Q_4K = 0x01, 9652c9ce25SScott Long } ada_quirks; 9752c9ce25SScott Long 9852c9ce25SScott Long typedef enum { 991ed6aaf9SAlexander Motin ADA_CCB_RAHEAD = 0x01, 1001ed6aaf9SAlexander Motin ADA_CCB_WCACHE = 0x02, 10152c9ce25SScott Long ADA_CCB_BUFFER_IO = 0x03, 10252c9ce25SScott Long ADA_CCB_WAITING = 0x04, 10352c9ce25SScott Long ADA_CCB_DUMP = 0x05, 1041c80ec0aSAlexander Motin ADA_CCB_TRIM = 0x06, 10552c9ce25SScott Long ADA_CCB_TYPE_MASK = 0x0F, 10652c9ce25SScott Long } ada_ccb_state; 10752c9ce25SScott Long 10852c9ce25SScott Long /* Offsets into our private area for storing information */ 10952c9ce25SScott Long #define ccb_state ppriv_field0 11052c9ce25SScott Long #define ccb_bp ppriv_ptr1 11152c9ce25SScott Long 11252c9ce25SScott Long struct disk_params { 11352c9ce25SScott Long u_int8_t heads; 11452c9ce25SScott Long u_int8_t secs_per_track; 115c1bd46c2SAlexander Motin u_int32_t cylinders; 116c1bd46c2SAlexander Motin u_int32_t secsize; /* Number of bytes/logical sector */ 117c1bd46c2SAlexander Motin u_int64_t sectors; /* Total number sectors */ 11852c9ce25SScott Long }; 11952c9ce25SScott Long 1201524677aSAlexander Motin #define TRIM_MAX_BLOCKS 8 12137ddbd16SAlexander Motin #define TRIM_MAX_RANGES (TRIM_MAX_BLOCKS * 64) 1221524677aSAlexander Motin #define TRIM_MAX_BIOS (TRIM_MAX_RANGES * 4) 1231c80ec0aSAlexander Motin struct trim_request { 1241c80ec0aSAlexander Motin uint8_t data[TRIM_MAX_RANGES * 8]; 12537ddbd16SAlexander Motin struct bio *bps[TRIM_MAX_BIOS]; 1261c80ec0aSAlexander Motin }; 1271c80ec0aSAlexander Motin 12852c9ce25SScott Long struct ada_softc { 12952c9ce25SScott Long struct bio_queue_head bio_queue; 1301c80ec0aSAlexander Motin struct bio_queue_head trim_queue; 13152c9ce25SScott Long ada_state state; 13252c9ce25SScott Long ada_flags flags; 13352c9ce25SScott Long ada_quirks quirks; 1345f83aee5SSteven Hartland int sort_io_queue; 13552c9ce25SScott Long int ordered_tag_count; 13652c9ce25SScott Long int outstanding_cmds; 1371c80ec0aSAlexander Motin int trim_max_ranges; 1381c80ec0aSAlexander Motin int trim_running; 1391ed6aaf9SAlexander Motin int read_ahead; 140e3a6d3a4SAlexander Motin int write_cache; 141e3a6d3a4SAlexander Motin #ifdef ADA_TEST_FAILURE 142e3a6d3a4SAlexander Motin int force_read_error; 143e3a6d3a4SAlexander Motin int force_write_error; 144e3a6d3a4SAlexander Motin int periodic_read_error; 145e3a6d3a4SAlexander Motin int periodic_read_count; 146e3a6d3a4SAlexander Motin #endif 14752c9ce25SScott Long struct disk_params params; 14852c9ce25SScott Long struct disk *disk; 14952c9ce25SScott Long struct task sysctl_task; 15052c9ce25SScott Long struct sysctl_ctx_list sysctl_ctx; 15152c9ce25SScott Long struct sysctl_oid *sysctl_tree; 15252c9ce25SScott Long struct callout sendordered_c; 1531c80ec0aSAlexander Motin struct trim_request trim_req; 15452c9ce25SScott Long }; 15552c9ce25SScott Long 15652c9ce25SScott Long struct ada_quirk_entry { 15752c9ce25SScott Long struct scsi_inquiry_pattern inq_pat; 15852c9ce25SScott Long ada_quirks quirks; 15952c9ce25SScott Long }; 16052c9ce25SScott Long 16130a4094fSAlexander Motin static struct ada_quirk_entry ada_quirk_table[] = 16230a4094fSAlexander Motin { 16330a4094fSAlexander Motin { 164d3a460d3SAlexander Motin /* Hitachi Advanced Format (4k) drives */ 165d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "Hitachi H??????????E3*", "*" }, 166d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 167d3a460d3SAlexander Motin }, 168d3a460d3SAlexander Motin { 169d3a460d3SAlexander Motin /* Samsung Advanced Format (4k) drives */ 170643d1826SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "SAMSUNG HD155UI*", "*" }, 171643d1826SAlexander Motin /*quirks*/ADA_Q_4K 172643d1826SAlexander Motin }, 173643d1826SAlexander Motin { 174643d1826SAlexander Motin /* Samsung Advanced Format (4k) drives */ 175d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "SAMSUNG HD204UI*", "*" }, 176d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 177d3a460d3SAlexander Motin }, 178d3a460d3SAlexander Motin { 179d3a460d3SAlexander Motin /* Seagate Barracuda Green Advanced Format (4k) drives */ 180d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST????DL*", "*" }, 181d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 182d3a460d3SAlexander Motin }, 183d3a460d3SAlexander Motin { 184643d1826SAlexander Motin /* Seagate Barracuda Advanced Format (4k) drives */ 185643d1826SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST???DM*", "*" }, 186643d1826SAlexander Motin /*quirks*/ADA_Q_4K 187643d1826SAlexander Motin }, 188643d1826SAlexander Motin { 189643d1826SAlexander Motin /* Seagate Barracuda Advanced Format (4k) drives */ 190643d1826SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST????DM*", "*" }, 191643d1826SAlexander Motin /*quirks*/ADA_Q_4K 192643d1826SAlexander Motin }, 193643d1826SAlexander Motin { 194d3a460d3SAlexander Motin /* Seagate Momentus Advanced Format (4k) drives */ 195d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9500423AS*", "*" }, 196d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 197d3a460d3SAlexander Motin }, 198d3a460d3SAlexander Motin { 199d3a460d3SAlexander Motin /* Seagate Momentus Advanced Format (4k) drives */ 200d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9500424AS*", "*" }, 201d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 202d3a460d3SAlexander Motin }, 203d3a460d3SAlexander Motin { 204d3a460d3SAlexander Motin /* Seagate Momentus Advanced Format (4k) drives */ 205643d1826SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9640423AS*", "*" }, 206643d1826SAlexander Motin /*quirks*/ADA_Q_4K 207643d1826SAlexander Motin }, 208643d1826SAlexander Motin { 209643d1826SAlexander Motin /* Seagate Momentus Advanced Format (4k) drives */ 210643d1826SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9640424AS*", "*" }, 211643d1826SAlexander Motin /*quirks*/ADA_Q_4K 212643d1826SAlexander Motin }, 213643d1826SAlexander Motin { 214643d1826SAlexander Motin /* Seagate Momentus Advanced Format (4k) drives */ 215d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9750420AS*", "*" }, 216d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 217d3a460d3SAlexander Motin }, 218d3a460d3SAlexander Motin { 219d3a460d3SAlexander Motin /* Seagate Momentus Advanced Format (4k) drives */ 220d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9750422AS*", "*" }, 221d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 222d3a460d3SAlexander Motin }, 223d3a460d3SAlexander Motin { 224643d1826SAlexander Motin /* Seagate Momentus Advanced Format (4k) drives */ 225643d1826SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9750423AS*", "*" }, 226643d1826SAlexander Motin /*quirks*/ADA_Q_4K 227643d1826SAlexander Motin }, 228643d1826SAlexander Motin { 229d3a460d3SAlexander Motin /* Seagate Momentus Thin Advanced Format (4k) drives */ 230d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST???LT*", "*" }, 231d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 232d3a460d3SAlexander Motin }, 233d3a460d3SAlexander Motin { 234d3a460d3SAlexander Motin /* WDC Caviar Green Advanced Format (4k) drives */ 235d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD????RS*", "*" }, 236d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 237d3a460d3SAlexander Motin }, 238d3a460d3SAlexander Motin { 239d3a460d3SAlexander Motin /* WDC Caviar Green Advanced Format (4k) drives */ 240d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD????RX*", "*" }, 241d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 242d3a460d3SAlexander Motin }, 243d3a460d3SAlexander Motin { 244d3a460d3SAlexander Motin /* WDC Caviar Green Advanced Format (4k) drives */ 245d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD??????RS*", "*" }, 246d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 247d3a460d3SAlexander Motin }, 248d3a460d3SAlexander Motin { 249d3a460d3SAlexander Motin /* WDC Caviar Green Advanced Format (4k) drives */ 250d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD??????RX*", "*" }, 251d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 252d3a460d3SAlexander Motin }, 253d3a460d3SAlexander Motin { 254d3a460d3SAlexander Motin /* WDC Scorpio Black Advanced Format (4k) drives */ 255d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD???PKT*", "*" }, 256d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 257d3a460d3SAlexander Motin }, 258d3a460d3SAlexander Motin { 259d3a460d3SAlexander Motin /* WDC Scorpio Black Advanced Format (4k) drives */ 260d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD?????PKT*", "*" }, 261d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 262d3a460d3SAlexander Motin }, 263d3a460d3SAlexander Motin { 264d3a460d3SAlexander Motin /* WDC Scorpio Blue Advanced Format (4k) drives */ 265d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD???PVT*", "*" }, 266d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 267d3a460d3SAlexander Motin }, 268d3a460d3SAlexander Motin { 269d3a460d3SAlexander Motin /* WDC Scorpio Blue Advanced Format (4k) drives */ 270d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD?????PVT*", "*" }, 271d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 272d3a460d3SAlexander Motin }, 273d3a460d3SAlexander Motin { 2749d3334e1SEitan Adler /* 2759d3334e1SEitan Adler * Corsair Force 2 SSDs 2769d3334e1SEitan Adler * 4k optimised & trim only works in 4k requests + 4k aligned 2779d3334e1SEitan Adler * Submitted by: Steven Hartland <steven.hartland@multiplay.co.uk> 2789d3334e1SEitan Adler * PR: 169974 2799d3334e1SEitan Adler */ 2809d3334e1SEitan Adler { T_DIRECT, SIP_MEDIA_FIXED, "*", "Corsair CSSD-F*", "*" }, 2819d3334e1SEitan Adler /*quirks*/ADA_Q_4K 2829d3334e1SEitan Adler }, 2839d3334e1SEitan Adler { 2849d3334e1SEitan Adler /* 2859d3334e1SEitan Adler * Corsair Force 3 SSDs 2869d3334e1SEitan Adler * 4k optimised & trim only works in 4k requests + 4k aligned 2879d3334e1SEitan Adler * Submitted by: Steven Hartland <steven.hartland@multiplay.co.uk> 2889d3334e1SEitan Adler * PR: 169974 2899d3334e1SEitan Adler */ 2909d3334e1SEitan Adler { T_DIRECT, SIP_MEDIA_FIXED, "*", "Corsair Force 3*", "*" }, 2919d3334e1SEitan Adler /*quirks*/ADA_Q_4K 2929d3334e1SEitan Adler }, 2939d3334e1SEitan Adler { 2949d3334e1SEitan Adler /* 2959d3334e1SEitan Adler * OCZ Agility 3 SSDs 2969d3334e1SEitan Adler * 4k optimised & trim only works in 4k requests + 4k aligned 2979d3334e1SEitan Adler * Submitted by: Steven Hartland <steven.hartland@multiplay.co.uk> 2989d3334e1SEitan Adler * PR: 169974 2999d3334e1SEitan Adler */ 3009d3334e1SEitan Adler { T_DIRECT, SIP_MEDIA_FIXED, "*", "OCZ-AGILITY3*", "*" }, 3019d3334e1SEitan Adler /*quirks*/ADA_Q_4K 3029d3334e1SEitan Adler }, 3039d3334e1SEitan Adler { 3049d3334e1SEitan Adler /* 3059d3334e1SEitan Adler * OCZ Vertex 2 SSDs (inc pro series) 3069d3334e1SEitan Adler * 4k optimised & trim only works in 4k requests + 4k aligned 3079d3334e1SEitan Adler * Submitted by: Steven Hartland <steven.hartland@multiplay.co.uk> 3089d3334e1SEitan Adler * PR: 169974 3099d3334e1SEitan Adler */ 3109d3334e1SEitan Adler { T_DIRECT, SIP_MEDIA_FIXED, "*", "OCZ?VERTEX2*", "*" }, 3119d3334e1SEitan Adler /*quirks*/ADA_Q_4K 3129d3334e1SEitan Adler }, 3139d3334e1SEitan Adler { 3149d3334e1SEitan Adler /* 3159d3334e1SEitan Adler * OCZ Vertex 3 SSDs 3169d3334e1SEitan Adler * 4k optimised & trim only works in 4k requests + 4k aligned 3179d3334e1SEitan Adler * Submitted by: Steven Hartland <steven.hartland@multiplay.co.uk> 3189d3334e1SEitan Adler * PR: 169974 3199d3334e1SEitan Adler */ 3209d3334e1SEitan Adler { T_DIRECT, SIP_MEDIA_FIXED, "*", "OCZ-VERTEX3*", "*" }, 3219d3334e1SEitan Adler /*quirks*/ADA_Q_4K 3229d3334e1SEitan Adler }, 3239d3334e1SEitan Adler { 3249d3334e1SEitan Adler /* 3259d3334e1SEitan Adler * SuperTalent TeraDrive CT SSDs 3269d3334e1SEitan Adler * 4k optimised & trim only works in 4k requests + 4k aligned 3279d3334e1SEitan Adler * Submitted by: Steven Hartland <steven.hartland@multiplay.co.uk> 3289d3334e1SEitan Adler * PR: 169974 3299d3334e1SEitan Adler */ 3309d3334e1SEitan Adler { T_DIRECT, SIP_MEDIA_FIXED, "*", "FTM??CT25H*", "*" }, 3319d3334e1SEitan Adler /*quirks*/ADA_Q_4K 3329d3334e1SEitan Adler }, 3339d3334e1SEitan Adler { 3349d3334e1SEitan Adler /* 3359d3334e1SEitan Adler * Crucial RealSSD C300 SSDs 3369d3334e1SEitan Adler * 4k optimised 3379d3334e1SEitan Adler * Submitted by: Steven Hartland <steven.hartland@multiplay.co.uk> 3389d3334e1SEitan Adler * PR: 169974 3399d3334e1SEitan Adler */ 3409d3334e1SEitan Adler { T_DIRECT, SIP_MEDIA_FIXED, "*", "C300-CTFDDAC???MAG*", 3419d3334e1SEitan Adler "*" }, /*quirks*/ADA_Q_4K 3429d3334e1SEitan Adler }, 3439d3334e1SEitan Adler { 3449d3334e1SEitan Adler /* 3459d3334e1SEitan Adler * XceedIOPS SATA SSDs 3469d3334e1SEitan Adler * 4k optimised 3479d3334e1SEitan Adler * Submitted by: Steven Hartland <steven.hartland@multiplay.co.uk> 3489d3334e1SEitan Adler * PR: 169974 3499d3334e1SEitan Adler */ 3509d3334e1SEitan Adler { T_DIRECT, SIP_MEDIA_FIXED, "*", "SG9XCS2D*", "*" }, 3519d3334e1SEitan Adler /*quirks*/ADA_Q_4K 3529d3334e1SEitan Adler }, 3539d3334e1SEitan Adler { 3549d3334e1SEitan Adler /* 3559d3334e1SEitan Adler * Intel 330 Series SSDs 3569d3334e1SEitan Adler * 4k optimised & trim only works in 4k requests + 4k aligned 3579d3334e1SEitan Adler * Submitted by: Steven Hartland <steven.hartland@multiplay.co.uk> 3589d3334e1SEitan Adler * PR: 169974 3599d3334e1SEitan Adler */ 3609d3334e1SEitan Adler { T_DIRECT, SIP_MEDIA_FIXED, "*", "INTEL SSDSC2ct*", "*" }, 3619d3334e1SEitan Adler /*quirks*/ADA_Q_4K 3629d3334e1SEitan Adler }, 3639d3334e1SEitan Adler { 3649d3334e1SEitan Adler /* 3659d3334e1SEitan Adler * OCZ Deneva R 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, "*", "DENRSTE251M45*", "*" }, 3719d3334e1SEitan Adler /*quirks*/ADA_Q_4K 3729d3334e1SEitan Adler }, 3739d3334e1SEitan Adler { 3749d3334e1SEitan Adler /* 3759d3334e1SEitan Adler * Kingston HyperX 3k SSDs 3769d3334e1SEitan Adler * 4k optimised & trim only works in 4k requests + 4k aligned 3779d3334e1SEitan Adler * Submitted by: Steven Hartland <steven.hartland@multiplay.co.uk> 3789d3334e1SEitan Adler * PR: 169974 3799d3334e1SEitan Adler */ 3809d3334e1SEitan Adler { T_DIRECT, SIP_MEDIA_FIXED, "*", "KINGSTON SH103S3*", "*" }, 3819d3334e1SEitan Adler /*quirks*/ADA_Q_4K 3829d3334e1SEitan Adler }, 3839d3334e1SEitan Adler { 38430a4094fSAlexander Motin /* Default */ 38530a4094fSAlexander Motin { 38630a4094fSAlexander Motin T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED, 38730a4094fSAlexander Motin /*vendor*/"*", /*product*/"*", /*revision*/"*" 38830a4094fSAlexander Motin }, 38930a4094fSAlexander Motin /*quirks*/0 39030a4094fSAlexander Motin }, 39130a4094fSAlexander Motin }; 39252c9ce25SScott Long 39352c9ce25SScott Long static disk_strategy_t adastrategy; 39452c9ce25SScott Long static dumper_t adadump; 39552c9ce25SScott Long static periph_init_t adainit; 39652c9ce25SScott Long static void adaasync(void *callback_arg, u_int32_t code, 39752c9ce25SScott Long struct cam_path *path, void *arg); 39852c9ce25SScott Long static void adasysctlinit(void *context, int pending); 39952c9ce25SScott Long static periph_ctor_t adaregister; 40052c9ce25SScott Long static periph_dtor_t adacleanup; 40152c9ce25SScott Long static periph_start_t adastart; 40252c9ce25SScott Long static periph_oninv_t adaoninvalidate; 40352c9ce25SScott Long static void adadone(struct cam_periph *periph, 40452c9ce25SScott Long union ccb *done_ccb); 40552c9ce25SScott Long static int adaerror(union ccb *ccb, u_int32_t cam_flags, 40652c9ce25SScott Long u_int32_t sense_flags); 407c1bd46c2SAlexander Motin static void adagetparams(struct cam_periph *periph, 40852c9ce25SScott Long struct ccb_getdev *cgd); 40952c9ce25SScott Long static timeout_t adasendorderedtag; 41052c9ce25SScott Long static void adashutdown(void *arg, int howto); 411c3d0d168SAlexander Motin static void adasuspend(void *arg); 412c3d0d168SAlexander Motin static void adaresume(void *arg); 41352c9ce25SScott Long 4140d307e09SAlexander Motin #ifndef ADA_DEFAULT_LEGACY_ALIASES 4150d307e09SAlexander Motin #define ADA_DEFAULT_LEGACY_ALIASES 1 4160d307e09SAlexander Motin #endif 4170d307e09SAlexander Motin 41852c9ce25SScott Long #ifndef ADA_DEFAULT_TIMEOUT 41952c9ce25SScott Long #define ADA_DEFAULT_TIMEOUT 30 /* Timeout in seconds */ 42052c9ce25SScott Long #endif 42152c9ce25SScott Long 42252c9ce25SScott Long #ifndef ADA_DEFAULT_RETRY 42352c9ce25SScott Long #define ADA_DEFAULT_RETRY 4 42452c9ce25SScott Long #endif 42552c9ce25SScott Long 42652c9ce25SScott Long #ifndef ADA_DEFAULT_SEND_ORDERED 42752c9ce25SScott Long #define ADA_DEFAULT_SEND_ORDERED 1 42852c9ce25SScott Long #endif 42952c9ce25SScott Long 430fd104c15SRebecca Cran #ifndef ADA_DEFAULT_SPINDOWN_SHUTDOWN 431fd104c15SRebecca Cran #define ADA_DEFAULT_SPINDOWN_SHUTDOWN 1 432fd104c15SRebecca Cran #endif 433fd104c15SRebecca Cran 434c3d0d168SAlexander Motin #ifndef ADA_DEFAULT_SPINDOWN_SUSPEND 435c3d0d168SAlexander Motin #define ADA_DEFAULT_SPINDOWN_SUSPEND 1 436c3d0d168SAlexander Motin #endif 437c3d0d168SAlexander Motin 4381ed6aaf9SAlexander Motin #ifndef ADA_DEFAULT_READ_AHEAD 4391ed6aaf9SAlexander Motin #define ADA_DEFAULT_READ_AHEAD 1 4401ed6aaf9SAlexander Motin #endif 4411ed6aaf9SAlexander Motin 442f513d14cSAlexander Motin #ifndef ADA_DEFAULT_WRITE_CACHE 443f513d14cSAlexander Motin #define ADA_DEFAULT_WRITE_CACHE 1 444f513d14cSAlexander Motin #endif 445f513d14cSAlexander Motin 4461ed6aaf9SAlexander Motin #define ADA_RA (softc->read_ahead >= 0 ? \ 4471ed6aaf9SAlexander Motin softc->read_ahead : ada_read_ahead) 4481ed6aaf9SAlexander Motin #define ADA_WC (softc->write_cache >= 0 ? \ 4491ed6aaf9SAlexander Motin softc->write_cache : ada_write_cache) 4505f83aee5SSteven Hartland #define ADA_SIO (softc->sort_io_queue >= 0 ? \ 4515f83aee5SSteven Hartland softc->sort_io_queue : cam_sort_io_queues) 4521ed6aaf9SAlexander Motin 4534461491bSMarius Strobl /* 4544461491bSMarius Strobl * Most platforms map firmware geometry to actual, but some don't. If 4554461491bSMarius Strobl * not overridden, default to nothing. 4564461491bSMarius Strobl */ 4574461491bSMarius Strobl #ifndef ata_disk_firmware_geom_adjust 4584461491bSMarius Strobl #define ata_disk_firmware_geom_adjust(disk) 4594461491bSMarius Strobl #endif 46052c9ce25SScott Long 4610d307e09SAlexander Motin static int ada_legacy_aliases = ADA_DEFAULT_LEGACY_ALIASES; 46252c9ce25SScott Long static int ada_retry_count = ADA_DEFAULT_RETRY; 46352c9ce25SScott Long static int ada_default_timeout = ADA_DEFAULT_TIMEOUT; 46452c9ce25SScott Long static int ada_send_ordered = ADA_DEFAULT_SEND_ORDERED; 465fd104c15SRebecca Cran static int ada_spindown_shutdown = ADA_DEFAULT_SPINDOWN_SHUTDOWN; 466c3d0d168SAlexander Motin static int ada_spindown_suspend = ADA_DEFAULT_SPINDOWN_SUSPEND; 4671ed6aaf9SAlexander Motin static int ada_read_ahead = ADA_DEFAULT_READ_AHEAD; 468f513d14cSAlexander Motin static int ada_write_cache = ADA_DEFAULT_WRITE_CACHE; 46952c9ce25SScott Long 4706472ac3dSEd Schouten static SYSCTL_NODE(_kern_cam, OID_AUTO, ada, CTLFLAG_RD, 0, 47152c9ce25SScott Long "CAM Direct Access Disk driver"); 4720d307e09SAlexander Motin SYSCTL_INT(_kern_cam_ada, OID_AUTO, legacy_aliases, CTLFLAG_RW, 4730d307e09SAlexander Motin &ada_legacy_aliases, 0, "Create legacy-like device aliases"); 4740d307e09SAlexander Motin TUNABLE_INT("kern.cam.ada.legacy_aliases", &ada_legacy_aliases); 47552c9ce25SScott Long SYSCTL_INT(_kern_cam_ada, OID_AUTO, retry_count, CTLFLAG_RW, 47652c9ce25SScott Long &ada_retry_count, 0, "Normal I/O retry count"); 47752c9ce25SScott Long TUNABLE_INT("kern.cam.ada.retry_count", &ada_retry_count); 47852c9ce25SScott Long SYSCTL_INT(_kern_cam_ada, OID_AUTO, default_timeout, CTLFLAG_RW, 47952c9ce25SScott Long &ada_default_timeout, 0, "Normal I/O timeout (in seconds)"); 48052c9ce25SScott Long TUNABLE_INT("kern.cam.ada.default_timeout", &ada_default_timeout); 481af010905SChristian Brueffer SYSCTL_INT(_kern_cam_ada, OID_AUTO, send_ordered, CTLFLAG_RW, 48252c9ce25SScott Long &ada_send_ordered, 0, "Send Ordered Tags"); 483af010905SChristian Brueffer TUNABLE_INT("kern.cam.ada.send_ordered", &ada_send_ordered); 484fd104c15SRebecca Cran SYSCTL_INT(_kern_cam_ada, OID_AUTO, spindown_shutdown, CTLFLAG_RW, 485fd104c15SRebecca Cran &ada_spindown_shutdown, 0, "Spin down upon shutdown"); 486fd104c15SRebecca Cran TUNABLE_INT("kern.cam.ada.spindown_shutdown", &ada_spindown_shutdown); 487c3d0d168SAlexander Motin SYSCTL_INT(_kern_cam_ada, OID_AUTO, spindown_suspend, CTLFLAG_RW, 488c3d0d168SAlexander Motin &ada_spindown_suspend, 0, "Spin down upon suspend"); 489c3d0d168SAlexander Motin TUNABLE_INT("kern.cam.ada.spindown_suspend", &ada_spindown_suspend); 4901ed6aaf9SAlexander Motin SYSCTL_INT(_kern_cam_ada, OID_AUTO, read_ahead, CTLFLAG_RW, 4911ed6aaf9SAlexander Motin &ada_read_ahead, 0, "Enable disk read-ahead"); 4921ed6aaf9SAlexander Motin TUNABLE_INT("kern.cam.ada.read_ahead", &ada_read_ahead); 493f513d14cSAlexander Motin SYSCTL_INT(_kern_cam_ada, OID_AUTO, write_cache, CTLFLAG_RW, 494f513d14cSAlexander Motin &ada_write_cache, 0, "Enable disk write cache"); 495f513d14cSAlexander Motin TUNABLE_INT("kern.cam.ada.write_cache", &ada_write_cache); 49652c9ce25SScott Long 49752c9ce25SScott Long /* 49852c9ce25SScott Long * ADA_ORDEREDTAG_INTERVAL determines how often, relative 49952c9ce25SScott Long * to the default timeout, we check to see whether an ordered 50052c9ce25SScott Long * tagged transaction is appropriate to prevent simple tag 50152c9ce25SScott Long * starvation. Since we'd like to ensure that there is at least 50252c9ce25SScott Long * 1/2 of the timeout length left for a starved transaction to 50352c9ce25SScott Long * complete after we've sent an ordered tag, we must poll at least 50452c9ce25SScott Long * four times in every timeout period. This takes care of the worst 50552c9ce25SScott Long * case where a starved transaction starts during an interval that 50652c9ce25SScott Long * meets the requirement "don't send an ordered tag" test so it takes 50752c9ce25SScott Long * us two intervals to determine that a tag must be sent. 50852c9ce25SScott Long */ 50952c9ce25SScott Long #ifndef ADA_ORDEREDTAG_INTERVAL 51052c9ce25SScott Long #define ADA_ORDEREDTAG_INTERVAL 4 51152c9ce25SScott Long #endif 51252c9ce25SScott Long 51352c9ce25SScott Long static struct periph_driver adadriver = 51452c9ce25SScott Long { 51552c9ce25SScott Long adainit, "ada", 51652c9ce25SScott Long TAILQ_HEAD_INITIALIZER(adadriver.units), /* generation */ 0 51752c9ce25SScott Long }; 51852c9ce25SScott Long 51952c9ce25SScott Long PERIPHDRIVER_DECLARE(ada, adadriver); 52052c9ce25SScott Long 521d745c852SEd Schouten static MALLOC_DEFINE(M_ATADA, "ata_da", "ata_da buffers"); 52252c9ce25SScott Long 52352c9ce25SScott Long static int 52452c9ce25SScott Long adaopen(struct disk *dp) 52552c9ce25SScott Long { 52652c9ce25SScott Long struct cam_periph *periph; 52752c9ce25SScott Long struct ada_softc *softc; 52852c9ce25SScott Long int error; 52952c9ce25SScott Long 53052c9ce25SScott Long periph = (struct cam_periph *)dp->d_drv1; 53152c9ce25SScott Long if (cam_periph_acquire(periph) != CAM_REQ_CMP) { 53252c9ce25SScott Long return(ENXIO); 53352c9ce25SScott Long } 53452c9ce25SScott Long 53552c9ce25SScott Long cam_periph_lock(periph); 53652c9ce25SScott Long if ((error = cam_periph_hold(periph, PRIBIO|PCATCH)) != 0) { 53752c9ce25SScott Long cam_periph_unlock(periph); 53852c9ce25SScott Long cam_periph_release(periph); 53952c9ce25SScott Long return (error); 54052c9ce25SScott Long } 54152c9ce25SScott Long 54252c9ce25SScott Long softc = (struct ada_softc *)periph->softc; 54352c9ce25SScott Long softc->flags |= ADA_FLAG_OPEN; 54452c9ce25SScott Long 545fddde2b8SAlexander Motin CAM_DEBUG(periph->path, CAM_DEBUG_TRACE | CAM_DEBUG_PERIPH, 546fddde2b8SAlexander Motin ("adaopen\n")); 54752c9ce25SScott Long 54852c9ce25SScott Long if ((softc->flags & ADA_FLAG_PACK_INVALID) != 0) { 54952c9ce25SScott Long /* Invalidate our pack information. */ 55052c9ce25SScott Long softc->flags &= ~ADA_FLAG_PACK_INVALID; 55152c9ce25SScott Long } 55252c9ce25SScott Long 55352c9ce25SScott Long cam_periph_unhold(periph); 55452c9ce25SScott Long cam_periph_unlock(periph); 55552c9ce25SScott Long return (0); 55652c9ce25SScott Long } 55752c9ce25SScott Long 55852c9ce25SScott Long static int 55952c9ce25SScott Long adaclose(struct disk *dp) 56052c9ce25SScott Long { 56152c9ce25SScott Long struct cam_periph *periph; 56252c9ce25SScott Long struct ada_softc *softc; 56352c9ce25SScott Long union ccb *ccb; 56452c9ce25SScott Long 56552c9ce25SScott Long periph = (struct cam_periph *)dp->d_drv1; 56652c9ce25SScott Long cam_periph_lock(periph); 5676f487924SAlexander Motin if (cam_periph_hold(periph, PRIBIO) != 0) { 56852c9ce25SScott Long cam_periph_unlock(periph); 56952c9ce25SScott Long cam_periph_release(periph); 5706f487924SAlexander Motin return (0); 57152c9ce25SScott Long } 57252c9ce25SScott Long 57352c9ce25SScott Long softc = (struct ada_softc *)periph->softc; 574fddde2b8SAlexander Motin 575fddde2b8SAlexander Motin CAM_DEBUG(periph->path, CAM_DEBUG_TRACE | CAM_DEBUG_PERIPH, 576fddde2b8SAlexander Motin ("adaclose\n")); 577fddde2b8SAlexander Motin 57852c9ce25SScott Long /* We only sync the cache if the drive is capable of it. */ 579c36bb43cSAlexander Motin if ((softc->flags & ADA_FLAG_CAN_FLUSHCACHE) != 0 && 580c36bb43cSAlexander Motin (softc->flags & ADA_FLAG_PACK_INVALID) == 0) { 58152c9ce25SScott Long 582bbfa4aa1SAlexander Motin ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 58352c9ce25SScott Long cam_fill_ataio(&ccb->ataio, 58452c9ce25SScott Long 1, 58552c9ce25SScott Long adadone, 58652c9ce25SScott Long CAM_DIR_NONE, 58752c9ce25SScott Long 0, 58852c9ce25SScott Long NULL, 58952c9ce25SScott Long 0, 59052c9ce25SScott Long ada_default_timeout*1000); 59152c9ce25SScott Long 59252c9ce25SScott Long if (softc->flags & ADA_FLAG_CAN_48BIT) 59352c9ce25SScott Long ata_48bit_cmd(&ccb->ataio, ATA_FLUSHCACHE48, 0, 0, 0); 59452c9ce25SScott Long else 5957606b445SAlexander Motin ata_28bit_cmd(&ccb->ataio, ATA_FLUSHCACHE, 0, 0, 0); 5967642883fSAlexander Motin cam_periph_runccb(ccb, adaerror, /*cam_flags*/0, 59746f118feSAlexander Motin /*sense_flags*/0, softc->disk->d_devstat); 59852c9ce25SScott Long 59952c9ce25SScott Long if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) 60052c9ce25SScott Long xpt_print(periph->path, "Synchronize cache failed\n"); 60152c9ce25SScott Long xpt_release_ccb(ccb); 60252c9ce25SScott Long } 60352c9ce25SScott Long 60452c9ce25SScott Long softc->flags &= ~ADA_FLAG_OPEN; 60552c9ce25SScott Long cam_periph_unhold(periph); 60652c9ce25SScott Long cam_periph_unlock(periph); 60752c9ce25SScott Long cam_periph_release(periph); 60852c9ce25SScott Long return (0); 60952c9ce25SScott Long } 61052c9ce25SScott Long 6111c80ec0aSAlexander Motin static void 6121c80ec0aSAlexander Motin adaschedule(struct cam_periph *periph) 6131c80ec0aSAlexander Motin { 6141c80ec0aSAlexander Motin struct ada_softc *softc = (struct ada_softc *)periph->softc; 61510a6c358SAlexander Motin uint32_t prio; 6161c80ec0aSAlexander Motin 61710a6c358SAlexander Motin /* Check if cam_periph_getccb() was called. */ 61810a6c358SAlexander Motin prio = periph->immediate_priority; 61910a6c358SAlexander Motin 62010a6c358SAlexander Motin /* Check if we have more work to do. */ 6211c80ec0aSAlexander Motin if (bioq_first(&softc->bio_queue) || 6221c80ec0aSAlexander Motin (!softc->trim_running && bioq_first(&softc->trim_queue))) { 62310a6c358SAlexander Motin prio = CAM_PRIORITY_NORMAL; 6241c80ec0aSAlexander Motin } 62510a6c358SAlexander Motin 62610a6c358SAlexander Motin /* Schedule CCB if any of above is true. */ 62710a6c358SAlexander Motin if (prio != CAM_PRIORITY_NONE) 62810a6c358SAlexander Motin xpt_schedule(periph, prio); 6291c80ec0aSAlexander Motin } 6301c80ec0aSAlexander Motin 63152c9ce25SScott Long /* 63252c9ce25SScott Long * Actually translate the requested transfer into one the physical driver 63352c9ce25SScott Long * can understand. The transfer is described by a buf and will include 63452c9ce25SScott Long * only one physical transfer. 63552c9ce25SScott Long */ 63652c9ce25SScott Long static void 63752c9ce25SScott Long adastrategy(struct bio *bp) 63852c9ce25SScott Long { 63952c9ce25SScott Long struct cam_periph *periph; 64052c9ce25SScott Long struct ada_softc *softc; 64152c9ce25SScott Long 64252c9ce25SScott Long periph = (struct cam_periph *)bp->bio_disk->d_drv1; 64352c9ce25SScott Long softc = (struct ada_softc *)periph->softc; 64452c9ce25SScott Long 64552c9ce25SScott Long cam_periph_lock(periph); 64652c9ce25SScott Long 647fddde2b8SAlexander Motin CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("adastrategy(%p)\n", bp)); 648fddde2b8SAlexander Motin 64952c9ce25SScott Long /* 65052c9ce25SScott Long * If the device has been made invalid, error out 65152c9ce25SScott Long */ 65252c9ce25SScott Long if ((softc->flags & ADA_FLAG_PACK_INVALID)) { 65352c9ce25SScott Long cam_periph_unlock(periph); 65452c9ce25SScott Long biofinish(bp, NULL, ENXIO); 65552c9ce25SScott Long return; 65652c9ce25SScott Long } 65752c9ce25SScott Long 65852c9ce25SScott Long /* 65952c9ce25SScott Long * Place it in the queue of disk activities for this disk 66052c9ce25SScott Long */ 6611c80ec0aSAlexander Motin if (bp->bio_cmd == BIO_DELETE && 6625f83aee5SSteven Hartland (softc->flags & ADA_FLAG_CAN_TRIM)) { 6635f83aee5SSteven Hartland if (ADA_SIO) 6641c80ec0aSAlexander Motin bioq_disksort(&softc->trim_queue, bp); 6651c80ec0aSAlexander Motin else 6665f83aee5SSteven Hartland bioq_insert_tail(&softc->trim_queue, bp); 6675f83aee5SSteven Hartland } else { 6685f83aee5SSteven Hartland if (ADA_SIO) 66952c9ce25SScott Long bioq_disksort(&softc->bio_queue, bp); 6705f83aee5SSteven Hartland else 6715f83aee5SSteven Hartland bioq_insert_tail(&softc->bio_queue, bp); 6725f83aee5SSteven Hartland } 67352c9ce25SScott Long 67452c9ce25SScott Long /* 67552c9ce25SScott Long * Schedule ourselves for performing the work. 67652c9ce25SScott Long */ 6771c80ec0aSAlexander Motin adaschedule(periph); 67852c9ce25SScott Long cam_periph_unlock(periph); 67952c9ce25SScott Long 68052c9ce25SScott Long return; 68152c9ce25SScott Long } 68252c9ce25SScott Long 68352c9ce25SScott Long static int 68452c9ce25SScott Long adadump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t length) 68552c9ce25SScott Long { 68652c9ce25SScott Long struct cam_periph *periph; 68752c9ce25SScott Long struct ada_softc *softc; 68852c9ce25SScott Long u_int secsize; 68952c9ce25SScott Long union ccb ccb; 69052c9ce25SScott Long struct disk *dp; 69152c9ce25SScott Long uint64_t lba; 69252c9ce25SScott Long uint16_t count; 6930191d9b3SAlexander Motin int error = 0; 69452c9ce25SScott Long 69552c9ce25SScott Long dp = arg; 69652c9ce25SScott Long periph = dp->d_drv1; 69752c9ce25SScott Long softc = (struct ada_softc *)periph->softc; 69852c9ce25SScott Long cam_periph_lock(periph); 69952c9ce25SScott Long secsize = softc->params.secsize; 70052c9ce25SScott Long lba = offset / secsize; 70152c9ce25SScott Long count = length / secsize; 70252c9ce25SScott Long 70352c9ce25SScott Long if ((softc->flags & ADA_FLAG_PACK_INVALID) != 0) { 70452c9ce25SScott Long cam_periph_unlock(periph); 70552c9ce25SScott Long return (ENXIO); 70652c9ce25SScott Long } 70752c9ce25SScott Long 70852c9ce25SScott Long if (length > 0) { 709bbfa4aa1SAlexander Motin xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 71052c9ce25SScott Long ccb.ccb_h.ccb_state = ADA_CCB_DUMP; 71152c9ce25SScott Long cam_fill_ataio(&ccb.ataio, 71252c9ce25SScott Long 0, 71352c9ce25SScott Long adadone, 71452c9ce25SScott Long CAM_DIR_OUT, 71552c9ce25SScott Long 0, 71652c9ce25SScott Long (u_int8_t *) virtual, 71752c9ce25SScott Long length, 71852c9ce25SScott Long ada_default_timeout*1000); 71952c9ce25SScott Long if ((softc->flags & ADA_FLAG_CAN_48BIT) && 72052c9ce25SScott Long (lba + count >= ATA_MAX_28BIT_LBA || 72152c9ce25SScott Long count >= 256)) { 72252c9ce25SScott Long ata_48bit_cmd(&ccb.ataio, ATA_WRITE_DMA48, 72352c9ce25SScott Long 0, lba, count); 72452c9ce25SScott Long } else { 7257606b445SAlexander Motin ata_28bit_cmd(&ccb.ataio, ATA_WRITE_DMA, 72652c9ce25SScott Long 0, lba, count); 72752c9ce25SScott Long } 72852c9ce25SScott Long xpt_polled_action(&ccb); 72952c9ce25SScott Long 7300191d9b3SAlexander Motin error = cam_periph_error(&ccb, 7310191d9b3SAlexander Motin 0, SF_NO_RECOVERY | SF_NO_RETRY, NULL); 7320191d9b3SAlexander Motin if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0) 7330191d9b3SAlexander Motin cam_release_devq(ccb.ccb_h.path, /*relsim_flags*/0, 7340191d9b3SAlexander Motin /*reduction*/0, /*timeout*/0, /*getcount_only*/0); 7350191d9b3SAlexander Motin if (error != 0) 73652c9ce25SScott Long printf("Aborting dump due to I/O error.\n"); 7370191d9b3SAlexander Motin 73852c9ce25SScott Long cam_periph_unlock(periph); 7390191d9b3SAlexander Motin return (error); 74052c9ce25SScott Long } 74152c9ce25SScott Long 74252c9ce25SScott Long if (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) { 743bbfa4aa1SAlexander Motin xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 74452c9ce25SScott Long 74552c9ce25SScott Long ccb.ccb_h.ccb_state = ADA_CCB_DUMP; 74652c9ce25SScott Long cam_fill_ataio(&ccb.ataio, 7470191d9b3SAlexander Motin 0, 74852c9ce25SScott Long adadone, 74952c9ce25SScott Long CAM_DIR_NONE, 75052c9ce25SScott Long 0, 75152c9ce25SScott Long NULL, 75252c9ce25SScott Long 0, 75352c9ce25SScott Long ada_default_timeout*1000); 75452c9ce25SScott Long 75552c9ce25SScott Long if (softc->flags & ADA_FLAG_CAN_48BIT) 75652c9ce25SScott Long ata_48bit_cmd(&ccb.ataio, ATA_FLUSHCACHE48, 0, 0, 0); 75752c9ce25SScott Long else 7587606b445SAlexander Motin ata_28bit_cmd(&ccb.ataio, ATA_FLUSHCACHE, 0, 0, 0); 75952c9ce25SScott Long xpt_polled_action(&ccb); 76052c9ce25SScott Long 7610191d9b3SAlexander Motin error = cam_periph_error(&ccb, 7620191d9b3SAlexander Motin 0, SF_NO_RECOVERY | SF_NO_RETRY, NULL); 76352c9ce25SScott Long if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0) 7640191d9b3SAlexander Motin cam_release_devq(ccb.ccb_h.path, /*relsim_flags*/0, 7650191d9b3SAlexander Motin /*reduction*/0, /*timeout*/0, /*getcount_only*/0); 7660191d9b3SAlexander Motin if (error != 0) 7670191d9b3SAlexander Motin xpt_print(periph->path, "Synchronize cache failed\n"); 76852c9ce25SScott Long } 76952c9ce25SScott Long cam_periph_unlock(periph); 7700191d9b3SAlexander Motin return (error); 77152c9ce25SScott Long } 77252c9ce25SScott Long 77352c9ce25SScott Long static void 77452c9ce25SScott Long adainit(void) 77552c9ce25SScott Long { 77652c9ce25SScott Long cam_status status; 77752c9ce25SScott Long 77852c9ce25SScott Long /* 77952c9ce25SScott Long * Install a global async callback. This callback will 78052c9ce25SScott Long * receive async callbacks like "new device found". 78152c9ce25SScott Long */ 78252c9ce25SScott Long status = xpt_register_async(AC_FOUND_DEVICE, adaasync, NULL, NULL); 78352c9ce25SScott Long 78452c9ce25SScott Long if (status != CAM_REQ_CMP) { 78552c9ce25SScott Long printf("ada: Failed to attach master async callback " 78652c9ce25SScott Long "due to status 0x%x!\n", status); 78752c9ce25SScott Long } else if (ada_send_ordered) { 78852c9ce25SScott Long 789c3d0d168SAlexander Motin /* Register our event handlers */ 790c3d0d168SAlexander Motin if ((EVENTHANDLER_REGISTER(power_suspend, adasuspend, 791c3d0d168SAlexander Motin NULL, EVENTHANDLER_PRI_LAST)) == NULL) 792c3d0d168SAlexander Motin printf("adainit: power event registration failed!\n"); 793c3d0d168SAlexander Motin if ((EVENTHANDLER_REGISTER(power_resume, adaresume, 794c3d0d168SAlexander Motin NULL, EVENTHANDLER_PRI_LAST)) == NULL) 795c3d0d168SAlexander Motin printf("adainit: power event registration failed!\n"); 79652c9ce25SScott Long if ((EVENTHANDLER_REGISTER(shutdown_post_sync, adashutdown, 79752c9ce25SScott Long NULL, SHUTDOWN_PRI_DEFAULT)) == NULL) 79852c9ce25SScott Long printf("adainit: shutdown event registration failed!\n"); 79952c9ce25SScott Long } 80052c9ce25SScott Long } 80152c9ce25SScott Long 80252c9ce25SScott Long static void 80352c9ce25SScott Long adaoninvalidate(struct cam_periph *periph) 80452c9ce25SScott Long { 80552c9ce25SScott Long struct ada_softc *softc; 80652c9ce25SScott Long 80752c9ce25SScott Long softc = (struct ada_softc *)periph->softc; 80852c9ce25SScott Long 80952c9ce25SScott Long /* 81052c9ce25SScott Long * De-register any async callbacks. 81152c9ce25SScott Long */ 81252c9ce25SScott Long xpt_register_async(0, adaasync, periph, periph->path); 81352c9ce25SScott Long 81452c9ce25SScott Long softc->flags |= ADA_FLAG_PACK_INVALID; 81552c9ce25SScott Long 81652c9ce25SScott Long /* 81752c9ce25SScott Long * Return all queued I/O with ENXIO. 81852c9ce25SScott Long * XXX Handle any transactions queued to the card 81952c9ce25SScott Long * with XPT_ABORT_CCB. 82052c9ce25SScott Long */ 82152c9ce25SScott Long bioq_flush(&softc->bio_queue, NULL, ENXIO); 8221c80ec0aSAlexander Motin bioq_flush(&softc->trim_queue, NULL, ENXIO); 82352c9ce25SScott Long 82452c9ce25SScott Long disk_gone(softc->disk); 82552c9ce25SScott Long xpt_print(periph->path, "lost device\n"); 82652c9ce25SScott Long } 82752c9ce25SScott Long 82852c9ce25SScott Long static void 82952c9ce25SScott Long adacleanup(struct cam_periph *periph) 83052c9ce25SScott Long { 83152c9ce25SScott Long struct ada_softc *softc; 83252c9ce25SScott Long 83352c9ce25SScott Long softc = (struct ada_softc *)periph->softc; 83452c9ce25SScott Long 83552c9ce25SScott Long xpt_print(periph->path, "removing device entry\n"); 83652c9ce25SScott Long cam_periph_unlock(periph); 83752c9ce25SScott Long 83852c9ce25SScott Long /* 83952c9ce25SScott Long * If we can't free the sysctl tree, oh well... 84052c9ce25SScott Long */ 84152c9ce25SScott Long if ((softc->flags & ADA_FLAG_SCTX_INIT) != 0 84252c9ce25SScott Long && sysctl_ctx_free(&softc->sysctl_ctx) != 0) { 84352c9ce25SScott Long xpt_print(periph->path, "can't remove sysctl context\n"); 84452c9ce25SScott Long } 84552c9ce25SScott Long 84652c9ce25SScott Long disk_destroy(softc->disk); 84752c9ce25SScott Long callout_drain(&softc->sendordered_c); 84852c9ce25SScott Long free(softc, M_DEVBUF); 84952c9ce25SScott Long cam_periph_lock(periph); 85052c9ce25SScott Long } 85152c9ce25SScott Long 85252c9ce25SScott Long static void 85352c9ce25SScott Long adaasync(void *callback_arg, u_int32_t code, 85452c9ce25SScott Long struct cam_path *path, void *arg) 85552c9ce25SScott Long { 856581b2e78SAlexander Motin struct ccb_getdev cgd; 85752c9ce25SScott Long struct cam_periph *periph; 858f513d14cSAlexander Motin struct ada_softc *softc; 85952c9ce25SScott Long 86052c9ce25SScott Long periph = (struct cam_periph *)callback_arg; 86152c9ce25SScott Long switch (code) { 86252c9ce25SScott Long case AC_FOUND_DEVICE: 86352c9ce25SScott Long { 86452c9ce25SScott Long struct ccb_getdev *cgd; 86552c9ce25SScott Long cam_status status; 86652c9ce25SScott Long 86752c9ce25SScott Long cgd = (struct ccb_getdev *)arg; 86852c9ce25SScott Long if (cgd == NULL) 86952c9ce25SScott Long break; 87052c9ce25SScott Long 87152c9ce25SScott Long if (cgd->protocol != PROTO_ATA) 87252c9ce25SScott Long break; 87352c9ce25SScott Long 87452c9ce25SScott Long /* 87552c9ce25SScott Long * Allocate a peripheral instance for 87652c9ce25SScott Long * this device and start the probe 87752c9ce25SScott Long * process. 87852c9ce25SScott Long */ 87952c9ce25SScott Long status = cam_periph_alloc(adaregister, adaoninvalidate, 88052c9ce25SScott Long adacleanup, adastart, 88152c9ce25SScott Long "ada", CAM_PERIPH_BIO, 88252c9ce25SScott Long cgd->ccb_h.path, adaasync, 88352c9ce25SScott Long AC_FOUND_DEVICE, cgd); 88452c9ce25SScott Long 88552c9ce25SScott Long if (status != CAM_REQ_CMP 88652c9ce25SScott Long && status != CAM_REQ_INPROG) 88752c9ce25SScott Long printf("adaasync: Unable to attach to new device " 88852c9ce25SScott Long "due to status 0x%x\n", status); 88952c9ce25SScott Long break; 89052c9ce25SScott Long } 891581b2e78SAlexander Motin case AC_GETDEV_CHANGED: 892581b2e78SAlexander Motin { 893581b2e78SAlexander Motin softc = (struct ada_softc *)periph->softc; 894581b2e78SAlexander Motin xpt_setup_ccb(&cgd.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 895581b2e78SAlexander Motin cgd.ccb_h.func_code = XPT_GDEV_TYPE; 896581b2e78SAlexander Motin xpt_action((union ccb *)&cgd); 897581b2e78SAlexander Motin 898581b2e78SAlexander Motin if ((cgd.ident_data.capabilities1 & ATA_SUPPORT_DMA) && 899581b2e78SAlexander Motin (cgd.inq_flags & SID_DMA)) 900581b2e78SAlexander Motin softc->flags |= ADA_FLAG_CAN_DMA; 901581b2e78SAlexander Motin else 902581b2e78SAlexander Motin softc->flags &= ~ADA_FLAG_CAN_DMA; 903*2e1eb332SMarius Strobl if (cgd.ident_data.support.command2 & ATA_SUPPORT_ADDRESS48) { 904*2e1eb332SMarius Strobl softc->flags |= ADA_FLAG_CAN_48BIT; 905*2e1eb332SMarius Strobl if (cgd.inq_flags & SID_DMA48) 906*2e1eb332SMarius Strobl softc->flags |= ADA_FLAG_CAN_DMA48; 907*2e1eb332SMarius Strobl else 908*2e1eb332SMarius Strobl softc->flags &= ~ADA_FLAG_CAN_DMA48; 909*2e1eb332SMarius Strobl } else 910*2e1eb332SMarius Strobl softc->flags &= ~(ADA_FLAG_CAN_48BIT | 911*2e1eb332SMarius Strobl ADA_FLAG_CAN_DMA48); 912581b2e78SAlexander Motin if ((cgd.ident_data.satacapabilities & ATA_SUPPORT_NCQ) && 913581b2e78SAlexander Motin (cgd.inq_flags & SID_DMA) && (cgd.inq_flags & SID_CmdQue)) 914581b2e78SAlexander Motin softc->flags |= ADA_FLAG_CAN_NCQ; 915581b2e78SAlexander Motin else 916581b2e78SAlexander Motin softc->flags &= ~ADA_FLAG_CAN_NCQ; 917581b2e78SAlexander Motin if ((cgd.ident_data.support_dsm & ATA_SUPPORT_DSM_TRIM) && 918581b2e78SAlexander Motin (cgd.inq_flags & SID_DMA)) 919581b2e78SAlexander Motin softc->flags |= ADA_FLAG_CAN_TRIM; 920581b2e78SAlexander Motin else 921581b2e78SAlexander Motin softc->flags &= ~ADA_FLAG_CAN_TRIM; 922581b2e78SAlexander Motin 923581b2e78SAlexander Motin cam_periph_async(periph, code, path, arg); 924581b2e78SAlexander Motin break; 925581b2e78SAlexander Motin } 9263089bb2eSAlexander Motin case AC_ADVINFO_CHANGED: 9273089bb2eSAlexander Motin { 9283089bb2eSAlexander Motin uintptr_t buftype; 9293089bb2eSAlexander Motin 9303089bb2eSAlexander Motin buftype = (uintptr_t)arg; 9313089bb2eSAlexander Motin if (buftype == CDAI_TYPE_PHYS_PATH) { 9323089bb2eSAlexander Motin struct ada_softc *softc; 9333089bb2eSAlexander Motin 9343089bb2eSAlexander Motin softc = periph->softc; 9353089bb2eSAlexander Motin disk_attr_changed(softc->disk, "GEOM::physpath", 9363089bb2eSAlexander Motin M_NOWAIT); 9373089bb2eSAlexander Motin } 9383089bb2eSAlexander Motin break; 9393089bb2eSAlexander Motin } 940f513d14cSAlexander Motin case AC_SENT_BDR: 941f513d14cSAlexander Motin case AC_BUS_RESET: 942f513d14cSAlexander Motin { 943f513d14cSAlexander Motin softc = (struct ada_softc *)periph->softc; 944f513d14cSAlexander Motin cam_periph_async(periph, code, path, arg); 945f513d14cSAlexander Motin if (softc->state != ADA_STATE_NORMAL) 946f513d14cSAlexander Motin break; 947e3a6d3a4SAlexander Motin xpt_setup_ccb(&cgd.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 948f513d14cSAlexander Motin cgd.ccb_h.func_code = XPT_GDEV_TYPE; 949f513d14cSAlexander Motin xpt_action((union ccb *)&cgd); 9501ed6aaf9SAlexander Motin if (ADA_RA >= 0 && 9511ed6aaf9SAlexander Motin cgd.ident_data.support.command1 & ATA_SUPPORT_LOOKAHEAD) 9521ed6aaf9SAlexander Motin softc->state = ADA_STATE_RAHEAD; 9531ed6aaf9SAlexander Motin else if (ADA_WC >= 0 && 9541ed6aaf9SAlexander Motin cgd.ident_data.support.command1 & ATA_SUPPORT_WRITECACHE) 955f513d14cSAlexander Motin softc->state = ADA_STATE_WCACHE; 9561ed6aaf9SAlexander Motin else 9571ed6aaf9SAlexander Motin break; 958f513d14cSAlexander Motin cam_periph_acquire(periph); 959f513d14cSAlexander Motin cam_freeze_devq_arg(periph->path, 960f513d14cSAlexander Motin RELSIM_RELEASE_RUNLEVEL, CAM_RL_DEV + 1); 961f513d14cSAlexander Motin xpt_schedule(periph, CAM_PRIORITY_DEV); 962f513d14cSAlexander Motin } 96352c9ce25SScott Long default: 96452c9ce25SScott Long cam_periph_async(periph, code, path, arg); 96552c9ce25SScott Long break; 96652c9ce25SScott Long } 96752c9ce25SScott Long } 96852c9ce25SScott Long 96952c9ce25SScott Long static void 97052c9ce25SScott Long adasysctlinit(void *context, int pending) 97152c9ce25SScott Long { 97252c9ce25SScott Long struct cam_periph *periph; 97352c9ce25SScott Long struct ada_softc *softc; 97452c9ce25SScott Long char tmpstr[80], tmpstr2[80]; 97552c9ce25SScott Long 97652c9ce25SScott Long periph = (struct cam_periph *)context; 977e3a6d3a4SAlexander Motin 978e3a6d3a4SAlexander Motin /* periph was held for us when this task was enqueued */ 979e3a6d3a4SAlexander Motin if (periph->flags & CAM_PERIPH_INVALID) { 980e3a6d3a4SAlexander Motin cam_periph_release(periph); 98152c9ce25SScott Long return; 982e3a6d3a4SAlexander Motin } 98352c9ce25SScott Long 98452c9ce25SScott Long softc = (struct ada_softc *)periph->softc; 98552c9ce25SScott Long snprintf(tmpstr, sizeof(tmpstr), "CAM ADA unit %d", periph->unit_number); 98652c9ce25SScott Long snprintf(tmpstr2, sizeof(tmpstr2), "%d", periph->unit_number); 98752c9ce25SScott Long 98852c9ce25SScott Long sysctl_ctx_init(&softc->sysctl_ctx); 98952c9ce25SScott Long softc->flags |= ADA_FLAG_SCTX_INIT; 99052c9ce25SScott Long softc->sysctl_tree = SYSCTL_ADD_NODE(&softc->sysctl_ctx, 99152c9ce25SScott Long SYSCTL_STATIC_CHILDREN(_kern_cam_ada), OID_AUTO, tmpstr2, 99252c9ce25SScott Long CTLFLAG_RD, 0, tmpstr); 99352c9ce25SScott Long if (softc->sysctl_tree == NULL) { 99452c9ce25SScott Long printf("adasysctlinit: unable to allocate sysctl tree\n"); 99552c9ce25SScott Long cam_periph_release(periph); 99652c9ce25SScott Long return; 99752c9ce25SScott Long } 99852c9ce25SScott Long 999e3a6d3a4SAlexander Motin SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 10001ed6aaf9SAlexander Motin OID_AUTO, "read_ahead", CTLFLAG_RW | CTLFLAG_MPSAFE, 10011ed6aaf9SAlexander Motin &softc->read_ahead, 0, "Enable disk read ahead."); 10021ed6aaf9SAlexander Motin SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 1003e3a6d3a4SAlexander Motin OID_AUTO, "write_cache", CTLFLAG_RW | CTLFLAG_MPSAFE, 1004e3a6d3a4SAlexander Motin &softc->write_cache, 0, "Enable disk write cache."); 10055f83aee5SSteven Hartland SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 10065f83aee5SSteven Hartland OID_AUTO, "sort_io_queue", CTLFLAG_RW | CTLFLAG_MPSAFE, 10075f83aee5SSteven Hartland &softc->sort_io_queue, 0, 10085f83aee5SSteven Hartland "Sort IO queue to try and optimise disk access patterns"); 1009e3a6d3a4SAlexander Motin #ifdef ADA_TEST_FAILURE 1010e3a6d3a4SAlexander Motin /* 1011e3a6d3a4SAlexander Motin * Add a 'door bell' sysctl which allows one to set it from userland 1012e3a6d3a4SAlexander Motin * and cause something bad to happen. For the moment, we only allow 1013e3a6d3a4SAlexander Motin * whacking the next read or write. 1014e3a6d3a4SAlexander Motin */ 1015e3a6d3a4SAlexander Motin SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 1016e3a6d3a4SAlexander Motin OID_AUTO, "force_read_error", CTLFLAG_RW | CTLFLAG_MPSAFE, 1017e3a6d3a4SAlexander Motin &softc->force_read_error, 0, 1018e3a6d3a4SAlexander Motin "Force a read error for the next N reads."); 1019e3a6d3a4SAlexander Motin SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 1020e3a6d3a4SAlexander Motin OID_AUTO, "force_write_error", CTLFLAG_RW | CTLFLAG_MPSAFE, 1021e3a6d3a4SAlexander Motin &softc->force_write_error, 0, 1022e3a6d3a4SAlexander Motin "Force a write error for the next N writes."); 1023e3a6d3a4SAlexander Motin SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 1024e3a6d3a4SAlexander Motin OID_AUTO, "periodic_read_error", CTLFLAG_RW | CTLFLAG_MPSAFE, 1025e3a6d3a4SAlexander Motin &softc->periodic_read_error, 0, 1026e3a6d3a4SAlexander Motin "Force a read error every N reads (don't set too low)."); 1027e3a6d3a4SAlexander Motin #endif 102852c9ce25SScott Long cam_periph_release(periph); 102952c9ce25SScott Long } 103052c9ce25SScott Long 1031416494d7SJustin T. Gibbs static int 1032416494d7SJustin T. Gibbs adagetattr(struct bio *bp) 1033416494d7SJustin T. Gibbs { 10346884b662SAlexander Motin int ret; 1035416494d7SJustin T. Gibbs struct cam_periph *periph; 1036416494d7SJustin T. Gibbs 1037416494d7SJustin T. Gibbs periph = (struct cam_periph *)bp->bio_disk->d_drv1; 10386884b662SAlexander Motin cam_periph_lock(periph); 1039416494d7SJustin T. Gibbs ret = xpt_getattr(bp->bio_data, bp->bio_length, bp->bio_attribute, 1040416494d7SJustin T. Gibbs periph->path); 10416884b662SAlexander Motin cam_periph_unlock(periph); 1042416494d7SJustin T. Gibbs if (ret == 0) 1043416494d7SJustin T. Gibbs bp->bio_completed = bp->bio_length; 1044416494d7SJustin T. Gibbs return ret; 1045416494d7SJustin T. Gibbs } 1046416494d7SJustin T. Gibbs 104752c9ce25SScott Long static cam_status 104852c9ce25SScott Long adaregister(struct cam_periph *periph, void *arg) 104952c9ce25SScott Long { 105052c9ce25SScott Long struct ada_softc *softc; 105152c9ce25SScott Long struct ccb_pathinq cpi; 105252c9ce25SScott Long struct ccb_getdev *cgd; 10530d307e09SAlexander Motin char announce_buf[80], buf1[32]; 105452c9ce25SScott Long struct disk_params *dp; 105552c9ce25SScott Long caddr_t match; 105652c9ce25SScott Long u_int maxio; 1057d3a460d3SAlexander Motin int legacy_id, quirks; 105852c9ce25SScott Long 105952c9ce25SScott Long cgd = (struct ccb_getdev *)arg; 106052c9ce25SScott Long if (cgd == NULL) { 106152c9ce25SScott Long printf("adaregister: no getdev CCB, can't register device\n"); 106252c9ce25SScott Long return(CAM_REQ_CMP_ERR); 106352c9ce25SScott Long } 106452c9ce25SScott Long 106552c9ce25SScott Long softc = (struct ada_softc *)malloc(sizeof(*softc), M_DEVBUF, 106652c9ce25SScott Long M_NOWAIT|M_ZERO); 106752c9ce25SScott Long 106852c9ce25SScott Long if (softc == NULL) { 106952c9ce25SScott Long printf("adaregister: Unable to probe new device. " 107052c9ce25SScott Long "Unable to allocate softc\n"); 107152c9ce25SScott Long return(CAM_REQ_CMP_ERR); 107252c9ce25SScott Long } 107352c9ce25SScott Long 107452c9ce25SScott Long bioq_init(&softc->bio_queue); 10751c80ec0aSAlexander Motin bioq_init(&softc->trim_queue); 107652c9ce25SScott Long 1077581b2e78SAlexander Motin if ((cgd->ident_data.capabilities1 & ATA_SUPPORT_DMA) && 1078cf2b9a5fSAlexander Motin (cgd->inq_flags & SID_DMA)) 107946f118feSAlexander Motin softc->flags |= ADA_FLAG_CAN_DMA; 1080*2e1eb332SMarius Strobl if (cgd->ident_data.support.command2 & ATA_SUPPORT_ADDRESS48) { 108152c9ce25SScott Long softc->flags |= ADA_FLAG_CAN_48BIT; 1082*2e1eb332SMarius Strobl if (cgd->inq_flags & SID_DMA48) 1083*2e1eb332SMarius Strobl softc->flags |= ADA_FLAG_CAN_DMA48; 1084*2e1eb332SMarius Strobl } 108552c9ce25SScott Long if (cgd->ident_data.support.command2 & ATA_SUPPORT_FLUSHCACHE) 108652c9ce25SScott Long softc->flags |= ADA_FLAG_CAN_FLUSHCACHE; 1087fd104c15SRebecca Cran if (cgd->ident_data.support.command1 & ATA_SUPPORT_POWERMGT) 1088fd104c15SRebecca Cran softc->flags |= ADA_FLAG_CAN_POWERMGT; 1089581b2e78SAlexander Motin if ((cgd->ident_data.satacapabilities & ATA_SUPPORT_NCQ) && 1090cf2b9a5fSAlexander Motin (cgd->inq_flags & SID_DMA) && (cgd->inq_flags & SID_CmdQue)) 109152c9ce25SScott Long softc->flags |= ADA_FLAG_CAN_NCQ; 1092581b2e78SAlexander Motin if ((cgd->ident_data.support_dsm & ATA_SUPPORT_DSM_TRIM) && 1093581b2e78SAlexander Motin (cgd->inq_flags & SID_DMA)) { 10941c80ec0aSAlexander Motin softc->flags |= ADA_FLAG_CAN_TRIM; 10951c80ec0aSAlexander Motin softc->trim_max_ranges = TRIM_MAX_RANGES; 10961c80ec0aSAlexander Motin if (cgd->ident_data.max_dsm_blocks != 0) { 10971c80ec0aSAlexander Motin softc->trim_max_ranges = 10981c80ec0aSAlexander Motin min(cgd->ident_data.max_dsm_blocks * 64, 10991c80ec0aSAlexander Motin softc->trim_max_ranges); 11001c80ec0aSAlexander Motin } 11011c80ec0aSAlexander Motin } 11021c80ec0aSAlexander Motin if (cgd->ident_data.support.command2 & ATA_SUPPORT_CFA) 11031c80ec0aSAlexander Motin softc->flags |= ADA_FLAG_CAN_CFA; 110452c9ce25SScott Long 110552c9ce25SScott Long periph->softc = softc; 110652c9ce25SScott Long 110752c9ce25SScott Long /* 110852c9ce25SScott Long * See if this device has any quirks. 110952c9ce25SScott Long */ 111030a4094fSAlexander Motin match = cam_quirkmatch((caddr_t)&cgd->ident_data, 111130a4094fSAlexander Motin (caddr_t)ada_quirk_table, 111230a4094fSAlexander Motin sizeof(ada_quirk_table)/sizeof(*ada_quirk_table), 111330a4094fSAlexander Motin sizeof(*ada_quirk_table), ata_identify_match); 111452c9ce25SScott Long if (match != NULL) 111552c9ce25SScott Long softc->quirks = ((struct ada_quirk_entry *)match)->quirks; 111652c9ce25SScott Long else 111752c9ce25SScott Long softc->quirks = ADA_Q_NONE; 111852c9ce25SScott Long 111952c9ce25SScott Long bzero(&cpi, sizeof(cpi)); 112083c5d981SAlexander Motin xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NONE); 112152c9ce25SScott Long cpi.ccb_h.func_code = XPT_PATH_INQ; 112252c9ce25SScott Long xpt_action((union ccb *)&cpi); 112352c9ce25SScott Long 112452c9ce25SScott Long TASK_INIT(&softc->sysctl_task, 0, adasysctlinit, periph); 112552c9ce25SScott Long 112652c9ce25SScott Long /* 112752c9ce25SScott Long * Register this media as a disk 112852c9ce25SScott Long */ 1129781338b6SAlexander Motin (void)cam_periph_hold(periph, PRIBIO); 1130edec59d9SAlexander Motin cam_periph_unlock(periph); 1131d3a460d3SAlexander Motin snprintf(announce_buf, sizeof(announce_buf), 1132d3a460d3SAlexander Motin "kern.cam.ada.%d.quirks", periph->unit_number); 1133d3a460d3SAlexander Motin quirks = softc->quirks; 1134d3a460d3SAlexander Motin TUNABLE_INT_FETCH(announce_buf, &quirks); 1135d3a460d3SAlexander Motin softc->quirks = quirks; 11361ed6aaf9SAlexander Motin softc->read_ahead = -1; 11371ed6aaf9SAlexander Motin snprintf(announce_buf, sizeof(announce_buf), 11381ed6aaf9SAlexander Motin "kern.cam.ada.%d.read_ahead", periph->unit_number); 11391ed6aaf9SAlexander Motin TUNABLE_INT_FETCH(announce_buf, &softc->read_ahead); 1140781338b6SAlexander Motin softc->write_cache = -1; 1141781338b6SAlexander Motin snprintf(announce_buf, sizeof(announce_buf), 1142781338b6SAlexander Motin "kern.cam.ada.%d.write_cache", periph->unit_number); 1143781338b6SAlexander Motin TUNABLE_INT_FETCH(announce_buf, &softc->write_cache); 11445f83aee5SSteven Hartland softc->sort_io_queue = -1; 1145c1bd46c2SAlexander Motin adagetparams(periph, cgd); 114652c9ce25SScott Long softc->disk = disk_alloc(); 1147b8b6b5d3SAlexander Motin softc->disk->d_devstat = devstat_new_entry(periph->periph_name, 1148b8b6b5d3SAlexander Motin periph->unit_number, softc->params.secsize, 1149b8b6b5d3SAlexander Motin DEVSTAT_ALL_SUPPORTED, 1150b8b6b5d3SAlexander Motin DEVSTAT_TYPE_DIRECT | 1151b8b6b5d3SAlexander Motin XPORT_DEVSTAT_TYPE(cpi.transport), 1152b8b6b5d3SAlexander Motin DEVSTAT_PRIORITY_DISK); 115352c9ce25SScott Long softc->disk->d_open = adaopen; 115452c9ce25SScott Long softc->disk->d_close = adaclose; 115552c9ce25SScott Long softc->disk->d_strategy = adastrategy; 1156416494d7SJustin T. Gibbs softc->disk->d_getattr = adagetattr; 115752c9ce25SScott Long softc->disk->d_dump = adadump; 115852c9ce25SScott Long softc->disk->d_name = "ada"; 115952c9ce25SScott Long softc->disk->d_drv1 = periph; 116052c9ce25SScott Long maxio = cpi.maxio; /* Honor max I/O size of SIM */ 116152c9ce25SScott Long if (maxio == 0) 116252c9ce25SScott Long maxio = DFLTPHYS; /* traditional default */ 116352c9ce25SScott Long else if (maxio > MAXPHYS) 116452c9ce25SScott Long maxio = MAXPHYS; /* for safety */ 11651c80ec0aSAlexander Motin if (softc->flags & ADA_FLAG_CAN_48BIT) 1166c1bd46c2SAlexander Motin maxio = min(maxio, 65536 * softc->params.secsize); 116752c9ce25SScott Long else /* 28bit ATA command limit */ 1168c1bd46c2SAlexander Motin maxio = min(maxio, 256 * softc->params.secsize); 116952c9ce25SScott Long softc->disk->d_maxsize = maxio; 117052c9ce25SScott Long softc->disk->d_unit = periph->unit_number; 117152c9ce25SScott Long softc->disk->d_flags = 0; 117252c9ce25SScott Long if (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) 117352c9ce25SScott Long softc->disk->d_flags |= DISKFLAG_CANFLUSHCACHE; 11741c80ec0aSAlexander Motin if ((softc->flags & ADA_FLAG_CAN_TRIM) || 11751c80ec0aSAlexander Motin ((softc->flags & ADA_FLAG_CAN_CFA) && 11761c80ec0aSAlexander Motin !(softc->flags & ADA_FLAG_CAN_48BIT))) 11771c80ec0aSAlexander Motin softc->disk->d_flags |= DISKFLAG_CANDELETE; 1178abc1e60eSKonstantin Belousov if ((cpi.hba_misc & PIM_UNMAPPED) != 0) 1179abc1e60eSKonstantin Belousov softc->disk->d_flags |= DISKFLAG_UNMAPPED_BIO; 118065cb6238SNathan Whitehorn strlcpy(softc->disk->d_descr, cgd->ident_data.model, 118165cb6238SNathan Whitehorn MIN(sizeof(softc->disk->d_descr), sizeof(cgd->ident_data.model))); 1182d50aaa6dSAndriy Gapon strlcpy(softc->disk->d_ident, cgd->ident_data.serial, 1183d50aaa6dSAndriy Gapon MIN(sizeof(softc->disk->d_ident), sizeof(cgd->ident_data.serial))); 11848edcf694SAlexander Motin softc->disk->d_hba_vendor = cpi.hba_vendor; 11858edcf694SAlexander Motin softc->disk->d_hba_device = cpi.hba_device; 11868edcf694SAlexander Motin softc->disk->d_hba_subvendor = cpi.hba_subvendor; 11878edcf694SAlexander Motin softc->disk->d_hba_subdevice = cpi.hba_subdevice; 118852c9ce25SScott Long 118952c9ce25SScott Long softc->disk->d_sectorsize = softc->params.secsize; 1190c1bd46c2SAlexander Motin softc->disk->d_mediasize = (off_t)softc->params.sectors * 1191c1bd46c2SAlexander Motin softc->params.secsize; 1192ce8332d4SAlexander Motin if (ata_physical_sector_size(&cgd->ident_data) != 1193ce8332d4SAlexander Motin softc->params.secsize) { 1194ce8332d4SAlexander Motin softc->disk->d_stripesize = 1195ce8332d4SAlexander Motin ata_physical_sector_size(&cgd->ident_data); 1196ce8332d4SAlexander Motin softc->disk->d_stripeoffset = (softc->disk->d_stripesize - 1197ce8332d4SAlexander Motin ata_logical_sector_offset(&cgd->ident_data)) % 1198ce8332d4SAlexander Motin softc->disk->d_stripesize; 1199d3a460d3SAlexander Motin } else if (softc->quirks & ADA_Q_4K) { 1200d3a460d3SAlexander Motin softc->disk->d_stripesize = 4096; 1201d3a460d3SAlexander Motin softc->disk->d_stripeoffset = 0; 1202ce8332d4SAlexander Motin } 120352c9ce25SScott Long softc->disk->d_fwsectors = softc->params.secs_per_track; 120452c9ce25SScott Long softc->disk->d_fwheads = softc->params.heads; 12054461491bSMarius Strobl ata_disk_firmware_geom_adjust(softc->disk); 120652c9ce25SScott Long 12070d307e09SAlexander Motin if (ada_legacy_aliases) { 12080d307e09SAlexander Motin #ifdef ATA_STATIC_ID 12090d307e09SAlexander Motin legacy_id = xpt_path_legacy_ata_id(periph->path); 12100d307e09SAlexander Motin #else 12110d307e09SAlexander Motin legacy_id = softc->disk->d_unit; 12120d307e09SAlexander Motin #endif 12130d307e09SAlexander Motin if (legacy_id >= 0) { 12140d307e09SAlexander Motin snprintf(announce_buf, sizeof(announce_buf), 12150d307e09SAlexander Motin "kern.devalias.%s%d", 12160d307e09SAlexander Motin softc->disk->d_name, softc->disk->d_unit); 12170d307e09SAlexander Motin snprintf(buf1, sizeof(buf1), 12180d307e09SAlexander Motin "ad%d", legacy_id); 12190d307e09SAlexander Motin setenv(announce_buf, buf1); 12200d307e09SAlexander Motin } 12210d307e09SAlexander Motin } else 12220d307e09SAlexander Motin legacy_id = -1; 122352c9ce25SScott Long disk_create(softc->disk, DISK_VERSION); 1224edec59d9SAlexander Motin cam_periph_lock(periph); 1225781338b6SAlexander Motin cam_periph_unhold(periph); 122652c9ce25SScott Long 122752c9ce25SScott Long dp = &softc->params; 122852c9ce25SScott Long snprintf(announce_buf, sizeof(announce_buf), 122952c9ce25SScott Long "%juMB (%ju %u byte sectors: %dH %dS/T %dC)", 123052c9ce25SScott Long (uintmax_t)(((uintmax_t)dp->secsize * 123152c9ce25SScott Long dp->sectors) / (1024*1024)), 123252c9ce25SScott Long (uintmax_t)dp->sectors, 123352c9ce25SScott Long dp->secsize, dp->heads, 123452c9ce25SScott Long dp->secs_per_track, dp->cylinders); 123552c9ce25SScott Long xpt_announce_periph(periph, announce_buf); 12360d307e09SAlexander Motin if (legacy_id >= 0) 12370d307e09SAlexander Motin printf("%s%d: Previously was known as ad%d\n", 12380d307e09SAlexander Motin periph->periph_name, periph->unit_number, legacy_id); 1239e3a6d3a4SAlexander Motin 1240e3a6d3a4SAlexander Motin /* 1241e3a6d3a4SAlexander Motin * Create our sysctl variables, now that we know 1242e3a6d3a4SAlexander Motin * we have successfully attached. 1243e3a6d3a4SAlexander Motin */ 1244e3a6d3a4SAlexander Motin cam_periph_acquire(periph); 1245e3a6d3a4SAlexander Motin taskqueue_enqueue(taskqueue_thread, &softc->sysctl_task); 1246e3a6d3a4SAlexander Motin 124752c9ce25SScott Long /* 124852c9ce25SScott Long * Add async callbacks for bus reset and 124952c9ce25SScott Long * bus device reset calls. I don't bother 125052c9ce25SScott Long * checking if this fails as, in most cases, 125152c9ce25SScott Long * the system will function just fine without 125252c9ce25SScott Long * them and the only alternative would be to 125352c9ce25SScott Long * not attach the device on failure. 125452c9ce25SScott Long */ 12553089bb2eSAlexander Motin xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE | 1256581b2e78SAlexander Motin AC_GETDEV_CHANGED | AC_ADVINFO_CHANGED, 1257581b2e78SAlexander Motin adaasync, periph, periph->path); 125852c9ce25SScott Long 125952c9ce25SScott Long /* 126052c9ce25SScott Long * Schedule a periodic event to occasionally send an 126152c9ce25SScott Long * ordered tag to a device. 126252c9ce25SScott Long */ 126352c9ce25SScott Long callout_init_mtx(&softc->sendordered_c, periph->sim->mtx, 0); 126452c9ce25SScott Long callout_reset(&softc->sendordered_c, 126547bb9643SAlexander Motin (ada_default_timeout * hz) / ADA_ORDEREDTAG_INTERVAL, 126652c9ce25SScott Long adasendorderedtag, softc); 126752c9ce25SScott Long 12681ed6aaf9SAlexander Motin if (ADA_RA >= 0 && 12691ed6aaf9SAlexander Motin cgd->ident_data.support.command1 & ATA_SUPPORT_LOOKAHEAD) { 12701ed6aaf9SAlexander Motin softc->state = ADA_STATE_RAHEAD; 12711ed6aaf9SAlexander Motin cam_periph_acquire(periph); 12721ed6aaf9SAlexander Motin cam_freeze_devq_arg(periph->path, 12731ed6aaf9SAlexander Motin RELSIM_RELEASE_RUNLEVEL, CAM_RL_DEV + 1); 12741ed6aaf9SAlexander Motin xpt_schedule(periph, CAM_PRIORITY_DEV); 12751ed6aaf9SAlexander Motin } else if (ADA_WC >= 0 && 1276f513d14cSAlexander Motin cgd->ident_data.support.command1 & ATA_SUPPORT_WRITECACHE) { 1277f513d14cSAlexander Motin softc->state = ADA_STATE_WCACHE; 1278f513d14cSAlexander Motin cam_periph_acquire(periph); 1279f513d14cSAlexander Motin cam_freeze_devq_arg(periph->path, 1280f513d14cSAlexander Motin RELSIM_RELEASE_RUNLEVEL, CAM_RL_DEV + 1); 1281f513d14cSAlexander Motin xpt_schedule(periph, CAM_PRIORITY_DEV); 1282f513d14cSAlexander Motin } else 1283f513d14cSAlexander Motin softc->state = ADA_STATE_NORMAL; 1284f513d14cSAlexander Motin 128552c9ce25SScott Long return(CAM_REQ_CMP); 128652c9ce25SScott Long } 128752c9ce25SScott Long 128852c9ce25SScott Long static void 128952c9ce25SScott Long adastart(struct cam_periph *periph, union ccb *start_ccb) 129052c9ce25SScott Long { 129146f118feSAlexander Motin struct ada_softc *softc = (struct ada_softc *)periph->softc; 129246f118feSAlexander Motin struct ccb_ataio *ataio = &start_ccb->ataio; 129352c9ce25SScott Long 1294fddde2b8SAlexander Motin CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("adastart\n")); 1295fddde2b8SAlexander Motin 129652c9ce25SScott Long switch (softc->state) { 129752c9ce25SScott Long case ADA_STATE_NORMAL: 129852c9ce25SScott Long { 129952c9ce25SScott Long struct bio *bp; 13001c80ec0aSAlexander Motin u_int8_t tag_code; 130152c9ce25SScott Long 13021c80ec0aSAlexander Motin /* Execute immediate CCB if waiting. */ 130352c9ce25SScott Long if (periph->immediate_priority <= periph->pinfo.priority) { 1304fddde2b8SAlexander Motin CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 130552c9ce25SScott Long ("queuing for immediate ccb\n")); 130652c9ce25SScott Long start_ccb->ccb_h.ccb_state = ADA_CCB_WAITING; 130752c9ce25SScott Long SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, 130852c9ce25SScott Long periph_links.sle); 130952c9ce25SScott Long periph->immediate_priority = CAM_PRIORITY_NONE; 131052c9ce25SScott Long wakeup(&periph->ccb_list); 13111c80ec0aSAlexander Motin /* Have more work to do, so ensure we stay scheduled */ 13121c80ec0aSAlexander Motin adaschedule(periph); 13131c80ec0aSAlexander Motin break; 13141c80ec0aSAlexander Motin } 13151c80ec0aSAlexander Motin /* Run TRIM if not running yet. */ 13161c80ec0aSAlexander Motin if (!softc->trim_running && 13171c80ec0aSAlexander Motin (bp = bioq_first(&softc->trim_queue)) != 0) { 13181c80ec0aSAlexander Motin struct trim_request *req = &softc->trim_req; 13191c80ec0aSAlexander Motin struct bio *bp1; 132037ddbd16SAlexander Motin uint64_t lastlba = (uint64_t)-1; 132137ddbd16SAlexander Motin int bps = 0, c, lastcount = 0, off, ranges = 0; 132252c9ce25SScott Long 13231c80ec0aSAlexander Motin softc->trim_running = 1; 13241c80ec0aSAlexander Motin bzero(req, sizeof(*req)); 13251c80ec0aSAlexander Motin bp1 = bp; 13261c80ec0aSAlexander Motin do { 13271c80ec0aSAlexander Motin uint64_t lba = bp1->bio_pblkno; 13281c80ec0aSAlexander Motin int count = bp1->bio_bcount / 13291c80ec0aSAlexander Motin softc->params.secsize; 13301c80ec0aSAlexander Motin 13311c80ec0aSAlexander Motin bioq_remove(&softc->trim_queue, bp1); 13321c80ec0aSAlexander Motin 133337ddbd16SAlexander Motin /* Try to extend the previous range. */ 133437ddbd16SAlexander Motin if (lba == lastlba) { 133537ddbd16SAlexander Motin c = min(count, 0xffff - lastcount); 133637ddbd16SAlexander Motin lastcount += c; 133737ddbd16SAlexander Motin off = (ranges - 1) * 8; 133837ddbd16SAlexander Motin req->data[off + 6] = lastcount & 0xff; 133937ddbd16SAlexander Motin req->data[off + 7] = 134037ddbd16SAlexander Motin (lastcount >> 8) & 0xff; 134137ddbd16SAlexander Motin count -= c; 134237ddbd16SAlexander Motin lba += c; 134337ddbd16SAlexander Motin } 134437ddbd16SAlexander Motin 134537ddbd16SAlexander Motin while (count > 0) { 134637ddbd16SAlexander Motin c = min(count, 0xffff); 134737ddbd16SAlexander Motin off = ranges * 8; 13481c80ec0aSAlexander Motin req->data[off + 0] = lba & 0xff; 13491c80ec0aSAlexander Motin req->data[off + 1] = (lba >> 8) & 0xff; 13501c80ec0aSAlexander Motin req->data[off + 2] = (lba >> 16) & 0xff; 13511c80ec0aSAlexander Motin req->data[off + 3] = (lba >> 24) & 0xff; 13521c80ec0aSAlexander Motin req->data[off + 4] = (lba >> 32) & 0xff; 13531c80ec0aSAlexander Motin req->data[off + 5] = (lba >> 40) & 0xff; 13541c80ec0aSAlexander Motin req->data[off + 6] = c & 0xff; 13551c80ec0aSAlexander Motin req->data[off + 7] = (c >> 8) & 0xff; 13561c80ec0aSAlexander Motin lba += c; 13571c80ec0aSAlexander Motin count -= c; 135837ddbd16SAlexander Motin lastcount = c; 13591c80ec0aSAlexander Motin ranges++; 13601c80ec0aSAlexander Motin } 136137ddbd16SAlexander Motin lastlba = lba; 13621c80ec0aSAlexander Motin req->bps[bps++] = bp1; 13631c80ec0aSAlexander Motin bp1 = bioq_first(&softc->trim_queue); 136437ddbd16SAlexander Motin if (bps >= TRIM_MAX_BIOS || 136537ddbd16SAlexander Motin bp1 == NULL || 13661c80ec0aSAlexander Motin bp1->bio_bcount / softc->params.secsize > 13671c80ec0aSAlexander Motin (softc->trim_max_ranges - ranges) * 0xffff) 13681c80ec0aSAlexander Motin break; 13691c80ec0aSAlexander Motin } while (1); 13701c80ec0aSAlexander Motin cam_fill_ataio(ataio, 13711c80ec0aSAlexander Motin ada_retry_count, 13721c80ec0aSAlexander Motin adadone, 13731c80ec0aSAlexander Motin CAM_DIR_OUT, 13741c80ec0aSAlexander Motin 0, 13751c80ec0aSAlexander Motin req->data, 13761c80ec0aSAlexander Motin ((ranges + 63) / 64) * 512, 13771c80ec0aSAlexander Motin ada_default_timeout * 1000); 13781c80ec0aSAlexander Motin ata_48bit_cmd(ataio, ATA_DATA_SET_MANAGEMENT, 13791c80ec0aSAlexander Motin ATA_DSM_TRIM, 0, (ranges + 63) / 64); 13801c80ec0aSAlexander Motin start_ccb->ccb_h.ccb_state = ADA_CCB_TRIM; 13811c80ec0aSAlexander Motin goto out; 13821c80ec0aSAlexander Motin } 13831c80ec0aSAlexander Motin /* Run regular command. */ 13841c80ec0aSAlexander Motin bp = bioq_first(&softc->bio_queue); 13851c80ec0aSAlexander Motin if (bp == NULL) { 13861c80ec0aSAlexander Motin xpt_release_ccb(start_ccb); 13871c80ec0aSAlexander Motin break; 13881c80ec0aSAlexander Motin } 138952c9ce25SScott Long bioq_remove(&softc->bio_queue, bp); 139052c9ce25SScott Long 1391f03f7a0cSJustin T. Gibbs if ((bp->bio_flags & BIO_ORDERED) != 0 1392f03f7a0cSJustin T. Gibbs || (softc->flags & ADA_FLAG_NEED_OTAG) != 0) { 139352c9ce25SScott Long softc->flags &= ~ADA_FLAG_NEED_OTAG; 139452c9ce25SScott Long softc->ordered_tag_count++; 139546f118feSAlexander Motin tag_code = 0; 139652c9ce25SScott Long } else { 139746f118feSAlexander Motin tag_code = 1; 139852c9ce25SScott Long } 139952c9ce25SScott Long switch (bp->bio_cmd) { 140052c9ce25SScott Long case BIO_READ: 140152c9ce25SScott Long case BIO_WRITE: 140252c9ce25SScott Long { 140352c9ce25SScott Long uint64_t lba = bp->bio_pblkno; 140452c9ce25SScott Long uint16_t count = bp->bio_bcount / softc->params.secsize; 1405e3a6d3a4SAlexander Motin #ifdef ADA_TEST_FAILURE 1406e3a6d3a4SAlexander Motin int fail = 0; 140752c9ce25SScott Long 1408e3a6d3a4SAlexander Motin /* 1409e3a6d3a4SAlexander Motin * Support the failure ioctls. If the command is a 1410e3a6d3a4SAlexander Motin * read, and there are pending forced read errors, or 1411e3a6d3a4SAlexander Motin * if a write and pending write errors, then fail this 1412e3a6d3a4SAlexander Motin * operation with EIO. This is useful for testing 1413e3a6d3a4SAlexander Motin * purposes. Also, support having every Nth read fail. 1414e3a6d3a4SAlexander Motin * 1415e3a6d3a4SAlexander Motin * This is a rather blunt tool. 1416e3a6d3a4SAlexander Motin */ 1417e3a6d3a4SAlexander Motin if (bp->bio_cmd == BIO_READ) { 1418e3a6d3a4SAlexander Motin if (softc->force_read_error) { 1419e3a6d3a4SAlexander Motin softc->force_read_error--; 1420e3a6d3a4SAlexander Motin fail = 1; 1421e3a6d3a4SAlexander Motin } 1422e3a6d3a4SAlexander Motin if (softc->periodic_read_error > 0) { 1423e3a6d3a4SAlexander Motin if (++softc->periodic_read_count >= 1424e3a6d3a4SAlexander Motin softc->periodic_read_error) { 1425e3a6d3a4SAlexander Motin softc->periodic_read_count = 0; 1426e3a6d3a4SAlexander Motin fail = 1; 1427e3a6d3a4SAlexander Motin } 1428e3a6d3a4SAlexander Motin } 1429e3a6d3a4SAlexander Motin } else { 1430e3a6d3a4SAlexander Motin if (softc->force_write_error) { 1431e3a6d3a4SAlexander Motin softc->force_write_error--; 1432e3a6d3a4SAlexander Motin fail = 1; 1433e3a6d3a4SAlexander Motin } 1434e3a6d3a4SAlexander Motin } 1435e3a6d3a4SAlexander Motin if (fail) { 1436e3a6d3a4SAlexander Motin bp->bio_error = EIO; 1437e3a6d3a4SAlexander Motin bp->bio_flags |= BIO_ERROR; 1438e3a6d3a4SAlexander Motin biodone(bp); 1439e3a6d3a4SAlexander Motin xpt_release_ccb(start_ccb); 1440e3a6d3a4SAlexander Motin adaschedule(periph); 1441e3a6d3a4SAlexander Motin return; 1442e3a6d3a4SAlexander Motin } 1443e3a6d3a4SAlexander Motin #endif 1444abc1e60eSKonstantin Belousov KASSERT((bp->bio_flags & BIO_UNMAPPED) == 0 || 1445abc1e60eSKonstantin Belousov round_page(bp->bio_bcount + bp->bio_ma_offset) / 1446abc1e60eSKonstantin Belousov PAGE_SIZE == bp->bio_ma_n, 1447abc1e60eSKonstantin Belousov ("Short bio %p", bp)); 144852c9ce25SScott Long cam_fill_ataio(ataio, 144952c9ce25SScott Long ada_retry_count, 145052c9ce25SScott Long adadone, 1451abc1e60eSKonstantin Belousov (bp->bio_cmd == BIO_READ ? CAM_DIR_IN : 1452abc1e60eSKonstantin Belousov CAM_DIR_OUT) | ((bp->bio_flags & BIO_UNMAPPED) 1453abc1e60eSKonstantin Belousov != 0 ? CAM_DATA_BIO : 0), 145452c9ce25SScott Long tag_code, 1455abc1e60eSKonstantin Belousov ((bp->bio_flags & BIO_UNMAPPED) != 0) ? (void *)bp : 145652c9ce25SScott Long bp->bio_data, 145752c9ce25SScott Long bp->bio_bcount, 145852c9ce25SScott Long ada_default_timeout*1000); 145952c9ce25SScott Long 146046f118feSAlexander Motin if ((softc->flags & ADA_FLAG_CAN_NCQ) && tag_code) { 146152c9ce25SScott Long if (bp->bio_cmd == BIO_READ) { 146252c9ce25SScott Long ata_ncq_cmd(ataio, ATA_READ_FPDMA_QUEUED, 146352c9ce25SScott Long lba, count); 146452c9ce25SScott Long } else { 146552c9ce25SScott Long ata_ncq_cmd(ataio, ATA_WRITE_FPDMA_QUEUED, 146652c9ce25SScott Long lba, count); 146752c9ce25SScott Long } 146852c9ce25SScott Long } else if ((softc->flags & ADA_FLAG_CAN_48BIT) && 146952c9ce25SScott Long (lba + count >= ATA_MAX_28BIT_LBA || 147046f118feSAlexander Motin count > 256)) { 1471*2e1eb332SMarius Strobl if (softc->flags & ADA_FLAG_CAN_DMA48) { 147252c9ce25SScott Long if (bp->bio_cmd == BIO_READ) { 147352c9ce25SScott Long ata_48bit_cmd(ataio, ATA_READ_DMA48, 147452c9ce25SScott Long 0, lba, count); 147552c9ce25SScott Long } else { 147652c9ce25SScott Long ata_48bit_cmd(ataio, ATA_WRITE_DMA48, 147752c9ce25SScott Long 0, lba, count); 147852c9ce25SScott Long } 147952c9ce25SScott Long } else { 148052c9ce25SScott Long if (bp->bio_cmd == BIO_READ) { 148146f118feSAlexander Motin ata_48bit_cmd(ataio, ATA_READ_MUL48, 148246f118feSAlexander Motin 0, lba, count); 148346f118feSAlexander Motin } else { 148446f118feSAlexander Motin ata_48bit_cmd(ataio, ATA_WRITE_MUL48, 148546f118feSAlexander Motin 0, lba, count); 148646f118feSAlexander Motin } 148746f118feSAlexander Motin } 148846f118feSAlexander Motin } else { 148946f118feSAlexander Motin if (count == 256) 149046f118feSAlexander Motin count = 0; 149146f118feSAlexander Motin if (softc->flags & ADA_FLAG_CAN_DMA) { 149246f118feSAlexander Motin if (bp->bio_cmd == BIO_READ) { 14937606b445SAlexander Motin ata_28bit_cmd(ataio, ATA_READ_DMA, 149452c9ce25SScott Long 0, lba, count); 149552c9ce25SScott Long } else { 14967606b445SAlexander Motin ata_28bit_cmd(ataio, ATA_WRITE_DMA, 149752c9ce25SScott Long 0, lba, count); 149852c9ce25SScott Long } 149946f118feSAlexander Motin } else { 150046f118feSAlexander Motin if (bp->bio_cmd == BIO_READ) { 150146f118feSAlexander Motin ata_28bit_cmd(ataio, ATA_READ_MUL, 150246f118feSAlexander Motin 0, lba, count); 150346f118feSAlexander Motin } else { 150446f118feSAlexander Motin ata_28bit_cmd(ataio, ATA_WRITE_MUL, 150546f118feSAlexander Motin 0, lba, count); 150646f118feSAlexander Motin } 150746f118feSAlexander Motin } 150852c9ce25SScott Long } 150952c9ce25SScott Long break; 15101c80ec0aSAlexander Motin } 15111c80ec0aSAlexander Motin case BIO_DELETE: 15121c80ec0aSAlexander Motin { 15131c80ec0aSAlexander Motin uint64_t lba = bp->bio_pblkno; 15141c80ec0aSAlexander Motin uint16_t count = bp->bio_bcount / softc->params.secsize; 15151c80ec0aSAlexander Motin 15161c80ec0aSAlexander Motin cam_fill_ataio(ataio, 15171c80ec0aSAlexander Motin ada_retry_count, 15181c80ec0aSAlexander Motin adadone, 15191c80ec0aSAlexander Motin CAM_DIR_NONE, 15201c80ec0aSAlexander Motin 0, 15211c80ec0aSAlexander Motin NULL, 15221c80ec0aSAlexander Motin 0, 15231c80ec0aSAlexander Motin ada_default_timeout*1000); 15241c80ec0aSAlexander Motin 15251c80ec0aSAlexander Motin if (count >= 256) 15261c80ec0aSAlexander Motin count = 0; 15271c80ec0aSAlexander Motin ata_28bit_cmd(ataio, ATA_CFA_ERASE, 0, lba, count); 15281c80ec0aSAlexander Motin break; 15291c80ec0aSAlexander Motin } 153052c9ce25SScott Long case BIO_FLUSH: 153152c9ce25SScott Long cam_fill_ataio(ataio, 153252c9ce25SScott Long 1, 153352c9ce25SScott Long adadone, 153452c9ce25SScott Long CAM_DIR_NONE, 153546f118feSAlexander Motin 0, 153652c9ce25SScott Long NULL, 153752c9ce25SScott Long 0, 153852c9ce25SScott Long ada_default_timeout*1000); 153952c9ce25SScott Long 154052c9ce25SScott Long if (softc->flags & ADA_FLAG_CAN_48BIT) 154152c9ce25SScott Long ata_48bit_cmd(ataio, ATA_FLUSHCACHE48, 0, 0, 0); 154252c9ce25SScott Long else 15437606b445SAlexander Motin ata_28bit_cmd(ataio, ATA_FLUSHCACHE, 0, 0, 0); 154452c9ce25SScott Long break; 154552c9ce25SScott Long } 154652c9ce25SScott Long start_ccb->ccb_h.ccb_state = ADA_CCB_BUFFER_IO; 15471c80ec0aSAlexander Motin out: 154852c9ce25SScott Long start_ccb->ccb_h.ccb_bp = bp; 1549c1bd46c2SAlexander Motin softc->outstanding_cmds++; 155052c9ce25SScott Long xpt_action(start_ccb); 155152c9ce25SScott Long 15521c80ec0aSAlexander Motin /* May have more work to do, so ensure we stay scheduled */ 15531c80ec0aSAlexander Motin adaschedule(periph); 155452c9ce25SScott Long break; 155552c9ce25SScott Long } 15561ed6aaf9SAlexander Motin case ADA_STATE_RAHEAD: 1557f513d14cSAlexander Motin case ADA_STATE_WCACHE: 1558f513d14cSAlexander Motin { 15591ed6aaf9SAlexander Motin if (softc->flags & ADA_FLAG_PACK_INVALID) { 15601ed6aaf9SAlexander Motin softc->state = ADA_STATE_NORMAL; 15611ed6aaf9SAlexander Motin xpt_release_ccb(start_ccb); 15621ed6aaf9SAlexander Motin cam_release_devq(periph->path, 15631ed6aaf9SAlexander Motin RELSIM_RELEASE_RUNLEVEL, 0, CAM_RL_DEV + 1, FALSE); 15641ed6aaf9SAlexander Motin adaschedule(periph); 15651ed6aaf9SAlexander Motin cam_periph_release_locked(periph); 15661ed6aaf9SAlexander Motin return; 15671ed6aaf9SAlexander Motin } 15681ed6aaf9SAlexander Motin 1569f513d14cSAlexander Motin cam_fill_ataio(ataio, 1570f513d14cSAlexander Motin 1, 1571f513d14cSAlexander Motin adadone, 1572f513d14cSAlexander Motin CAM_DIR_NONE, 1573f513d14cSAlexander Motin 0, 1574f513d14cSAlexander Motin NULL, 1575f513d14cSAlexander Motin 0, 1576f513d14cSAlexander Motin ada_default_timeout*1000); 1577f513d14cSAlexander Motin 15781ed6aaf9SAlexander Motin if (softc->state == ADA_STATE_RAHEAD) { 15791ed6aaf9SAlexander Motin ata_28bit_cmd(ataio, ATA_SETFEATURES, ADA_RA ? 15801ed6aaf9SAlexander Motin ATA_SF_ENAB_RCACHE : ATA_SF_DIS_RCACHE, 0, 0); 15811ed6aaf9SAlexander Motin start_ccb->ccb_h.ccb_state = ADA_CCB_RAHEAD; 15821ed6aaf9SAlexander Motin } else { 15831ed6aaf9SAlexander Motin ata_28bit_cmd(ataio, ATA_SETFEATURES, ADA_WC ? 1584f513d14cSAlexander Motin ATA_SF_ENAB_WCACHE : ATA_SF_DIS_WCACHE, 0, 0); 1585f513d14cSAlexander Motin start_ccb->ccb_h.ccb_state = ADA_CCB_WCACHE; 15861ed6aaf9SAlexander Motin } 1587f513d14cSAlexander Motin xpt_action(start_ccb); 1588f513d14cSAlexander Motin break; 1589f513d14cSAlexander Motin } 159052c9ce25SScott Long } 159152c9ce25SScott Long } 159252c9ce25SScott Long 159352c9ce25SScott Long static void 159452c9ce25SScott Long adadone(struct cam_periph *periph, union ccb *done_ccb) 159552c9ce25SScott Long { 159652c9ce25SScott Long struct ada_softc *softc; 159752c9ce25SScott Long struct ccb_ataio *ataio; 15981ed6aaf9SAlexander Motin struct ccb_getdev *cgd; 159952c9ce25SScott Long 160052c9ce25SScott Long softc = (struct ada_softc *)periph->softc; 160152c9ce25SScott Long ataio = &done_ccb->ataio; 1602fddde2b8SAlexander Motin 1603fddde2b8SAlexander Motin CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("adadone\n")); 1604fddde2b8SAlexander Motin 160552c9ce25SScott Long switch (ataio->ccb_h.ccb_state & ADA_CCB_TYPE_MASK) { 160652c9ce25SScott Long case ADA_CCB_BUFFER_IO: 16071c80ec0aSAlexander Motin case ADA_CCB_TRIM: 160852c9ce25SScott Long { 160952c9ce25SScott Long struct bio *bp; 161052c9ce25SScott Long 161152c9ce25SScott Long bp = (struct bio *)done_ccb->ccb_h.ccb_bp; 161252c9ce25SScott Long if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 161352c9ce25SScott Long int error; 161452c9ce25SScott Long 161546f118feSAlexander Motin error = adaerror(done_ccb, 0, 0); 161652c9ce25SScott Long if (error == ERESTART) { 161746f118feSAlexander Motin /* A retry was scheduled, so just return. */ 161852c9ce25SScott Long return; 161952c9ce25SScott Long } 162052c9ce25SScott Long if (error != 0) { 1621c36bb43cSAlexander Motin if (error == ENXIO && 1622c36bb43cSAlexander Motin (softc->flags & ADA_FLAG_PACK_INVALID) == 0) { 162352c9ce25SScott Long /* 162452c9ce25SScott Long * Catastrophic error. Mark our pack as 162552c9ce25SScott Long * invalid. 162652c9ce25SScott Long */ 162752c9ce25SScott Long /* 162852c9ce25SScott Long * XXX See if this is really a media 162952c9ce25SScott Long * XXX change first? 163052c9ce25SScott Long */ 163152c9ce25SScott Long xpt_print(periph->path, 163252c9ce25SScott Long "Invalidating pack\n"); 163352c9ce25SScott Long softc->flags |= ADA_FLAG_PACK_INVALID; 163452c9ce25SScott Long } 163552c9ce25SScott Long bp->bio_error = error; 163652c9ce25SScott Long bp->bio_resid = bp->bio_bcount; 163752c9ce25SScott Long bp->bio_flags |= BIO_ERROR; 163852c9ce25SScott Long } else { 163952c9ce25SScott Long bp->bio_resid = ataio->resid; 164052c9ce25SScott Long bp->bio_error = 0; 164152c9ce25SScott Long if (bp->bio_resid != 0) 164252c9ce25SScott Long bp->bio_flags |= BIO_ERROR; 164352c9ce25SScott Long } 164452c9ce25SScott Long if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 164552c9ce25SScott Long cam_release_devq(done_ccb->ccb_h.path, 164652c9ce25SScott Long /*relsim_flags*/0, 164752c9ce25SScott Long /*reduction*/0, 164852c9ce25SScott Long /*timeout*/0, 164952c9ce25SScott Long /*getcount_only*/0); 165052c9ce25SScott Long } else { 165152c9ce25SScott Long if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 165252c9ce25SScott Long panic("REQ_CMP with QFRZN"); 165352c9ce25SScott Long bp->bio_resid = ataio->resid; 165452c9ce25SScott Long if (ataio->resid > 0) 165552c9ce25SScott Long bp->bio_flags |= BIO_ERROR; 165652c9ce25SScott Long } 165752c9ce25SScott Long softc->outstanding_cmds--; 165852c9ce25SScott Long if (softc->outstanding_cmds == 0) 165952c9ce25SScott Long softc->flags |= ADA_FLAG_WENT_IDLE; 16601c80ec0aSAlexander Motin if ((ataio->ccb_h.ccb_state & ADA_CCB_TYPE_MASK) == 16611c80ec0aSAlexander Motin ADA_CCB_TRIM) { 16621c80ec0aSAlexander Motin struct trim_request *req = 16631c80ec0aSAlexander Motin (struct trim_request *)ataio->data_ptr; 16641c80ec0aSAlexander Motin int i; 166552c9ce25SScott Long 166637ddbd16SAlexander Motin for (i = 1; i < TRIM_MAX_BIOS && req->bps[i]; i++) { 16671c80ec0aSAlexander Motin struct bio *bp1 = req->bps[i]; 16681c80ec0aSAlexander Motin 16691c80ec0aSAlexander Motin bp1->bio_resid = bp->bio_resid; 16701c80ec0aSAlexander Motin bp1->bio_error = bp->bio_error; 16711c80ec0aSAlexander Motin if (bp->bio_flags & BIO_ERROR) 16721c80ec0aSAlexander Motin bp1->bio_flags |= BIO_ERROR; 16731c80ec0aSAlexander Motin biodone(bp1); 16741c80ec0aSAlexander Motin } 16751c80ec0aSAlexander Motin softc->trim_running = 0; 16761c80ec0aSAlexander Motin biodone(bp); 16771c80ec0aSAlexander Motin adaschedule(periph); 16781c80ec0aSAlexander Motin } else 167952c9ce25SScott Long biodone(bp); 168052c9ce25SScott Long break; 168152c9ce25SScott Long } 16821ed6aaf9SAlexander Motin case ADA_CCB_RAHEAD: 16831ed6aaf9SAlexander Motin { 16841ed6aaf9SAlexander Motin if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 16851ed6aaf9SAlexander Motin if (adaerror(done_ccb, 0, 0) == ERESTART) { 16861ed6aaf9SAlexander Motin return; 16871ed6aaf9SAlexander Motin } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 16881ed6aaf9SAlexander Motin cam_release_devq(done_ccb->ccb_h.path, 16891ed6aaf9SAlexander Motin /*relsim_flags*/0, 16901ed6aaf9SAlexander Motin /*reduction*/0, 16911ed6aaf9SAlexander Motin /*timeout*/0, 16921ed6aaf9SAlexander Motin /*getcount_only*/0); 16931ed6aaf9SAlexander Motin } 16941ed6aaf9SAlexander Motin } 16951ed6aaf9SAlexander Motin 16961ed6aaf9SAlexander Motin /* 16971ed6aaf9SAlexander Motin * Since our peripheral may be invalidated by an error 16981ed6aaf9SAlexander Motin * above or an external event, we must release our CCB 16991ed6aaf9SAlexander Motin * before releasing the reference on the peripheral. 17001ed6aaf9SAlexander Motin * The peripheral will only go away once the last reference 17011ed6aaf9SAlexander Motin * is removed, and we need it around for the CCB release 17021ed6aaf9SAlexander Motin * operation. 17031ed6aaf9SAlexander Motin */ 17041ed6aaf9SAlexander Motin cgd = (struct ccb_getdev *)done_ccb; 17051ed6aaf9SAlexander Motin xpt_setup_ccb(&cgd->ccb_h, periph->path, CAM_PRIORITY_NORMAL); 17061ed6aaf9SAlexander Motin cgd->ccb_h.func_code = XPT_GDEV_TYPE; 17071ed6aaf9SAlexander Motin xpt_action((union ccb *)cgd); 17081ed6aaf9SAlexander Motin if (ADA_WC >= 0 && 17091ed6aaf9SAlexander Motin cgd->ident_data.support.command1 & ATA_SUPPORT_WRITECACHE) { 17101ed6aaf9SAlexander Motin softc->state = ADA_STATE_WCACHE; 17111ed6aaf9SAlexander Motin xpt_release_ccb(done_ccb); 17121ed6aaf9SAlexander Motin xpt_schedule(periph, CAM_PRIORITY_DEV); 17131ed6aaf9SAlexander Motin return; 17141ed6aaf9SAlexander Motin } 17151ed6aaf9SAlexander Motin softc->state = ADA_STATE_NORMAL; 17161ed6aaf9SAlexander Motin xpt_release_ccb(done_ccb); 17171ed6aaf9SAlexander Motin cam_release_devq(periph->path, 17181ed6aaf9SAlexander Motin RELSIM_RELEASE_RUNLEVEL, 0, CAM_RL_DEV + 1, FALSE); 17191ed6aaf9SAlexander Motin adaschedule(periph); 17201ed6aaf9SAlexander Motin cam_periph_release_locked(periph); 17211ed6aaf9SAlexander Motin return; 17221ed6aaf9SAlexander Motin } 1723f513d14cSAlexander Motin case ADA_CCB_WCACHE: 1724f513d14cSAlexander Motin { 1725f513d14cSAlexander Motin if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 1726f513d14cSAlexander Motin if (adaerror(done_ccb, 0, 0) == ERESTART) { 1727f513d14cSAlexander Motin return; 1728f513d14cSAlexander Motin } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 1729f513d14cSAlexander Motin cam_release_devq(done_ccb->ccb_h.path, 1730f513d14cSAlexander Motin /*relsim_flags*/0, 1731f513d14cSAlexander Motin /*reduction*/0, 1732f513d14cSAlexander Motin /*timeout*/0, 1733f513d14cSAlexander Motin /*getcount_only*/0); 1734f513d14cSAlexander Motin } 1735f513d14cSAlexander Motin } 1736f513d14cSAlexander Motin 1737f513d14cSAlexander Motin softc->state = ADA_STATE_NORMAL; 1738f513d14cSAlexander Motin /* 1739f513d14cSAlexander Motin * Since our peripheral may be invalidated by an error 1740f513d14cSAlexander Motin * above or an external event, we must release our CCB 1741f513d14cSAlexander Motin * before releasing the reference on the peripheral. 1742f513d14cSAlexander Motin * The peripheral will only go away once the last reference 1743f513d14cSAlexander Motin * is removed, and we need it around for the CCB release 1744f513d14cSAlexander Motin * operation. 1745f513d14cSAlexander Motin */ 1746f513d14cSAlexander Motin xpt_release_ccb(done_ccb); 1747f513d14cSAlexander Motin cam_release_devq(periph->path, 1748f513d14cSAlexander Motin RELSIM_RELEASE_RUNLEVEL, 0, CAM_RL_DEV + 1, FALSE); 1749f513d14cSAlexander Motin adaschedule(periph); 1750f513d14cSAlexander Motin cam_periph_release_locked(periph); 1751f513d14cSAlexander Motin return; 1752f513d14cSAlexander Motin } 175352c9ce25SScott Long case ADA_CCB_WAITING: 175452c9ce25SScott Long { 175552c9ce25SScott Long /* Caller will release the CCB */ 175652c9ce25SScott Long wakeup(&done_ccb->ccb_h.cbfcnp); 175752c9ce25SScott Long return; 175852c9ce25SScott Long } 175952c9ce25SScott Long case ADA_CCB_DUMP: 176052c9ce25SScott Long /* No-op. We're polling */ 176152c9ce25SScott Long return; 176252c9ce25SScott Long default: 176352c9ce25SScott Long break; 176452c9ce25SScott Long } 176552c9ce25SScott Long xpt_release_ccb(done_ccb); 176652c9ce25SScott Long } 176752c9ce25SScott Long 176852c9ce25SScott Long static int 176952c9ce25SScott Long adaerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) 177052c9ce25SScott Long { 177152c9ce25SScott Long 1772a9b8edb1SAlexander Motin return(cam_periph_error(ccb, cam_flags, sense_flags, NULL)); 177352c9ce25SScott Long } 177452c9ce25SScott Long 177552c9ce25SScott Long static void 1776c1bd46c2SAlexander Motin adagetparams(struct cam_periph *periph, struct ccb_getdev *cgd) 177752c9ce25SScott Long { 177852c9ce25SScott Long struct ada_softc *softc = (struct ada_softc *)periph->softc; 177952c9ce25SScott Long struct disk_params *dp = &softc->params; 178052c9ce25SScott Long u_int64_t lbasize48; 178152c9ce25SScott Long u_int32_t lbasize; 178252c9ce25SScott Long 1783c1bd46c2SAlexander Motin dp->secsize = ata_logical_sector_size(&cgd->ident_data); 178452c9ce25SScott Long if ((cgd->ident_data.atavalid & ATA_FLAG_54_58) && 178552c9ce25SScott Long cgd->ident_data.current_heads && cgd->ident_data.current_sectors) { 178652c9ce25SScott Long dp->heads = cgd->ident_data.current_heads; 178752c9ce25SScott Long dp->secs_per_track = cgd->ident_data.current_sectors; 178852c9ce25SScott Long dp->cylinders = cgd->ident_data.cylinders; 178952c9ce25SScott Long dp->sectors = (u_int32_t)cgd->ident_data.current_size_1 | 179052c9ce25SScott Long ((u_int32_t)cgd->ident_data.current_size_2 << 16); 179152c9ce25SScott Long } else { 179252c9ce25SScott Long dp->heads = cgd->ident_data.heads; 179352c9ce25SScott Long dp->secs_per_track = cgd->ident_data.sectors; 179452c9ce25SScott Long dp->cylinders = cgd->ident_data.cylinders; 179552c9ce25SScott Long dp->sectors = cgd->ident_data.cylinders * dp->heads * dp->secs_per_track; 179652c9ce25SScott Long } 179752c9ce25SScott Long lbasize = (u_int32_t)cgd->ident_data.lba_size_1 | 179852c9ce25SScott Long ((u_int32_t)cgd->ident_data.lba_size_2 << 16); 179952c9ce25SScott Long 180052c9ce25SScott Long /* use the 28bit LBA size if valid or bigger than the CHS mapping */ 180152c9ce25SScott Long if (cgd->ident_data.cylinders == 16383 || dp->sectors < lbasize) 180252c9ce25SScott Long dp->sectors = lbasize; 180352c9ce25SScott Long 180452c9ce25SScott Long /* use the 48bit LBA size if valid */ 180552c9ce25SScott Long lbasize48 = ((u_int64_t)cgd->ident_data.lba_size48_1) | 180652c9ce25SScott Long ((u_int64_t)cgd->ident_data.lba_size48_2 << 16) | 180752c9ce25SScott Long ((u_int64_t)cgd->ident_data.lba_size48_3 << 32) | 180852c9ce25SScott Long ((u_int64_t)cgd->ident_data.lba_size48_4 << 48); 180952c9ce25SScott Long if ((cgd->ident_data.support.command2 & ATA_SUPPORT_ADDRESS48) && 181052c9ce25SScott Long lbasize48 > ATA_MAX_28BIT_LBA) 181152c9ce25SScott Long dp->sectors = lbasize48; 181252c9ce25SScott Long } 181352c9ce25SScott Long 181452c9ce25SScott Long static void 181552c9ce25SScott Long adasendorderedtag(void *arg) 181652c9ce25SScott Long { 181752c9ce25SScott Long struct ada_softc *softc = arg; 181852c9ce25SScott Long 181952c9ce25SScott Long if (ada_send_ordered) { 182052c9ce25SScott Long if ((softc->ordered_tag_count == 0) 182152c9ce25SScott Long && ((softc->flags & ADA_FLAG_WENT_IDLE) == 0)) { 182252c9ce25SScott Long softc->flags |= ADA_FLAG_NEED_OTAG; 182352c9ce25SScott Long } 182452c9ce25SScott Long if (softc->outstanding_cmds > 0) 182552c9ce25SScott Long softc->flags &= ~ADA_FLAG_WENT_IDLE; 182652c9ce25SScott Long 182752c9ce25SScott Long softc->ordered_tag_count = 0; 182852c9ce25SScott Long } 182952c9ce25SScott Long /* Queue us up again */ 183052c9ce25SScott Long callout_reset(&softc->sendordered_c, 183147bb9643SAlexander Motin (ada_default_timeout * hz) / ADA_ORDEREDTAG_INTERVAL, 183252c9ce25SScott Long adasendorderedtag, softc); 183352c9ce25SScott Long } 183452c9ce25SScott Long 183552c9ce25SScott Long /* 183652c9ce25SScott Long * Step through all ADA peripheral drivers, and if the device is still open, 183752c9ce25SScott Long * sync the disk cache to physical media. 183852c9ce25SScott Long */ 183952c9ce25SScott Long static void 1840c3d0d168SAlexander Motin adaflush(void) 184152c9ce25SScott Long { 184252c9ce25SScott Long struct cam_periph *periph; 184352c9ce25SScott Long struct ada_softc *softc; 184409cfadbeSAlexander Motin union ccb *ccb; 18450191d9b3SAlexander Motin int error; 184652c9ce25SScott Long 1847f371c9e2SAlexander Motin CAM_PERIPH_FOREACH(periph, &adadriver) { 184821cc8587SAlexander Motin /* If we paniced with lock held - not recurse here. */ 184921cc8587SAlexander Motin if (cam_periph_owned(periph)) 185021cc8587SAlexander Motin continue; 185152c9ce25SScott Long cam_periph_lock(periph); 185252c9ce25SScott Long softc = (struct ada_softc *)periph->softc; 185352c9ce25SScott Long /* 185452c9ce25SScott Long * We only sync the cache if the drive is still open, and 185552c9ce25SScott Long * if the drive is capable of it.. 185652c9ce25SScott Long */ 185752c9ce25SScott Long if (((softc->flags & ADA_FLAG_OPEN) == 0) || 185852c9ce25SScott Long (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) == 0) { 185952c9ce25SScott Long cam_periph_unlock(periph); 186052c9ce25SScott Long continue; 186152c9ce25SScott Long } 186252c9ce25SScott Long 186309cfadbeSAlexander Motin ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 186409cfadbeSAlexander Motin cam_fill_ataio(&ccb->ataio, 18650191d9b3SAlexander Motin 0, 186652c9ce25SScott Long adadone, 186752c9ce25SScott Long CAM_DIR_NONE, 186852c9ce25SScott Long 0, 186952c9ce25SScott Long NULL, 187052c9ce25SScott Long 0, 187152c9ce25SScott Long ada_default_timeout*1000); 187252c9ce25SScott Long if (softc->flags & ADA_FLAG_CAN_48BIT) 187309cfadbeSAlexander Motin ata_48bit_cmd(&ccb->ataio, ATA_FLUSHCACHE48, 0, 0, 0); 187452c9ce25SScott Long else 187509cfadbeSAlexander Motin ata_28bit_cmd(&ccb->ataio, ATA_FLUSHCACHE, 0, 0, 0); 187652c9ce25SScott Long 187709cfadbeSAlexander Motin error = cam_periph_runccb(ccb, adaerror, /*cam_flags*/0, 187809cfadbeSAlexander Motin /*sense_flags*/ SF_NO_RECOVERY | SF_NO_RETRY, 187909cfadbeSAlexander Motin softc->disk->d_devstat); 18800191d9b3SAlexander Motin if (error != 0) 18810191d9b3SAlexander Motin xpt_print(periph->path, "Synchronize cache failed\n"); 1882d6794b70SAlexander Motin xpt_release_ccb(ccb); 188352c9ce25SScott Long cam_periph_unlock(periph); 188452c9ce25SScott Long } 1885c3d0d168SAlexander Motin } 1886fd104c15SRebecca Cran 1887c3d0d168SAlexander Motin static void 1888c3d0d168SAlexander Motin adaspindown(uint8_t cmd, int flags) 1889c3d0d168SAlexander Motin { 1890c3d0d168SAlexander Motin struct cam_periph *periph; 1891c3d0d168SAlexander Motin struct ada_softc *softc; 189209cfadbeSAlexander Motin union ccb *ccb; 18930191d9b3SAlexander Motin int error; 1894fd104c15SRebecca Cran 1895f371c9e2SAlexander Motin CAM_PERIPH_FOREACH(periph, &adadriver) { 1896fd104c15SRebecca Cran /* If we paniced with lock held - not recurse here. */ 1897fd104c15SRebecca Cran if (cam_periph_owned(periph)) 1898fd104c15SRebecca Cran continue; 1899fd104c15SRebecca Cran cam_periph_lock(periph); 1900fd104c15SRebecca Cran softc = (struct ada_softc *)periph->softc; 1901fd104c15SRebecca Cran /* 1902fd104c15SRebecca Cran * We only spin-down the drive if it is capable of it.. 1903fd104c15SRebecca Cran */ 1904fd104c15SRebecca Cran if ((softc->flags & ADA_FLAG_CAN_POWERMGT) == 0) { 1905fd104c15SRebecca Cran cam_periph_unlock(periph); 1906fd104c15SRebecca Cran continue; 1907fd104c15SRebecca Cran } 1908fd104c15SRebecca Cran 1909fd104c15SRebecca Cran if (bootverbose) 1910fd104c15SRebecca Cran xpt_print(periph->path, "spin-down\n"); 1911fd104c15SRebecca Cran 191209cfadbeSAlexander Motin ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 191309cfadbeSAlexander Motin cam_fill_ataio(&ccb->ataio, 19140191d9b3SAlexander Motin 0, 1915fd104c15SRebecca Cran adadone, 1916c3d0d168SAlexander Motin CAM_DIR_NONE | flags, 1917fd104c15SRebecca Cran 0, 1918fd104c15SRebecca Cran NULL, 1919fd104c15SRebecca Cran 0, 1920fd104c15SRebecca Cran ada_default_timeout*1000); 192109cfadbeSAlexander Motin ata_28bit_cmd(&ccb->ataio, cmd, 0, 0, 0); 1922fd104c15SRebecca Cran 192309cfadbeSAlexander Motin error = cam_periph_runccb(ccb, adaerror, /*cam_flags*/0, 192409cfadbeSAlexander Motin /*sense_flags*/ SF_NO_RECOVERY | SF_NO_RETRY, 192509cfadbeSAlexander Motin softc->disk->d_devstat); 19260191d9b3SAlexander Motin if (error != 0) 19270191d9b3SAlexander Motin xpt_print(periph->path, "Spin-down disk failed\n"); 1928d6794b70SAlexander Motin xpt_release_ccb(ccb); 1929fd104c15SRebecca Cran cam_periph_unlock(periph); 1930fd104c15SRebecca Cran } 193152c9ce25SScott Long } 193252c9ce25SScott Long 1933c3d0d168SAlexander Motin static void 1934c3d0d168SAlexander Motin adashutdown(void *arg, int howto) 1935c3d0d168SAlexander Motin { 1936c3d0d168SAlexander Motin 1937c3d0d168SAlexander Motin adaflush(); 1938c3d0d168SAlexander Motin if (ada_spindown_shutdown != 0 && 1939c3d0d168SAlexander Motin (howto & (RB_HALT | RB_POWEROFF)) != 0) 1940c3d0d168SAlexander Motin adaspindown(ATA_STANDBY_IMMEDIATE, 0); 1941c3d0d168SAlexander Motin } 1942c3d0d168SAlexander Motin 1943c3d0d168SAlexander Motin static void 1944c3d0d168SAlexander Motin adasuspend(void *arg) 1945c3d0d168SAlexander Motin { 1946c3d0d168SAlexander Motin 1947c3d0d168SAlexander Motin adaflush(); 1948c3d0d168SAlexander Motin if (ada_spindown_suspend != 0) 1949c3d0d168SAlexander Motin adaspindown(ATA_SLEEP, CAM_DEV_QFREEZE); 1950c3d0d168SAlexander Motin } 1951c3d0d168SAlexander Motin 1952c3d0d168SAlexander Motin static void 1953c3d0d168SAlexander Motin adaresume(void *arg) 1954c3d0d168SAlexander Motin { 1955c3d0d168SAlexander Motin struct cam_periph *periph; 1956c3d0d168SAlexander Motin struct ada_softc *softc; 1957c3d0d168SAlexander Motin 1958c3d0d168SAlexander Motin if (ada_spindown_suspend == 0) 1959c3d0d168SAlexander Motin return; 1960c3d0d168SAlexander Motin 1961f371c9e2SAlexander Motin CAM_PERIPH_FOREACH(periph, &adadriver) { 1962c3d0d168SAlexander Motin cam_periph_lock(periph); 1963c3d0d168SAlexander Motin softc = (struct ada_softc *)periph->softc; 1964c3d0d168SAlexander Motin /* 1965c3d0d168SAlexander Motin * We only spin-down the drive if it is capable of it.. 1966c3d0d168SAlexander Motin */ 1967c3d0d168SAlexander Motin if ((softc->flags & ADA_FLAG_CAN_POWERMGT) == 0) { 1968c3d0d168SAlexander Motin cam_periph_unlock(periph); 1969c3d0d168SAlexander Motin continue; 1970c3d0d168SAlexander Motin } 1971c3d0d168SAlexander Motin 1972c3d0d168SAlexander Motin if (bootverbose) 1973c3d0d168SAlexander Motin xpt_print(periph->path, "resume\n"); 1974c3d0d168SAlexander Motin 1975c3d0d168SAlexander Motin /* 1976c3d0d168SAlexander Motin * Drop freeze taken due to CAM_DEV_QFREEZE flag set on 1977c3d0d168SAlexander Motin * sleep request. 1978c3d0d168SAlexander Motin */ 1979c3d0d168SAlexander Motin cam_release_devq(periph->path, 1980c3d0d168SAlexander Motin /*relsim_flags*/0, 1981c3d0d168SAlexander Motin /*openings*/0, 1982c3d0d168SAlexander Motin /*timeout*/0, 1983c3d0d168SAlexander Motin /*getcount_only*/0); 1984c3d0d168SAlexander Motin 1985c3d0d168SAlexander Motin cam_periph_unlock(periph); 1986c3d0d168SAlexander Motin } 1987c3d0d168SAlexander Motin } 1988c3d0d168SAlexander Motin 198952c9ce25SScott Long #endif /* _KERNEL */ 1990