152c9ce25SScott Long /*- 252c9ce25SScott Long * Copyright (c) 2009 Alexander Motin <mav@FreeBSD.org> 352c9ce25SScott Long * All rights reserved. 452c9ce25SScott Long * 552c9ce25SScott Long * Redistribution and use in source and binary forms, with or without 652c9ce25SScott Long * modification, are permitted provided that the following conditions 752c9ce25SScott Long * are met: 852c9ce25SScott Long * 1. Redistributions of source code must retain the above copyright 952c9ce25SScott Long * notice, this list of conditions and the following disclaimer, 1052c9ce25SScott Long * without modification, immediately at the beginning of the file. 1152c9ce25SScott Long * 2. Redistributions in binary form must reproduce the above copyright 1252c9ce25SScott Long * notice, this list of conditions and the following disclaimer in the 1352c9ce25SScott Long * documentation and/or other materials provided with the distribution. 1452c9ce25SScott Long * 1552c9ce25SScott Long * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1652c9ce25SScott Long * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1752c9ce25SScott Long * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1852c9ce25SScott Long * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1952c9ce25SScott Long * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2052c9ce25SScott Long * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2152c9ce25SScott Long * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2252c9ce25SScott Long * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2352c9ce25SScott Long * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2452c9ce25SScott Long * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2552c9ce25SScott Long */ 2652c9ce25SScott Long 2752c9ce25SScott Long #include <sys/cdefs.h> 2852c9ce25SScott Long __FBSDID("$FreeBSD$"); 2952c9ce25SScott Long 30e3a6d3a4SAlexander Motin #include "opt_ada.h" 31e3a6d3a4SAlexander Motin 3252c9ce25SScott Long #include <sys/param.h> 3352c9ce25SScott Long 3452c9ce25SScott Long #ifdef _KERNEL 3552c9ce25SScott Long #include <sys/systm.h> 3652c9ce25SScott Long #include <sys/kernel.h> 3752c9ce25SScott Long #include <sys/bio.h> 3852c9ce25SScott Long #include <sys/sysctl.h> 3952c9ce25SScott Long #include <sys/taskqueue.h> 4052c9ce25SScott Long #include <sys/lock.h> 4152c9ce25SScott Long #include <sys/mutex.h> 4252c9ce25SScott Long #include <sys/conf.h> 4352c9ce25SScott Long #include <sys/devicestat.h> 4452c9ce25SScott Long #include <sys/eventhandler.h> 4552c9ce25SScott Long #include <sys/malloc.h> 4652c9ce25SScott Long #include <sys/cons.h> 472f87dfb0SAlexander Motin #include <sys/proc.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> 62*a6e0c5daSWarner Losh #include <cam/cam_iosched.h> 6352c9ce25SScott Long 6452c9ce25SScott Long #include <cam/ata/ata_all.h> 6552c9ce25SScott Long 664461491bSMarius Strobl #include <machine/md_var.h> /* geometry translation */ 674461491bSMarius Strobl 6852c9ce25SScott Long #ifdef _KERNEL 6952c9ce25SScott Long 7052c9ce25SScott Long #define ATA_MAX_28BIT_LBA 268435455UL 7152c9ce25SScott Long 72*a6e0c5daSWarner Losh extern int iosched_debug; 73*a6e0c5daSWarner Losh 7452c9ce25SScott Long typedef enum { 751ed6aaf9SAlexander Motin ADA_STATE_RAHEAD, 76f513d14cSAlexander Motin ADA_STATE_WCACHE, 771e637ba6SAlexander Motin ADA_STATE_NORMAL 7852c9ce25SScott Long } ada_state; 7952c9ce25SScott Long 8052c9ce25SScott Long typedef enum { 812e1eb332SMarius Strobl ADA_FLAG_CAN_48BIT = 0x0002, 822e1eb332SMarius Strobl ADA_FLAG_CAN_FLUSHCACHE = 0x0004, 832e1eb332SMarius Strobl ADA_FLAG_CAN_NCQ = 0x0008, 842e1eb332SMarius Strobl ADA_FLAG_CAN_DMA = 0x0010, 852e1eb332SMarius Strobl ADA_FLAG_NEED_OTAG = 0x0020, 86030844d1SAlexander Motin ADA_FLAG_WAS_OTAG = 0x0040, 872e1eb332SMarius Strobl ADA_FLAG_CAN_TRIM = 0x0080, 882e1eb332SMarius Strobl ADA_FLAG_OPEN = 0x0100, 892e1eb332SMarius Strobl ADA_FLAG_SCTX_INIT = 0x0200, 902e1eb332SMarius Strobl ADA_FLAG_CAN_CFA = 0x0400, 912e1eb332SMarius Strobl ADA_FLAG_CAN_POWERMGT = 0x0800, 9269114bc0SAlexander Motin ADA_FLAG_CAN_DMA48 = 0x1000, 93*a6e0c5daSWarner Losh ADA_FLAG_DIRTY = 0x2000, 94*a6e0c5daSWarner Losh ADA_FLAG_CAN_NCQ_TRIM = 0x4000, /* CAN_TRIM also set */ 95*a6e0c5daSWarner Losh ADA_FLAG_PIM_CAN_NCQ_TRIM = 0x8000 9652c9ce25SScott Long } ada_flags; 9752c9ce25SScott Long 9852c9ce25SScott Long typedef enum { 99d3a460d3SAlexander Motin ADA_Q_NONE = 0x00, 100d3a460d3SAlexander Motin ADA_Q_4K = 0x01, 101*a6e0c5daSWarner Losh ADA_Q_NCQ_TRIM_BROKEN = 0x02, 10252c9ce25SScott Long } ada_quirks; 10352c9ce25SScott Long 1046fb5c84eSSteven Hartland #define ADA_Q_BIT_STRING \ 1056fb5c84eSSteven Hartland "\020" \ 106*a6e0c5daSWarner Losh "\0014K" \ 107*a6e0c5daSWarner Losh "\002NCQ_TRIM_BROKEN" 1086fb5c84eSSteven Hartland 10952c9ce25SScott Long typedef enum { 1101ed6aaf9SAlexander Motin ADA_CCB_RAHEAD = 0x01, 1111ed6aaf9SAlexander Motin ADA_CCB_WCACHE = 0x02, 11252c9ce25SScott Long ADA_CCB_BUFFER_IO = 0x03, 11352c9ce25SScott Long ADA_CCB_DUMP = 0x05, 1141c80ec0aSAlexander Motin ADA_CCB_TRIM = 0x06, 11552c9ce25SScott Long ADA_CCB_TYPE_MASK = 0x0F, 11652c9ce25SScott Long } ada_ccb_state; 11752c9ce25SScott Long 11852c9ce25SScott Long /* Offsets into our private area for storing information */ 11952c9ce25SScott Long #define ccb_state ppriv_field0 12052c9ce25SScott Long #define ccb_bp ppriv_ptr1 12152c9ce25SScott Long 122*a6e0c5daSWarner Losh typedef enum { 123*a6e0c5daSWarner Losh ADA_DELETE_NONE, 124*a6e0c5daSWarner Losh ADA_DELETE_DISABLE, 125*a6e0c5daSWarner Losh ADA_DELETE_CFA_ERASE, 126*a6e0c5daSWarner Losh ADA_DELETE_DSM_TRIM, 127*a6e0c5daSWarner Losh ADA_DELETE_NCQ_DSM_TRIM, 128*a6e0c5daSWarner Losh ADA_DELETE_MIN = ADA_DELETE_CFA_ERASE, 129*a6e0c5daSWarner Losh ADA_DELETE_MAX = ADA_DELETE_NCQ_DSM_TRIM, 130*a6e0c5daSWarner Losh } ada_delete_methods; 131*a6e0c5daSWarner Losh 132*a6e0c5daSWarner Losh static const char *ada_delete_method_names[] = 133*a6e0c5daSWarner Losh { "NONE", "DISABLE", "CFA_ERASE", "DSM_TRIM", "NCQ_DSM_TRIM" }; 134*a6e0c5daSWarner Losh #if 0 135*a6e0c5daSWarner Losh static const char *ada_delete_method_desc[] = 136*a6e0c5daSWarner Losh { "NONE", "DISABLED", "CFA Erase", "DSM Trim", "DSM Trim via NCQ" }; 137*a6e0c5daSWarner Losh #endif 138*a6e0c5daSWarner Losh 13952c9ce25SScott Long struct disk_params { 14052c9ce25SScott Long u_int8_t heads; 14152c9ce25SScott Long u_int8_t secs_per_track; 142c1bd46c2SAlexander Motin u_int32_t cylinders; 143c1bd46c2SAlexander Motin u_int32_t secsize; /* Number of bytes/logical sector */ 144c1bd46c2SAlexander Motin u_int64_t sectors; /* Total number sectors */ 14552c9ce25SScott Long }; 14652c9ce25SScott Long 1471524677aSAlexander Motin #define TRIM_MAX_BLOCKS 8 148c213c551SSteven Hartland #define TRIM_MAX_RANGES (TRIM_MAX_BLOCKS * ATA_DSM_BLK_RANGES) 1491c80ec0aSAlexander Motin struct trim_request { 150c213c551SSteven Hartland uint8_t data[TRIM_MAX_RANGES * ATA_DSM_RANGE_SIZE]; 1512030b294SAlexander Motin TAILQ_HEAD(, bio) bps; 1521c80ec0aSAlexander Motin }; 1531c80ec0aSAlexander Motin 15452c9ce25SScott Long struct ada_softc { 155*a6e0c5daSWarner Losh struct cam_iosched_softc *cam_iosched; 156030844d1SAlexander Motin int outstanding_cmds; /* Number of active commands */ 157030844d1SAlexander Motin int refcount; /* Active xpt_action() calls */ 15852c9ce25SScott Long ada_state state; 15952c9ce25SScott Long ada_flags flags; 16052c9ce25SScott Long ada_quirks quirks; 161*a6e0c5daSWarner Losh ada_delete_methods delete_method; 1621c80ec0aSAlexander Motin int trim_max_ranges; 1631ed6aaf9SAlexander Motin int read_ahead; 164e3a6d3a4SAlexander Motin int write_cache; 165*a6e0c5daSWarner Losh int unmappedio; 166*a6e0c5daSWarner Losh int rotating; 167e3a6d3a4SAlexander Motin #ifdef ADA_TEST_FAILURE 168e3a6d3a4SAlexander Motin int force_read_error; 169e3a6d3a4SAlexander Motin int force_write_error; 170e3a6d3a4SAlexander Motin int periodic_read_error; 171e3a6d3a4SAlexander Motin int periodic_read_count; 172e3a6d3a4SAlexander Motin #endif 17352c9ce25SScott Long struct disk_params params; 17452c9ce25SScott Long struct disk *disk; 17552c9ce25SScott Long struct task sysctl_task; 17652c9ce25SScott Long struct sysctl_ctx_list sysctl_ctx; 17752c9ce25SScott Long struct sysctl_oid *sysctl_tree; 17852c9ce25SScott Long struct callout sendordered_c; 1791c80ec0aSAlexander Motin struct trim_request trim_req; 180*a6e0c5daSWarner Losh #ifdef CAM_IO_STATS 181*a6e0c5daSWarner Losh struct sysctl_ctx_list sysctl_stats_ctx; 182*a6e0c5daSWarner Losh struct sysctl_oid *sysctl_stats_tree; 183*a6e0c5daSWarner Losh u_int timeouts; 184*a6e0c5daSWarner Losh u_int errors; 185*a6e0c5daSWarner Losh u_int invalidations; 186*a6e0c5daSWarner Losh #endif 18752c9ce25SScott Long }; 18852c9ce25SScott Long 18952c9ce25SScott Long struct ada_quirk_entry { 19052c9ce25SScott Long struct scsi_inquiry_pattern inq_pat; 19152c9ce25SScott Long ada_quirks quirks; 19252c9ce25SScott Long }; 19352c9ce25SScott Long 19430a4094fSAlexander Motin static struct ada_quirk_entry ada_quirk_table[] = 19530a4094fSAlexander Motin { 19630a4094fSAlexander Motin { 197d3a460d3SAlexander Motin /* Hitachi Advanced Format (4k) drives */ 198d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "Hitachi H??????????E3*", "*" }, 199d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 200d3a460d3SAlexander Motin }, 201d3a460d3SAlexander Motin { 202d3a460d3SAlexander Motin /* Samsung Advanced Format (4k) drives */ 203643d1826SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "SAMSUNG HD155UI*", "*" }, 204643d1826SAlexander Motin /*quirks*/ADA_Q_4K 205643d1826SAlexander Motin }, 206643d1826SAlexander Motin { 207643d1826SAlexander Motin /* Samsung Advanced Format (4k) drives */ 208d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "SAMSUNG HD204UI*", "*" }, 209d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 210d3a460d3SAlexander Motin }, 211d3a460d3SAlexander Motin { 212d3a460d3SAlexander Motin /* Seagate Barracuda Green Advanced Format (4k) drives */ 213d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST????DL*", "*" }, 214d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 215d3a460d3SAlexander Motin }, 216d3a460d3SAlexander Motin { 217643d1826SAlexander Motin /* Seagate Barracuda Advanced Format (4k) drives */ 218643d1826SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST???DM*", "*" }, 219643d1826SAlexander Motin /*quirks*/ADA_Q_4K 220643d1826SAlexander Motin }, 221643d1826SAlexander Motin { 222643d1826SAlexander Motin /* Seagate Barracuda Advanced Format (4k) drives */ 223643d1826SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST????DM*", "*" }, 224643d1826SAlexander Motin /*quirks*/ADA_Q_4K 225643d1826SAlexander Motin }, 226643d1826SAlexander Motin { 227d3a460d3SAlexander Motin /* Seagate Momentus Advanced Format (4k) drives */ 228d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9500423AS*", "*" }, 229d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 230d3a460d3SAlexander Motin }, 231d3a460d3SAlexander Motin { 232d3a460d3SAlexander Motin /* Seagate Momentus Advanced Format (4k) drives */ 233d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9500424AS*", "*" }, 234d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 235d3a460d3SAlexander Motin }, 236d3a460d3SAlexander Motin { 237d3a460d3SAlexander Motin /* Seagate Momentus Advanced Format (4k) drives */ 238643d1826SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9640423AS*", "*" }, 239643d1826SAlexander Motin /*quirks*/ADA_Q_4K 240643d1826SAlexander Motin }, 241643d1826SAlexander Motin { 242643d1826SAlexander Motin /* Seagate Momentus Advanced Format (4k) drives */ 243643d1826SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9640424AS*", "*" }, 244643d1826SAlexander Motin /*quirks*/ADA_Q_4K 245643d1826SAlexander Motin }, 246643d1826SAlexander Motin { 247643d1826SAlexander Motin /* Seagate Momentus Advanced Format (4k) drives */ 248d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9750420AS*", "*" }, 249d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 250d3a460d3SAlexander Motin }, 251d3a460d3SAlexander Motin { 252d3a460d3SAlexander Motin /* Seagate Momentus Advanced Format (4k) drives */ 253d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9750422AS*", "*" }, 254d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 255d3a460d3SAlexander Motin }, 256d3a460d3SAlexander Motin { 257643d1826SAlexander Motin /* Seagate Momentus Advanced Format (4k) drives */ 258643d1826SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9750423AS*", "*" }, 259643d1826SAlexander Motin /*quirks*/ADA_Q_4K 260643d1826SAlexander Motin }, 261643d1826SAlexander Motin { 262d3a460d3SAlexander Motin /* Seagate Momentus Thin Advanced Format (4k) drives */ 263d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST???LT*", "*" }, 264d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 265d3a460d3SAlexander Motin }, 266d3a460d3SAlexander Motin { 2679073a96aSEitan Adler /* WDC Caviar Red Advanced Format (4k) drives */ 2689073a96aSEitan Adler { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD????CX*", "*" }, 2699073a96aSEitan Adler /*quirks*/ADA_Q_4K 2709073a96aSEitan Adler }, 2719073a96aSEitan Adler { 272d3a460d3SAlexander Motin /* WDC Caviar Green Advanced Format (4k) drives */ 273d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD????RS*", "*" }, 274d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 275d3a460d3SAlexander Motin }, 276d3a460d3SAlexander Motin { 2779073a96aSEitan Adler /* WDC Caviar Green/Red Advanced Format (4k) drives */ 278d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD????RX*", "*" }, 279d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 280d3a460d3SAlexander Motin }, 281d3a460d3SAlexander Motin { 2829073a96aSEitan Adler /* WDC Caviar Red Advanced Format (4k) drives */ 2839073a96aSEitan Adler { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD??????CX*", "*" }, 2849073a96aSEitan Adler /*quirks*/ADA_Q_4K 2859073a96aSEitan Adler }, 2869073a96aSEitan Adler { 2879073a96aSEitan Adler /* WDC Caviar Black Advanced Format (4k) drives */ 2889073a96aSEitan Adler { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD??????EX*", "*" }, 2899073a96aSEitan Adler /*quirks*/ADA_Q_4K 2909073a96aSEitan Adler }, 2919073a96aSEitan Adler { 292d3a460d3SAlexander Motin /* WDC Caviar Green Advanced Format (4k) drives */ 293d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD??????RS*", "*" }, 294d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 295d3a460d3SAlexander Motin }, 296d3a460d3SAlexander Motin { 297d3a460d3SAlexander Motin /* WDC Caviar Green Advanced Format (4k) drives */ 298d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD??????RX*", "*" }, 299d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 300d3a460d3SAlexander Motin }, 301d3a460d3SAlexander Motin { 302d3a460d3SAlexander Motin /* WDC Scorpio Black Advanced Format (4k) drives */ 303d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD???PKT*", "*" }, 304d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 305d3a460d3SAlexander Motin }, 306d3a460d3SAlexander Motin { 307d3a460d3SAlexander Motin /* WDC Scorpio Black Advanced Format (4k) drives */ 308d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD?????PKT*", "*" }, 309d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 310d3a460d3SAlexander Motin }, 311d3a460d3SAlexander Motin { 312d3a460d3SAlexander Motin /* WDC Scorpio Blue Advanced Format (4k) drives */ 313d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD???PVT*", "*" }, 314d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 315d3a460d3SAlexander Motin }, 316d3a460d3SAlexander Motin { 317d3a460d3SAlexander Motin /* WDC Scorpio Blue Advanced Format (4k) drives */ 318d3a460d3SAlexander Motin { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD?????PVT*", "*" }, 319d3a460d3SAlexander Motin /*quirks*/ADA_Q_4K 320d3a460d3SAlexander Motin }, 32132fe0ef7SSteven Hartland /* SSDs */ 322d3a460d3SAlexander Motin { 3239d3334e1SEitan Adler /* 3249d3334e1SEitan Adler * Corsair Force 2 SSDs 3259d3334e1SEitan Adler * 4k optimised & trim only works in 4k requests + 4k aligned 3269d3334e1SEitan Adler */ 3279d3334e1SEitan Adler { T_DIRECT, SIP_MEDIA_FIXED, "*", "Corsair CSSD-F*", "*" }, 3289d3334e1SEitan Adler /*quirks*/ADA_Q_4K 3299d3334e1SEitan Adler }, 3309d3334e1SEitan Adler { 3319d3334e1SEitan Adler /* 3329d3334e1SEitan Adler * Corsair Force 3 SSDs 3339d3334e1SEitan Adler * 4k optimised & trim only works in 4k requests + 4k aligned 3349d3334e1SEitan Adler */ 3359d3334e1SEitan Adler { T_DIRECT, SIP_MEDIA_FIXED, "*", "Corsair Force 3*", "*" }, 3369d3334e1SEitan Adler /*quirks*/ADA_Q_4K 3379d3334e1SEitan Adler }, 3389d3334e1SEitan Adler { 3399d3334e1SEitan Adler /* 340d85805b2SSteven Hartland * Corsair Neutron GTX SSDs 341d85805b2SSteven Hartland * 4k optimised & trim only works in 4k requests + 4k aligned 342d85805b2SSteven Hartland */ 343d85805b2SSteven Hartland { T_DIRECT, SIP_MEDIA_FIXED, "*", "Corsair Neutron GTX*", "*" }, 344d85805b2SSteven Hartland /*quirks*/ADA_Q_4K 345d85805b2SSteven Hartland }, 346d85805b2SSteven Hartland { 347d85805b2SSteven Hartland /* 348dc98c62fSSteven Hartland * Corsair Force GT & GS SSDs 3499d3334e1SEitan Adler * 4k optimised & trim only works in 4k requests + 4k aligned 3509d3334e1SEitan Adler */ 351dc98c62fSSteven Hartland { T_DIRECT, SIP_MEDIA_FIXED, "*", "Corsair Force G*", "*" }, 3529d3334e1SEitan Adler /*quirks*/ADA_Q_4K 3539d3334e1SEitan Adler }, 3549d3334e1SEitan Adler { 3559d3334e1SEitan Adler /* 35632fe0ef7SSteven Hartland * Crucial M4 SSDs 3579d3334e1SEitan Adler * 4k optimised & trim only works in 4k requests + 4k aligned 3589d3334e1SEitan Adler */ 35932fe0ef7SSteven Hartland { T_DIRECT, SIP_MEDIA_FIXED, "*", "M4-CT???M4SSD2*", "*" }, 3609d3334e1SEitan Adler /*quirks*/ADA_Q_4K 3619d3334e1SEitan Adler }, 3629d3334e1SEitan Adler { 3639d3334e1SEitan Adler /* 364*a6e0c5daSWarner Losh * Crucial M500 SSDs EU07 firmware 365*a6e0c5daSWarner Losh * NCQ Trim works ? 366*a6e0c5daSWarner Losh */ 367*a6e0c5daSWarner Losh { T_DIRECT, SIP_MEDIA_FIXED, "*", "Crucial CT*M500*", "EU07" }, 368*a6e0c5daSWarner Losh /*quirks*/0 369*a6e0c5daSWarner Losh }, 370*a6e0c5daSWarner Losh { 371*a6e0c5daSWarner Losh /* 372*a6e0c5daSWarner Losh * Crucial M500 SSDs all other firmware 373*a6e0c5daSWarner Losh * NCQ Trim doesn't work 374*a6e0c5daSWarner Losh */ 375*a6e0c5daSWarner Losh { T_DIRECT, SIP_MEDIA_FIXED, "*", "Crucial CT*M500*", "*" }, 376*a6e0c5daSWarner Losh /*quirks*/ADA_Q_NCQ_TRIM_BROKEN 377*a6e0c5daSWarner Losh }, 378*a6e0c5daSWarner Losh { 379*a6e0c5daSWarner Losh /* 380*a6e0c5daSWarner Losh * Crucial M550 SSDs 381*a6e0c5daSWarner Losh * NCQ Trim doesn't work, but only on MU01 firmware 382*a6e0c5daSWarner Losh */ 383*a6e0c5daSWarner Losh { T_DIRECT, SIP_MEDIA_FIXED, "*", "Crucial CT*M550*", "MU01" }, 384*a6e0c5daSWarner Losh /*quirks*/ADA_Q_NCQ_TRIM_BROKEN 385*a6e0c5daSWarner Losh }, 386*a6e0c5daSWarner Losh { 387*a6e0c5daSWarner Losh /* 388*a6e0c5daSWarner Losh * Crucial MX100 SSDs 389*a6e0c5daSWarner Losh * NCQ Trim doesn't work, but only on MU01 firmware 390*a6e0c5daSWarner Losh */ 391*a6e0c5daSWarner Losh { T_DIRECT, SIP_MEDIA_FIXED, "*", "Crucial CT*MX100*", "MU01" }, 392*a6e0c5daSWarner Losh /*quirks*/ADA_Q_NCQ_TRIM_BROKEN 393*a6e0c5daSWarner Losh }, 394*a6e0c5daSWarner Losh { 395*a6e0c5daSWarner Losh /* 3969d3334e1SEitan Adler * Crucial RealSSD C300 SSDs 3979d3334e1SEitan Adler * 4k optimised 3989d3334e1SEitan Adler */ 3999d3334e1SEitan Adler { T_DIRECT, SIP_MEDIA_FIXED, "*", "C300-CTFDDAC???MAG*", 4009d3334e1SEitan Adler "*" }, /*quirks*/ADA_Q_4K 4019d3334e1SEitan Adler }, 4029d3334e1SEitan Adler { 4039d3334e1SEitan Adler /* 404883db1c1SEitan Adler * Intel 320 Series SSDs 405883db1c1SEitan Adler * 4k optimised & trim only works in 4k requests + 4k aligned 406883db1c1SEitan Adler */ 407883db1c1SEitan Adler { T_DIRECT, SIP_MEDIA_FIXED, "*", "INTEL SSDSA2CW*", "*" }, 408883db1c1SEitan Adler /*quirks*/ADA_Q_4K 409883db1c1SEitan Adler }, 410883db1c1SEitan Adler { 411883db1c1SEitan Adler /* 4129d3334e1SEitan Adler * Intel 330 Series SSDs 4139d3334e1SEitan Adler * 4k optimised & trim only works in 4k requests + 4k aligned 4149d3334e1SEitan Adler */ 41532fe0ef7SSteven Hartland { T_DIRECT, SIP_MEDIA_FIXED, "*", "INTEL SSDSC2CT*", "*" }, 4169d3334e1SEitan Adler /*quirks*/ADA_Q_4K 4179d3334e1SEitan Adler }, 4189d3334e1SEitan Adler { 4199d3334e1SEitan Adler /* 420883db1c1SEitan Adler * Intel 510 Series SSDs 421883db1c1SEitan Adler * 4k optimised & trim only works in 4k requests + 4k aligned 422883db1c1SEitan Adler */ 423883db1c1SEitan Adler { T_DIRECT, SIP_MEDIA_FIXED, "*", "INTEL SSDSC2MH*", "*" }, 424883db1c1SEitan Adler /*quirks*/ADA_Q_4K 425883db1c1SEitan Adler }, 426883db1c1SEitan Adler { 427883db1c1SEitan Adler /* 42832fe0ef7SSteven Hartland * Intel 520 Series SSDs 4299d3334e1SEitan Adler * 4k optimised & trim only works in 4k requests + 4k aligned 4309d3334e1SEitan Adler */ 43132fe0ef7SSteven Hartland { T_DIRECT, SIP_MEDIA_FIXED, "*", "INTEL SSDSC2BW*", "*" }, 43232fe0ef7SSteven Hartland /*quirks*/ADA_Q_4K 43332fe0ef7SSteven Hartland }, 43432fe0ef7SSteven Hartland { 43532fe0ef7SSteven Hartland /* 436dce643c8SSteven Hartland * Intel X25-M Series SSDs 437dce643c8SSteven Hartland * 4k optimised & trim only works in 4k requests + 4k aligned 438dce643c8SSteven Hartland */ 439dce643c8SSteven Hartland { T_DIRECT, SIP_MEDIA_FIXED, "*", "INTEL SSDSA2M*", "*" }, 440dce643c8SSteven Hartland /*quirks*/ADA_Q_4K 441dce643c8SSteven Hartland }, 442dce643c8SSteven Hartland { 443dce643c8SSteven Hartland /* 44432fe0ef7SSteven Hartland * Kingston E100 Series SSDs 44532fe0ef7SSteven Hartland * 4k optimised & trim only works in 4k requests + 4k aligned 44632fe0ef7SSteven Hartland */ 44732fe0ef7SSteven Hartland { T_DIRECT, SIP_MEDIA_FIXED, "*", "KINGSTON SE100S3*", "*" }, 4489d3334e1SEitan Adler /*quirks*/ADA_Q_4K 4499d3334e1SEitan Adler }, 4509d3334e1SEitan Adler { 4519d3334e1SEitan Adler /* 4529d3334e1SEitan Adler * Kingston HyperX 3k SSDs 4539d3334e1SEitan Adler * 4k optimised & trim only works in 4k requests + 4k aligned 4549d3334e1SEitan Adler */ 4559d3334e1SEitan Adler { T_DIRECT, SIP_MEDIA_FIXED, "*", "KINGSTON SH103S3*", "*" }, 4569d3334e1SEitan Adler /*quirks*/ADA_Q_4K 4579d3334e1SEitan Adler }, 4589d3334e1SEitan Adler { 45932fe0ef7SSteven Hartland /* 460dce643c8SSteven Hartland * Marvell SSDs (entry taken from OpenSolaris) 461dce643c8SSteven Hartland * 4k optimised & trim only works in 4k requests + 4k aligned 462dce643c8SSteven Hartland */ 463dce643c8SSteven Hartland { T_DIRECT, SIP_MEDIA_FIXED, "*", "MARVELL SD88SA02*", "*" }, 464dce643c8SSteven Hartland /*quirks*/ADA_Q_4K 465dce643c8SSteven Hartland }, 466dce643c8SSteven Hartland { 467dce643c8SSteven Hartland /* 468*a6e0c5daSWarner Losh * Micron M500 SSDs firmware EU07 469*a6e0c5daSWarner Losh * NCQ Trim works? 470*a6e0c5daSWarner Losh */ 471*a6e0c5daSWarner Losh { T_DIRECT, SIP_MEDIA_FIXED, "*", "Micron M500*", "EU07" }, 472*a6e0c5daSWarner Losh /*quirks*/0 473*a6e0c5daSWarner Losh }, 474*a6e0c5daSWarner Losh { 475*a6e0c5daSWarner Losh /* 476*a6e0c5daSWarner Losh * Micron M500 SSDs all other firmware 477*a6e0c5daSWarner Losh * NCQ Trim doesn't work 478*a6e0c5daSWarner Losh */ 479*a6e0c5daSWarner Losh { T_DIRECT, SIP_MEDIA_FIXED, "*", "Micron M500*", "*" }, 480*a6e0c5daSWarner Losh /*quirks*/ADA_Q_NCQ_TRIM_BROKEN 481*a6e0c5daSWarner Losh }, 482*a6e0c5daSWarner Losh { 483*a6e0c5daSWarner Losh /* 484*a6e0c5daSWarner Losh * Micron M5[15]0 SSDs 485*a6e0c5daSWarner Losh * NCQ Trim doesn't work, but only MU01 firmware 486*a6e0c5daSWarner Losh */ 487*a6e0c5daSWarner Losh { T_DIRECT, SIP_MEDIA_FIXED, "*", "Micron M5[15]0*", "MU01" }, 488*a6e0c5daSWarner Losh /*quirks*/ADA_Q_NCQ_TRIM_BROKEN 489*a6e0c5daSWarner Losh }, 490*a6e0c5daSWarner Losh { 491*a6e0c5daSWarner Losh /* 492dce643c8SSteven Hartland * OCZ Agility 2 SSDs 493dce643c8SSteven Hartland * 4k optimised & trim only works in 4k requests + 4k aligned 494dce643c8SSteven Hartland */ 495dce643c8SSteven Hartland { T_DIRECT, SIP_MEDIA_FIXED, "*", "OCZ-AGILITY2*", "*" }, 496dce643c8SSteven Hartland /*quirks*/ADA_Q_4K 497dce643c8SSteven Hartland }, 498dce643c8SSteven Hartland { 499dce643c8SSteven Hartland /* 50032fe0ef7SSteven Hartland * OCZ Agility 3 SSDs 50132fe0ef7SSteven Hartland * 4k optimised & trim only works in 4k requests + 4k aligned 50232fe0ef7SSteven Hartland */ 50332fe0ef7SSteven Hartland { T_DIRECT, SIP_MEDIA_FIXED, "*", "OCZ-AGILITY3*", "*" }, 50432fe0ef7SSteven Hartland /*quirks*/ADA_Q_4K 50532fe0ef7SSteven Hartland }, 50632fe0ef7SSteven Hartland { 50732fe0ef7SSteven Hartland /* 50832fe0ef7SSteven Hartland * OCZ Deneva R Series SSDs 50932fe0ef7SSteven Hartland * 4k optimised & trim only works in 4k requests + 4k aligned 51032fe0ef7SSteven Hartland */ 51132fe0ef7SSteven Hartland { T_DIRECT, SIP_MEDIA_FIXED, "*", "DENRSTE251M45*", "*" }, 51232fe0ef7SSteven Hartland /*quirks*/ADA_Q_4K 51332fe0ef7SSteven Hartland }, 51432fe0ef7SSteven Hartland { 51532fe0ef7SSteven Hartland /* 51632fe0ef7SSteven Hartland * OCZ Vertex 2 SSDs (inc pro series) 51732fe0ef7SSteven Hartland * 4k optimised & trim only works in 4k requests + 4k aligned 51832fe0ef7SSteven Hartland */ 51932fe0ef7SSteven Hartland { T_DIRECT, SIP_MEDIA_FIXED, "*", "OCZ?VERTEX2*", "*" }, 52032fe0ef7SSteven Hartland /*quirks*/ADA_Q_4K 52132fe0ef7SSteven Hartland }, 52232fe0ef7SSteven Hartland { 52332fe0ef7SSteven Hartland /* 52432fe0ef7SSteven Hartland * OCZ Vertex 3 SSDs 52532fe0ef7SSteven Hartland * 4k optimised & trim only works in 4k requests + 4k aligned 52632fe0ef7SSteven Hartland */ 52732fe0ef7SSteven Hartland { T_DIRECT, SIP_MEDIA_FIXED, "*", "OCZ-VERTEX3*", "*" }, 52832fe0ef7SSteven Hartland /*quirks*/ADA_Q_4K 52932fe0ef7SSteven Hartland }, 53032fe0ef7SSteven Hartland { 53132fe0ef7SSteven Hartland /* 5327f1c7787SSteven Hartland * OCZ Vertex 4 SSDs 5337f1c7787SSteven Hartland * 4k optimised & trim only works in 4k requests + 4k aligned 5347f1c7787SSteven Hartland */ 5357f1c7787SSteven Hartland { T_DIRECT, SIP_MEDIA_FIXED, "*", "OCZ-VERTEX4*", "*" }, 5367f1c7787SSteven Hartland /*quirks*/ADA_Q_4K 5377f1c7787SSteven Hartland }, 5387f1c7787SSteven Hartland { 5397f1c7787SSteven Hartland /* 54032fe0ef7SSteven Hartland * Samsung 830 Series SSDs 541*a6e0c5daSWarner Losh * 4k optimised, NCQ TRIM Broken (normal TRIM is fine) 54232fe0ef7SSteven Hartland */ 54332fe0ef7SSteven Hartland { T_DIRECT, SIP_MEDIA_FIXED, "*", "SAMSUNG SSD 830 Series*", "*" }, 544*a6e0c5daSWarner Losh /*quirks*/ADA_Q_4K | ADA_Q_NCQ_TRIM_BROKEN 54532fe0ef7SSteven Hartland }, 54632fe0ef7SSteven Hartland { 54732fe0ef7SSteven Hartland /* 548dc98c62fSSteven Hartland * Samsung 840 SSDs 549*a6e0c5daSWarner Losh * 4k optimised, NCQ TRIM Broken (normal TRIM is fine) 550dc98c62fSSteven Hartland */ 551dc98c62fSSteven Hartland { T_DIRECT, SIP_MEDIA_FIXED, "*", "Samsung SSD 840*", "*" }, 552*a6e0c5daSWarner Losh /*quirks*/ADA_Q_4K | ADA_Q_NCQ_TRIM_BROKEN 553dc98c62fSSteven Hartland }, 554dc98c62fSSteven Hartland { 555dc98c62fSSteven Hartland /* 556e3a21bd1SGeorge V. Neville-Neil * Samsung 850 SSDs 557*a6e0c5daSWarner Losh * 4k optimised, NCQ TRIM broken (normal TRIM fine) 558e3a21bd1SGeorge V. Neville-Neil */ 559e3a21bd1SGeorge V. Neville-Neil { T_DIRECT, SIP_MEDIA_FIXED, "*", "Samsung SSD 850*", "*" }, 560*a6e0c5daSWarner Losh /*quirks*/ADA_Q_4K | ADA_Q_NCQ_TRIM_BROKEN 561e3a21bd1SGeorge V. Neville-Neil }, 5625f91863aSSean Bruno { 5635f91863aSSean Bruno /* 564eae90da9SJean-Sébastien Pédron * Samsung 843T Series SSDs (MZ7WD*) 565eae90da9SJean-Sébastien Pédron * Samsung PM851 Series SSDs (MZ7TE*) 566eae90da9SJean-Sébastien Pédron * Samsung PM853T Series SSDs (MZ7GE*) 567eae90da9SJean-Sébastien Pédron * Samsung SM863 Series SSDs (MZ7KM*) 568*a6e0c5daSWarner Losh * 4k optimised, NCQ Trim believed working 569323e0f6dSSean Bruno */ 570eae90da9SJean-Sébastien Pédron { T_DIRECT, SIP_MEDIA_FIXED, "*", "SAMSUNG MZ7*", "*" }, 571844b7984SSean Bruno /*quirks*/ADA_Q_4K 572844b7984SSean Bruno }, 573844b7984SSean Bruno { 574844b7984SSean Bruno /* 57532fe0ef7SSteven Hartland * SuperTalent TeraDrive CT SSDs 57632fe0ef7SSteven Hartland * 4k optimised & trim only works in 4k requests + 4k aligned 57732fe0ef7SSteven Hartland */ 57832fe0ef7SSteven Hartland { T_DIRECT, SIP_MEDIA_FIXED, "*", "FTM??CT25H*", "*" }, 57932fe0ef7SSteven Hartland /*quirks*/ADA_Q_4K 58032fe0ef7SSteven Hartland }, 58132fe0ef7SSteven Hartland { 58232fe0ef7SSteven Hartland /* 58332fe0ef7SSteven Hartland * XceedIOPS SATA SSDs 58432fe0ef7SSteven Hartland * 4k optimised 58532fe0ef7SSteven Hartland */ 58632fe0ef7SSteven Hartland { T_DIRECT, SIP_MEDIA_FIXED, "*", "SG9XCS2D*", "*" }, 58732fe0ef7SSteven Hartland /*quirks*/ADA_Q_4K 58832fe0ef7SSteven Hartland }, 58932fe0ef7SSteven Hartland { 59030a4094fSAlexander Motin /* Default */ 59130a4094fSAlexander Motin { 59230a4094fSAlexander Motin T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED, 59330a4094fSAlexander Motin /*vendor*/"*", /*product*/"*", /*revision*/"*" 59430a4094fSAlexander Motin }, 59530a4094fSAlexander Motin /*quirks*/0 59630a4094fSAlexander Motin }, 59730a4094fSAlexander Motin }; 59852c9ce25SScott Long 59952c9ce25SScott Long static disk_strategy_t adastrategy; 60052c9ce25SScott Long static dumper_t adadump; 60152c9ce25SScott Long static periph_init_t adainit; 60252c9ce25SScott Long static void adaasync(void *callback_arg, u_int32_t code, 60352c9ce25SScott Long struct cam_path *path, void *arg); 60452c9ce25SScott Long static void adasysctlinit(void *context, int pending); 60552c9ce25SScott Long static periph_ctor_t adaregister; 60652c9ce25SScott Long static periph_dtor_t adacleanup; 60752c9ce25SScott Long static periph_start_t adastart; 60852c9ce25SScott Long static periph_oninv_t adaoninvalidate; 60952c9ce25SScott Long static void adadone(struct cam_periph *periph, 61052c9ce25SScott Long union ccb *done_ccb); 61152c9ce25SScott Long static int adaerror(union ccb *ccb, u_int32_t cam_flags, 61252c9ce25SScott Long u_int32_t sense_flags); 613c1bd46c2SAlexander Motin static void adagetparams(struct cam_periph *periph, 61452c9ce25SScott Long struct ccb_getdev *cgd); 61552c9ce25SScott Long static timeout_t adasendorderedtag; 61652c9ce25SScott Long static void adashutdown(void *arg, int howto); 617c3d0d168SAlexander Motin static void adasuspend(void *arg); 618c3d0d168SAlexander Motin static void adaresume(void *arg); 61952c9ce25SScott Long 6200d307e09SAlexander Motin #ifndef ADA_DEFAULT_LEGACY_ALIASES 6210d307e09SAlexander Motin #define ADA_DEFAULT_LEGACY_ALIASES 1 6220d307e09SAlexander Motin #endif 6230d307e09SAlexander Motin 62452c9ce25SScott Long #ifndef ADA_DEFAULT_TIMEOUT 62552c9ce25SScott Long #define ADA_DEFAULT_TIMEOUT 30 /* Timeout in seconds */ 62652c9ce25SScott Long #endif 62752c9ce25SScott Long 62852c9ce25SScott Long #ifndef ADA_DEFAULT_RETRY 62952c9ce25SScott Long #define ADA_DEFAULT_RETRY 4 63052c9ce25SScott Long #endif 63152c9ce25SScott Long 63252c9ce25SScott Long #ifndef ADA_DEFAULT_SEND_ORDERED 63352c9ce25SScott Long #define ADA_DEFAULT_SEND_ORDERED 1 63452c9ce25SScott Long #endif 63552c9ce25SScott Long 636fd104c15SRebecca Cran #ifndef ADA_DEFAULT_SPINDOWN_SHUTDOWN 637fd104c15SRebecca Cran #define ADA_DEFAULT_SPINDOWN_SHUTDOWN 1 638fd104c15SRebecca Cran #endif 639fd104c15SRebecca Cran 640c3d0d168SAlexander Motin #ifndef ADA_DEFAULT_SPINDOWN_SUSPEND 641c3d0d168SAlexander Motin #define ADA_DEFAULT_SPINDOWN_SUSPEND 1 642c3d0d168SAlexander Motin #endif 643c3d0d168SAlexander Motin 6441ed6aaf9SAlexander Motin #ifndef ADA_DEFAULT_READ_AHEAD 6451ed6aaf9SAlexander Motin #define ADA_DEFAULT_READ_AHEAD 1 6461ed6aaf9SAlexander Motin #endif 6471ed6aaf9SAlexander Motin 648f513d14cSAlexander Motin #ifndef ADA_DEFAULT_WRITE_CACHE 649f513d14cSAlexander Motin #define ADA_DEFAULT_WRITE_CACHE 1 650f513d14cSAlexander Motin #endif 651f513d14cSAlexander Motin 6521ed6aaf9SAlexander Motin #define ADA_RA (softc->read_ahead >= 0 ? \ 6531ed6aaf9SAlexander Motin softc->read_ahead : ada_read_ahead) 6541ed6aaf9SAlexander Motin #define ADA_WC (softc->write_cache >= 0 ? \ 6551ed6aaf9SAlexander Motin softc->write_cache : ada_write_cache) 6561ed6aaf9SAlexander Motin 6574461491bSMarius Strobl /* 6584461491bSMarius Strobl * Most platforms map firmware geometry to actual, but some don't. If 6594461491bSMarius Strobl * not overridden, default to nothing. 6604461491bSMarius Strobl */ 6614461491bSMarius Strobl #ifndef ata_disk_firmware_geom_adjust 6624461491bSMarius Strobl #define ata_disk_firmware_geom_adjust(disk) 6634461491bSMarius Strobl #endif 66452c9ce25SScott Long 66552c9ce25SScott Long static int ada_retry_count = ADA_DEFAULT_RETRY; 66652c9ce25SScott Long static int ada_default_timeout = ADA_DEFAULT_TIMEOUT; 66752c9ce25SScott Long static int ada_send_ordered = ADA_DEFAULT_SEND_ORDERED; 668fd104c15SRebecca Cran static int ada_spindown_shutdown = ADA_DEFAULT_SPINDOWN_SHUTDOWN; 669c3d0d168SAlexander Motin static int ada_spindown_suspend = ADA_DEFAULT_SPINDOWN_SUSPEND; 6701ed6aaf9SAlexander Motin static int ada_read_ahead = ADA_DEFAULT_READ_AHEAD; 671f513d14cSAlexander Motin static int ada_write_cache = ADA_DEFAULT_WRITE_CACHE; 67252c9ce25SScott Long 6736472ac3dSEd Schouten static SYSCTL_NODE(_kern_cam, OID_AUTO, ada, CTLFLAG_RD, 0, 67452c9ce25SScott Long "CAM Direct Access Disk driver"); 675af3b2549SHans Petter Selasky SYSCTL_INT(_kern_cam_ada, OID_AUTO, retry_count, CTLFLAG_RWTUN, 67652c9ce25SScott Long &ada_retry_count, 0, "Normal I/O retry count"); 677af3b2549SHans Petter Selasky SYSCTL_INT(_kern_cam_ada, OID_AUTO, default_timeout, CTLFLAG_RWTUN, 67852c9ce25SScott Long &ada_default_timeout, 0, "Normal I/O timeout (in seconds)"); 679af3b2549SHans Petter Selasky SYSCTL_INT(_kern_cam_ada, OID_AUTO, send_ordered, CTLFLAG_RWTUN, 68052c9ce25SScott Long &ada_send_ordered, 0, "Send Ordered Tags"); 681af3b2549SHans Petter Selasky SYSCTL_INT(_kern_cam_ada, OID_AUTO, spindown_shutdown, CTLFLAG_RWTUN, 682fd104c15SRebecca Cran &ada_spindown_shutdown, 0, "Spin down upon shutdown"); 683af3b2549SHans Petter Selasky SYSCTL_INT(_kern_cam_ada, OID_AUTO, spindown_suspend, CTLFLAG_RWTUN, 684c3d0d168SAlexander Motin &ada_spindown_suspend, 0, "Spin down upon suspend"); 685af3b2549SHans Petter Selasky SYSCTL_INT(_kern_cam_ada, OID_AUTO, read_ahead, CTLFLAG_RWTUN, 6861ed6aaf9SAlexander Motin &ada_read_ahead, 0, "Enable disk read-ahead"); 687af3b2549SHans Petter Selasky SYSCTL_INT(_kern_cam_ada, OID_AUTO, write_cache, CTLFLAG_RWTUN, 688f513d14cSAlexander Motin &ada_write_cache, 0, "Enable disk write cache"); 68952c9ce25SScott Long 69052c9ce25SScott Long /* 69152c9ce25SScott Long * ADA_ORDEREDTAG_INTERVAL determines how often, relative 69252c9ce25SScott Long * to the default timeout, we check to see whether an ordered 69352c9ce25SScott Long * tagged transaction is appropriate to prevent simple tag 69452c9ce25SScott Long * starvation. Since we'd like to ensure that there is at least 69552c9ce25SScott Long * 1/2 of the timeout length left for a starved transaction to 69652c9ce25SScott Long * complete after we've sent an ordered tag, we must poll at least 69752c9ce25SScott Long * four times in every timeout period. This takes care of the worst 69852c9ce25SScott Long * case where a starved transaction starts during an interval that 69952c9ce25SScott Long * meets the requirement "don't send an ordered tag" test so it takes 70052c9ce25SScott Long * us two intervals to determine that a tag must be sent. 70152c9ce25SScott Long */ 70252c9ce25SScott Long #ifndef ADA_ORDEREDTAG_INTERVAL 70352c9ce25SScott Long #define ADA_ORDEREDTAG_INTERVAL 4 70452c9ce25SScott Long #endif 70552c9ce25SScott Long 70652c9ce25SScott Long static struct periph_driver adadriver = 70752c9ce25SScott Long { 70852c9ce25SScott Long adainit, "ada", 70952c9ce25SScott Long TAILQ_HEAD_INITIALIZER(adadriver.units), /* generation */ 0 71052c9ce25SScott Long }; 71152c9ce25SScott Long 712*a6e0c5daSWarner Losh static int adadeletemethodsysctl(SYSCTL_HANDLER_ARGS); 713*a6e0c5daSWarner Losh 71452c9ce25SScott Long PERIPHDRIVER_DECLARE(ada, adadriver); 71552c9ce25SScott Long 71652c9ce25SScott Long static int 71752c9ce25SScott Long adaopen(struct disk *dp) 71852c9ce25SScott Long { 71952c9ce25SScott Long struct cam_periph *periph; 72052c9ce25SScott Long struct ada_softc *softc; 72152c9ce25SScott Long int error; 72252c9ce25SScott Long 72352c9ce25SScott Long periph = (struct cam_periph *)dp->d_drv1; 72452c9ce25SScott Long if (cam_periph_acquire(periph) != CAM_REQ_CMP) { 72552c9ce25SScott Long return(ENXIO); 72652c9ce25SScott Long } 72752c9ce25SScott Long 72852c9ce25SScott Long cam_periph_lock(periph); 72952c9ce25SScott Long if ((error = cam_periph_hold(periph, PRIBIO|PCATCH)) != 0) { 73052c9ce25SScott Long cam_periph_unlock(periph); 73152c9ce25SScott Long cam_periph_release(periph); 73252c9ce25SScott Long return (error); 73352c9ce25SScott Long } 73452c9ce25SScott Long 735fddde2b8SAlexander Motin CAM_DEBUG(periph->path, CAM_DEBUG_TRACE | CAM_DEBUG_PERIPH, 736fddde2b8SAlexander Motin ("adaopen\n")); 73752c9ce25SScott Long 7387338ef1aSAlexander Motin softc = (struct ada_softc *)periph->softc; 7397338ef1aSAlexander Motin softc->flags |= ADA_FLAG_OPEN; 74052c9ce25SScott Long 74152c9ce25SScott Long cam_periph_unhold(periph); 74252c9ce25SScott Long cam_periph_unlock(periph); 74352c9ce25SScott Long return (0); 74452c9ce25SScott Long } 74552c9ce25SScott Long 74652c9ce25SScott Long static int 74752c9ce25SScott Long adaclose(struct disk *dp) 74852c9ce25SScott Long { 74952c9ce25SScott Long struct cam_periph *periph; 75052c9ce25SScott Long struct ada_softc *softc; 75152c9ce25SScott Long union ccb *ccb; 75269114bc0SAlexander Motin int error; 75352c9ce25SScott Long 75452c9ce25SScott Long periph = (struct cam_periph *)dp->d_drv1; 75552c9ce25SScott Long softc = (struct ada_softc *)periph->softc; 756227d67aaSAlexander Motin cam_periph_lock(periph); 757fddde2b8SAlexander Motin 758fddde2b8SAlexander Motin CAM_DEBUG(periph->path, CAM_DEBUG_TRACE | CAM_DEBUG_PERIPH, 759fddde2b8SAlexander Motin ("adaclose\n")); 760fddde2b8SAlexander Motin 76152c9ce25SScott Long /* We only sync the cache if the drive is capable of it. */ 76269114bc0SAlexander Motin if ((softc->flags & ADA_FLAG_DIRTY) != 0 && 76369114bc0SAlexander Motin (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) != 0 && 764227d67aaSAlexander Motin (periph->flags & CAM_PERIPH_INVALID) == 0 && 765227d67aaSAlexander Motin cam_periph_hold(periph, PRIBIO) == 0) { 76652c9ce25SScott Long 767bbfa4aa1SAlexander Motin ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 76852c9ce25SScott Long cam_fill_ataio(&ccb->ataio, 76952c9ce25SScott Long 1, 77052c9ce25SScott Long adadone, 77152c9ce25SScott Long CAM_DIR_NONE, 77252c9ce25SScott Long 0, 77352c9ce25SScott Long NULL, 77452c9ce25SScott Long 0, 77552c9ce25SScott Long ada_default_timeout*1000); 77652c9ce25SScott Long 77752c9ce25SScott Long if (softc->flags & ADA_FLAG_CAN_48BIT) 77852c9ce25SScott Long ata_48bit_cmd(&ccb->ataio, ATA_FLUSHCACHE48, 0, 0, 0); 77952c9ce25SScott Long else 7807606b445SAlexander Motin ata_28bit_cmd(&ccb->ataio, ATA_FLUSHCACHE, 0, 0, 0); 78169114bc0SAlexander Motin error = cam_periph_runccb(ccb, adaerror, /*cam_flags*/0, 78246f118feSAlexander Motin /*sense_flags*/0, softc->disk->d_devstat); 78352c9ce25SScott Long 78469114bc0SAlexander Motin if (error != 0) 78552c9ce25SScott Long xpt_print(periph->path, "Synchronize cache failed\n"); 78669114bc0SAlexander Motin else 78769114bc0SAlexander Motin softc->flags &= ~ADA_FLAG_DIRTY; 78852c9ce25SScott Long xpt_release_ccb(ccb); 789227d67aaSAlexander Motin cam_periph_unhold(periph); 79052c9ce25SScott Long } 79152c9ce25SScott Long 79252c9ce25SScott Long softc->flags &= ~ADA_FLAG_OPEN; 793227d67aaSAlexander Motin 794227d67aaSAlexander Motin while (softc->refcount != 0) 795227d67aaSAlexander Motin cam_periph_sleep(periph, &softc->refcount, PRIBIO, "adaclose", 1); 79652c9ce25SScott Long cam_periph_unlock(periph); 79752c9ce25SScott Long cam_periph_release(periph); 79852c9ce25SScott Long return (0); 79952c9ce25SScott Long } 80052c9ce25SScott Long 8011c80ec0aSAlexander Motin static void 8021c80ec0aSAlexander Motin adaschedule(struct cam_periph *periph) 8031c80ec0aSAlexander Motin { 8041c80ec0aSAlexander Motin struct ada_softc *softc = (struct ada_softc *)periph->softc; 8051c80ec0aSAlexander Motin 8066bf435dcSAlexander Motin if (softc->state != ADA_STATE_NORMAL) 8076bf435dcSAlexander Motin return; 8086bf435dcSAlexander Motin 809*a6e0c5daSWarner Losh cam_iosched_schedule(softc->cam_iosched, periph); 8101c80ec0aSAlexander Motin } 8111c80ec0aSAlexander Motin 81252c9ce25SScott Long /* 81352c9ce25SScott Long * Actually translate the requested transfer into one the physical driver 81452c9ce25SScott Long * can understand. The transfer is described by a buf and will include 81552c9ce25SScott Long * only one physical transfer. 81652c9ce25SScott Long */ 81752c9ce25SScott Long static void 81852c9ce25SScott Long adastrategy(struct bio *bp) 81952c9ce25SScott Long { 82052c9ce25SScott Long struct cam_periph *periph; 82152c9ce25SScott Long struct ada_softc *softc; 82252c9ce25SScott Long 82352c9ce25SScott Long periph = (struct cam_periph *)bp->bio_disk->d_drv1; 82452c9ce25SScott Long softc = (struct ada_softc *)periph->softc; 82552c9ce25SScott Long 82652c9ce25SScott Long cam_periph_lock(periph); 82752c9ce25SScott Long 828fddde2b8SAlexander Motin CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("adastrategy(%p)\n", bp)); 829fddde2b8SAlexander Motin 83052c9ce25SScott Long /* 83152c9ce25SScott Long * If the device has been made invalid, error out 83252c9ce25SScott Long */ 8337338ef1aSAlexander Motin if ((periph->flags & CAM_PERIPH_INVALID) != 0) { 83452c9ce25SScott Long cam_periph_unlock(periph); 83552c9ce25SScott Long biofinish(bp, NULL, ENXIO); 83652c9ce25SScott Long return; 83752c9ce25SScott Long } 83852c9ce25SScott Long 83952c9ce25SScott Long /* 84052c9ce25SScott Long * Place it in the queue of disk activities for this disk 84152c9ce25SScott Long */ 842*a6e0c5daSWarner Losh cam_iosched_queue_work(softc->cam_iosched, bp); 84352c9ce25SScott Long 84452c9ce25SScott Long /* 84552c9ce25SScott Long * Schedule ourselves for performing the work. 84652c9ce25SScott Long */ 8471c80ec0aSAlexander Motin adaschedule(periph); 84852c9ce25SScott Long cam_periph_unlock(periph); 84952c9ce25SScott Long 85052c9ce25SScott Long return; 85152c9ce25SScott Long } 85252c9ce25SScott Long 85352c9ce25SScott Long static int 85452c9ce25SScott Long adadump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t length) 85552c9ce25SScott Long { 85652c9ce25SScott Long struct cam_periph *periph; 85752c9ce25SScott Long struct ada_softc *softc; 85852c9ce25SScott Long u_int secsize; 85952c9ce25SScott Long union ccb ccb; 86052c9ce25SScott Long struct disk *dp; 86152c9ce25SScott Long uint64_t lba; 86252c9ce25SScott Long uint16_t count; 8630191d9b3SAlexander Motin int error = 0; 86452c9ce25SScott Long 86552c9ce25SScott Long dp = arg; 86652c9ce25SScott Long periph = dp->d_drv1; 86752c9ce25SScott Long softc = (struct ada_softc *)periph->softc; 86852c9ce25SScott Long cam_periph_lock(periph); 86952c9ce25SScott Long secsize = softc->params.secsize; 87052c9ce25SScott Long lba = offset / secsize; 87152c9ce25SScott Long count = length / secsize; 87252c9ce25SScott Long 8737338ef1aSAlexander Motin if ((periph->flags & CAM_PERIPH_INVALID) != 0) { 87452c9ce25SScott Long cam_periph_unlock(periph); 87552c9ce25SScott Long return (ENXIO); 87652c9ce25SScott Long } 87752c9ce25SScott Long 87852c9ce25SScott Long if (length > 0) { 879bbfa4aa1SAlexander Motin xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 88052c9ce25SScott Long ccb.ccb_h.ccb_state = ADA_CCB_DUMP; 88152c9ce25SScott Long cam_fill_ataio(&ccb.ataio, 88252c9ce25SScott Long 0, 88352c9ce25SScott Long adadone, 88452c9ce25SScott Long CAM_DIR_OUT, 88552c9ce25SScott Long 0, 88652c9ce25SScott Long (u_int8_t *) virtual, 88752c9ce25SScott Long length, 88852c9ce25SScott Long ada_default_timeout*1000); 88952c9ce25SScott Long if ((softc->flags & ADA_FLAG_CAN_48BIT) && 89052c9ce25SScott Long (lba + count >= ATA_MAX_28BIT_LBA || 89152c9ce25SScott Long count >= 256)) { 89252c9ce25SScott Long ata_48bit_cmd(&ccb.ataio, ATA_WRITE_DMA48, 89352c9ce25SScott Long 0, lba, count); 89452c9ce25SScott Long } else { 8957606b445SAlexander Motin ata_28bit_cmd(&ccb.ataio, ATA_WRITE_DMA, 89652c9ce25SScott Long 0, lba, count); 89752c9ce25SScott Long } 89852c9ce25SScott Long xpt_polled_action(&ccb); 89952c9ce25SScott Long 9000191d9b3SAlexander Motin error = cam_periph_error(&ccb, 9010191d9b3SAlexander Motin 0, SF_NO_RECOVERY | SF_NO_RETRY, NULL); 9020191d9b3SAlexander Motin if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0) 9030191d9b3SAlexander Motin cam_release_devq(ccb.ccb_h.path, /*relsim_flags*/0, 9040191d9b3SAlexander Motin /*reduction*/0, /*timeout*/0, /*getcount_only*/0); 9050191d9b3SAlexander Motin if (error != 0) 90652c9ce25SScott Long printf("Aborting dump due to I/O error.\n"); 9070191d9b3SAlexander Motin 90852c9ce25SScott Long cam_periph_unlock(periph); 9090191d9b3SAlexander Motin return (error); 91052c9ce25SScott Long } 91152c9ce25SScott Long 91252c9ce25SScott Long if (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) { 913bbfa4aa1SAlexander Motin xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 91452c9ce25SScott Long 91552c9ce25SScott Long ccb.ccb_h.ccb_state = ADA_CCB_DUMP; 91652c9ce25SScott Long cam_fill_ataio(&ccb.ataio, 9170191d9b3SAlexander Motin 0, 91852c9ce25SScott Long adadone, 91952c9ce25SScott Long CAM_DIR_NONE, 92052c9ce25SScott Long 0, 92152c9ce25SScott Long NULL, 92252c9ce25SScott Long 0, 923*a6e0c5daSWarner Losh 5*1000); 92452c9ce25SScott Long 92552c9ce25SScott Long if (softc->flags & ADA_FLAG_CAN_48BIT) 92652c9ce25SScott Long ata_48bit_cmd(&ccb.ataio, ATA_FLUSHCACHE48, 0, 0, 0); 92752c9ce25SScott Long else 9287606b445SAlexander Motin ata_28bit_cmd(&ccb.ataio, ATA_FLUSHCACHE, 0, 0, 0); 92952c9ce25SScott Long xpt_polled_action(&ccb); 93052c9ce25SScott Long 9310191d9b3SAlexander Motin error = cam_periph_error(&ccb, 9320191d9b3SAlexander Motin 0, SF_NO_RECOVERY | SF_NO_RETRY, NULL); 93352c9ce25SScott Long if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0) 9340191d9b3SAlexander Motin cam_release_devq(ccb.ccb_h.path, /*relsim_flags*/0, 9350191d9b3SAlexander Motin /*reduction*/0, /*timeout*/0, /*getcount_only*/0); 9360191d9b3SAlexander Motin if (error != 0) 9370191d9b3SAlexander Motin xpt_print(periph->path, "Synchronize cache failed\n"); 93852c9ce25SScott Long } 93952c9ce25SScott Long cam_periph_unlock(periph); 9400191d9b3SAlexander Motin return (error); 94152c9ce25SScott Long } 94252c9ce25SScott Long 94352c9ce25SScott Long static void 94452c9ce25SScott Long adainit(void) 94552c9ce25SScott Long { 94652c9ce25SScott Long cam_status status; 94752c9ce25SScott Long 94852c9ce25SScott Long /* 94952c9ce25SScott Long * Install a global async callback. This callback will 95052c9ce25SScott Long * receive async callbacks like "new device found". 95152c9ce25SScott Long */ 95252c9ce25SScott Long status = xpt_register_async(AC_FOUND_DEVICE, adaasync, NULL, NULL); 95352c9ce25SScott Long 95452c9ce25SScott Long if (status != CAM_REQ_CMP) { 95552c9ce25SScott Long printf("ada: Failed to attach master async callback " 95652c9ce25SScott Long "due to status 0x%x!\n", status); 95752c9ce25SScott Long } else if (ada_send_ordered) { 95852c9ce25SScott Long 959c3d0d168SAlexander Motin /* Register our event handlers */ 960c3d0d168SAlexander Motin if ((EVENTHANDLER_REGISTER(power_suspend, adasuspend, 961c3d0d168SAlexander Motin NULL, EVENTHANDLER_PRI_LAST)) == NULL) 962c3d0d168SAlexander Motin printf("adainit: power event registration failed!\n"); 963c3d0d168SAlexander Motin if ((EVENTHANDLER_REGISTER(power_resume, adaresume, 964c3d0d168SAlexander Motin NULL, EVENTHANDLER_PRI_LAST)) == NULL) 965c3d0d168SAlexander Motin printf("adainit: power event registration failed!\n"); 96652c9ce25SScott Long if ((EVENTHANDLER_REGISTER(shutdown_post_sync, adashutdown, 96752c9ce25SScott Long NULL, SHUTDOWN_PRI_DEFAULT)) == NULL) 96852c9ce25SScott Long printf("adainit: shutdown event registration failed!\n"); 96952c9ce25SScott Long } 97052c9ce25SScott Long } 97152c9ce25SScott Long 9720ba1e4d0SKenneth D. Merry /* 9730ba1e4d0SKenneth D. Merry * Callback from GEOM, called when it has finished cleaning up its 9740ba1e4d0SKenneth D. Merry * resources. 9750ba1e4d0SKenneth D. Merry */ 9760ba1e4d0SKenneth D. Merry static void 9770ba1e4d0SKenneth D. Merry adadiskgonecb(struct disk *dp) 9780ba1e4d0SKenneth D. Merry { 9790ba1e4d0SKenneth D. Merry struct cam_periph *periph; 9800ba1e4d0SKenneth D. Merry 9810ba1e4d0SKenneth D. Merry periph = (struct cam_periph *)dp->d_drv1; 9820ba1e4d0SKenneth D. Merry 9830ba1e4d0SKenneth D. Merry cam_periph_release(periph); 9840ba1e4d0SKenneth D. Merry } 9850ba1e4d0SKenneth D. Merry 98652c9ce25SScott Long static void 98752c9ce25SScott Long adaoninvalidate(struct cam_periph *periph) 98852c9ce25SScott Long { 98952c9ce25SScott Long struct ada_softc *softc; 99052c9ce25SScott Long 99152c9ce25SScott Long softc = (struct ada_softc *)periph->softc; 99252c9ce25SScott Long 99352c9ce25SScott Long /* 99452c9ce25SScott Long * De-register any async callbacks. 99552c9ce25SScott Long */ 99652c9ce25SScott Long xpt_register_async(0, adaasync, periph, periph->path); 997*a6e0c5daSWarner Losh #ifdef CAM_IO_STATS 998*a6e0c5daSWarner Losh softc->invalidations++; 999*a6e0c5daSWarner Losh #endif 100052c9ce25SScott Long 100152c9ce25SScott Long /* 100252c9ce25SScott Long * Return all queued I/O with ENXIO. 100352c9ce25SScott Long * XXX Handle any transactions queued to the card 100452c9ce25SScott Long * with XPT_ABORT_CCB. 100552c9ce25SScott Long */ 1006*a6e0c5daSWarner Losh cam_iosched_flush(softc->cam_iosched, NULL, ENXIO); 100752c9ce25SScott Long 100852c9ce25SScott Long disk_gone(softc->disk); 100952c9ce25SScott Long } 101052c9ce25SScott Long 101152c9ce25SScott Long static void 101252c9ce25SScott Long adacleanup(struct cam_periph *periph) 101352c9ce25SScott Long { 101452c9ce25SScott Long struct ada_softc *softc; 101552c9ce25SScott Long 101652c9ce25SScott Long softc = (struct ada_softc *)periph->softc; 101752c9ce25SScott Long 101852c9ce25SScott Long cam_periph_unlock(periph); 101952c9ce25SScott Long 1020*a6e0c5daSWarner Losh cam_iosched_fini(softc->cam_iosched); 1021*a6e0c5daSWarner Losh 102252c9ce25SScott Long /* 102352c9ce25SScott Long * If we can't free the sysctl tree, oh well... 102452c9ce25SScott Long */ 1025*a6e0c5daSWarner Losh if ((softc->flags & ADA_FLAG_SCTX_INIT) != 0) { 1026*a6e0c5daSWarner Losh #ifdef CAM_IO_STATS 1027*a6e0c5daSWarner Losh if (sysctl_ctx_free(&softc->sysctl_stats_ctx) != 0) 1028*a6e0c5daSWarner Losh xpt_print(periph->path, 1029*a6e0c5daSWarner Losh "can't remove sysctl stats context\n"); 1030*a6e0c5daSWarner Losh #endif 1031*a6e0c5daSWarner Losh if (sysctl_ctx_free(&softc->sysctl_ctx) != 0) 1032*a6e0c5daSWarner Losh xpt_print(periph->path, 1033*a6e0c5daSWarner Losh "can't remove sysctl context\n"); 103452c9ce25SScott Long } 103552c9ce25SScott Long 103652c9ce25SScott Long disk_destroy(softc->disk); 103752c9ce25SScott Long callout_drain(&softc->sendordered_c); 103852c9ce25SScott Long free(softc, M_DEVBUF); 103952c9ce25SScott Long cam_periph_lock(periph); 104052c9ce25SScott Long } 104152c9ce25SScott Long 104252c9ce25SScott Long static void 1043*a6e0c5daSWarner Losh adasetdeletemethod(struct ada_softc *softc) 1044*a6e0c5daSWarner Losh { 1045*a6e0c5daSWarner Losh 1046*a6e0c5daSWarner Losh if (softc->flags & ADA_FLAG_CAN_NCQ_TRIM) 1047*a6e0c5daSWarner Losh softc->delete_method = ADA_DELETE_NCQ_DSM_TRIM; 1048*a6e0c5daSWarner Losh else if (softc->flags & ADA_FLAG_CAN_TRIM) 1049*a6e0c5daSWarner Losh softc->delete_method = ADA_DELETE_DSM_TRIM; 1050*a6e0c5daSWarner Losh else if ((softc->flags & ADA_FLAG_CAN_CFA) && !(softc->flags & ADA_FLAG_CAN_48BIT)) 1051*a6e0c5daSWarner Losh softc->delete_method = ADA_DELETE_CFA_ERASE; 1052*a6e0c5daSWarner Losh else 1053*a6e0c5daSWarner Losh softc->delete_method = ADA_DELETE_NONE; 1054*a6e0c5daSWarner Losh } 1055*a6e0c5daSWarner Losh 1056*a6e0c5daSWarner Losh static void 105752c9ce25SScott Long adaasync(void *callback_arg, u_int32_t code, 105852c9ce25SScott Long struct cam_path *path, void *arg) 105952c9ce25SScott Long { 1060581b2e78SAlexander Motin struct ccb_getdev cgd; 106152c9ce25SScott Long struct cam_periph *periph; 1062f513d14cSAlexander Motin struct ada_softc *softc; 106352c9ce25SScott Long 106452c9ce25SScott Long periph = (struct cam_periph *)callback_arg; 106552c9ce25SScott Long switch (code) { 106652c9ce25SScott Long case AC_FOUND_DEVICE: 106752c9ce25SScott Long { 106852c9ce25SScott Long struct ccb_getdev *cgd; 106952c9ce25SScott Long cam_status status; 107052c9ce25SScott Long 107152c9ce25SScott Long cgd = (struct ccb_getdev *)arg; 107252c9ce25SScott Long if (cgd == NULL) 107352c9ce25SScott Long break; 107452c9ce25SScott Long 107552c9ce25SScott Long if (cgd->protocol != PROTO_ATA) 107652c9ce25SScott Long break; 107752c9ce25SScott Long 107852c9ce25SScott Long /* 107952c9ce25SScott Long * Allocate a peripheral instance for 108052c9ce25SScott Long * this device and start the probe 108152c9ce25SScott Long * process. 108252c9ce25SScott Long */ 108352c9ce25SScott Long status = cam_periph_alloc(adaregister, adaoninvalidate, 108452c9ce25SScott Long adacleanup, adastart, 108552c9ce25SScott Long "ada", CAM_PERIPH_BIO, 1086227d67aaSAlexander Motin path, adaasync, 108752c9ce25SScott Long AC_FOUND_DEVICE, cgd); 108852c9ce25SScott Long 108952c9ce25SScott Long if (status != CAM_REQ_CMP 109052c9ce25SScott Long && status != CAM_REQ_INPROG) 109152c9ce25SScott Long printf("adaasync: Unable to attach to new device " 109252c9ce25SScott Long "due to status 0x%x\n", status); 109352c9ce25SScott Long break; 109452c9ce25SScott Long } 1095581b2e78SAlexander Motin case AC_GETDEV_CHANGED: 1096581b2e78SAlexander Motin { 1097581b2e78SAlexander Motin softc = (struct ada_softc *)periph->softc; 1098581b2e78SAlexander Motin xpt_setup_ccb(&cgd.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 1099581b2e78SAlexander Motin cgd.ccb_h.func_code = XPT_GDEV_TYPE; 1100581b2e78SAlexander Motin xpt_action((union ccb *)&cgd); 1101581b2e78SAlexander Motin 1102581b2e78SAlexander Motin if ((cgd.ident_data.capabilities1 & ATA_SUPPORT_DMA) && 1103581b2e78SAlexander Motin (cgd.inq_flags & SID_DMA)) 1104581b2e78SAlexander Motin softc->flags |= ADA_FLAG_CAN_DMA; 1105581b2e78SAlexander Motin else 1106581b2e78SAlexander Motin softc->flags &= ~ADA_FLAG_CAN_DMA; 11072e1eb332SMarius Strobl if (cgd.ident_data.support.command2 & ATA_SUPPORT_ADDRESS48) { 11082e1eb332SMarius Strobl softc->flags |= ADA_FLAG_CAN_48BIT; 11092e1eb332SMarius Strobl if (cgd.inq_flags & SID_DMA48) 11102e1eb332SMarius Strobl softc->flags |= ADA_FLAG_CAN_DMA48; 11112e1eb332SMarius Strobl else 11122e1eb332SMarius Strobl softc->flags &= ~ADA_FLAG_CAN_DMA48; 11132e1eb332SMarius Strobl } else 11142e1eb332SMarius Strobl softc->flags &= ~(ADA_FLAG_CAN_48BIT | 11152e1eb332SMarius Strobl ADA_FLAG_CAN_DMA48); 1116581b2e78SAlexander Motin if ((cgd.ident_data.satacapabilities & ATA_SUPPORT_NCQ) && 1117581b2e78SAlexander Motin (cgd.inq_flags & SID_DMA) && (cgd.inq_flags & SID_CmdQue)) 1118581b2e78SAlexander Motin softc->flags |= ADA_FLAG_CAN_NCQ; 1119581b2e78SAlexander Motin else 1120581b2e78SAlexander Motin softc->flags &= ~ADA_FLAG_CAN_NCQ; 1121*a6e0c5daSWarner Losh 1122581b2e78SAlexander Motin if ((cgd.ident_data.support_dsm & ATA_SUPPORT_DSM_TRIM) && 1123*a6e0c5daSWarner Losh (cgd.inq_flags & SID_DMA)) { 1124581b2e78SAlexander Motin softc->flags |= ADA_FLAG_CAN_TRIM; 1125*a6e0c5daSWarner Losh /* 1126*a6e0c5daSWarner Losh * If we can do RCVSND_FPDMA_QUEUED commands, we may be able to do 1127*a6e0c5daSWarner Losh * NCQ trims, if we support trims at all. We also need support from 1128*a6e0c5daSWarner Losh * the sim do do things properly. Perhaps we should look at log 13 1129*a6e0c5daSWarner Losh * dword 0 bit 0 and dword 1 bit 0 are set too... 1130*a6e0c5daSWarner Losh */ 1131*a6e0c5daSWarner Losh if ((softc->quirks & ADA_Q_NCQ_TRIM_BROKEN) == 0 && 1132*a6e0c5daSWarner Losh (softc->flags & ADA_FLAG_PIM_CAN_NCQ_TRIM) != 0 && 1133*a6e0c5daSWarner Losh (cgd.ident_data.satacapabilities2 & ATA_SUPPORT_RCVSND_FPDMA_QUEUED) != 0 && 1134*a6e0c5daSWarner Losh (softc->flags & ADA_FLAG_CAN_TRIM) != 0) 1135*a6e0c5daSWarner Losh softc->flags |= ADA_FLAG_CAN_NCQ_TRIM; 1136581b2e78SAlexander Motin else 1137*a6e0c5daSWarner Losh softc->flags &= ~ADA_FLAG_CAN_NCQ_TRIM; 1138*a6e0c5daSWarner Losh } else 1139*a6e0c5daSWarner Losh softc->flags &= ~(ADA_FLAG_CAN_TRIM | ADA_FLAG_CAN_NCQ_TRIM); 1140*a6e0c5daSWarner Losh adasetdeletemethod(softc); 1141581b2e78SAlexander Motin 1142581b2e78SAlexander Motin cam_periph_async(periph, code, path, arg); 1143581b2e78SAlexander Motin break; 1144581b2e78SAlexander Motin } 11453089bb2eSAlexander Motin case AC_ADVINFO_CHANGED: 11463089bb2eSAlexander Motin { 11473089bb2eSAlexander Motin uintptr_t buftype; 11483089bb2eSAlexander Motin 11493089bb2eSAlexander Motin buftype = (uintptr_t)arg; 11503089bb2eSAlexander Motin if (buftype == CDAI_TYPE_PHYS_PATH) { 11513089bb2eSAlexander Motin struct ada_softc *softc; 11523089bb2eSAlexander Motin 11533089bb2eSAlexander Motin softc = periph->softc; 11543089bb2eSAlexander Motin disk_attr_changed(softc->disk, "GEOM::physpath", 11553089bb2eSAlexander Motin M_NOWAIT); 11563089bb2eSAlexander Motin } 11573089bb2eSAlexander Motin break; 11583089bb2eSAlexander Motin } 1159f513d14cSAlexander Motin case AC_SENT_BDR: 1160f513d14cSAlexander Motin case AC_BUS_RESET: 1161f513d14cSAlexander Motin { 1162f513d14cSAlexander Motin softc = (struct ada_softc *)periph->softc; 1163f513d14cSAlexander Motin cam_periph_async(periph, code, path, arg); 1164f513d14cSAlexander Motin if (softc->state != ADA_STATE_NORMAL) 1165f513d14cSAlexander Motin break; 1166e3a6d3a4SAlexander Motin xpt_setup_ccb(&cgd.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 1167f513d14cSAlexander Motin cgd.ccb_h.func_code = XPT_GDEV_TYPE; 1168f513d14cSAlexander Motin xpt_action((union ccb *)&cgd); 11691ed6aaf9SAlexander Motin if (ADA_RA >= 0 && 11701ed6aaf9SAlexander Motin cgd.ident_data.support.command1 & ATA_SUPPORT_LOOKAHEAD) 11711ed6aaf9SAlexander Motin softc->state = ADA_STATE_RAHEAD; 11721ed6aaf9SAlexander Motin else if (ADA_WC >= 0 && 11731ed6aaf9SAlexander Motin cgd.ident_data.support.command1 & ATA_SUPPORT_WRITECACHE) 1174f513d14cSAlexander Motin softc->state = ADA_STATE_WCACHE; 11751ed6aaf9SAlexander Motin else 11761ed6aaf9SAlexander Motin break; 1177227d67aaSAlexander Motin if (cam_periph_acquire(periph) != CAM_REQ_CMP) 1178227d67aaSAlexander Motin softc->state = ADA_STATE_NORMAL; 1179227d67aaSAlexander Motin else 1180f513d14cSAlexander Motin xpt_schedule(periph, CAM_PRIORITY_DEV); 1181f513d14cSAlexander Motin } 118252c9ce25SScott Long default: 118352c9ce25SScott Long cam_periph_async(periph, code, path, arg); 118452c9ce25SScott Long break; 118552c9ce25SScott Long } 118652c9ce25SScott Long } 118752c9ce25SScott Long 118852c9ce25SScott Long static void 118952c9ce25SScott Long adasysctlinit(void *context, int pending) 119052c9ce25SScott Long { 119152c9ce25SScott Long struct cam_periph *periph; 119252c9ce25SScott Long struct ada_softc *softc; 119352c9ce25SScott Long char tmpstr[80], tmpstr2[80]; 119452c9ce25SScott Long 119552c9ce25SScott Long periph = (struct cam_periph *)context; 1196e3a6d3a4SAlexander Motin 1197e3a6d3a4SAlexander Motin /* periph was held for us when this task was enqueued */ 11987338ef1aSAlexander Motin if ((periph->flags & CAM_PERIPH_INVALID) != 0) { 1199e3a6d3a4SAlexander Motin cam_periph_release(periph); 120052c9ce25SScott Long return; 1201e3a6d3a4SAlexander Motin } 120252c9ce25SScott Long 120352c9ce25SScott Long softc = (struct ada_softc *)periph->softc; 120452c9ce25SScott Long snprintf(tmpstr, sizeof(tmpstr), "CAM ADA unit %d", periph->unit_number); 120552c9ce25SScott Long snprintf(tmpstr2, sizeof(tmpstr2), "%d", periph->unit_number); 120652c9ce25SScott Long 120752c9ce25SScott Long sysctl_ctx_init(&softc->sysctl_ctx); 120852c9ce25SScott Long softc->flags |= ADA_FLAG_SCTX_INIT; 120952c9ce25SScott Long softc->sysctl_tree = SYSCTL_ADD_NODE(&softc->sysctl_ctx, 121052c9ce25SScott Long SYSCTL_STATIC_CHILDREN(_kern_cam_ada), OID_AUTO, tmpstr2, 121152c9ce25SScott Long CTLFLAG_RD, 0, tmpstr); 121252c9ce25SScott Long if (softc->sysctl_tree == NULL) { 121352c9ce25SScott Long printf("adasysctlinit: unable to allocate sysctl tree\n"); 121452c9ce25SScott Long cam_periph_release(periph); 121552c9ce25SScott Long return; 121652c9ce25SScott Long } 121752c9ce25SScott Long 1218*a6e0c5daSWarner Losh SYSCTL_ADD_PROC(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 1219*a6e0c5daSWarner Losh OID_AUTO, "delete_method", CTLTYPE_STRING | CTLFLAG_RW, 1220*a6e0c5daSWarner Losh softc, 0, adadeletemethodsysctl, "A", 1221*a6e0c5daSWarner Losh "BIO_DELETE execution method"); 1222e3a6d3a4SAlexander Motin SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 12231ed6aaf9SAlexander Motin OID_AUTO, "read_ahead", CTLFLAG_RW | CTLFLAG_MPSAFE, 12241ed6aaf9SAlexander Motin &softc->read_ahead, 0, "Enable disk read ahead."); 12251ed6aaf9SAlexander Motin SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 1226e3a6d3a4SAlexander Motin OID_AUTO, "write_cache", CTLFLAG_RW | CTLFLAG_MPSAFE, 1227e3a6d3a4SAlexander Motin &softc->write_cache, 0, "Enable disk write cache."); 12285f83aee5SSteven Hartland SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 1229*a6e0c5daSWarner Losh OID_AUTO, "unmapped_io", CTLFLAG_RD | CTLFLAG_MPSAFE, 1230*a6e0c5daSWarner Losh &softc->unmappedio, 0, "Unmapped I/O leaf"); 1231*a6e0c5daSWarner Losh SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 1232*a6e0c5daSWarner Losh OID_AUTO, "rotating", CTLFLAG_RD | CTLFLAG_MPSAFE, 1233*a6e0c5daSWarner Losh &softc->rotating, 0, "Rotating media"); 1234e3a6d3a4SAlexander Motin #ifdef ADA_TEST_FAILURE 1235e3a6d3a4SAlexander Motin /* 1236e3a6d3a4SAlexander Motin * Add a 'door bell' sysctl which allows one to set it from userland 1237e3a6d3a4SAlexander Motin * and cause something bad to happen. For the moment, we only allow 1238e3a6d3a4SAlexander Motin * whacking the next read or write. 1239e3a6d3a4SAlexander Motin */ 1240e3a6d3a4SAlexander Motin SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 1241e3a6d3a4SAlexander Motin OID_AUTO, "force_read_error", CTLFLAG_RW | CTLFLAG_MPSAFE, 1242e3a6d3a4SAlexander Motin &softc->force_read_error, 0, 1243e3a6d3a4SAlexander Motin "Force a read error for the next N reads."); 1244e3a6d3a4SAlexander Motin SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 1245e3a6d3a4SAlexander Motin OID_AUTO, "force_write_error", CTLFLAG_RW | CTLFLAG_MPSAFE, 1246e3a6d3a4SAlexander Motin &softc->force_write_error, 0, 1247e3a6d3a4SAlexander Motin "Force a write error for the next N writes."); 1248e3a6d3a4SAlexander Motin SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 1249e3a6d3a4SAlexander Motin OID_AUTO, "periodic_read_error", CTLFLAG_RW | CTLFLAG_MPSAFE, 1250e3a6d3a4SAlexander Motin &softc->periodic_read_error, 0, 1251e3a6d3a4SAlexander Motin "Force a read error every N reads (don't set too low)."); 1252e3a6d3a4SAlexander Motin #endif 1253*a6e0c5daSWarner Losh 1254*a6e0c5daSWarner Losh #ifdef CAM_IO_STATS 1255*a6e0c5daSWarner Losh softc->sysctl_stats_tree = SYSCTL_ADD_NODE(&softc->sysctl_stats_ctx, 1256*a6e0c5daSWarner Losh SYSCTL_CHILDREN(softc->sysctl_tree), OID_AUTO, "stats", 1257*a6e0c5daSWarner Losh CTLFLAG_RD, 0, "Statistics"); 1258*a6e0c5daSWarner Losh SYSCTL_ADD_INT(&softc->sysctl_stats_ctx, 1259*a6e0c5daSWarner Losh SYSCTL_CHILDREN(softc->sysctl_stats_tree), 1260*a6e0c5daSWarner Losh OID_AUTO, "timeouts", CTLFLAG_RD | CTLFLAG_MPSAFE, 1261*a6e0c5daSWarner Losh &softc->timeouts, 0, 1262*a6e0c5daSWarner Losh "Device timeouts reported by the SIM"); 1263*a6e0c5daSWarner Losh SYSCTL_ADD_INT(&softc->sysctl_stats_ctx, 1264*a6e0c5daSWarner Losh SYSCTL_CHILDREN(softc->sysctl_stats_tree), 1265*a6e0c5daSWarner Losh OID_AUTO, "errors", CTLFLAG_RD | CTLFLAG_MPSAFE, 1266*a6e0c5daSWarner Losh &softc->errors, 0, 1267*a6e0c5daSWarner Losh "Transport errors reported by the SIM."); 1268*a6e0c5daSWarner Losh SYSCTL_ADD_INT(&softc->sysctl_stats_ctx, 1269*a6e0c5daSWarner Losh SYSCTL_CHILDREN(softc->sysctl_stats_tree), 1270*a6e0c5daSWarner Losh OID_AUTO, "pack_invalidations", CTLFLAG_RD | CTLFLAG_MPSAFE, 1271*a6e0c5daSWarner Losh &softc->invalidations, 0, 1272*a6e0c5daSWarner Losh "Device pack invalidations."); 1273*a6e0c5daSWarner Losh #endif 1274*a6e0c5daSWarner Losh 1275*a6e0c5daSWarner Losh cam_iosched_sysctl_init(softc->cam_iosched, &softc->sysctl_ctx, 1276*a6e0c5daSWarner Losh softc->sysctl_tree); 1277*a6e0c5daSWarner Losh 127852c9ce25SScott Long cam_periph_release(periph); 127952c9ce25SScott Long } 128052c9ce25SScott Long 1281416494d7SJustin T. Gibbs static int 1282416494d7SJustin T. Gibbs adagetattr(struct bio *bp) 1283416494d7SJustin T. Gibbs { 12846884b662SAlexander Motin int ret; 1285416494d7SJustin T. Gibbs struct cam_periph *periph; 1286416494d7SJustin T. Gibbs 1287416494d7SJustin T. Gibbs periph = (struct cam_periph *)bp->bio_disk->d_drv1; 12886884b662SAlexander Motin cam_periph_lock(periph); 1289416494d7SJustin T. Gibbs ret = xpt_getattr(bp->bio_data, bp->bio_length, bp->bio_attribute, 1290416494d7SJustin T. Gibbs periph->path); 12916884b662SAlexander Motin cam_periph_unlock(periph); 1292416494d7SJustin T. Gibbs if (ret == 0) 1293416494d7SJustin T. Gibbs bp->bio_completed = bp->bio_length; 1294416494d7SJustin T. Gibbs return ret; 1295416494d7SJustin T. Gibbs } 1296416494d7SJustin T. Gibbs 1297*a6e0c5daSWarner Losh static int 1298*a6e0c5daSWarner Losh adadeletemethodsysctl(SYSCTL_HANDLER_ARGS) 1299*a6e0c5daSWarner Losh { 1300*a6e0c5daSWarner Losh char buf[16]; 1301*a6e0c5daSWarner Losh const char *p; 1302*a6e0c5daSWarner Losh struct ada_softc *softc; 1303*a6e0c5daSWarner Losh int i, error, value, methods; 1304*a6e0c5daSWarner Losh 1305*a6e0c5daSWarner Losh softc = (struct ada_softc *)arg1; 1306*a6e0c5daSWarner Losh 1307*a6e0c5daSWarner Losh value = softc->delete_method; 1308*a6e0c5daSWarner Losh if (value < 0 || value > ADA_DELETE_MAX) 1309*a6e0c5daSWarner Losh p = "UNKNOWN"; 1310*a6e0c5daSWarner Losh else 1311*a6e0c5daSWarner Losh p = ada_delete_method_names[value]; 1312*a6e0c5daSWarner Losh strncpy(buf, p, sizeof(buf)); 1313*a6e0c5daSWarner Losh error = sysctl_handle_string(oidp, buf, sizeof(buf), req); 1314*a6e0c5daSWarner Losh if (error != 0 || req->newptr == NULL) 1315*a6e0c5daSWarner Losh return (error); 1316*a6e0c5daSWarner Losh methods = 1 << ADA_DELETE_DISABLE; 1317*a6e0c5daSWarner Losh if ((softc->flags & ADA_FLAG_CAN_CFA) && 1318*a6e0c5daSWarner Losh !(softc->flags & ADA_FLAG_CAN_48BIT)) 1319*a6e0c5daSWarner Losh methods |= 1 << ADA_DELETE_CFA_ERASE; 1320*a6e0c5daSWarner Losh if (softc->flags & ADA_FLAG_CAN_TRIM) 1321*a6e0c5daSWarner Losh methods |= 1 << ADA_DELETE_DSM_TRIM; 1322*a6e0c5daSWarner Losh if (softc->flags & ADA_FLAG_CAN_NCQ_TRIM) 1323*a6e0c5daSWarner Losh methods |= 1 << ADA_DELETE_NCQ_DSM_TRIM; 1324*a6e0c5daSWarner Losh for (i = 0; i <= ADA_DELETE_MAX; i++) { 1325*a6e0c5daSWarner Losh if (!(methods & (1 << i)) || 1326*a6e0c5daSWarner Losh strcmp(buf, ada_delete_method_names[i]) != 0) 1327*a6e0c5daSWarner Losh continue; 1328*a6e0c5daSWarner Losh softc->delete_method = i; 1329*a6e0c5daSWarner Losh return (0); 1330*a6e0c5daSWarner Losh } 1331*a6e0c5daSWarner Losh return (EINVAL); 1332*a6e0c5daSWarner Losh } 1333*a6e0c5daSWarner Losh 133452c9ce25SScott Long static cam_status 133552c9ce25SScott Long adaregister(struct cam_periph *periph, void *arg) 133652c9ce25SScott Long { 133752c9ce25SScott Long struct ada_softc *softc; 133852c9ce25SScott Long struct ccb_pathinq cpi; 133952c9ce25SScott Long struct ccb_getdev *cgd; 13404a3760baSAlexander Motin char announce_buf[80]; 134152c9ce25SScott Long struct disk_params *dp; 134252c9ce25SScott Long caddr_t match; 134352c9ce25SScott Long u_int maxio; 13444a3760baSAlexander Motin int quirks; 134552c9ce25SScott Long 134652c9ce25SScott Long cgd = (struct ccb_getdev *)arg; 134752c9ce25SScott Long if (cgd == NULL) { 134852c9ce25SScott Long printf("adaregister: no getdev CCB, can't register device\n"); 134952c9ce25SScott Long return(CAM_REQ_CMP_ERR); 135052c9ce25SScott Long } 135152c9ce25SScott Long 135252c9ce25SScott Long softc = (struct ada_softc *)malloc(sizeof(*softc), M_DEVBUF, 135352c9ce25SScott Long M_NOWAIT|M_ZERO); 135452c9ce25SScott Long 135552c9ce25SScott Long if (softc == NULL) { 135652c9ce25SScott Long printf("adaregister: Unable to probe new device. " 135752c9ce25SScott Long "Unable to allocate softc\n"); 135852c9ce25SScott Long return(CAM_REQ_CMP_ERR); 135952c9ce25SScott Long } 136052c9ce25SScott Long 1361*a6e0c5daSWarner Losh if (cam_iosched_init(&softc->cam_iosched, periph) != 0) { 1362*a6e0c5daSWarner Losh printf("adaregister: Unable to probe new device. " 1363*a6e0c5daSWarner Losh "Unable to allocate iosched memory\n"); 1364*a6e0c5daSWarner Losh return(CAM_REQ_CMP_ERR); 1365*a6e0c5daSWarner Losh } 136652c9ce25SScott Long 1367581b2e78SAlexander Motin if ((cgd->ident_data.capabilities1 & ATA_SUPPORT_DMA) && 1368cf2b9a5fSAlexander Motin (cgd->inq_flags & SID_DMA)) 136946f118feSAlexander Motin softc->flags |= ADA_FLAG_CAN_DMA; 13702e1eb332SMarius Strobl if (cgd->ident_data.support.command2 & ATA_SUPPORT_ADDRESS48) { 137152c9ce25SScott Long softc->flags |= ADA_FLAG_CAN_48BIT; 13722e1eb332SMarius Strobl if (cgd->inq_flags & SID_DMA48) 13732e1eb332SMarius Strobl softc->flags |= ADA_FLAG_CAN_DMA48; 13742e1eb332SMarius Strobl } 137552c9ce25SScott Long if (cgd->ident_data.support.command2 & ATA_SUPPORT_FLUSHCACHE) 137652c9ce25SScott Long softc->flags |= ADA_FLAG_CAN_FLUSHCACHE; 1377fd104c15SRebecca Cran if (cgd->ident_data.support.command1 & ATA_SUPPORT_POWERMGT) 1378fd104c15SRebecca Cran softc->flags |= ADA_FLAG_CAN_POWERMGT; 1379581b2e78SAlexander Motin if ((cgd->ident_data.satacapabilities & ATA_SUPPORT_NCQ) && 1380cf2b9a5fSAlexander Motin (cgd->inq_flags & SID_DMA) && (cgd->inq_flags & SID_CmdQue)) 138152c9ce25SScott Long softc->flags |= ADA_FLAG_CAN_NCQ; 1382581b2e78SAlexander Motin if ((cgd->ident_data.support_dsm & ATA_SUPPORT_DSM_TRIM) && 1383581b2e78SAlexander Motin (cgd->inq_flags & SID_DMA)) { 13841c80ec0aSAlexander Motin softc->flags |= ADA_FLAG_CAN_TRIM; 13851c80ec0aSAlexander Motin softc->trim_max_ranges = TRIM_MAX_RANGES; 13861c80ec0aSAlexander Motin if (cgd->ident_data.max_dsm_blocks != 0) { 13871c80ec0aSAlexander Motin softc->trim_max_ranges = 1388c213c551SSteven Hartland min(cgd->ident_data.max_dsm_blocks * 1389c213c551SSteven Hartland ATA_DSM_BLK_RANGES, softc->trim_max_ranges); 13901c80ec0aSAlexander Motin } 13911c80ec0aSAlexander Motin } 13921c80ec0aSAlexander Motin if (cgd->ident_data.support.command2 & ATA_SUPPORT_CFA) 13931c80ec0aSAlexander Motin softc->flags |= ADA_FLAG_CAN_CFA; 139452c9ce25SScott Long 1395*a6e0c5daSWarner Losh adasetdeletemethod(softc); 1396*a6e0c5daSWarner Losh 139752c9ce25SScott Long periph->softc = softc; 139852c9ce25SScott Long 139952c9ce25SScott Long /* 140052c9ce25SScott Long * See if this device has any quirks. 140152c9ce25SScott Long */ 140230a4094fSAlexander Motin match = cam_quirkmatch((caddr_t)&cgd->ident_data, 140330a4094fSAlexander Motin (caddr_t)ada_quirk_table, 140430a4094fSAlexander Motin sizeof(ada_quirk_table)/sizeof(*ada_quirk_table), 140530a4094fSAlexander Motin sizeof(*ada_quirk_table), ata_identify_match); 140652c9ce25SScott Long if (match != NULL) 140752c9ce25SScott Long softc->quirks = ((struct ada_quirk_entry *)match)->quirks; 140852c9ce25SScott Long else 140952c9ce25SScott Long softc->quirks = ADA_Q_NONE; 141052c9ce25SScott Long 141152c9ce25SScott Long bzero(&cpi, sizeof(cpi)); 141283c5d981SAlexander Motin xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NONE); 141352c9ce25SScott Long cpi.ccb_h.func_code = XPT_PATH_INQ; 141452c9ce25SScott Long xpt_action((union ccb *)&cpi); 141552c9ce25SScott Long 141652c9ce25SScott Long TASK_INIT(&softc->sysctl_task, 0, adasysctlinit, periph); 141752c9ce25SScott Long 141852c9ce25SScott Long /* 141952c9ce25SScott Long * Register this media as a disk 142052c9ce25SScott Long */ 1421781338b6SAlexander Motin (void)cam_periph_hold(periph, PRIBIO); 1422edec59d9SAlexander Motin cam_periph_unlock(periph); 1423d3a460d3SAlexander Motin snprintf(announce_buf, sizeof(announce_buf), 1424d3a460d3SAlexander Motin "kern.cam.ada.%d.quirks", periph->unit_number); 1425d3a460d3SAlexander Motin quirks = softc->quirks; 1426d3a460d3SAlexander Motin TUNABLE_INT_FETCH(announce_buf, &quirks); 1427d3a460d3SAlexander Motin softc->quirks = quirks; 14281ed6aaf9SAlexander Motin softc->read_ahead = -1; 14291ed6aaf9SAlexander Motin snprintf(announce_buf, sizeof(announce_buf), 14301ed6aaf9SAlexander Motin "kern.cam.ada.%d.read_ahead", periph->unit_number); 14311ed6aaf9SAlexander Motin TUNABLE_INT_FETCH(announce_buf, &softc->read_ahead); 1432781338b6SAlexander Motin softc->write_cache = -1; 1433781338b6SAlexander Motin snprintf(announce_buf, sizeof(announce_buf), 1434781338b6SAlexander Motin "kern.cam.ada.%d.write_cache", periph->unit_number); 1435781338b6SAlexander Motin TUNABLE_INT_FETCH(announce_buf, &softc->write_cache); 143662cc3a63SSteven Hartland /* Disable queue sorting for non-rotational media by default. */ 1437*a6e0c5daSWarner Losh if (cgd->ident_data.media_rotation_rate == ATA_RATE_NON_ROTATING) { 1438*a6e0c5daSWarner Losh softc->rotating = 0; 1439*a6e0c5daSWarner Losh } else { 1440*a6e0c5daSWarner Losh softc->rotating = 1; 1441*a6e0c5daSWarner Losh } 1442*a6e0c5daSWarner Losh cam_iosched_set_sort_queue(softc->cam_iosched, softc->rotating ? -1 : 0); 1443c1bd46c2SAlexander Motin adagetparams(periph, cgd); 144452c9ce25SScott Long softc->disk = disk_alloc(); 1445c28078e9SSteven Hartland softc->disk->d_rotation_rate = cgd->ident_data.media_rotation_rate; 1446b8b6b5d3SAlexander Motin softc->disk->d_devstat = devstat_new_entry(periph->periph_name, 1447b8b6b5d3SAlexander Motin periph->unit_number, softc->params.secsize, 1448b8b6b5d3SAlexander Motin DEVSTAT_ALL_SUPPORTED, 1449b8b6b5d3SAlexander Motin DEVSTAT_TYPE_DIRECT | 1450b8b6b5d3SAlexander Motin XPORT_DEVSTAT_TYPE(cpi.transport), 1451b8b6b5d3SAlexander Motin DEVSTAT_PRIORITY_DISK); 145252c9ce25SScott Long softc->disk->d_open = adaopen; 145352c9ce25SScott Long softc->disk->d_close = adaclose; 145452c9ce25SScott Long softc->disk->d_strategy = adastrategy; 1455416494d7SJustin T. Gibbs softc->disk->d_getattr = adagetattr; 145652c9ce25SScott Long softc->disk->d_dump = adadump; 14570ba1e4d0SKenneth D. Merry softc->disk->d_gone = adadiskgonecb; 145852c9ce25SScott Long softc->disk->d_name = "ada"; 145952c9ce25SScott Long softc->disk->d_drv1 = periph; 146052c9ce25SScott Long maxio = cpi.maxio; /* Honor max I/O size of SIM */ 146152c9ce25SScott Long if (maxio == 0) 146252c9ce25SScott Long maxio = DFLTPHYS; /* traditional default */ 146352c9ce25SScott Long else if (maxio > MAXPHYS) 146452c9ce25SScott Long maxio = MAXPHYS; /* for safety */ 14651c80ec0aSAlexander Motin if (softc->flags & ADA_FLAG_CAN_48BIT) 1466c1bd46c2SAlexander Motin maxio = min(maxio, 65536 * softc->params.secsize); 146752c9ce25SScott Long else /* 28bit ATA command limit */ 1468c1bd46c2SAlexander Motin maxio = min(maxio, 256 * softc->params.secsize); 146952c9ce25SScott Long softc->disk->d_maxsize = maxio; 147052c9ce25SScott Long softc->disk->d_unit = periph->unit_number; 147140ea77a0SAlexander Motin softc->disk->d_flags = DISKFLAG_DIRECT_COMPLETION; 147252c9ce25SScott Long if (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) 147352c9ce25SScott Long softc->disk->d_flags |= DISKFLAG_CANFLUSHCACHE; 1474c213c551SSteven Hartland if (softc->flags & ADA_FLAG_CAN_TRIM) { 14751c80ec0aSAlexander Motin softc->disk->d_flags |= DISKFLAG_CANDELETE; 14769fe9ba5bSSteven Hartland softc->disk->d_delmaxsize = softc->params.secsize * 14779fe9ba5bSSteven Hartland ATA_DSM_RANGE_MAX * 14789fe9ba5bSSteven Hartland softc->trim_max_ranges; 1479c213c551SSteven Hartland } else if ((softc->flags & ADA_FLAG_CAN_CFA) && 1480c213c551SSteven Hartland !(softc->flags & ADA_FLAG_CAN_48BIT)) { 1481c213c551SSteven Hartland softc->disk->d_flags |= DISKFLAG_CANDELETE; 14829fe9ba5bSSteven Hartland softc->disk->d_delmaxsize = 256 * softc->params.secsize; 14839fe9ba5bSSteven Hartland } else 14849fe9ba5bSSteven Hartland softc->disk->d_delmaxsize = maxio; 1485*a6e0c5daSWarner Losh if ((cpi.hba_misc & PIM_UNMAPPED) != 0) { 1486abc1e60eSKonstantin Belousov softc->disk->d_flags |= DISKFLAG_UNMAPPED_BIO; 1487*a6e0c5daSWarner Losh softc->unmappedio = 1; 1488*a6e0c5daSWarner Losh } 1489*a6e0c5daSWarner Losh /* 1490*a6e0c5daSWarner Losh * If we can do RCVSND_FPDMA_QUEUED commands, we may be able to do 1491*a6e0c5daSWarner Losh * NCQ trims, if we support trims at all. We also need support from 1492*a6e0c5daSWarner Losh * the sim do do things properly. Perhaps we should look at log 13 1493*a6e0c5daSWarner Losh * dword 0 bit 0 and dword 1 bit 0 are set too... 1494*a6e0c5daSWarner Losh */ 1495*a6e0c5daSWarner Losh if (cpi.hba_misc & PIM_NCQ_KLUDGE) 1496*a6e0c5daSWarner Losh softc->flags |= ADA_FLAG_PIM_CAN_NCQ_TRIM; 1497*a6e0c5daSWarner Losh if ((softc->quirks & ADA_Q_NCQ_TRIM_BROKEN) == 0 && 1498*a6e0c5daSWarner Losh (softc->flags & ADA_FLAG_PIM_CAN_NCQ_TRIM) != 0 && 1499*a6e0c5daSWarner Losh (cgd->ident_data.satacapabilities2 & ATA_SUPPORT_RCVSND_FPDMA_QUEUED) != 0 && 1500*a6e0c5daSWarner Losh (softc->flags & ADA_FLAG_CAN_TRIM) != 0) 1501*a6e0c5daSWarner Losh softc->flags |= ADA_FLAG_CAN_NCQ_TRIM; 150265cb6238SNathan Whitehorn strlcpy(softc->disk->d_descr, cgd->ident_data.model, 150365cb6238SNathan Whitehorn MIN(sizeof(softc->disk->d_descr), sizeof(cgd->ident_data.model))); 1504d50aaa6dSAndriy Gapon strlcpy(softc->disk->d_ident, cgd->ident_data.serial, 1505d50aaa6dSAndriy Gapon MIN(sizeof(softc->disk->d_ident), sizeof(cgd->ident_data.serial))); 15068edcf694SAlexander Motin softc->disk->d_hba_vendor = cpi.hba_vendor; 15078edcf694SAlexander Motin softc->disk->d_hba_device = cpi.hba_device; 15088edcf694SAlexander Motin softc->disk->d_hba_subvendor = cpi.hba_subvendor; 15098edcf694SAlexander Motin softc->disk->d_hba_subdevice = cpi.hba_subdevice; 151052c9ce25SScott Long 151152c9ce25SScott Long softc->disk->d_sectorsize = softc->params.secsize; 1512c1bd46c2SAlexander Motin softc->disk->d_mediasize = (off_t)softc->params.sectors * 1513c1bd46c2SAlexander Motin softc->params.secsize; 1514ce8332d4SAlexander Motin if (ata_physical_sector_size(&cgd->ident_data) != 1515ce8332d4SAlexander Motin softc->params.secsize) { 1516ce8332d4SAlexander Motin softc->disk->d_stripesize = 1517ce8332d4SAlexander Motin ata_physical_sector_size(&cgd->ident_data); 1518ce8332d4SAlexander Motin softc->disk->d_stripeoffset = (softc->disk->d_stripesize - 1519ce8332d4SAlexander Motin ata_logical_sector_offset(&cgd->ident_data)) % 1520ce8332d4SAlexander Motin softc->disk->d_stripesize; 1521d3a460d3SAlexander Motin } else if (softc->quirks & ADA_Q_4K) { 1522d3a460d3SAlexander Motin softc->disk->d_stripesize = 4096; 1523d3a460d3SAlexander Motin softc->disk->d_stripeoffset = 0; 1524ce8332d4SAlexander Motin } 152552c9ce25SScott Long softc->disk->d_fwsectors = softc->params.secs_per_track; 152652c9ce25SScott Long softc->disk->d_fwheads = softc->params.heads; 15274461491bSMarius Strobl ata_disk_firmware_geom_adjust(softc->disk); 1528*a6e0c5daSWarner Losh adasetdeletemethod(softc); 152952c9ce25SScott Long 15300ba1e4d0SKenneth D. Merry /* 15310ba1e4d0SKenneth D. Merry * Acquire a reference to the periph before we register with GEOM. 15320ba1e4d0SKenneth D. Merry * We'll release this reference once GEOM calls us back (via 15330ba1e4d0SKenneth D. Merry * adadiskgonecb()) telling us that our provider has been freed. 15340ba1e4d0SKenneth D. Merry */ 15350ba1e4d0SKenneth D. Merry if (cam_periph_acquire(periph) != CAM_REQ_CMP) { 15360ba1e4d0SKenneth D. Merry xpt_print(periph->path, "%s: lost periph during " 15370ba1e4d0SKenneth D. Merry "registration!\n", __func__); 15380ba1e4d0SKenneth D. Merry cam_periph_lock(periph); 15390ba1e4d0SKenneth D. Merry return (CAM_REQ_CMP_ERR); 15400ba1e4d0SKenneth D. Merry } 154152c9ce25SScott Long disk_create(softc->disk, DISK_VERSION); 1542edec59d9SAlexander Motin cam_periph_lock(periph); 1543781338b6SAlexander Motin cam_periph_unhold(periph); 154452c9ce25SScott Long 154552c9ce25SScott Long dp = &softc->params; 154652c9ce25SScott Long snprintf(announce_buf, sizeof(announce_buf), 154768546995SAlexander Motin "%juMB (%ju %u byte sectors)", 154868546995SAlexander Motin ((uintmax_t)dp->secsize * dp->sectors) / (1024 * 1024), 154968546995SAlexander Motin (uintmax_t)dp->sectors, dp->secsize); 155052c9ce25SScott Long xpt_announce_periph(periph, announce_buf); 15516fb5c84eSSteven Hartland xpt_announce_quirks(periph, softc->quirks, ADA_Q_BIT_STRING); 1552e3a6d3a4SAlexander Motin 1553e3a6d3a4SAlexander Motin /* 1554e3a6d3a4SAlexander Motin * Create our sysctl variables, now that we know 1555e3a6d3a4SAlexander Motin * we have successfully attached. 1556e3a6d3a4SAlexander Motin */ 1557227d67aaSAlexander Motin if (cam_periph_acquire(periph) == CAM_REQ_CMP) 1558e3a6d3a4SAlexander Motin taskqueue_enqueue(taskqueue_thread, &softc->sysctl_task); 1559e3a6d3a4SAlexander Motin 156052c9ce25SScott Long /* 156152c9ce25SScott Long * Add async callbacks for bus reset and 156252c9ce25SScott Long * bus device reset calls. I don't bother 156352c9ce25SScott Long * checking if this fails as, in most cases, 156452c9ce25SScott Long * the system will function just fine without 156552c9ce25SScott Long * them and the only alternative would be to 156652c9ce25SScott Long * not attach the device on failure. 156752c9ce25SScott Long */ 15683089bb2eSAlexander Motin xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE | 1569581b2e78SAlexander Motin AC_GETDEV_CHANGED | AC_ADVINFO_CHANGED, 1570581b2e78SAlexander Motin adaasync, periph, periph->path); 157152c9ce25SScott Long 157252c9ce25SScott Long /* 157352c9ce25SScott Long * Schedule a periodic event to occasionally send an 157452c9ce25SScott Long * ordered tag to a device. 157552c9ce25SScott Long */ 1576227d67aaSAlexander Motin callout_init_mtx(&softc->sendordered_c, cam_periph_mtx(periph), 0); 157752c9ce25SScott Long callout_reset(&softc->sendordered_c, 157847bb9643SAlexander Motin (ada_default_timeout * hz) / ADA_ORDEREDTAG_INTERVAL, 157952c9ce25SScott Long adasendorderedtag, softc); 158052c9ce25SScott Long 15811ed6aaf9SAlexander Motin if (ADA_RA >= 0 && 15821ed6aaf9SAlexander Motin cgd->ident_data.support.command1 & ATA_SUPPORT_LOOKAHEAD) { 15831ed6aaf9SAlexander Motin softc->state = ADA_STATE_RAHEAD; 15841ed6aaf9SAlexander Motin } else if (ADA_WC >= 0 && 1585f513d14cSAlexander Motin cgd->ident_data.support.command1 & ATA_SUPPORT_WRITECACHE) { 1586f513d14cSAlexander Motin softc->state = ADA_STATE_WCACHE; 1587227d67aaSAlexander Motin } else { 1588f513d14cSAlexander Motin softc->state = ADA_STATE_NORMAL; 1589227d67aaSAlexander Motin return(CAM_REQ_CMP); 1590227d67aaSAlexander Motin } 1591227d67aaSAlexander Motin if (cam_periph_acquire(periph) != CAM_REQ_CMP) 1592227d67aaSAlexander Motin softc->state = ADA_STATE_NORMAL; 1593227d67aaSAlexander Motin else 1594227d67aaSAlexander Motin xpt_schedule(periph, CAM_PRIORITY_DEV); 159552c9ce25SScott Long return(CAM_REQ_CMP); 159652c9ce25SScott Long } 159752c9ce25SScott Long 1598*a6e0c5daSWarner Losh static int 1599*a6e0c5daSWarner Losh ada_dsmtrim_req_create(struct ada_softc *softc, struct bio *bp, struct trim_request *req) 160052c9ce25SScott Long { 160137ddbd16SAlexander Motin uint64_t lastlba = (uint64_t)-1; 16022030b294SAlexander Motin int c, lastcount = 0, off, ranges = 0; 160352c9ce25SScott Long 16041c80ec0aSAlexander Motin bzero(req, sizeof(*req)); 16052030b294SAlexander Motin TAILQ_INIT(&req->bps); 16061c80ec0aSAlexander Motin do { 16077ddad071SWarner Losh uint64_t lba = bp->bio_pblkno; 16087ddad071SWarner Losh int count = bp->bio_bcount / softc->params.secsize; 16091c80ec0aSAlexander Motin 161037ddbd16SAlexander Motin /* Try to extend the previous range. */ 161137ddbd16SAlexander Motin if (lba == lastlba) { 1612c213c551SSteven Hartland c = min(count, ATA_DSM_RANGE_MAX - lastcount); 161337ddbd16SAlexander Motin lastcount += c; 1614c213c551SSteven Hartland off = (ranges - 1) * ATA_DSM_RANGE_SIZE; 161537ddbd16SAlexander Motin req->data[off + 6] = lastcount & 0xff; 161637ddbd16SAlexander Motin req->data[off + 7] = 161737ddbd16SAlexander Motin (lastcount >> 8) & 0xff; 161837ddbd16SAlexander Motin count -= c; 161937ddbd16SAlexander Motin lba += c; 162037ddbd16SAlexander Motin } 162137ddbd16SAlexander Motin 162237ddbd16SAlexander Motin while (count > 0) { 1623c213c551SSteven Hartland c = min(count, ATA_DSM_RANGE_MAX); 1624c213c551SSteven Hartland off = ranges * ATA_DSM_RANGE_SIZE; 16251c80ec0aSAlexander Motin req->data[off + 0] = lba & 0xff; 16261c80ec0aSAlexander Motin req->data[off + 1] = (lba >> 8) & 0xff; 16271c80ec0aSAlexander Motin req->data[off + 2] = (lba >> 16) & 0xff; 16281c80ec0aSAlexander Motin req->data[off + 3] = (lba >> 24) & 0xff; 16291c80ec0aSAlexander Motin req->data[off + 4] = (lba >> 32) & 0xff; 16301c80ec0aSAlexander Motin req->data[off + 5] = (lba >> 40) & 0xff; 16311c80ec0aSAlexander Motin req->data[off + 6] = c & 0xff; 16321c80ec0aSAlexander Motin req->data[off + 7] = (c >> 8) & 0xff; 16331c80ec0aSAlexander Motin lba += c; 16341c80ec0aSAlexander Motin count -= c; 163537ddbd16SAlexander Motin lastcount = c; 16361c80ec0aSAlexander Motin ranges++; 1637c213c551SSteven Hartland /* 1638c213c551SSteven Hartland * Its the caller's responsibility to ensure the 1639c213c551SSteven Hartland * request will fit so we don't need to check for 1640c213c551SSteven Hartland * overrun here 1641c213c551SSteven Hartland */ 16421c80ec0aSAlexander Motin } 164337ddbd16SAlexander Motin lastlba = lba; 16447ddad071SWarner Losh TAILQ_INSERT_TAIL(&req->bps, bp, bio_queue); 1645*a6e0c5daSWarner Losh 1646*a6e0c5daSWarner Losh bp = cam_iosched_next_trim(softc->cam_iosched); 1647*a6e0c5daSWarner Losh if (bp == NULL) 16481c80ec0aSAlexander Motin break; 1649*a6e0c5daSWarner Losh if (bp->bio_bcount / softc->params.secsize > 1650*a6e0c5daSWarner Losh (softc->trim_max_ranges - ranges) * ATA_DSM_RANGE_MAX) { 1651*a6e0c5daSWarner Losh cam_iosched_put_back_trim(softc->cam_iosched, bp); 1652*a6e0c5daSWarner Losh break; 1653*a6e0c5daSWarner Losh } 16541c80ec0aSAlexander Motin } while (1); 1655*a6e0c5daSWarner Losh 1656*a6e0c5daSWarner Losh return (ranges); 1657*a6e0c5daSWarner Losh } 1658*a6e0c5daSWarner Losh 1659*a6e0c5daSWarner Losh static void 1660*a6e0c5daSWarner Losh ada_dsmtrim(struct ada_softc *softc, struct bio *bp, struct ccb_ataio *ataio) 1661*a6e0c5daSWarner Losh { 1662*a6e0c5daSWarner Losh struct trim_request *req = &softc->trim_req; 1663*a6e0c5daSWarner Losh int ranges; 1664*a6e0c5daSWarner Losh 1665*a6e0c5daSWarner Losh ranges = ada_dsmtrim_req_create(softc, bp, req); 16661c80ec0aSAlexander Motin cam_fill_ataio(ataio, 16671c80ec0aSAlexander Motin ada_retry_count, 16681c80ec0aSAlexander Motin adadone, 16691c80ec0aSAlexander Motin CAM_DIR_OUT, 16701c80ec0aSAlexander Motin 0, 16711c80ec0aSAlexander Motin req->data, 1672c213c551SSteven Hartland ((ranges + ATA_DSM_BLK_RANGES - 1) / 1673c213c551SSteven Hartland ATA_DSM_BLK_RANGES) * ATA_DSM_BLK_SIZE, 16741c80ec0aSAlexander Motin ada_default_timeout * 1000); 16751c80ec0aSAlexander Motin ata_48bit_cmd(ataio, ATA_DATA_SET_MANAGEMENT, 1676c213c551SSteven Hartland ATA_DSM_TRIM, 0, (ranges + ATA_DSM_BLK_RANGES - 1677c213c551SSteven Hartland 1) / ATA_DSM_BLK_RANGES); 16787ddad071SWarner Losh } 16797ddad071SWarner Losh 16807ddad071SWarner Losh static void 1681*a6e0c5daSWarner Losh ada_ncq_dsmtrim(struct ada_softc *softc, struct bio *bp, struct ccb_ataio *ataio) 1682*a6e0c5daSWarner Losh { 1683*a6e0c5daSWarner Losh struct trim_request *req = &softc->trim_req; 1684*a6e0c5daSWarner Losh int ranges; 1685*a6e0c5daSWarner Losh 1686*a6e0c5daSWarner Losh ranges = ada_dsmtrim_req_create(softc, bp, req); 1687*a6e0c5daSWarner Losh cam_fill_ataio(ataio, 1688*a6e0c5daSWarner Losh ada_retry_count, 1689*a6e0c5daSWarner Losh adadone, 1690*a6e0c5daSWarner Losh CAM_DIR_OUT, 1691*a6e0c5daSWarner Losh 0, 1692*a6e0c5daSWarner Losh req->data, 1693*a6e0c5daSWarner Losh ((ranges + ATA_DSM_BLK_RANGES - 1) / 1694*a6e0c5daSWarner Losh ATA_DSM_BLK_RANGES) * ATA_DSM_BLK_SIZE, 1695*a6e0c5daSWarner Losh ada_default_timeout * 1000); 1696*a6e0c5daSWarner Losh ata_ncq_cmd(ataio, 1697*a6e0c5daSWarner Losh ATA_SEND_FPDMA_QUEUED, 1698*a6e0c5daSWarner Losh 0, 1699*a6e0c5daSWarner Losh (ranges + ATA_DSM_BLK_RANGES - 1) / ATA_DSM_BLK_RANGES); 1700*a6e0c5daSWarner Losh ataio->cmd.sector_count_exp = ATA_SFPDMA_DSM; 1701*a6e0c5daSWarner Losh ataio->cmd.flags |= CAM_ATAIO_AUX_HACK; 1702*a6e0c5daSWarner Losh } 1703*a6e0c5daSWarner Losh 1704*a6e0c5daSWarner Losh static void 17057ddad071SWarner Losh ada_cfaerase(struct ada_softc *softc, struct bio *bp, struct ccb_ataio *ataio) 17067ddad071SWarner Losh { 1707467298f5SSteven Hartland struct trim_request *req = &softc->trim_req; 17087ddad071SWarner Losh uint64_t lba = bp->bio_pblkno; 17097ddad071SWarner Losh uint16_t count = bp->bio_bcount / softc->params.secsize; 17107ddad071SWarner Losh 1711467298f5SSteven Hartland bzero(req, sizeof(*req)); 1712467298f5SSteven Hartland TAILQ_INIT(&req->bps); 1713467298f5SSteven Hartland TAILQ_INSERT_TAIL(&req->bps, bp, bio_queue); 1714467298f5SSteven Hartland 17157ddad071SWarner Losh cam_fill_ataio(ataio, 17167ddad071SWarner Losh ada_retry_count, 17177ddad071SWarner Losh adadone, 17187ddad071SWarner Losh CAM_DIR_NONE, 17197ddad071SWarner Losh 0, 17207ddad071SWarner Losh NULL, 17217ddad071SWarner Losh 0, 17227ddad071SWarner Losh ada_default_timeout*1000); 17237ddad071SWarner Losh 17247ddad071SWarner Losh if (count >= 256) 17257ddad071SWarner Losh count = 0; 17267ddad071SWarner Losh ata_28bit_cmd(ataio, ATA_CFA_ERASE, 0, lba, count); 17277ddad071SWarner Losh } 17287ddad071SWarner Losh 17297ddad071SWarner Losh static void 17307ddad071SWarner Losh adastart(struct cam_periph *periph, union ccb *start_ccb) 17317ddad071SWarner Losh { 17327ddad071SWarner Losh struct ada_softc *softc = (struct ada_softc *)periph->softc; 17337ddad071SWarner Losh struct ccb_ataio *ataio = &start_ccb->ataio; 17347ddad071SWarner Losh 17357ddad071SWarner Losh CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("adastart\n")); 17367ddad071SWarner Losh 17377ddad071SWarner Losh switch (softc->state) { 17387ddad071SWarner Losh case ADA_STATE_NORMAL: 17397ddad071SWarner Losh { 17407ddad071SWarner Losh struct bio *bp; 17417ddad071SWarner Losh u_int8_t tag_code; 17427ddad071SWarner Losh 1743*a6e0c5daSWarner Losh bp = cam_iosched_next_bio(softc->cam_iosched); 17441c80ec0aSAlexander Motin if (bp == NULL) { 17451c80ec0aSAlexander Motin xpt_release_ccb(start_ccb); 17461c80ec0aSAlexander Motin break; 17471c80ec0aSAlexander Motin } 174852c9ce25SScott Long 1749*a6e0c5daSWarner Losh if ((bp->bio_flags & BIO_ORDERED) != 0 || 1750*a6e0c5daSWarner Losh (bp->bio_cmd != BIO_DELETE && (softc->flags & ADA_FLAG_NEED_OTAG) != 0)) { 175152c9ce25SScott Long softc->flags &= ~ADA_FLAG_NEED_OTAG; 1752030844d1SAlexander Motin softc->flags |= ADA_FLAG_WAS_OTAG; 175346f118feSAlexander Motin tag_code = 0; 175452c9ce25SScott Long } else { 175546f118feSAlexander Motin tag_code = 1; 175652c9ce25SScott Long } 175752c9ce25SScott Long switch (bp->bio_cmd) { 175852c9ce25SScott Long case BIO_WRITE: 175969114bc0SAlexander Motin case BIO_READ: 176052c9ce25SScott Long { 176152c9ce25SScott Long uint64_t lba = bp->bio_pblkno; 176252c9ce25SScott Long uint16_t count = bp->bio_bcount / softc->params.secsize; 1763a9934668SKenneth D. Merry void *data_ptr; 1764a9934668SKenneth D. Merry int rw_op; 1765a9934668SKenneth D. Merry 1766a9934668SKenneth D. Merry if (bp->bio_cmd == BIO_WRITE) { 1767a9934668SKenneth D. Merry softc->flags |= ADA_FLAG_DIRTY; 1768a9934668SKenneth D. Merry rw_op = CAM_DIR_OUT; 1769a9934668SKenneth D. Merry } else { 1770a9934668SKenneth D. Merry rw_op = CAM_DIR_IN; 1771a9934668SKenneth D. Merry } 1772a9934668SKenneth D. Merry 1773a9934668SKenneth D. Merry data_ptr = bp->bio_data; 1774a9934668SKenneth D. Merry if ((bp->bio_flags & (BIO_UNMAPPED|BIO_VLIST)) != 0) { 1775a9934668SKenneth D. Merry rw_op |= CAM_DATA_BIO; 1776a9934668SKenneth D. Merry data_ptr = bp; 1777a9934668SKenneth D. Merry } 1778a9934668SKenneth D. Merry 1779e3a6d3a4SAlexander Motin #ifdef ADA_TEST_FAILURE 1780e3a6d3a4SAlexander Motin int fail = 0; 178152c9ce25SScott Long 1782e3a6d3a4SAlexander Motin /* 1783e3a6d3a4SAlexander Motin * Support the failure ioctls. If the command is a 1784e3a6d3a4SAlexander Motin * read, and there are pending forced read errors, or 1785e3a6d3a4SAlexander Motin * if a write and pending write errors, then fail this 1786e3a6d3a4SAlexander Motin * operation with EIO. This is useful for testing 1787e3a6d3a4SAlexander Motin * purposes. Also, support having every Nth read fail. 1788e3a6d3a4SAlexander Motin * 1789e3a6d3a4SAlexander Motin * This is a rather blunt tool. 1790e3a6d3a4SAlexander Motin */ 1791e3a6d3a4SAlexander Motin if (bp->bio_cmd == BIO_READ) { 1792e3a6d3a4SAlexander Motin if (softc->force_read_error) { 1793e3a6d3a4SAlexander Motin softc->force_read_error--; 1794e3a6d3a4SAlexander Motin fail = 1; 1795e3a6d3a4SAlexander Motin } 1796e3a6d3a4SAlexander Motin if (softc->periodic_read_error > 0) { 1797e3a6d3a4SAlexander Motin if (++softc->periodic_read_count >= 1798e3a6d3a4SAlexander Motin softc->periodic_read_error) { 1799e3a6d3a4SAlexander Motin softc->periodic_read_count = 0; 1800e3a6d3a4SAlexander Motin fail = 1; 1801e3a6d3a4SAlexander Motin } 1802e3a6d3a4SAlexander Motin } 1803e3a6d3a4SAlexander Motin } else { 1804e3a6d3a4SAlexander Motin if (softc->force_write_error) { 1805e3a6d3a4SAlexander Motin softc->force_write_error--; 1806e3a6d3a4SAlexander Motin fail = 1; 1807e3a6d3a4SAlexander Motin } 1808e3a6d3a4SAlexander Motin } 1809e3a6d3a4SAlexander Motin if (fail) { 18104beec135SAlexander Motin biofinish(bp, NULL, EIO); 1811e3a6d3a4SAlexander Motin xpt_release_ccb(start_ccb); 1812e3a6d3a4SAlexander Motin adaschedule(periph); 1813e3a6d3a4SAlexander Motin return; 1814e3a6d3a4SAlexander Motin } 1815e3a6d3a4SAlexander Motin #endif 1816abc1e60eSKonstantin Belousov KASSERT((bp->bio_flags & BIO_UNMAPPED) == 0 || 1817abc1e60eSKonstantin Belousov round_page(bp->bio_bcount + bp->bio_ma_offset) / 1818abc1e60eSKonstantin Belousov PAGE_SIZE == bp->bio_ma_n, 1819abc1e60eSKonstantin Belousov ("Short bio %p", bp)); 182052c9ce25SScott Long cam_fill_ataio(ataio, 182152c9ce25SScott Long ada_retry_count, 182252c9ce25SScott Long adadone, 1823a9934668SKenneth D. Merry rw_op, 182452c9ce25SScott Long tag_code, 1825a9934668SKenneth D. Merry data_ptr, 182652c9ce25SScott Long bp->bio_bcount, 182752c9ce25SScott Long ada_default_timeout*1000); 182852c9ce25SScott Long 182946f118feSAlexander Motin if ((softc->flags & ADA_FLAG_CAN_NCQ) && tag_code) { 183052c9ce25SScott Long if (bp->bio_cmd == BIO_READ) { 183152c9ce25SScott Long ata_ncq_cmd(ataio, ATA_READ_FPDMA_QUEUED, 183252c9ce25SScott Long lba, count); 183352c9ce25SScott Long } else { 183452c9ce25SScott Long ata_ncq_cmd(ataio, ATA_WRITE_FPDMA_QUEUED, 183552c9ce25SScott Long lba, count); 183652c9ce25SScott Long } 183752c9ce25SScott Long } else if ((softc->flags & ADA_FLAG_CAN_48BIT) && 183852c9ce25SScott Long (lba + count >= ATA_MAX_28BIT_LBA || 183946f118feSAlexander Motin count > 256)) { 18402e1eb332SMarius Strobl if (softc->flags & ADA_FLAG_CAN_DMA48) { 184152c9ce25SScott Long if (bp->bio_cmd == BIO_READ) { 184252c9ce25SScott Long ata_48bit_cmd(ataio, ATA_READ_DMA48, 184352c9ce25SScott Long 0, lba, count); 184452c9ce25SScott Long } else { 184552c9ce25SScott Long ata_48bit_cmd(ataio, ATA_WRITE_DMA48, 184652c9ce25SScott Long 0, lba, count); 184752c9ce25SScott Long } 184852c9ce25SScott Long } else { 184952c9ce25SScott Long if (bp->bio_cmd == BIO_READ) { 185046f118feSAlexander Motin ata_48bit_cmd(ataio, ATA_READ_MUL48, 185146f118feSAlexander Motin 0, lba, count); 185246f118feSAlexander Motin } else { 185346f118feSAlexander Motin ata_48bit_cmd(ataio, ATA_WRITE_MUL48, 185446f118feSAlexander Motin 0, lba, count); 185546f118feSAlexander Motin } 185646f118feSAlexander Motin } 185746f118feSAlexander Motin } else { 185846f118feSAlexander Motin if (count == 256) 185946f118feSAlexander Motin count = 0; 186046f118feSAlexander Motin if (softc->flags & ADA_FLAG_CAN_DMA) { 186146f118feSAlexander Motin if (bp->bio_cmd == BIO_READ) { 18627606b445SAlexander Motin ata_28bit_cmd(ataio, ATA_READ_DMA, 186352c9ce25SScott Long 0, lba, count); 186452c9ce25SScott Long } else { 18657606b445SAlexander Motin ata_28bit_cmd(ataio, ATA_WRITE_DMA, 186652c9ce25SScott Long 0, lba, count); 186752c9ce25SScott Long } 186846f118feSAlexander Motin } else { 186946f118feSAlexander Motin if (bp->bio_cmd == BIO_READ) { 187046f118feSAlexander Motin ata_28bit_cmd(ataio, ATA_READ_MUL, 187146f118feSAlexander Motin 0, lba, count); 187246f118feSAlexander Motin } else { 187346f118feSAlexander Motin ata_28bit_cmd(ataio, ATA_WRITE_MUL, 187446f118feSAlexander Motin 0, lba, count); 187546f118feSAlexander Motin } 187646f118feSAlexander Motin } 187752c9ce25SScott Long } 187852c9ce25SScott Long break; 18791c80ec0aSAlexander Motin } 1880*a6e0c5daSWarner Losh case BIO_DELETE: 1881*a6e0c5daSWarner Losh switch (softc->delete_method) { 1882*a6e0c5daSWarner Losh case ADA_DELETE_NCQ_DSM_TRIM: 1883*a6e0c5daSWarner Losh ada_ncq_dsmtrim(softc, bp, ataio); 1884*a6e0c5daSWarner Losh break; 1885*a6e0c5daSWarner Losh case ADA_DELETE_DSM_TRIM: 1886*a6e0c5daSWarner Losh ada_dsmtrim(softc, bp, ataio); 1887*a6e0c5daSWarner Losh break; 1888*a6e0c5daSWarner Losh case ADA_DELETE_CFA_ERASE: 1889*a6e0c5daSWarner Losh ada_cfaerase(softc, bp, ataio); 1890*a6e0c5daSWarner Losh break; 1891*a6e0c5daSWarner Losh default: 1892*a6e0c5daSWarner Losh biofinish(bp, NULL, EOPNOTSUPP); 1893*a6e0c5daSWarner Losh xpt_release_ccb(start_ccb); 1894*a6e0c5daSWarner Losh adaschedule(periph); 1895*a6e0c5daSWarner Losh return; 1896*a6e0c5daSWarner Losh } 1897*a6e0c5daSWarner Losh start_ccb->ccb_h.ccb_state = ADA_CCB_TRIM; 1898*a6e0c5daSWarner Losh start_ccb->ccb_h.flags |= CAM_UNLOCKED; 1899*a6e0c5daSWarner Losh cam_iosched_submit_trim(softc->cam_iosched); 1900*a6e0c5daSWarner Losh goto out; 190152c9ce25SScott Long case BIO_FLUSH: 190252c9ce25SScott Long cam_fill_ataio(ataio, 190352c9ce25SScott Long 1, 190452c9ce25SScott Long adadone, 190552c9ce25SScott Long CAM_DIR_NONE, 190646f118feSAlexander Motin 0, 190752c9ce25SScott Long NULL, 190852c9ce25SScott Long 0, 190952c9ce25SScott Long ada_default_timeout*1000); 191052c9ce25SScott Long 191152c9ce25SScott Long if (softc->flags & ADA_FLAG_CAN_48BIT) 191252c9ce25SScott Long ata_48bit_cmd(ataio, ATA_FLUSHCACHE48, 0, 0, 0); 191352c9ce25SScott Long else 19147606b445SAlexander Motin ata_28bit_cmd(ataio, ATA_FLUSHCACHE, 0, 0, 0); 191552c9ce25SScott Long break; 191652c9ce25SScott Long } 191752c9ce25SScott Long start_ccb->ccb_h.ccb_state = ADA_CCB_BUFFER_IO; 1918227d67aaSAlexander Motin start_ccb->ccb_h.flags |= CAM_UNLOCKED; 19191c80ec0aSAlexander Motin out: 192052c9ce25SScott Long start_ccb->ccb_h.ccb_bp = bp; 1921c1bd46c2SAlexander Motin softc->outstanding_cmds++; 1922227d67aaSAlexander Motin softc->refcount++; 1923227d67aaSAlexander Motin cam_periph_unlock(periph); 192452c9ce25SScott Long xpt_action(start_ccb); 1925227d67aaSAlexander Motin cam_periph_lock(periph); 1926227d67aaSAlexander Motin softc->refcount--; 192752c9ce25SScott Long 19281c80ec0aSAlexander Motin /* May have more work to do, so ensure we stay scheduled */ 19291c80ec0aSAlexander Motin adaschedule(periph); 193052c9ce25SScott Long break; 193152c9ce25SScott Long } 19321ed6aaf9SAlexander Motin case ADA_STATE_RAHEAD: 1933f513d14cSAlexander Motin case ADA_STATE_WCACHE: 1934f513d14cSAlexander Motin { 1935f513d14cSAlexander Motin cam_fill_ataio(ataio, 1936f513d14cSAlexander Motin 1, 1937f513d14cSAlexander Motin adadone, 1938f513d14cSAlexander Motin CAM_DIR_NONE, 1939f513d14cSAlexander Motin 0, 1940f513d14cSAlexander Motin NULL, 1941f513d14cSAlexander Motin 0, 1942f513d14cSAlexander Motin ada_default_timeout*1000); 1943f513d14cSAlexander Motin 19441ed6aaf9SAlexander Motin if (softc->state == ADA_STATE_RAHEAD) { 19451ed6aaf9SAlexander Motin ata_28bit_cmd(ataio, ATA_SETFEATURES, ADA_RA ? 19461ed6aaf9SAlexander Motin ATA_SF_ENAB_RCACHE : ATA_SF_DIS_RCACHE, 0, 0); 19471ed6aaf9SAlexander Motin start_ccb->ccb_h.ccb_state = ADA_CCB_RAHEAD; 19481ed6aaf9SAlexander Motin } else { 19491ed6aaf9SAlexander Motin ata_28bit_cmd(ataio, ATA_SETFEATURES, ADA_WC ? 1950f513d14cSAlexander Motin ATA_SF_ENAB_WCACHE : ATA_SF_DIS_WCACHE, 0, 0); 1951f513d14cSAlexander Motin start_ccb->ccb_h.ccb_state = ADA_CCB_WCACHE; 19521ed6aaf9SAlexander Motin } 1953cccf4220SAlexander Motin start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE; 1954f513d14cSAlexander Motin xpt_action(start_ccb); 1955f513d14cSAlexander Motin break; 1956f513d14cSAlexander Motin } 195752c9ce25SScott Long } 195852c9ce25SScott Long } 195952c9ce25SScott Long 196052c9ce25SScott Long static void 196152c9ce25SScott Long adadone(struct cam_periph *periph, union ccb *done_ccb) 196252c9ce25SScott Long { 196352c9ce25SScott Long struct ada_softc *softc; 196452c9ce25SScott Long struct ccb_ataio *ataio; 19651ed6aaf9SAlexander Motin struct ccb_getdev *cgd; 1966cccf4220SAlexander Motin struct cam_path *path; 19677651b989SAlexander Motin int state; 196852c9ce25SScott Long 196952c9ce25SScott Long softc = (struct ada_softc *)periph->softc; 197052c9ce25SScott Long ataio = &done_ccb->ataio; 1971cccf4220SAlexander Motin path = done_ccb->ccb_h.path; 1972fddde2b8SAlexander Motin 1973cccf4220SAlexander Motin CAM_DEBUG(path, CAM_DEBUG_TRACE, ("adadone\n")); 1974fddde2b8SAlexander Motin 19757651b989SAlexander Motin state = ataio->ccb_h.ccb_state & ADA_CCB_TYPE_MASK; 19767651b989SAlexander Motin switch (state) { 197752c9ce25SScott Long case ADA_CCB_BUFFER_IO: 19781c80ec0aSAlexander Motin case ADA_CCB_TRIM: 197952c9ce25SScott Long { 198052c9ce25SScott Long struct bio *bp; 198152c9ce25SScott Long int error; 198252c9ce25SScott Long 1983227d67aaSAlexander Motin cam_periph_lock(periph); 1984*a6e0c5daSWarner Losh bp = (struct bio *)done_ccb->ccb_h.ccb_bp; 19857651b989SAlexander Motin if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 198646f118feSAlexander Motin error = adaerror(done_ccb, 0, 0); 198752c9ce25SScott Long if (error == ERESTART) { 198846f118feSAlexander Motin /* A retry was scheduled, so just return. */ 1989227d67aaSAlexander Motin cam_periph_unlock(periph); 199052c9ce25SScott Long return; 199152c9ce25SScott Long } 199252c9ce25SScott Long if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 1993cccf4220SAlexander Motin cam_release_devq(path, 199452c9ce25SScott Long /*relsim_flags*/0, 199552c9ce25SScott Long /*reduction*/0, 199652c9ce25SScott Long /*timeout*/0, 199752c9ce25SScott Long /*getcount_only*/0); 1998*a6e0c5daSWarner Losh /* 1999*a6e0c5daSWarner Losh * If we get an error on an NCQ DSM TRIM, fall back 2000*a6e0c5daSWarner Losh * to a non-NCQ DSM TRIM forever. Please note that if 2001*a6e0c5daSWarner Losh * CAN_NCQ_TRIM is set, CAN_TRIM is necessarily set too. 2002*a6e0c5daSWarner Losh * However, for this one trim, we treat it as advisory 2003*a6e0c5daSWarner Losh * and return success up the stack. 2004*a6e0c5daSWarner Losh */ 2005*a6e0c5daSWarner Losh if (state == ADA_CCB_TRIM && 2006*a6e0c5daSWarner Losh error != 0 && 2007*a6e0c5daSWarner Losh (softc->flags & ADA_FLAG_CAN_NCQ_TRIM) != 0) { 2008*a6e0c5daSWarner Losh softc->flags &= ~ADA_FLAG_CAN_NCQ_TRIM; 2009*a6e0c5daSWarner Losh error = 0; 2010*a6e0c5daSWarner Losh adasetdeletemethod(softc); 2011*a6e0c5daSWarner Losh } 201252c9ce25SScott Long } else { 201352c9ce25SScott Long if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 201452c9ce25SScott Long panic("REQ_CMP with QFRZN"); 20157651b989SAlexander Motin error = 0; 20167651b989SAlexander Motin } 20177651b989SAlexander Motin bp->bio_error = error; 20187651b989SAlexander Motin if (error != 0) { 20197651b989SAlexander Motin bp->bio_resid = bp->bio_bcount; 20207651b989SAlexander Motin bp->bio_flags |= BIO_ERROR; 20217651b989SAlexander Motin } else { 20227651b989SAlexander Motin if (state == ADA_CCB_TRIM) 20237651b989SAlexander Motin bp->bio_resid = 0; 20247651b989SAlexander Motin else 202552c9ce25SScott Long bp->bio_resid = ataio->resid; 20267651b989SAlexander Motin if (bp->bio_resid > 0) 202752c9ce25SScott Long bp->bio_flags |= BIO_ERROR; 202852c9ce25SScott Long } 202952c9ce25SScott Long softc->outstanding_cmds--; 203052c9ce25SScott Long if (softc->outstanding_cmds == 0) 2031030844d1SAlexander Motin softc->flags |= ADA_FLAG_WAS_OTAG; 2032*a6e0c5daSWarner Losh 2033*a6e0c5daSWarner Losh cam_iosched_bio_complete(softc->cam_iosched, bp, done_ccb); 2034227d67aaSAlexander Motin xpt_release_ccb(done_ccb); 20357651b989SAlexander Motin if (state == ADA_CCB_TRIM) { 20362030b294SAlexander Motin TAILQ_HEAD(, bio) queue; 20372030b294SAlexander Motin struct bio *bp1; 203852c9ce25SScott Long 20392030b294SAlexander Motin TAILQ_INIT(&queue); 20402030b294SAlexander Motin TAILQ_CONCAT(&queue, &softc->trim_req.bps, bio_queue); 20410ac66574SWarner Losh /* 20420ac66574SWarner Losh * Normally, the xpt_release_ccb() above would make sure 20430ac66574SWarner Losh * that when we have more work to do, that work would 20440ac66574SWarner Losh * get kicked off. However, we specifically keep 20450ac66574SWarner Losh * trim_running set to 0 before the call above to allow 20460ac66574SWarner Losh * other I/O to progress when many BIO_DELETE requests 20470ac66574SWarner Losh * are pushed down. We set trim_running to 0 and call 20480ac66574SWarner Losh * daschedule again so that we don't stall if there are 20490ac66574SWarner Losh * no other I/Os pending apart from BIO_DELETEs. 20500ac66574SWarner Losh */ 2051*a6e0c5daSWarner Losh cam_iosched_trim_done(softc->cam_iosched); 2052227d67aaSAlexander Motin adaschedule(periph); 2053227d67aaSAlexander Motin cam_periph_unlock(periph); 20542030b294SAlexander Motin while ((bp1 = TAILQ_FIRST(&queue)) != NULL) { 20552030b294SAlexander Motin TAILQ_REMOVE(&queue, bp1, bio_queue); 20562030b294SAlexander Motin bp1->bio_error = error; 20572030b294SAlexander Motin if (error != 0) { 20581c80ec0aSAlexander Motin bp1->bio_flags |= BIO_ERROR; 20597651b989SAlexander Motin bp1->bio_resid = bp1->bio_bcount; 20607651b989SAlexander Motin } else 20617651b989SAlexander Motin bp1->bio_resid = 0; 20621c80ec0aSAlexander Motin biodone(bp1); 20631c80ec0aSAlexander Motin } 2064227d67aaSAlexander Motin } else { 2065*a6e0c5daSWarner Losh adaschedule(periph); 2066227d67aaSAlexander Motin cam_periph_unlock(periph); 206752c9ce25SScott Long biodone(bp); 2068227d67aaSAlexander Motin } 2069227d67aaSAlexander Motin return; 207052c9ce25SScott Long } 20711ed6aaf9SAlexander Motin case ADA_CCB_RAHEAD: 20721ed6aaf9SAlexander Motin { 20731ed6aaf9SAlexander Motin if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 20741ed6aaf9SAlexander Motin if (adaerror(done_ccb, 0, 0) == ERESTART) { 2075cccf4220SAlexander Motin out: 2076cccf4220SAlexander Motin /* Drop freeze taken due to CAM_DEV_QFREEZE */ 2077cccf4220SAlexander Motin cam_release_devq(path, 0, 0, 0, FALSE); 20781ed6aaf9SAlexander Motin return; 20791ed6aaf9SAlexander Motin } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 2080cccf4220SAlexander Motin cam_release_devq(path, 20811ed6aaf9SAlexander Motin /*relsim_flags*/0, 20821ed6aaf9SAlexander Motin /*reduction*/0, 20831ed6aaf9SAlexander Motin /*timeout*/0, 20841ed6aaf9SAlexander Motin /*getcount_only*/0); 20851ed6aaf9SAlexander Motin } 20861ed6aaf9SAlexander Motin } 20871ed6aaf9SAlexander Motin 20881ed6aaf9SAlexander Motin /* 20891ed6aaf9SAlexander Motin * Since our peripheral may be invalidated by an error 20901ed6aaf9SAlexander Motin * above or an external event, we must release our CCB 20911ed6aaf9SAlexander Motin * before releasing the reference on the peripheral. 20921ed6aaf9SAlexander Motin * The peripheral will only go away once the last reference 20931ed6aaf9SAlexander Motin * is removed, and we need it around for the CCB release 20941ed6aaf9SAlexander Motin * operation. 20951ed6aaf9SAlexander Motin */ 20961ed6aaf9SAlexander Motin cgd = (struct ccb_getdev *)done_ccb; 2097cccf4220SAlexander Motin xpt_setup_ccb(&cgd->ccb_h, path, CAM_PRIORITY_NORMAL); 20981ed6aaf9SAlexander Motin cgd->ccb_h.func_code = XPT_GDEV_TYPE; 20991ed6aaf9SAlexander Motin xpt_action((union ccb *)cgd); 21001ed6aaf9SAlexander Motin if (ADA_WC >= 0 && 21011ed6aaf9SAlexander Motin cgd->ident_data.support.command1 & ATA_SUPPORT_WRITECACHE) { 21021ed6aaf9SAlexander Motin softc->state = ADA_STATE_WCACHE; 21031ed6aaf9SAlexander Motin xpt_release_ccb(done_ccb); 21041ed6aaf9SAlexander Motin xpt_schedule(periph, CAM_PRIORITY_DEV); 2105cccf4220SAlexander Motin goto out; 21061ed6aaf9SAlexander Motin } 21071ed6aaf9SAlexander Motin softc->state = ADA_STATE_NORMAL; 21081ed6aaf9SAlexander Motin xpt_release_ccb(done_ccb); 2109cccf4220SAlexander Motin /* Drop freeze taken due to CAM_DEV_QFREEZE */ 2110cccf4220SAlexander Motin cam_release_devq(path, 0, 0, 0, FALSE); 21111ed6aaf9SAlexander Motin adaschedule(periph); 21121ed6aaf9SAlexander Motin cam_periph_release_locked(periph); 21131ed6aaf9SAlexander Motin return; 21141ed6aaf9SAlexander Motin } 2115f513d14cSAlexander Motin case ADA_CCB_WCACHE: 2116f513d14cSAlexander Motin { 2117f513d14cSAlexander Motin if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 2118f513d14cSAlexander Motin if (adaerror(done_ccb, 0, 0) == ERESTART) { 2119cccf4220SAlexander Motin goto out; 2120f513d14cSAlexander Motin } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 2121cccf4220SAlexander Motin cam_release_devq(path, 2122f513d14cSAlexander Motin /*relsim_flags*/0, 2123f513d14cSAlexander Motin /*reduction*/0, 2124f513d14cSAlexander Motin /*timeout*/0, 2125f513d14cSAlexander Motin /*getcount_only*/0); 2126f513d14cSAlexander Motin } 2127f513d14cSAlexander Motin } 2128f513d14cSAlexander Motin 2129f513d14cSAlexander Motin softc->state = ADA_STATE_NORMAL; 2130f513d14cSAlexander Motin /* 2131f513d14cSAlexander Motin * Since our peripheral may be invalidated by an error 2132f513d14cSAlexander Motin * above or an external event, we must release our CCB 2133f513d14cSAlexander Motin * before releasing the reference on the peripheral. 2134f513d14cSAlexander Motin * The peripheral will only go away once the last reference 2135f513d14cSAlexander Motin * is removed, and we need it around for the CCB release 2136f513d14cSAlexander Motin * operation. 2137f513d14cSAlexander Motin */ 2138f513d14cSAlexander Motin xpt_release_ccb(done_ccb); 2139cccf4220SAlexander Motin /* Drop freeze taken due to CAM_DEV_QFREEZE */ 2140cccf4220SAlexander Motin cam_release_devq(path, 0, 0, 0, FALSE); 2141f513d14cSAlexander Motin adaschedule(periph); 2142f513d14cSAlexander Motin cam_periph_release_locked(periph); 2143f513d14cSAlexander Motin return; 2144f513d14cSAlexander Motin } 214552c9ce25SScott Long case ADA_CCB_DUMP: 214652c9ce25SScott Long /* No-op. We're polling */ 214752c9ce25SScott Long return; 214852c9ce25SScott Long default: 214952c9ce25SScott Long break; 215052c9ce25SScott Long } 215152c9ce25SScott Long xpt_release_ccb(done_ccb); 215252c9ce25SScott Long } 215352c9ce25SScott Long 215452c9ce25SScott Long static int 215552c9ce25SScott Long adaerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) 215652c9ce25SScott Long { 2157*a6e0c5daSWarner Losh struct ada_softc *softc; 2158*a6e0c5daSWarner Losh struct cam_periph *periph; 2159*a6e0c5daSWarner Losh 2160*a6e0c5daSWarner Losh periph = xpt_path_periph(ccb->ccb_h.path); 2161*a6e0c5daSWarner Losh softc = (struct ada_softc *)periph->softc; 2162*a6e0c5daSWarner Losh 2163*a6e0c5daSWarner Losh switch (ccb->ccb_h.status & CAM_STATUS_MASK) { 2164*a6e0c5daSWarner Losh case CAM_CMD_TIMEOUT: 2165*a6e0c5daSWarner Losh #ifdef CAM_IO_STATS 2166*a6e0c5daSWarner Losh softc->timeouts++; 2167*a6e0c5daSWarner Losh #endif 2168*a6e0c5daSWarner Losh break; 2169*a6e0c5daSWarner Losh case CAM_REQ_ABORTED: 2170*a6e0c5daSWarner Losh case CAM_REQ_CMP_ERR: 2171*a6e0c5daSWarner Losh case CAM_REQ_TERMIO: 2172*a6e0c5daSWarner Losh case CAM_UNREC_HBA_ERROR: 2173*a6e0c5daSWarner Losh case CAM_DATA_RUN_ERR: 2174*a6e0c5daSWarner Losh case CAM_ATA_STATUS_ERROR: 2175*a6e0c5daSWarner Losh #ifdef CAM_IO_STATS 2176*a6e0c5daSWarner Losh softc->errors++; 2177*a6e0c5daSWarner Losh #endif 2178*a6e0c5daSWarner Losh break; 2179*a6e0c5daSWarner Losh default: 2180*a6e0c5daSWarner Losh break; 2181*a6e0c5daSWarner Losh } 218252c9ce25SScott Long 2183a9b8edb1SAlexander Motin return(cam_periph_error(ccb, cam_flags, sense_flags, NULL)); 218452c9ce25SScott Long } 218552c9ce25SScott Long 218652c9ce25SScott Long static void 2187c1bd46c2SAlexander Motin adagetparams(struct cam_periph *periph, struct ccb_getdev *cgd) 218852c9ce25SScott Long { 218952c9ce25SScott Long struct ada_softc *softc = (struct ada_softc *)periph->softc; 219052c9ce25SScott Long struct disk_params *dp = &softc->params; 219152c9ce25SScott Long u_int64_t lbasize48; 219252c9ce25SScott Long u_int32_t lbasize; 219352c9ce25SScott Long 2194c1bd46c2SAlexander Motin dp->secsize = ata_logical_sector_size(&cgd->ident_data); 219552c9ce25SScott Long if ((cgd->ident_data.atavalid & ATA_FLAG_54_58) && 219652c9ce25SScott Long cgd->ident_data.current_heads && cgd->ident_data.current_sectors) { 219752c9ce25SScott Long dp->heads = cgd->ident_data.current_heads; 219852c9ce25SScott Long dp->secs_per_track = cgd->ident_data.current_sectors; 219952c9ce25SScott Long dp->cylinders = cgd->ident_data.cylinders; 220052c9ce25SScott Long dp->sectors = (u_int32_t)cgd->ident_data.current_size_1 | 220152c9ce25SScott Long ((u_int32_t)cgd->ident_data.current_size_2 << 16); 220252c9ce25SScott Long } else { 220352c9ce25SScott Long dp->heads = cgd->ident_data.heads; 220452c9ce25SScott Long dp->secs_per_track = cgd->ident_data.sectors; 220552c9ce25SScott Long dp->cylinders = cgd->ident_data.cylinders; 220652c9ce25SScott Long dp->sectors = cgd->ident_data.cylinders * dp->heads * dp->secs_per_track; 220752c9ce25SScott Long } 220852c9ce25SScott Long lbasize = (u_int32_t)cgd->ident_data.lba_size_1 | 220952c9ce25SScott Long ((u_int32_t)cgd->ident_data.lba_size_2 << 16); 221052c9ce25SScott Long 221152c9ce25SScott Long /* use the 28bit LBA size if valid or bigger than the CHS mapping */ 221252c9ce25SScott Long if (cgd->ident_data.cylinders == 16383 || dp->sectors < lbasize) 221352c9ce25SScott Long dp->sectors = lbasize; 221452c9ce25SScott Long 221552c9ce25SScott Long /* use the 48bit LBA size if valid */ 221652c9ce25SScott Long lbasize48 = ((u_int64_t)cgd->ident_data.lba_size48_1) | 221752c9ce25SScott Long ((u_int64_t)cgd->ident_data.lba_size48_2 << 16) | 221852c9ce25SScott Long ((u_int64_t)cgd->ident_data.lba_size48_3 << 32) | 221952c9ce25SScott Long ((u_int64_t)cgd->ident_data.lba_size48_4 << 48); 222052c9ce25SScott Long if ((cgd->ident_data.support.command2 & ATA_SUPPORT_ADDRESS48) && 222152c9ce25SScott Long lbasize48 > ATA_MAX_28BIT_LBA) 222252c9ce25SScott Long dp->sectors = lbasize48; 222352c9ce25SScott Long } 222452c9ce25SScott Long 222552c9ce25SScott Long static void 222652c9ce25SScott Long adasendorderedtag(void *arg) 222752c9ce25SScott Long { 222852c9ce25SScott Long struct ada_softc *softc = arg; 222952c9ce25SScott Long 223052c9ce25SScott Long if (ada_send_ordered) { 2231030844d1SAlexander Motin if (softc->outstanding_cmds > 0) { 2232030844d1SAlexander Motin if ((softc->flags & ADA_FLAG_WAS_OTAG) == 0) 223352c9ce25SScott Long softc->flags |= ADA_FLAG_NEED_OTAG; 2234030844d1SAlexander Motin softc->flags &= ~ADA_FLAG_WAS_OTAG; 223552c9ce25SScott Long } 223652c9ce25SScott Long } 223752c9ce25SScott Long /* Queue us up again */ 223852c9ce25SScott Long callout_reset(&softc->sendordered_c, 223947bb9643SAlexander Motin (ada_default_timeout * hz) / ADA_ORDEREDTAG_INTERVAL, 224052c9ce25SScott Long adasendorderedtag, softc); 224152c9ce25SScott Long } 224252c9ce25SScott Long 224352c9ce25SScott Long /* 224452c9ce25SScott Long * Step through all ADA peripheral drivers, and if the device is still open, 224552c9ce25SScott Long * sync the disk cache to physical media. 224652c9ce25SScott Long */ 224752c9ce25SScott Long static void 2248c3d0d168SAlexander Motin adaflush(void) 224952c9ce25SScott Long { 225052c9ce25SScott Long struct cam_periph *periph; 225152c9ce25SScott Long struct ada_softc *softc; 225209cfadbeSAlexander Motin union ccb *ccb; 22530191d9b3SAlexander Motin int error; 225452c9ce25SScott Long 2255f371c9e2SAlexander Motin CAM_PERIPH_FOREACH(periph, &adadriver) { 225652c9ce25SScott Long softc = (struct ada_softc *)periph->softc; 22572f87dfb0SAlexander Motin if (SCHEDULER_STOPPED()) { 22582f87dfb0SAlexander Motin /* If we paniced with the lock held, do not recurse. */ 22592f87dfb0SAlexander Motin if (!cam_periph_owned(periph) && 22602f87dfb0SAlexander Motin (softc->flags & ADA_FLAG_OPEN)) { 22612f87dfb0SAlexander Motin adadump(softc->disk, NULL, 0, 0, 0); 22622f87dfb0SAlexander Motin } 22632f87dfb0SAlexander Motin continue; 22642f87dfb0SAlexander Motin } 22652f87dfb0SAlexander Motin cam_periph_lock(periph); 226652c9ce25SScott Long /* 226752c9ce25SScott Long * We only sync the cache if the drive is still open, and 226852c9ce25SScott Long * if the drive is capable of it.. 226952c9ce25SScott Long */ 227052c9ce25SScott Long if (((softc->flags & ADA_FLAG_OPEN) == 0) || 227152c9ce25SScott Long (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) == 0) { 227252c9ce25SScott Long cam_periph_unlock(periph); 227352c9ce25SScott Long continue; 227452c9ce25SScott Long } 227552c9ce25SScott Long 227609cfadbeSAlexander Motin ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 227709cfadbeSAlexander Motin cam_fill_ataio(&ccb->ataio, 22780191d9b3SAlexander Motin 0, 227952c9ce25SScott Long adadone, 228052c9ce25SScott Long CAM_DIR_NONE, 228152c9ce25SScott Long 0, 228252c9ce25SScott Long NULL, 228352c9ce25SScott Long 0, 228452c9ce25SScott Long ada_default_timeout*1000); 228552c9ce25SScott Long if (softc->flags & ADA_FLAG_CAN_48BIT) 228609cfadbeSAlexander Motin ata_48bit_cmd(&ccb->ataio, ATA_FLUSHCACHE48, 0, 0, 0); 228752c9ce25SScott Long else 228809cfadbeSAlexander Motin ata_28bit_cmd(&ccb->ataio, ATA_FLUSHCACHE, 0, 0, 0); 228952c9ce25SScott Long 229009cfadbeSAlexander Motin error = cam_periph_runccb(ccb, adaerror, /*cam_flags*/0, 229109cfadbeSAlexander Motin /*sense_flags*/ SF_NO_RECOVERY | SF_NO_RETRY, 229209cfadbeSAlexander Motin softc->disk->d_devstat); 22930191d9b3SAlexander Motin if (error != 0) 22940191d9b3SAlexander Motin xpt_print(periph->path, "Synchronize cache failed\n"); 2295d6794b70SAlexander Motin xpt_release_ccb(ccb); 229652c9ce25SScott Long cam_periph_unlock(periph); 229752c9ce25SScott Long } 2298c3d0d168SAlexander Motin } 2299fd104c15SRebecca Cran 2300c3d0d168SAlexander Motin static void 2301c3d0d168SAlexander Motin adaspindown(uint8_t cmd, int flags) 2302c3d0d168SAlexander Motin { 2303c3d0d168SAlexander Motin struct cam_periph *periph; 2304c3d0d168SAlexander Motin struct ada_softc *softc; 230509cfadbeSAlexander Motin union ccb *ccb; 23060191d9b3SAlexander Motin int error; 2307fd104c15SRebecca Cran 2308f371c9e2SAlexander Motin CAM_PERIPH_FOREACH(periph, &adadriver) { 2309fd104c15SRebecca Cran /* If we paniced with lock held - not recurse here. */ 2310fd104c15SRebecca Cran if (cam_periph_owned(periph)) 2311fd104c15SRebecca Cran continue; 2312fd104c15SRebecca Cran cam_periph_lock(periph); 2313fd104c15SRebecca Cran softc = (struct ada_softc *)periph->softc; 2314fd104c15SRebecca Cran /* 2315fd104c15SRebecca Cran * We only spin-down the drive if it is capable of it.. 2316fd104c15SRebecca Cran */ 2317fd104c15SRebecca Cran if ((softc->flags & ADA_FLAG_CAN_POWERMGT) == 0) { 2318fd104c15SRebecca Cran cam_periph_unlock(periph); 2319fd104c15SRebecca Cran continue; 2320fd104c15SRebecca Cran } 2321fd104c15SRebecca Cran 2322fd104c15SRebecca Cran if (bootverbose) 2323fd104c15SRebecca Cran xpt_print(periph->path, "spin-down\n"); 2324fd104c15SRebecca Cran 232509cfadbeSAlexander Motin ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 232609cfadbeSAlexander Motin cam_fill_ataio(&ccb->ataio, 23270191d9b3SAlexander Motin 0, 2328fd104c15SRebecca Cran adadone, 2329c3d0d168SAlexander Motin CAM_DIR_NONE | flags, 2330fd104c15SRebecca Cran 0, 2331fd104c15SRebecca Cran NULL, 2332fd104c15SRebecca Cran 0, 2333fd104c15SRebecca Cran ada_default_timeout*1000); 233409cfadbeSAlexander Motin ata_28bit_cmd(&ccb->ataio, cmd, 0, 0, 0); 2335fd104c15SRebecca Cran 233609cfadbeSAlexander Motin error = cam_periph_runccb(ccb, adaerror, /*cam_flags*/0, 233709cfadbeSAlexander Motin /*sense_flags*/ SF_NO_RECOVERY | SF_NO_RETRY, 233809cfadbeSAlexander Motin softc->disk->d_devstat); 23390191d9b3SAlexander Motin if (error != 0) 23400191d9b3SAlexander Motin xpt_print(periph->path, "Spin-down disk failed\n"); 2341d6794b70SAlexander Motin xpt_release_ccb(ccb); 2342fd104c15SRebecca Cran cam_periph_unlock(periph); 2343fd104c15SRebecca Cran } 234452c9ce25SScott Long } 234552c9ce25SScott Long 2346c3d0d168SAlexander Motin static void 2347c3d0d168SAlexander Motin adashutdown(void *arg, int howto) 2348c3d0d168SAlexander Motin { 2349c3d0d168SAlexander Motin 2350c3d0d168SAlexander Motin adaflush(); 2351c3d0d168SAlexander Motin if (ada_spindown_shutdown != 0 && 2352c3d0d168SAlexander Motin (howto & (RB_HALT | RB_POWEROFF)) != 0) 2353c3d0d168SAlexander Motin adaspindown(ATA_STANDBY_IMMEDIATE, 0); 2354c3d0d168SAlexander Motin } 2355c3d0d168SAlexander Motin 2356c3d0d168SAlexander Motin static void 2357c3d0d168SAlexander Motin adasuspend(void *arg) 2358c3d0d168SAlexander Motin { 2359c3d0d168SAlexander Motin 2360c3d0d168SAlexander Motin adaflush(); 2361c3d0d168SAlexander Motin if (ada_spindown_suspend != 0) 2362c3d0d168SAlexander Motin adaspindown(ATA_SLEEP, CAM_DEV_QFREEZE); 2363c3d0d168SAlexander Motin } 2364c3d0d168SAlexander Motin 2365c3d0d168SAlexander Motin static void 2366c3d0d168SAlexander Motin adaresume(void *arg) 2367c3d0d168SAlexander Motin { 2368c3d0d168SAlexander Motin struct cam_periph *periph; 2369c3d0d168SAlexander Motin struct ada_softc *softc; 2370c3d0d168SAlexander Motin 2371c3d0d168SAlexander Motin if (ada_spindown_suspend == 0) 2372c3d0d168SAlexander Motin return; 2373c3d0d168SAlexander Motin 2374f371c9e2SAlexander Motin CAM_PERIPH_FOREACH(periph, &adadriver) { 2375c3d0d168SAlexander Motin cam_periph_lock(periph); 2376c3d0d168SAlexander Motin softc = (struct ada_softc *)periph->softc; 2377c3d0d168SAlexander Motin /* 2378c3d0d168SAlexander Motin * We only spin-down the drive if it is capable of it.. 2379c3d0d168SAlexander Motin */ 2380c3d0d168SAlexander Motin if ((softc->flags & ADA_FLAG_CAN_POWERMGT) == 0) { 2381c3d0d168SAlexander Motin cam_periph_unlock(periph); 2382c3d0d168SAlexander Motin continue; 2383c3d0d168SAlexander Motin } 2384c3d0d168SAlexander Motin 2385c3d0d168SAlexander Motin if (bootverbose) 2386c3d0d168SAlexander Motin xpt_print(periph->path, "resume\n"); 2387c3d0d168SAlexander Motin 2388c3d0d168SAlexander Motin /* 2389c3d0d168SAlexander Motin * Drop freeze taken due to CAM_DEV_QFREEZE flag set on 2390c3d0d168SAlexander Motin * sleep request. 2391c3d0d168SAlexander Motin */ 2392c3d0d168SAlexander Motin cam_release_devq(periph->path, 2393c3d0d168SAlexander Motin /*relsim_flags*/0, 2394c3d0d168SAlexander Motin /*openings*/0, 2395c3d0d168SAlexander Motin /*timeout*/0, 2396c3d0d168SAlexander Motin /*getcount_only*/0); 2397c3d0d168SAlexander Motin 2398c3d0d168SAlexander Motin cam_periph_unlock(periph); 2399c3d0d168SAlexander Motin } 2400c3d0d168SAlexander Motin } 2401c3d0d168SAlexander Motin 240252c9ce25SScott Long #endif /* _KERNEL */ 2403