ata_da.c revision 298035
1195534Sscottl/*- 2195534Sscottl * Copyright (c) 2009 Alexander Motin <mav@FreeBSD.org> 3195534Sscottl * All rights reserved. 4195534Sscottl * 5195534Sscottl * Redistribution and use in source and binary forms, with or without 6195534Sscottl * modification, are permitted provided that the following conditions 7195534Sscottl * are met: 8195534Sscottl * 1. Redistributions of source code must retain the above copyright 9195534Sscottl * notice, this list of conditions and the following disclaimer, 10195534Sscottl * without modification, immediately at the beginning of the file. 11195534Sscottl * 2. Redistributions in binary form must reproduce the above copyright 12195534Sscottl * notice, this list of conditions and the following disclaimer in the 13195534Sscottl * documentation and/or other materials provided with the distribution. 14195534Sscottl * 15195534Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16195534Sscottl * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17195534Sscottl * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18195534Sscottl * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19195534Sscottl * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20195534Sscottl * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21195534Sscottl * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22195534Sscottl * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23195534Sscottl * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24195534Sscottl * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25195534Sscottl */ 26195534Sscottl 27195534Sscottl#include <sys/cdefs.h> 28195534Sscottl__FBSDID("$FreeBSD: head/sys/cam/ata/ata_da.c 298035 2016-04-15 05:10:31Z imp $"); 29195534Sscottl 30220454Smav#include "opt_ada.h" 31220454Smav 32195534Sscottl#include <sys/param.h> 33195534Sscottl 34195534Sscottl#ifdef _KERNEL 35195534Sscottl#include <sys/systm.h> 36195534Sscottl#include <sys/kernel.h> 37195534Sscottl#include <sys/bio.h> 38195534Sscottl#include <sys/sysctl.h> 39195534Sscottl#include <sys/taskqueue.h> 40195534Sscottl#include <sys/lock.h> 41195534Sscottl#include <sys/mutex.h> 42195534Sscottl#include <sys/conf.h> 43195534Sscottl#include <sys/devicestat.h> 44195534Sscottl#include <sys/eventhandler.h> 45195534Sscottl#include <sys/malloc.h> 46195534Sscottl#include <sys/cons.h> 47251792Smav#include <sys/proc.h> 48214279Sbrucec#include <sys/reboot.h> 49195534Sscottl#include <geom/geom_disk.h> 50195534Sscottl#endif /* _KERNEL */ 51195534Sscottl 52195534Sscottl#ifndef _KERNEL 53195534Sscottl#include <stdio.h> 54195534Sscottl#include <string.h> 55195534Sscottl#endif /* _KERNEL */ 56195534Sscottl 57195534Sscottl#include <cam/cam.h> 58195534Sscottl#include <cam/cam_ccb.h> 59195534Sscottl#include <cam/cam_periph.h> 60195534Sscottl#include <cam/cam_xpt_periph.h> 61195534Sscottl#include <cam/cam_sim.h> 62298002Simp#include <cam/cam_iosched.h> 63195534Sscottl 64195534Sscottl#include <cam/ata/ata_all.h> 65195534Sscottl 66208349Smarius#include <machine/md_var.h> /* geometry translation */ 67208349Smarius 68195534Sscottl#ifdef _KERNEL 69195534Sscottl 70195534Sscottl#define ATA_MAX_28BIT_LBA 268435455UL 71195534Sscottl 72298002Simpextern int iosched_debug; 73298002Simp 74195534Sscottltypedef enum { 75224497Smav ADA_STATE_RAHEAD, 76220412Smav ADA_STATE_WCACHE, 77198708Smav ADA_STATE_NORMAL 78195534Sscottl} ada_state; 79195534Sscottl 80195534Sscottltypedef enum { 81249199Smarius ADA_FLAG_CAN_48BIT = 0x0002, 82249199Smarius ADA_FLAG_CAN_FLUSHCACHE = 0x0004, 83249199Smarius ADA_FLAG_CAN_NCQ = 0x0008, 84249199Smarius ADA_FLAG_CAN_DMA = 0x0010, 85249199Smarius ADA_FLAG_NEED_OTAG = 0x0020, 86257054Smav ADA_FLAG_WAS_OTAG = 0x0040, 87249199Smarius ADA_FLAG_CAN_TRIM = 0x0080, 88249199Smarius ADA_FLAG_OPEN = 0x0100, 89249199Smarius ADA_FLAG_SCTX_INIT = 0x0200, 90249199Smarius ADA_FLAG_CAN_CFA = 0x0400, 91249199Smarius ADA_FLAG_CAN_POWERMGT = 0x0800, 92253724Smav ADA_FLAG_CAN_DMA48 = 0x1000, 93298002Simp ADA_FLAG_DIRTY = 0x2000, 94298002Simp ADA_FLAG_CAN_NCQ_TRIM = 0x4000, /* CAN_TRIM also set */ 95298002Simp ADA_FLAG_PIM_CAN_NCQ_TRIM = 0x8000 96195534Sscottl} ada_flags; 97195534Sscottl 98195534Sscottltypedef enum { 99222520Smav ADA_Q_NONE = 0x00, 100222520Smav ADA_Q_4K = 0x01, 101298002Simp ADA_Q_NCQ_TRIM_BROKEN = 0x02, 102195534Sscottl} ada_quirks; 103195534Sscottl 104250792Ssmh#define ADA_Q_BIT_STRING \ 105250792Ssmh "\020" \ 106298002Simp "\0014K" \ 107298002Simp "\002NCQ_TRIM_BROKEN" 108250792Ssmh 109195534Sscottltypedef enum { 110224497Smav ADA_CCB_RAHEAD = 0x01, 111224497Smav ADA_CCB_WCACHE = 0x02, 112195534Sscottl ADA_CCB_BUFFER_IO = 0x03, 113195534Sscottl ADA_CCB_DUMP = 0x05, 114201139Smav ADA_CCB_TRIM = 0x06, 115195534Sscottl ADA_CCB_TYPE_MASK = 0x0F, 116195534Sscottl} ada_ccb_state; 117195534Sscottl 118195534Sscottl/* Offsets into our private area for storing information */ 119195534Sscottl#define ccb_state ppriv_field0 120195534Sscottl#define ccb_bp ppriv_ptr1 121195534Sscottl 122298002Simptypedef enum { 123298002Simp ADA_DELETE_NONE, 124298002Simp ADA_DELETE_DISABLE, 125298002Simp ADA_DELETE_CFA_ERASE, 126298002Simp ADA_DELETE_DSM_TRIM, 127298002Simp ADA_DELETE_NCQ_DSM_TRIM, 128298002Simp ADA_DELETE_MIN = ADA_DELETE_CFA_ERASE, 129298002Simp ADA_DELETE_MAX = ADA_DELETE_NCQ_DSM_TRIM, 130298002Simp} ada_delete_methods; 131298002Simp 132298002Simpstatic const char *ada_delete_method_names[] = 133298002Simp { "NONE", "DISABLE", "CFA_ERASE", "DSM_TRIM", "NCQ_DSM_TRIM" }; 134298002Simp#if 0 135298002Simpstatic const char *ada_delete_method_desc[] = 136298002Simp { "NONE", "DISABLED", "CFA Erase", "DSM Trim", "DSM Trim via NCQ" }; 137298002Simp#endif 138298002Simp 139195534Sscottlstruct disk_params { 140195534Sscottl u_int8_t heads; 141198897Smav u_int8_t secs_per_track; 142195534Sscottl u_int32_t cylinders; 143198897Smav u_int32_t secsize; /* Number of bytes/logical sector */ 144198897Smav u_int64_t sectors; /* Total number sectors */ 145195534Sscottl}; 146195534Sscottl 147222643Smav#define TRIM_MAX_BLOCKS 8 148249934Ssmh#define TRIM_MAX_RANGES (TRIM_MAX_BLOCKS * ATA_DSM_BLK_RANGES) 149201139Smavstruct trim_request { 150249934Ssmh uint8_t data[TRIM_MAX_RANGES * ATA_DSM_RANGE_SIZE]; 151256836Smav TAILQ_HEAD(, bio) bps; 152201139Smav}; 153201139Smav 154195534Sscottlstruct ada_softc { 155298002Simp struct cam_iosched_softc *cam_iosched; 156257054Smav int outstanding_cmds; /* Number of active commands */ 157257054Smav int refcount; /* Active xpt_action() calls */ 158195534Sscottl ada_state state; 159257054Smav ada_flags flags; 160195534Sscottl ada_quirks quirks; 161298002Simp ada_delete_methods delete_method; 162201139Smav int trim_max_ranges; 163224497Smav int read_ahead; 164220454Smav int write_cache; 165298002Simp int unmappedio; 166298002Simp int rotating; 167220454Smav#ifdef ADA_TEST_FAILURE 168220454Smav int force_read_error; 169220454Smav int force_write_error; 170220454Smav int periodic_read_error; 171220454Smav int periodic_read_count; 172220454Smav#endif 173195534Sscottl struct disk_params params; 174195534Sscottl struct disk *disk; 175195534Sscottl struct task sysctl_task; 176195534Sscottl struct sysctl_ctx_list sysctl_ctx; 177195534Sscottl struct sysctl_oid *sysctl_tree; 178195534Sscottl struct callout sendordered_c; 179201139Smav struct trim_request trim_req; 180298002Simp#ifdef CAM_IO_STATS 181298002Simp struct sysctl_ctx_list sysctl_stats_ctx; 182298002Simp struct sysctl_oid *sysctl_stats_tree; 183298002Simp u_int timeouts; 184298002Simp u_int errors; 185298002Simp u_int invalidations; 186298002Simp#endif 187195534Sscottl}; 188195534Sscottl 189195534Sscottlstruct ada_quirk_entry { 190195534Sscottl struct scsi_inquiry_pattern inq_pat; 191195534Sscottl ada_quirks quirks; 192195534Sscottl}; 193195534Sscottl 194199178Smavstatic struct ada_quirk_entry ada_quirk_table[] = 195199178Smav{ 196199178Smav { 197222520Smav /* Hitachi Advanced Format (4k) drives */ 198222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "Hitachi H??????????E3*", "*" }, 199222520Smav /*quirks*/ADA_Q_4K 200222520Smav }, 201222520Smav { 202222520Smav /* Samsung Advanced Format (4k) drives */ 203228819Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "SAMSUNG HD155UI*", "*" }, 204228819Smav /*quirks*/ADA_Q_4K 205228819Smav }, 206228819Smav { 207228819Smav /* Samsung Advanced Format (4k) drives */ 208222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "SAMSUNG HD204UI*", "*" }, 209222520Smav /*quirks*/ADA_Q_4K 210222520Smav }, 211222520Smav { 212222520Smav /* Seagate Barracuda Green Advanced Format (4k) drives */ 213222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST????DL*", "*" }, 214222520Smav /*quirks*/ADA_Q_4K 215222520Smav }, 216222520Smav { 217228819Smav /* Seagate Barracuda Advanced Format (4k) drives */ 218228819Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST???DM*", "*" }, 219228819Smav /*quirks*/ADA_Q_4K 220228819Smav }, 221228819Smav { 222228819Smav /* Seagate Barracuda Advanced Format (4k) drives */ 223228819Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST????DM*", "*" }, 224228819Smav /*quirks*/ADA_Q_4K 225228819Smav }, 226228819Smav { 227222520Smav /* Seagate Momentus Advanced Format (4k) drives */ 228222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9500423AS*", "*" }, 229222520Smav /*quirks*/ADA_Q_4K 230222520Smav }, 231222520Smav { 232222520Smav /* Seagate Momentus Advanced Format (4k) drives */ 233222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9500424AS*", "*" }, 234222520Smav /*quirks*/ADA_Q_4K 235222520Smav }, 236222520Smav { 237222520Smav /* Seagate Momentus Advanced Format (4k) drives */ 238228819Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9640423AS*", "*" }, 239228819Smav /*quirks*/ADA_Q_4K 240228819Smav }, 241228819Smav { 242228819Smav /* Seagate Momentus Advanced Format (4k) drives */ 243228819Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9640424AS*", "*" }, 244228819Smav /*quirks*/ADA_Q_4K 245228819Smav }, 246228819Smav { 247228819Smav /* Seagate Momentus Advanced Format (4k) drives */ 248222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9750420AS*", "*" }, 249222520Smav /*quirks*/ADA_Q_4K 250222520Smav }, 251222520Smav { 252222520Smav /* Seagate Momentus Advanced Format (4k) drives */ 253222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9750422AS*", "*" }, 254222520Smav /*quirks*/ADA_Q_4K 255222520Smav }, 256222520Smav { 257228819Smav /* Seagate Momentus Advanced Format (4k) drives */ 258228819Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9750423AS*", "*" }, 259228819Smav /*quirks*/ADA_Q_4K 260228819Smav }, 261228819Smav { 262222520Smav /* Seagate Momentus Thin Advanced Format (4k) drives */ 263222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST???LT*", "*" }, 264222520Smav /*quirks*/ADA_Q_4K 265222520Smav }, 266222520Smav { 267280845Seadler /* WDC Caviar Red Advanced Format (4k) drives */ 268280845Seadler { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD????CX*", "*" }, 269280845Seadler /*quirks*/ADA_Q_4K 270280845Seadler }, 271280845Seadler { 272222520Smav /* WDC Caviar Green Advanced Format (4k) drives */ 273222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD????RS*", "*" }, 274222520Smav /*quirks*/ADA_Q_4K 275222520Smav }, 276222520Smav { 277280845Seadler /* WDC Caviar Green/Red Advanced Format (4k) drives */ 278222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD????RX*", "*" }, 279222520Smav /*quirks*/ADA_Q_4K 280222520Smav }, 281222520Smav { 282280845Seadler /* WDC Caviar Red Advanced Format (4k) drives */ 283280845Seadler { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD??????CX*", "*" }, 284280845Seadler /*quirks*/ADA_Q_4K 285280845Seadler }, 286280845Seadler { 287280845Seadler /* WDC Caviar Black Advanced Format (4k) drives */ 288280845Seadler { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD??????EX*", "*" }, 289280845Seadler /*quirks*/ADA_Q_4K 290280845Seadler }, 291280845Seadler { 292222520Smav /* WDC Caviar Green Advanced Format (4k) drives */ 293222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD??????RS*", "*" }, 294222520Smav /*quirks*/ADA_Q_4K 295222520Smav }, 296222520Smav { 297222520Smav /* WDC Caviar Green Advanced Format (4k) drives */ 298222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD??????RX*", "*" }, 299222520Smav /*quirks*/ADA_Q_4K 300222520Smav }, 301222520Smav { 302222520Smav /* WDC Scorpio Black Advanced Format (4k) drives */ 303222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD???PKT*", "*" }, 304222520Smav /*quirks*/ADA_Q_4K 305222520Smav }, 306222520Smav { 307222520Smav /* WDC Scorpio Black Advanced Format (4k) drives */ 308222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD?????PKT*", "*" }, 309222520Smav /*quirks*/ADA_Q_4K 310222520Smav }, 311222520Smav { 312222520Smav /* WDC Scorpio Blue Advanced Format (4k) drives */ 313222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD???PVT*", "*" }, 314222520Smav /*quirks*/ADA_Q_4K 315222520Smav }, 316222520Smav { 317222520Smav /* WDC Scorpio Blue Advanced Format (4k) drives */ 318222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD?????PVT*", "*" }, 319222520Smav /*quirks*/ADA_Q_4K 320222520Smav }, 321251061Ssmh /* SSDs */ 322222520Smav { 323241784Seadler /* 324241784Seadler * Corsair Force 2 SSDs 325241784Seadler * 4k optimised & trim only works in 4k requests + 4k aligned 326241784Seadler */ 327241784Seadler { T_DIRECT, SIP_MEDIA_FIXED, "*", "Corsair CSSD-F*", "*" }, 328241784Seadler /*quirks*/ADA_Q_4K 329241784Seadler }, 330241784Seadler { 331241784Seadler /* 332241784Seadler * Corsair Force 3 SSDs 333241784Seadler * 4k optimised & trim only works in 4k requests + 4k aligned 334241784Seadler */ 335241784Seadler { T_DIRECT, SIP_MEDIA_FIXED, "*", "Corsair Force 3*", "*" }, 336241784Seadler /*quirks*/ADA_Q_4K 337241784Seadler }, 338241784Seadler { 339241784Seadler /* 340256547Ssmh * Corsair Neutron GTX SSDs 341256547Ssmh * 4k optimised & trim only works in 4k requests + 4k aligned 342256547Ssmh */ 343256547Ssmh { T_DIRECT, SIP_MEDIA_FIXED, "*", "Corsair Neutron GTX*", "*" }, 344256547Ssmh /*quirks*/ADA_Q_4K 345256547Ssmh }, 346256547Ssmh { 347256547Ssmh /* 348269974Ssmh * Corsair Force GT & GS SSDs 349241784Seadler * 4k optimised & trim only works in 4k requests + 4k aligned 350241784Seadler */ 351269974Ssmh { T_DIRECT, SIP_MEDIA_FIXED, "*", "Corsair Force G*", "*" }, 352241784Seadler /*quirks*/ADA_Q_4K 353241784Seadler }, 354241784Seadler { 355241784Seadler /* 356251061Ssmh * Crucial M4 SSDs 357241784Seadler * 4k optimised & trim only works in 4k requests + 4k aligned 358241784Seadler */ 359251061Ssmh { T_DIRECT, SIP_MEDIA_FIXED, "*", "M4-CT???M4SSD2*", "*" }, 360241784Seadler /*quirks*/ADA_Q_4K 361241784Seadler }, 362241784Seadler { 363241784Seadler /* 364298027Simp * Crucial M500 SSDs MU07 firmware 365298027Simp * NCQ Trim works 366298002Simp */ 367298027Simp { T_DIRECT, SIP_MEDIA_FIXED, "*", "Crucial CT*M500*", "MU07" }, 368298002Simp /*quirks*/0 369298002Simp }, 370298002Simp { 371298002Simp /* 372298002Simp * Crucial M500 SSDs all other firmware 373298002Simp * NCQ Trim doesn't work 374298002Simp */ 375298002Simp { T_DIRECT, SIP_MEDIA_FIXED, "*", "Crucial CT*M500*", "*" }, 376298002Simp /*quirks*/ADA_Q_NCQ_TRIM_BROKEN 377298002Simp }, 378298002Simp { 379298002Simp /* 380298002Simp * Crucial M550 SSDs 381298002Simp * NCQ Trim doesn't work, but only on MU01 firmware 382298002Simp */ 383298002Simp { T_DIRECT, SIP_MEDIA_FIXED, "*", "Crucial CT*M550*", "MU01" }, 384298002Simp /*quirks*/ADA_Q_NCQ_TRIM_BROKEN 385298002Simp }, 386298002Simp { 387298002Simp /* 388298002Simp * Crucial MX100 SSDs 389298002Simp * NCQ Trim doesn't work, but only on MU01 firmware 390298002Simp */ 391298002Simp { T_DIRECT, SIP_MEDIA_FIXED, "*", "Crucial CT*MX100*", "MU01" }, 392298002Simp /*quirks*/ADA_Q_NCQ_TRIM_BROKEN 393298002Simp }, 394298002Simp { 395298002Simp /* 396251061Ssmh * Crucial RealSSD C300 SSDs 397251061Ssmh * 4k optimised 398251061Ssmh */ 399251061Ssmh { T_DIRECT, SIP_MEDIA_FIXED, "*", "C300-CTFDDAC???MAG*", 400251061Ssmh "*" }, /*quirks*/ADA_Q_4K 401251061Ssmh }, 402251061Ssmh { 403251061Ssmh /* 404298027Simp * FCCT M500 SSDs 405298027Simp * NCQ Trim doesn't work 406298027Simp */ 407298027Simp { T_DIRECT, SIP_MEDIA_FIXED, "*", "FCCT*M500*", "*" }, 408298027Simp /*quirks*/ADA_Q_NCQ_TRIM_BROKEN 409298027Simp }, 410298027Simp { 411298027Simp /* 412251061Ssmh * Intel 320 Series SSDs 413241784Seadler * 4k optimised & trim only works in 4k requests + 4k aligned 414241784Seadler */ 415251061Ssmh { T_DIRECT, SIP_MEDIA_FIXED, "*", "INTEL SSDSA2CW*", "*" }, 416241784Seadler /*quirks*/ADA_Q_4K 417241784Seadler }, 418241784Seadler { 419241784Seadler /* 420251061Ssmh * Intel 330 Series SSDs 421241784Seadler * 4k optimised & trim only works in 4k requests + 4k aligned 422241784Seadler */ 423251061Ssmh { T_DIRECT, SIP_MEDIA_FIXED, "*", "INTEL SSDSC2CT*", "*" }, 424241784Seadler /*quirks*/ADA_Q_4K 425241784Seadler }, 426241784Seadler { 427241784Seadler /* 428251061Ssmh * Intel 510 Series SSDs 429251061Ssmh * 4k optimised & trim only works in 4k requests + 4k aligned 430241784Seadler */ 431251061Ssmh { T_DIRECT, SIP_MEDIA_FIXED, "*", "INTEL SSDSC2MH*", "*" }, 432251061Ssmh /*quirks*/ADA_Q_4K 433241784Seadler }, 434241784Seadler { 435241784Seadler /* 436251061Ssmh * Intel 520 Series SSDs 437251061Ssmh * 4k optimised & trim only works in 4k requests + 4k aligned 438241784Seadler */ 439251061Ssmh { T_DIRECT, SIP_MEDIA_FIXED, "*", "INTEL SSDSC2BW*", "*" }, 440241784Seadler /*quirks*/ADA_Q_4K 441241784Seadler }, 442241784Seadler { 443241784Seadler /* 444254329Ssmh * Intel X25-M Series SSDs 445254329Ssmh * 4k optimised & trim only works in 4k requests + 4k aligned 446254329Ssmh */ 447254329Ssmh { T_DIRECT, SIP_MEDIA_FIXED, "*", "INTEL SSDSA2M*", "*" }, 448254329Ssmh /*quirks*/ADA_Q_4K 449254329Ssmh }, 450254329Ssmh { 451254329Ssmh /* 452251061Ssmh * Kingston E100 Series SSDs 453250532Seadler * 4k optimised & trim only works in 4k requests + 4k aligned 454250532Seadler */ 455251061Ssmh { T_DIRECT, SIP_MEDIA_FIXED, "*", "KINGSTON SE100S3*", "*" }, 456250532Seadler /*quirks*/ADA_Q_4K 457250532Seadler }, 458250532Seadler { 459250532Seadler /* 460251061Ssmh * Kingston HyperX 3k SSDs 461241784Seadler * 4k optimised & trim only works in 4k requests + 4k aligned 462241784Seadler */ 463251061Ssmh { T_DIRECT, SIP_MEDIA_FIXED, "*", "KINGSTON SH103S3*", "*" }, 464241784Seadler /*quirks*/ADA_Q_4K 465241784Seadler }, 466241784Seadler { 467241784Seadler /* 468254329Ssmh * Marvell SSDs (entry taken from OpenSolaris) 469254329Ssmh * 4k optimised & trim only works in 4k requests + 4k aligned 470254329Ssmh */ 471254329Ssmh { T_DIRECT, SIP_MEDIA_FIXED, "*", "MARVELL SD88SA02*", "*" }, 472254329Ssmh /*quirks*/ADA_Q_4K 473254329Ssmh }, 474254329Ssmh { 475254329Ssmh /* 476298027Simp * Micron M500 SSDs firmware MU07 477298002Simp * NCQ Trim works? 478298002Simp */ 479298027Simp { T_DIRECT, SIP_MEDIA_FIXED, "*", "Micron M500*", "MU07" }, 480298002Simp /*quirks*/0 481298002Simp }, 482298002Simp { 483298002Simp /* 484298002Simp * Micron M500 SSDs all other firmware 485298002Simp * NCQ Trim doesn't work 486298002Simp */ 487298002Simp { T_DIRECT, SIP_MEDIA_FIXED, "*", "Micron M500*", "*" }, 488298002Simp /*quirks*/ADA_Q_NCQ_TRIM_BROKEN 489298002Simp }, 490298002Simp { 491298002Simp /* 492298002Simp * Micron M5[15]0 SSDs 493298002Simp * NCQ Trim doesn't work, but only MU01 firmware 494298002Simp */ 495298002Simp { T_DIRECT, SIP_MEDIA_FIXED, "*", "Micron M5[15]0*", "MU01" }, 496298002Simp /*quirks*/ADA_Q_NCQ_TRIM_BROKEN 497298002Simp }, 498298002Simp { 499298002Simp /* 500254329Ssmh * OCZ Agility 2 SSDs 501254329Ssmh * 4k optimised & trim only works in 4k requests + 4k aligned 502254329Ssmh */ 503254329Ssmh { T_DIRECT, SIP_MEDIA_FIXED, "*", "OCZ-AGILITY2*", "*" }, 504254329Ssmh /*quirks*/ADA_Q_4K 505254329Ssmh }, 506254329Ssmh { 507254329Ssmh /* 508251061Ssmh * OCZ Agility 3 SSDs 509250532Seadler * 4k optimised & trim only works in 4k requests + 4k aligned 510250532Seadler */ 511251061Ssmh { T_DIRECT, SIP_MEDIA_FIXED, "*", "OCZ-AGILITY3*", "*" }, 512250532Seadler /*quirks*/ADA_Q_4K 513250532Seadler }, 514250532Seadler { 515250532Seadler /* 516241784Seadler * OCZ Deneva R Series SSDs 517241784Seadler * 4k optimised & trim only works in 4k requests + 4k aligned 518241784Seadler */ 519241784Seadler { T_DIRECT, SIP_MEDIA_FIXED, "*", "DENRSTE251M45*", "*" }, 520241784Seadler /*quirks*/ADA_Q_4K 521241784Seadler }, 522241784Seadler { 523241784Seadler /* 524251061Ssmh * OCZ Vertex 2 SSDs (inc pro series) 525241784Seadler * 4k optimised & trim only works in 4k requests + 4k aligned 526241784Seadler */ 527251061Ssmh { T_DIRECT, SIP_MEDIA_FIXED, "*", "OCZ?VERTEX2*", "*" }, 528241784Seadler /*quirks*/ADA_Q_4K 529241784Seadler }, 530241784Seadler { 531251061Ssmh /* 532251061Ssmh * OCZ Vertex 3 SSDs 533251061Ssmh * 4k optimised & trim only works in 4k requests + 4k aligned 534251061Ssmh */ 535251061Ssmh { T_DIRECT, SIP_MEDIA_FIXED, "*", "OCZ-VERTEX3*", "*" }, 536251061Ssmh /*quirks*/ADA_Q_4K 537251061Ssmh }, 538251061Ssmh { 539251061Ssmh /* 540253091Ssmh * OCZ Vertex 4 SSDs 541253091Ssmh * 4k optimised & trim only works in 4k requests + 4k aligned 542253091Ssmh */ 543253091Ssmh { T_DIRECT, SIP_MEDIA_FIXED, "*", "OCZ-VERTEX4*", "*" }, 544253091Ssmh /*quirks*/ADA_Q_4K 545253091Ssmh }, 546253091Ssmh { 547253091Ssmh /* 548251061Ssmh * Samsung 830 Series SSDs 549298002Simp * 4k optimised, NCQ TRIM Broken (normal TRIM is fine) 550251061Ssmh */ 551251061Ssmh { T_DIRECT, SIP_MEDIA_FIXED, "*", "SAMSUNG SSD 830 Series*", "*" }, 552298002Simp /*quirks*/ADA_Q_4K | ADA_Q_NCQ_TRIM_BROKEN 553251061Ssmh }, 554251061Ssmh { 555251061Ssmh /* 556269974Ssmh * Samsung 840 SSDs 557298002Simp * 4k optimised, NCQ TRIM Broken (normal TRIM is fine) 558269974Ssmh */ 559269974Ssmh { T_DIRECT, SIP_MEDIA_FIXED, "*", "Samsung SSD 840*", "*" }, 560298002Simp /*quirks*/ADA_Q_4K | ADA_Q_NCQ_TRIM_BROKEN 561269974Ssmh }, 562269974Ssmh { 563269974Ssmh /* 564273279Sgnn * Samsung 850 SSDs 565298002Simp * 4k optimised, NCQ TRIM broken (normal TRIM fine) 566273279Sgnn */ 567273279Sgnn { T_DIRECT, SIP_MEDIA_FIXED, "*", "Samsung SSD 850*", "*" }, 568298002Simp /*quirks*/ADA_Q_4K | ADA_Q_NCQ_TRIM_BROKEN 569273279Sgnn }, 570270305Ssbruno { 571270305Ssbruno /* 572298035Simp * Samsung SM863 Series SSDs (MZ7KM*) 573298035Simp * 4k optimised, NCQ believed to be working 574298035Simp */ 575298035Simp { T_DIRECT, SIP_MEDIA_FIXED, "*", "SAMSUNG MZ7KM*", "*" }, 576298035Simp /*quirks*/ADA_Q_4K 577298035Simp }, 578298035Simp { 579298035Simp /* 580297370Sdumbbell * Samsung 843T Series SSDs (MZ7WD*) 581297370Sdumbbell * Samsung PM851 Series SSDs (MZ7TE*) 582297370Sdumbbell * Samsung PM853T Series SSDs (MZ7GE*) 583298035Simp * 4k optimised, NCQ believed to be broken since these are 584298035Simp * appear to be built with the same controllers as the 840/850. 585273183Ssbruno */ 586297370Sdumbbell { T_DIRECT, SIP_MEDIA_FIXED, "*", "SAMSUNG MZ7*", "*" }, 587298035Simp /*quirks*/ADA_Q_4K | ADA_Q_NCQ_TRIM_BROKEN 588273183Ssbruno }, 589273183Ssbruno { 590273183Ssbruno /* 591251061Ssmh * SuperTalent TeraDrive CT SSDs 592251061Ssmh * 4k optimised & trim only works in 4k requests + 4k aligned 593251061Ssmh */ 594251061Ssmh { T_DIRECT, SIP_MEDIA_FIXED, "*", "FTM??CT25H*", "*" }, 595251061Ssmh /*quirks*/ADA_Q_4K 596251061Ssmh }, 597251061Ssmh { 598251061Ssmh /* 599251061Ssmh * XceedIOPS SATA SSDs 600251061Ssmh * 4k optimised 601251061Ssmh */ 602251061Ssmh { T_DIRECT, SIP_MEDIA_FIXED, "*", "SG9XCS2D*", "*" }, 603251061Ssmh /*quirks*/ADA_Q_4K 604251061Ssmh }, 605251061Ssmh { 606199178Smav /* Default */ 607199178Smav { 608199178Smav T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED, 609199178Smav /*vendor*/"*", /*product*/"*", /*revision*/"*" 610199178Smav }, 611199178Smav /*quirks*/0 612199178Smav }, 613199178Smav}; 614195534Sscottl 615195534Sscottlstatic disk_strategy_t adastrategy; 616195534Sscottlstatic dumper_t adadump; 617195534Sscottlstatic periph_init_t adainit; 618195534Sscottlstatic void adaasync(void *callback_arg, u_int32_t code, 619195534Sscottl struct cam_path *path, void *arg); 620195534Sscottlstatic void adasysctlinit(void *context, int pending); 621195534Sscottlstatic periph_ctor_t adaregister; 622195534Sscottlstatic periph_dtor_t adacleanup; 623195534Sscottlstatic periph_start_t adastart; 624195534Sscottlstatic periph_oninv_t adaoninvalidate; 625195534Sscottlstatic void adadone(struct cam_periph *periph, 626195534Sscottl union ccb *done_ccb); 627195534Sscottlstatic int adaerror(union ccb *ccb, u_int32_t cam_flags, 628195534Sscottl u_int32_t sense_flags); 629198897Smavstatic void adagetparams(struct cam_periph *periph, 630195534Sscottl struct ccb_getdev *cgd); 631195534Sscottlstatic timeout_t adasendorderedtag; 632195534Sscottlstatic void adashutdown(void *arg, int howto); 633220650Smavstatic void adasuspend(void *arg); 634220650Smavstatic void adaresume(void *arg); 635195534Sscottl 636221071Smav#ifndef ADA_DEFAULT_LEGACY_ALIASES 637221071Smav#define ADA_DEFAULT_LEGACY_ALIASES 1 638221071Smav#endif 639221071Smav 640195534Sscottl#ifndef ADA_DEFAULT_TIMEOUT 641195534Sscottl#define ADA_DEFAULT_TIMEOUT 30 /* Timeout in seconds */ 642195534Sscottl#endif 643195534Sscottl 644195534Sscottl#ifndef ADA_DEFAULT_RETRY 645195534Sscottl#define ADA_DEFAULT_RETRY 4 646195534Sscottl#endif 647195534Sscottl 648195534Sscottl#ifndef ADA_DEFAULT_SEND_ORDERED 649195534Sscottl#define ADA_DEFAULT_SEND_ORDERED 1 650195534Sscottl#endif 651195534Sscottl 652214279Sbrucec#ifndef ADA_DEFAULT_SPINDOWN_SHUTDOWN 653214279Sbrucec#define ADA_DEFAULT_SPINDOWN_SHUTDOWN 1 654214279Sbrucec#endif 655214279Sbrucec 656220650Smav#ifndef ADA_DEFAULT_SPINDOWN_SUSPEND 657220650Smav#define ADA_DEFAULT_SPINDOWN_SUSPEND 1 658220650Smav#endif 659220650Smav 660224497Smav#ifndef ADA_DEFAULT_READ_AHEAD 661224497Smav#define ADA_DEFAULT_READ_AHEAD 1 662224497Smav#endif 663224497Smav 664220412Smav#ifndef ADA_DEFAULT_WRITE_CACHE 665220412Smav#define ADA_DEFAULT_WRITE_CACHE 1 666220412Smav#endif 667220412Smav 668224497Smav#define ADA_RA (softc->read_ahead >= 0 ? \ 669224497Smav softc->read_ahead : ada_read_ahead) 670224497Smav#define ADA_WC (softc->write_cache >= 0 ? \ 671224497Smav softc->write_cache : ada_write_cache) 672224497Smav 673208349Smarius/* 674208349Smarius * Most platforms map firmware geometry to actual, but some don't. If 675208349Smarius * not overridden, default to nothing. 676208349Smarius */ 677208349Smarius#ifndef ata_disk_firmware_geom_adjust 678208349Smarius#define ata_disk_firmware_geom_adjust(disk) 679208349Smarius#endif 680195534Sscottl 681195534Sscottlstatic int ada_retry_count = ADA_DEFAULT_RETRY; 682195534Sscottlstatic int ada_default_timeout = ADA_DEFAULT_TIMEOUT; 683195534Sscottlstatic int ada_send_ordered = ADA_DEFAULT_SEND_ORDERED; 684214279Sbrucecstatic int ada_spindown_shutdown = ADA_DEFAULT_SPINDOWN_SHUTDOWN; 685220650Smavstatic int ada_spindown_suspend = ADA_DEFAULT_SPINDOWN_SUSPEND; 686224497Smavstatic int ada_read_ahead = ADA_DEFAULT_READ_AHEAD; 687220412Smavstatic int ada_write_cache = ADA_DEFAULT_WRITE_CACHE; 688195534Sscottl 689227309Sedstatic SYSCTL_NODE(_kern_cam, OID_AUTO, ada, CTLFLAG_RD, 0, 690195534Sscottl "CAM Direct Access Disk driver"); 691267992ShselaskySYSCTL_INT(_kern_cam_ada, OID_AUTO, retry_count, CTLFLAG_RWTUN, 692195534Sscottl &ada_retry_count, 0, "Normal I/O retry count"); 693267992ShselaskySYSCTL_INT(_kern_cam_ada, OID_AUTO, default_timeout, CTLFLAG_RWTUN, 694195534Sscottl &ada_default_timeout, 0, "Normal I/O timeout (in seconds)"); 695267992ShselaskySYSCTL_INT(_kern_cam_ada, OID_AUTO, send_ordered, CTLFLAG_RWTUN, 696195534Sscottl &ada_send_ordered, 0, "Send Ordered Tags"); 697267992ShselaskySYSCTL_INT(_kern_cam_ada, OID_AUTO, spindown_shutdown, CTLFLAG_RWTUN, 698214279Sbrucec &ada_spindown_shutdown, 0, "Spin down upon shutdown"); 699267992ShselaskySYSCTL_INT(_kern_cam_ada, OID_AUTO, spindown_suspend, CTLFLAG_RWTUN, 700220650Smav &ada_spindown_suspend, 0, "Spin down upon suspend"); 701267992ShselaskySYSCTL_INT(_kern_cam_ada, OID_AUTO, read_ahead, CTLFLAG_RWTUN, 702224497Smav &ada_read_ahead, 0, "Enable disk read-ahead"); 703267992ShselaskySYSCTL_INT(_kern_cam_ada, OID_AUTO, write_cache, CTLFLAG_RWTUN, 704220412Smav &ada_write_cache, 0, "Enable disk write cache"); 705195534Sscottl 706195534Sscottl/* 707195534Sscottl * ADA_ORDEREDTAG_INTERVAL determines how often, relative 708195534Sscottl * to the default timeout, we check to see whether an ordered 709195534Sscottl * tagged transaction is appropriate to prevent simple tag 710195534Sscottl * starvation. Since we'd like to ensure that there is at least 711195534Sscottl * 1/2 of the timeout length left for a starved transaction to 712195534Sscottl * complete after we've sent an ordered tag, we must poll at least 713195534Sscottl * four times in every timeout period. This takes care of the worst 714195534Sscottl * case where a starved transaction starts during an interval that 715195534Sscottl * meets the requirement "don't send an ordered tag" test so it takes 716195534Sscottl * us two intervals to determine that a tag must be sent. 717195534Sscottl */ 718195534Sscottl#ifndef ADA_ORDEREDTAG_INTERVAL 719195534Sscottl#define ADA_ORDEREDTAG_INTERVAL 4 720195534Sscottl#endif 721195534Sscottl 722195534Sscottlstatic struct periph_driver adadriver = 723195534Sscottl{ 724195534Sscottl adainit, "ada", 725195534Sscottl TAILQ_HEAD_INITIALIZER(adadriver.units), /* generation */ 0 726195534Sscottl}; 727195534Sscottl 728298002Simpstatic int adadeletemethodsysctl(SYSCTL_HANDLER_ARGS); 729298002Simp 730195534SscottlPERIPHDRIVER_DECLARE(ada, adadriver); 731195534Sscottl 732195534Sscottlstatic int 733195534Sscottladaopen(struct disk *dp) 734195534Sscottl{ 735195534Sscottl struct cam_periph *periph; 736195534Sscottl struct ada_softc *softc; 737195534Sscottl int error; 738195534Sscottl 739195534Sscottl periph = (struct cam_periph *)dp->d_drv1; 740195534Sscottl if (cam_periph_acquire(periph) != CAM_REQ_CMP) { 741195534Sscottl return(ENXIO); 742195534Sscottl } 743195534Sscottl 744195534Sscottl cam_periph_lock(periph); 745195534Sscottl if ((error = cam_periph_hold(periph, PRIBIO|PCATCH)) != 0) { 746195534Sscottl cam_periph_unlock(periph); 747195534Sscottl cam_periph_release(periph); 748195534Sscottl return (error); 749195534Sscottl } 750195534Sscottl 751236602Smav CAM_DEBUG(periph->path, CAM_DEBUG_TRACE | CAM_DEBUG_PERIPH, 752236602Smav ("adaopen\n")); 753195534Sscottl 754249981Smav softc = (struct ada_softc *)periph->softc; 755249981Smav softc->flags |= ADA_FLAG_OPEN; 756195534Sscottl 757195534Sscottl cam_periph_unhold(periph); 758195534Sscottl cam_periph_unlock(periph); 759195534Sscottl return (0); 760195534Sscottl} 761195534Sscottl 762195534Sscottlstatic int 763195534Sscottladaclose(struct disk *dp) 764195534Sscottl{ 765195534Sscottl struct cam_periph *periph; 766195534Sscottl struct ada_softc *softc; 767195534Sscottl union ccb *ccb; 768253724Smav int error; 769195534Sscottl 770195534Sscottl periph = (struct cam_periph *)dp->d_drv1; 771256843Smav softc = (struct ada_softc *)periph->softc; 772195534Sscottl cam_periph_lock(periph); 773195534Sscottl 774236602Smav CAM_DEBUG(periph->path, CAM_DEBUG_TRACE | CAM_DEBUG_PERIPH, 775236602Smav ("adaclose\n")); 776236602Smav 777195534Sscottl /* We only sync the cache if the drive is capable of it. */ 778253724Smav if ((softc->flags & ADA_FLAG_DIRTY) != 0 && 779253724Smav (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) != 0 && 780256843Smav (periph->flags & CAM_PERIPH_INVALID) == 0 && 781256843Smav cam_periph_hold(periph, PRIBIO) == 0) { 782195534Sscottl 783198382Smav ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 784195534Sscottl cam_fill_ataio(&ccb->ataio, 785195534Sscottl 1, 786195534Sscottl adadone, 787195534Sscottl CAM_DIR_NONE, 788195534Sscottl 0, 789195534Sscottl NULL, 790195534Sscottl 0, 791195534Sscottl ada_default_timeout*1000); 792195534Sscottl 793195534Sscottl if (softc->flags & ADA_FLAG_CAN_48BIT) 794195534Sscottl ata_48bit_cmd(&ccb->ataio, ATA_FLUSHCACHE48, 0, 0, 0); 795195534Sscottl else 796196659Smav ata_28bit_cmd(&ccb->ataio, ATA_FLUSHCACHE, 0, 0, 0); 797253724Smav error = cam_periph_runccb(ccb, adaerror, /*cam_flags*/0, 798198328Smav /*sense_flags*/0, softc->disk->d_devstat); 799195534Sscottl 800253724Smav if (error != 0) 801195534Sscottl xpt_print(periph->path, "Synchronize cache failed\n"); 802253724Smav else 803253724Smav softc->flags &= ~ADA_FLAG_DIRTY; 804195534Sscottl xpt_release_ccb(ccb); 805256843Smav cam_periph_unhold(periph); 806195534Sscottl } 807195534Sscottl 808195534Sscottl softc->flags &= ~ADA_FLAG_OPEN; 809256843Smav 810256843Smav while (softc->refcount != 0) 811256843Smav cam_periph_sleep(periph, &softc->refcount, PRIBIO, "adaclose", 1); 812195534Sscottl cam_periph_unlock(periph); 813195534Sscottl cam_periph_release(periph); 814195534Sscottl return (0); 815195534Sscottl} 816195534Sscottl 817201139Smavstatic void 818201139Smavadaschedule(struct cam_periph *periph) 819201139Smav{ 820201139Smav struct ada_softc *softc = (struct ada_softc *)periph->softc; 821201139Smav 822249205Smav if (softc->state != ADA_STATE_NORMAL) 823249205Smav return; 824249205Smav 825298002Simp cam_iosched_schedule(softc->cam_iosched, periph); 826201139Smav} 827201139Smav 828195534Sscottl/* 829195534Sscottl * Actually translate the requested transfer into one the physical driver 830195534Sscottl * can understand. The transfer is described by a buf and will include 831195534Sscottl * only one physical transfer. 832195534Sscottl */ 833195534Sscottlstatic void 834195534Sscottladastrategy(struct bio *bp) 835195534Sscottl{ 836195534Sscottl struct cam_periph *periph; 837195534Sscottl struct ada_softc *softc; 838195534Sscottl 839195534Sscottl periph = (struct cam_periph *)bp->bio_disk->d_drv1; 840195534Sscottl softc = (struct ada_softc *)periph->softc; 841195534Sscottl 842195534Sscottl cam_periph_lock(periph); 843195534Sscottl 844236602Smav CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("adastrategy(%p)\n", bp)); 845236602Smav 846195534Sscottl /* 847195534Sscottl * If the device has been made invalid, error out 848195534Sscottl */ 849249981Smav if ((periph->flags & CAM_PERIPH_INVALID) != 0) { 850195534Sscottl cam_periph_unlock(periph); 851195534Sscottl biofinish(bp, NULL, ENXIO); 852195534Sscottl return; 853195534Sscottl } 854195534Sscottl 855195534Sscottl /* 856195534Sscottl * Place it in the queue of disk activities for this disk 857195534Sscottl */ 858298002Simp cam_iosched_queue_work(softc->cam_iosched, bp); 859195534Sscottl 860195534Sscottl /* 861195534Sscottl * Schedule ourselves for performing the work. 862195534Sscottl */ 863201139Smav adaschedule(periph); 864195534Sscottl cam_periph_unlock(periph); 865195534Sscottl 866195534Sscottl return; 867195534Sscottl} 868195534Sscottl 869195534Sscottlstatic int 870195534Sscottladadump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t length) 871195534Sscottl{ 872195534Sscottl struct cam_periph *periph; 873195534Sscottl struct ada_softc *softc; 874195534Sscottl u_int secsize; 875195534Sscottl union ccb ccb; 876195534Sscottl struct disk *dp; 877195534Sscottl uint64_t lba; 878195534Sscottl uint16_t count; 879236814Smav int error = 0; 880195534Sscottl 881195534Sscottl dp = arg; 882195534Sscottl periph = dp->d_drv1; 883195534Sscottl softc = (struct ada_softc *)periph->softc; 884195534Sscottl cam_periph_lock(periph); 885195534Sscottl secsize = softc->params.secsize; 886195534Sscottl lba = offset / secsize; 887195534Sscottl count = length / secsize; 888195534Sscottl 889249981Smav if ((periph->flags & CAM_PERIPH_INVALID) != 0) { 890195534Sscottl cam_periph_unlock(periph); 891195534Sscottl return (ENXIO); 892195534Sscottl } 893195534Sscottl 894195534Sscottl if (length > 0) { 895198382Smav xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 896195534Sscottl ccb.ccb_h.ccb_state = ADA_CCB_DUMP; 897195534Sscottl cam_fill_ataio(&ccb.ataio, 898195534Sscottl 0, 899195534Sscottl adadone, 900195534Sscottl CAM_DIR_OUT, 901195534Sscottl 0, 902195534Sscottl (u_int8_t *) virtual, 903195534Sscottl length, 904195534Sscottl ada_default_timeout*1000); 905195534Sscottl if ((softc->flags & ADA_FLAG_CAN_48BIT) && 906195534Sscottl (lba + count >= ATA_MAX_28BIT_LBA || 907195534Sscottl count >= 256)) { 908195534Sscottl ata_48bit_cmd(&ccb.ataio, ATA_WRITE_DMA48, 909195534Sscottl 0, lba, count); 910195534Sscottl } else { 911196659Smav ata_28bit_cmd(&ccb.ataio, ATA_WRITE_DMA, 912195534Sscottl 0, lba, count); 913195534Sscottl } 914195534Sscottl xpt_polled_action(&ccb); 915195534Sscottl 916236814Smav error = cam_periph_error(&ccb, 917236814Smav 0, SF_NO_RECOVERY | SF_NO_RETRY, NULL); 918236814Smav if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0) 919236814Smav cam_release_devq(ccb.ccb_h.path, /*relsim_flags*/0, 920236814Smav /*reduction*/0, /*timeout*/0, /*getcount_only*/0); 921236814Smav if (error != 0) 922195534Sscottl printf("Aborting dump due to I/O error.\n"); 923236814Smav 924195534Sscottl cam_periph_unlock(periph); 925236814Smav return (error); 926195534Sscottl } 927195534Sscottl 928195534Sscottl if (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) { 929198382Smav xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 930195534Sscottl 931298011Simp /* 932298023Sngie * Tell the drive to flush its internal cache. if we 933298011Simp * can't flush in 5s we have big problems. No need to 934298011Simp * wait the default 60s to detect problems. 935298011Simp */ 936195534Sscottl ccb.ccb_h.ccb_state = ADA_CCB_DUMP; 937195534Sscottl cam_fill_ataio(&ccb.ataio, 938236814Smav 0, 939195534Sscottl adadone, 940195534Sscottl CAM_DIR_NONE, 941195534Sscottl 0, 942195534Sscottl NULL, 943195534Sscottl 0, 944298002Simp 5*1000); 945195534Sscottl 946195534Sscottl if (softc->flags & ADA_FLAG_CAN_48BIT) 947195534Sscottl ata_48bit_cmd(&ccb.ataio, ATA_FLUSHCACHE48, 0, 0, 0); 948195534Sscottl else 949196659Smav ata_28bit_cmd(&ccb.ataio, ATA_FLUSHCACHE, 0, 0, 0); 950195534Sscottl xpt_polled_action(&ccb); 951195534Sscottl 952236814Smav error = cam_periph_error(&ccb, 953236814Smav 0, SF_NO_RECOVERY | SF_NO_RETRY, NULL); 954236814Smav if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0) 955236814Smav cam_release_devq(ccb.ccb_h.path, /*relsim_flags*/0, 956236814Smav /*reduction*/0, /*timeout*/0, /*getcount_only*/0); 957236814Smav if (error != 0) 958195534Sscottl xpt_print(periph->path, "Synchronize cache failed\n"); 959195534Sscottl } 960195534Sscottl cam_periph_unlock(periph); 961236814Smav return (error); 962195534Sscottl} 963195534Sscottl 964195534Sscottlstatic void 965195534Sscottladainit(void) 966195534Sscottl{ 967195534Sscottl cam_status status; 968195534Sscottl 969195534Sscottl /* 970195534Sscottl * Install a global async callback. This callback will 971195534Sscottl * receive async callbacks like "new device found". 972195534Sscottl */ 973195534Sscottl status = xpt_register_async(AC_FOUND_DEVICE, adaasync, NULL, NULL); 974195534Sscottl 975195534Sscottl if (status != CAM_REQ_CMP) { 976195534Sscottl printf("ada: Failed to attach master async callback " 977195534Sscottl "due to status 0x%x!\n", status); 978195534Sscottl } else if (ada_send_ordered) { 979195534Sscottl 980220650Smav /* Register our event handlers */ 981220650Smav if ((EVENTHANDLER_REGISTER(power_suspend, adasuspend, 982220650Smav NULL, EVENTHANDLER_PRI_LAST)) == NULL) 983220650Smav printf("adainit: power event registration failed!\n"); 984220650Smav if ((EVENTHANDLER_REGISTER(power_resume, adaresume, 985220650Smav NULL, EVENTHANDLER_PRI_LAST)) == NULL) 986220650Smav printf("adainit: power event registration failed!\n"); 987220650Smav if ((EVENTHANDLER_REGISTER(shutdown_post_sync, adashutdown, 988195534Sscottl NULL, SHUTDOWN_PRI_DEFAULT)) == NULL) 989195534Sscottl printf("adainit: shutdown event registration failed!\n"); 990195534Sscottl } 991195534Sscottl} 992195534Sscottl 993249347Sken/* 994249347Sken * Callback from GEOM, called when it has finished cleaning up its 995249347Sken * resources. 996249347Sken */ 997195534Sscottlstatic void 998249347Skenadadiskgonecb(struct disk *dp) 999249347Sken{ 1000249347Sken struct cam_periph *periph; 1001249347Sken 1002249347Sken periph = (struct cam_periph *)dp->d_drv1; 1003249347Sken 1004249347Sken cam_periph_release(periph); 1005249347Sken} 1006249347Sken 1007249347Skenstatic void 1008195534Sscottladaoninvalidate(struct cam_periph *periph) 1009195534Sscottl{ 1010195534Sscottl struct ada_softc *softc; 1011195534Sscottl 1012195534Sscottl softc = (struct ada_softc *)periph->softc; 1013195534Sscottl 1014195534Sscottl /* 1015195534Sscottl * De-register any async callbacks. 1016195534Sscottl */ 1017195534Sscottl xpt_register_async(0, adaasync, periph, periph->path); 1018298002Simp#ifdef CAM_IO_STATS 1019298002Simp softc->invalidations++; 1020298002Simp#endif 1021195534Sscottl 1022195534Sscottl /* 1023195534Sscottl * Return all queued I/O with ENXIO. 1024195534Sscottl * XXX Handle any transactions queued to the card 1025195534Sscottl * with XPT_ABORT_CCB. 1026195534Sscottl */ 1027298002Simp cam_iosched_flush(softc->cam_iosched, NULL, ENXIO); 1028195534Sscottl 1029195534Sscottl disk_gone(softc->disk); 1030195534Sscottl} 1031195534Sscottl 1032195534Sscottlstatic void 1033195534Sscottladacleanup(struct cam_periph *periph) 1034195534Sscottl{ 1035195534Sscottl struct ada_softc *softc; 1036195534Sscottl 1037195534Sscottl softc = (struct ada_softc *)periph->softc; 1038195534Sscottl 1039195534Sscottl cam_periph_unlock(periph); 1040195534Sscottl 1041298002Simp cam_iosched_fini(softc->cam_iosched); 1042298002Simp 1043195534Sscottl /* 1044195534Sscottl * If we can't free the sysctl tree, oh well... 1045195534Sscottl */ 1046298002Simp if ((softc->flags & ADA_FLAG_SCTX_INIT) != 0) { 1047298002Simp#ifdef CAM_IO_STATS 1048298002Simp if (sysctl_ctx_free(&softc->sysctl_stats_ctx) != 0) 1049298002Simp xpt_print(periph->path, 1050298002Simp "can't remove sysctl stats context\n"); 1051298002Simp#endif 1052298002Simp if (sysctl_ctx_free(&softc->sysctl_ctx) != 0) 1053298002Simp xpt_print(periph->path, 1054298002Simp "can't remove sysctl context\n"); 1055195534Sscottl } 1056195534Sscottl 1057195534Sscottl disk_destroy(softc->disk); 1058195534Sscottl callout_drain(&softc->sendordered_c); 1059195534Sscottl free(softc, M_DEVBUF); 1060195534Sscottl cam_periph_lock(periph); 1061195534Sscottl} 1062195534Sscottl 1063195534Sscottlstatic void 1064298002Simpadasetdeletemethod(struct ada_softc *softc) 1065298002Simp{ 1066298002Simp 1067298002Simp if (softc->flags & ADA_FLAG_CAN_NCQ_TRIM) 1068298002Simp softc->delete_method = ADA_DELETE_NCQ_DSM_TRIM; 1069298002Simp else if (softc->flags & ADA_FLAG_CAN_TRIM) 1070298002Simp softc->delete_method = ADA_DELETE_DSM_TRIM; 1071298002Simp else if ((softc->flags & ADA_FLAG_CAN_CFA) && !(softc->flags & ADA_FLAG_CAN_48BIT)) 1072298002Simp softc->delete_method = ADA_DELETE_CFA_ERASE; 1073298002Simp else 1074298002Simp softc->delete_method = ADA_DELETE_NONE; 1075298002Simp} 1076298002Simp 1077298002Simpstatic void 1078195534Sscottladaasync(void *callback_arg, u_int32_t code, 1079195534Sscottl struct cam_path *path, void *arg) 1080195534Sscottl{ 1081236393Smav struct ccb_getdev cgd; 1082195534Sscottl struct cam_periph *periph; 1083220412Smav struct ada_softc *softc; 1084195534Sscottl 1085195534Sscottl periph = (struct cam_periph *)callback_arg; 1086195534Sscottl switch (code) { 1087195534Sscottl case AC_FOUND_DEVICE: 1088195534Sscottl { 1089195534Sscottl struct ccb_getdev *cgd; 1090195534Sscottl cam_status status; 1091195534Sscottl 1092195534Sscottl cgd = (struct ccb_getdev *)arg; 1093195534Sscottl if (cgd == NULL) 1094195534Sscottl break; 1095195534Sscottl 1096195534Sscottl if (cgd->protocol != PROTO_ATA) 1097195534Sscottl break; 1098195534Sscottl 1099195534Sscottl /* 1100195534Sscottl * Allocate a peripheral instance for 1101195534Sscottl * this device and start the probe 1102195534Sscottl * process. 1103195534Sscottl */ 1104195534Sscottl status = cam_periph_alloc(adaregister, adaoninvalidate, 1105195534Sscottl adacleanup, adastart, 1106195534Sscottl "ada", CAM_PERIPH_BIO, 1107256843Smav path, adaasync, 1108195534Sscottl AC_FOUND_DEVICE, cgd); 1109195534Sscottl 1110195534Sscottl if (status != CAM_REQ_CMP 1111195534Sscottl && status != CAM_REQ_INPROG) 1112195534Sscottl printf("adaasync: Unable to attach to new device " 1113195534Sscottl "due to status 0x%x\n", status); 1114195534Sscottl break; 1115195534Sscottl } 1116236393Smav case AC_GETDEV_CHANGED: 1117236393Smav { 1118236393Smav softc = (struct ada_softc *)periph->softc; 1119236393Smav xpt_setup_ccb(&cgd.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 1120236393Smav cgd.ccb_h.func_code = XPT_GDEV_TYPE; 1121236393Smav xpt_action((union ccb *)&cgd); 1122236393Smav 1123236393Smav if ((cgd.ident_data.capabilities1 & ATA_SUPPORT_DMA) && 1124236393Smav (cgd.inq_flags & SID_DMA)) 1125236393Smav softc->flags |= ADA_FLAG_CAN_DMA; 1126236393Smav else 1127236393Smav softc->flags &= ~ADA_FLAG_CAN_DMA; 1128249199Smarius if (cgd.ident_data.support.command2 & ATA_SUPPORT_ADDRESS48) { 1129249199Smarius softc->flags |= ADA_FLAG_CAN_48BIT; 1130249199Smarius if (cgd.inq_flags & SID_DMA48) 1131249199Smarius softc->flags |= ADA_FLAG_CAN_DMA48; 1132249199Smarius else 1133249199Smarius softc->flags &= ~ADA_FLAG_CAN_DMA48; 1134249199Smarius } else 1135249199Smarius softc->flags &= ~(ADA_FLAG_CAN_48BIT | 1136249199Smarius ADA_FLAG_CAN_DMA48); 1137236393Smav if ((cgd.ident_data.satacapabilities & ATA_SUPPORT_NCQ) && 1138236393Smav (cgd.inq_flags & SID_DMA) && (cgd.inq_flags & SID_CmdQue)) 1139236393Smav softc->flags |= ADA_FLAG_CAN_NCQ; 1140236393Smav else 1141236393Smav softc->flags &= ~ADA_FLAG_CAN_NCQ; 1142298002Simp 1143236393Smav if ((cgd.ident_data.support_dsm & ATA_SUPPORT_DSM_TRIM) && 1144298002Simp (cgd.inq_flags & SID_DMA)) { 1145236393Smav softc->flags |= ADA_FLAG_CAN_TRIM; 1146298002Simp /* 1147298002Simp * If we can do RCVSND_FPDMA_QUEUED commands, we may be able to do 1148298002Simp * NCQ trims, if we support trims at all. We also need support from 1149298002Simp * the sim do do things properly. Perhaps we should look at log 13 1150298002Simp * dword 0 bit 0 and dword 1 bit 0 are set too... 1151298002Simp */ 1152298002Simp if ((softc->quirks & ADA_Q_NCQ_TRIM_BROKEN) == 0 && 1153298002Simp (softc->flags & ADA_FLAG_PIM_CAN_NCQ_TRIM) != 0 && 1154298002Simp (cgd.ident_data.satacapabilities2 & ATA_SUPPORT_RCVSND_FPDMA_QUEUED) != 0 && 1155298002Simp (softc->flags & ADA_FLAG_CAN_TRIM) != 0) 1156298002Simp softc->flags |= ADA_FLAG_CAN_NCQ_TRIM; 1157298002Simp else 1158298002Simp softc->flags &= ~ADA_FLAG_CAN_NCQ_TRIM; 1159298002Simp } else 1160298002Simp softc->flags &= ~(ADA_FLAG_CAN_TRIM | ADA_FLAG_CAN_NCQ_TRIM); 1161298002Simp adasetdeletemethod(softc); 1162236393Smav 1163236393Smav cam_periph_async(periph, code, path, arg); 1164236393Smav break; 1165236393Smav } 1166235897Smav case AC_ADVINFO_CHANGED: 1167235897Smav { 1168235897Smav uintptr_t buftype; 1169235897Smav 1170235897Smav buftype = (uintptr_t)arg; 1171235897Smav if (buftype == CDAI_TYPE_PHYS_PATH) { 1172235897Smav struct ada_softc *softc; 1173235897Smav 1174235897Smav softc = periph->softc; 1175235897Smav disk_attr_changed(softc->disk, "GEOM::physpath", 1176235897Smav M_NOWAIT); 1177235897Smav } 1178235897Smav break; 1179235897Smav } 1180220412Smav case AC_SENT_BDR: 1181220412Smav case AC_BUS_RESET: 1182220412Smav { 1183220412Smav softc = (struct ada_softc *)periph->softc; 1184220412Smav cam_periph_async(periph, code, path, arg); 1185220412Smav if (softc->state != ADA_STATE_NORMAL) 1186220412Smav break; 1187220454Smav xpt_setup_ccb(&cgd.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 1188220412Smav cgd.ccb_h.func_code = XPT_GDEV_TYPE; 1189220412Smav xpt_action((union ccb *)&cgd); 1190224497Smav if (ADA_RA >= 0 && 1191224497Smav cgd.ident_data.support.command1 & ATA_SUPPORT_LOOKAHEAD) 1192224497Smav softc->state = ADA_STATE_RAHEAD; 1193224497Smav else if (ADA_WC >= 0 && 1194224497Smav cgd.ident_data.support.command1 & ATA_SUPPORT_WRITECACHE) 1195224497Smav softc->state = ADA_STATE_WCACHE; 1196224497Smav else 1197224497Smav break; 1198256843Smav if (cam_periph_acquire(periph) != CAM_REQ_CMP) 1199256843Smav softc->state = ADA_STATE_NORMAL; 1200256843Smav else 1201256843Smav xpt_schedule(periph, CAM_PRIORITY_DEV); 1202220412Smav } 1203195534Sscottl default: 1204195534Sscottl cam_periph_async(periph, code, path, arg); 1205195534Sscottl break; 1206195534Sscottl } 1207195534Sscottl} 1208195534Sscottl 1209195534Sscottlstatic void 1210195534Sscottladasysctlinit(void *context, int pending) 1211195534Sscottl{ 1212195534Sscottl struct cam_periph *periph; 1213195534Sscottl struct ada_softc *softc; 1214195534Sscottl char tmpstr[80], tmpstr2[80]; 1215195534Sscottl 1216195534Sscottl periph = (struct cam_periph *)context; 1217220454Smav 1218220454Smav /* periph was held for us when this task was enqueued */ 1219249981Smav if ((periph->flags & CAM_PERIPH_INVALID) != 0) { 1220220454Smav cam_periph_release(periph); 1221195534Sscottl return; 1222220454Smav } 1223195534Sscottl 1224195534Sscottl softc = (struct ada_softc *)periph->softc; 1225195534Sscottl snprintf(tmpstr, sizeof(tmpstr), "CAM ADA unit %d", periph->unit_number); 1226195534Sscottl snprintf(tmpstr2, sizeof(tmpstr2), "%d", periph->unit_number); 1227195534Sscottl 1228195534Sscottl sysctl_ctx_init(&softc->sysctl_ctx); 1229195534Sscottl softc->flags |= ADA_FLAG_SCTX_INIT; 1230195534Sscottl softc->sysctl_tree = SYSCTL_ADD_NODE(&softc->sysctl_ctx, 1231195534Sscottl SYSCTL_STATIC_CHILDREN(_kern_cam_ada), OID_AUTO, tmpstr2, 1232195534Sscottl CTLFLAG_RD, 0, tmpstr); 1233195534Sscottl if (softc->sysctl_tree == NULL) { 1234195534Sscottl printf("adasysctlinit: unable to allocate sysctl tree\n"); 1235195534Sscottl cam_periph_release(periph); 1236195534Sscottl return; 1237195534Sscottl } 1238195534Sscottl 1239298002Simp SYSCTL_ADD_PROC(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 1240298002Simp OID_AUTO, "delete_method", CTLTYPE_STRING | CTLFLAG_RW, 1241298002Simp softc, 0, adadeletemethodsysctl, "A", 1242298002Simp "BIO_DELETE execution method"); 1243220454Smav SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 1244224497Smav OID_AUTO, "read_ahead", CTLFLAG_RW | CTLFLAG_MPSAFE, 1245224497Smav &softc->read_ahead, 0, "Enable disk read ahead."); 1246224497Smav SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 1247220454Smav OID_AUTO, "write_cache", CTLFLAG_RW | CTLFLAG_MPSAFE, 1248220454Smav &softc->write_cache, 0, "Enable disk write cache."); 1249248922Ssmh SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 1250298002Simp OID_AUTO, "unmapped_io", CTLFLAG_RD | CTLFLAG_MPSAFE, 1251298002Simp &softc->unmappedio, 0, "Unmapped I/O leaf"); 1252298002Simp SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 1253298002Simp OID_AUTO, "rotating", CTLFLAG_RD | CTLFLAG_MPSAFE, 1254298002Simp &softc->rotating, 0, "Rotating media"); 1255220454Smav#ifdef ADA_TEST_FAILURE 1256220454Smav /* 1257220454Smav * Add a 'door bell' sysctl which allows one to set it from userland 1258220454Smav * and cause something bad to happen. For the moment, we only allow 1259220454Smav * whacking the next read or write. 1260220454Smav */ 1261220454Smav SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 1262220454Smav OID_AUTO, "force_read_error", CTLFLAG_RW | CTLFLAG_MPSAFE, 1263220454Smav &softc->force_read_error, 0, 1264220454Smav "Force a read error for the next N reads."); 1265220454Smav SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 1266220454Smav OID_AUTO, "force_write_error", CTLFLAG_RW | CTLFLAG_MPSAFE, 1267220454Smav &softc->force_write_error, 0, 1268220454Smav "Force a write error for the next N writes."); 1269220454Smav SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 1270220454Smav OID_AUTO, "periodic_read_error", CTLFLAG_RW | CTLFLAG_MPSAFE, 1271220454Smav &softc->periodic_read_error, 0, 1272220454Smav "Force a read error every N reads (don't set too low)."); 1273220454Smav#endif 1274298002Simp 1275298002Simp#ifdef CAM_IO_STATS 1276298002Simp softc->sysctl_stats_tree = SYSCTL_ADD_NODE(&softc->sysctl_stats_ctx, 1277298002Simp SYSCTL_CHILDREN(softc->sysctl_tree), OID_AUTO, "stats", 1278298002Simp CTLFLAG_RD, 0, "Statistics"); 1279298002Simp SYSCTL_ADD_INT(&softc->sysctl_stats_ctx, 1280298002Simp SYSCTL_CHILDREN(softc->sysctl_stats_tree), 1281298002Simp OID_AUTO, "timeouts", CTLFLAG_RD | CTLFLAG_MPSAFE, 1282298002Simp &softc->timeouts, 0, 1283298002Simp "Device timeouts reported by the SIM"); 1284298002Simp SYSCTL_ADD_INT(&softc->sysctl_stats_ctx, 1285298002Simp SYSCTL_CHILDREN(softc->sysctl_stats_tree), 1286298002Simp OID_AUTO, "errors", CTLFLAG_RD | CTLFLAG_MPSAFE, 1287298002Simp &softc->errors, 0, 1288298002Simp "Transport errors reported by the SIM."); 1289298002Simp SYSCTL_ADD_INT(&softc->sysctl_stats_ctx, 1290298002Simp SYSCTL_CHILDREN(softc->sysctl_stats_tree), 1291298002Simp OID_AUTO, "pack_invalidations", CTLFLAG_RD | CTLFLAG_MPSAFE, 1292298002Simp &softc->invalidations, 0, 1293298002Simp "Device pack invalidations."); 1294298002Simp#endif 1295298002Simp 1296298002Simp cam_iosched_sysctl_init(softc->cam_iosched, &softc->sysctl_ctx, 1297298002Simp softc->sysctl_tree); 1298298002Simp 1299195534Sscottl cam_periph_release(periph); 1300195534Sscottl} 1301195534Sscottl 1302223089Sgibbsstatic int 1303223089Sgibbsadagetattr(struct bio *bp) 1304223089Sgibbs{ 1305241485Smav int ret; 1306223089Sgibbs struct cam_periph *periph; 1307223089Sgibbs 1308223089Sgibbs periph = (struct cam_periph *)bp->bio_disk->d_drv1; 1309241485Smav cam_periph_lock(periph); 1310223089Sgibbs ret = xpt_getattr(bp->bio_data, bp->bio_length, bp->bio_attribute, 1311223089Sgibbs periph->path); 1312241485Smav cam_periph_unlock(periph); 1313223089Sgibbs if (ret == 0) 1314223089Sgibbs bp->bio_completed = bp->bio_length; 1315223089Sgibbs return ret; 1316223089Sgibbs} 1317223089Sgibbs 1318298002Simpstatic int 1319298002Simpadadeletemethodsysctl(SYSCTL_HANDLER_ARGS) 1320298002Simp{ 1321298002Simp char buf[16]; 1322298002Simp const char *p; 1323298002Simp struct ada_softc *softc; 1324298002Simp int i, error, value, methods; 1325298002Simp 1326298002Simp softc = (struct ada_softc *)arg1; 1327298002Simp 1328298002Simp value = softc->delete_method; 1329298002Simp if (value < 0 || value > ADA_DELETE_MAX) 1330298002Simp p = "UNKNOWN"; 1331298002Simp else 1332298002Simp p = ada_delete_method_names[value]; 1333298002Simp strncpy(buf, p, sizeof(buf)); 1334298002Simp error = sysctl_handle_string(oidp, buf, sizeof(buf), req); 1335298002Simp if (error != 0 || req->newptr == NULL) 1336298002Simp return (error); 1337298002Simp methods = 1 << ADA_DELETE_DISABLE; 1338298002Simp if ((softc->flags & ADA_FLAG_CAN_CFA) && 1339298002Simp !(softc->flags & ADA_FLAG_CAN_48BIT)) 1340298002Simp methods |= 1 << ADA_DELETE_CFA_ERASE; 1341298002Simp if (softc->flags & ADA_FLAG_CAN_TRIM) 1342298002Simp methods |= 1 << ADA_DELETE_DSM_TRIM; 1343298002Simp if (softc->flags & ADA_FLAG_CAN_NCQ_TRIM) 1344298002Simp methods |= 1 << ADA_DELETE_NCQ_DSM_TRIM; 1345298002Simp for (i = 0; i <= ADA_DELETE_MAX; i++) { 1346298002Simp if (!(methods & (1 << i)) || 1347298002Simp strcmp(buf, ada_delete_method_names[i]) != 0) 1348298002Simp continue; 1349298002Simp softc->delete_method = i; 1350298002Simp return (0); 1351298002Simp } 1352298002Simp return (EINVAL); 1353298002Simp} 1354298002Simp 1355195534Sscottlstatic cam_status 1356195534Sscottladaregister(struct cam_periph *periph, void *arg) 1357195534Sscottl{ 1358195534Sscottl struct ada_softc *softc; 1359195534Sscottl struct ccb_pathinq cpi; 1360195534Sscottl struct ccb_getdev *cgd; 1361289137Smav char announce_buf[80]; 1362195534Sscottl struct disk_params *dp; 1363195534Sscottl caddr_t match; 1364195534Sscottl u_int maxio; 1365289137Smav int quirks; 1366195534Sscottl 1367195534Sscottl cgd = (struct ccb_getdev *)arg; 1368195534Sscottl if (cgd == NULL) { 1369195534Sscottl printf("adaregister: no getdev CCB, can't register device\n"); 1370195534Sscottl return(CAM_REQ_CMP_ERR); 1371195534Sscottl } 1372195534Sscottl 1373195534Sscottl softc = (struct ada_softc *)malloc(sizeof(*softc), M_DEVBUF, 1374195534Sscottl M_NOWAIT|M_ZERO); 1375195534Sscottl 1376195534Sscottl if (softc == NULL) { 1377195534Sscottl printf("adaregister: Unable to probe new device. " 1378198328Smav "Unable to allocate softc\n"); 1379195534Sscottl return(CAM_REQ_CMP_ERR); 1380195534Sscottl } 1381195534Sscottl 1382298002Simp if (cam_iosched_init(&softc->cam_iosched, periph) != 0) { 1383298002Simp printf("adaregister: Unable to probe new device. " 1384298002Simp "Unable to allocate iosched memory\n"); 1385298002Simp return(CAM_REQ_CMP_ERR); 1386298002Simp } 1387195534Sscottl 1388236393Smav if ((cgd->ident_data.capabilities1 & ATA_SUPPORT_DMA) && 1389220886Smav (cgd->inq_flags & SID_DMA)) 1390198328Smav softc->flags |= ADA_FLAG_CAN_DMA; 1391249199Smarius if (cgd->ident_data.support.command2 & ATA_SUPPORT_ADDRESS48) { 1392195534Sscottl softc->flags |= ADA_FLAG_CAN_48BIT; 1393249199Smarius if (cgd->inq_flags & SID_DMA48) 1394249199Smarius softc->flags |= ADA_FLAG_CAN_DMA48; 1395249199Smarius } 1396195534Sscottl if (cgd->ident_data.support.command2 & ATA_SUPPORT_FLUSHCACHE) 1397195534Sscottl softc->flags |= ADA_FLAG_CAN_FLUSHCACHE; 1398214279Sbrucec if (cgd->ident_data.support.command1 & ATA_SUPPORT_POWERMGT) 1399214279Sbrucec softc->flags |= ADA_FLAG_CAN_POWERMGT; 1400236393Smav if ((cgd->ident_data.satacapabilities & ATA_SUPPORT_NCQ) && 1401220886Smav (cgd->inq_flags & SID_DMA) && (cgd->inq_flags & SID_CmdQue)) 1402195534Sscottl softc->flags |= ADA_FLAG_CAN_NCQ; 1403236393Smav if ((cgd->ident_data.support_dsm & ATA_SUPPORT_DSM_TRIM) && 1404236393Smav (cgd->inq_flags & SID_DMA)) { 1405201139Smav softc->flags |= ADA_FLAG_CAN_TRIM; 1406201139Smav softc->trim_max_ranges = TRIM_MAX_RANGES; 1407201139Smav if (cgd->ident_data.max_dsm_blocks != 0) { 1408201139Smav softc->trim_max_ranges = 1409249934Ssmh min(cgd->ident_data.max_dsm_blocks * 1410249934Ssmh ATA_DSM_BLK_RANGES, softc->trim_max_ranges); 1411201139Smav } 1412201139Smav } 1413201139Smav if (cgd->ident_data.support.command2 & ATA_SUPPORT_CFA) 1414201139Smav softc->flags |= ADA_FLAG_CAN_CFA; 1415195534Sscottl 1416298002Simp adasetdeletemethod(softc); 1417298002Simp 1418195534Sscottl periph->softc = softc; 1419195534Sscottl 1420195534Sscottl /* 1421195534Sscottl * See if this device has any quirks. 1422195534Sscottl */ 1423199178Smav match = cam_quirkmatch((caddr_t)&cgd->ident_data, 1424199178Smav (caddr_t)ada_quirk_table, 1425199178Smav sizeof(ada_quirk_table)/sizeof(*ada_quirk_table), 1426199178Smav sizeof(*ada_quirk_table), ata_identify_match); 1427195534Sscottl if (match != NULL) 1428195534Sscottl softc->quirks = ((struct ada_quirk_entry *)match)->quirks; 1429195534Sscottl else 1430195534Sscottl softc->quirks = ADA_Q_NONE; 1431195534Sscottl 1432195534Sscottl bzero(&cpi, sizeof(cpi)); 1433203108Smav xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NONE); 1434195534Sscottl cpi.ccb_h.func_code = XPT_PATH_INQ; 1435195534Sscottl xpt_action((union ccb *)&cpi); 1436195534Sscottl 1437195534Sscottl TASK_INIT(&softc->sysctl_task, 0, adasysctlinit, periph); 1438195534Sscottl 1439195534Sscottl /* 1440195534Sscottl * Register this media as a disk 1441195534Sscottl */ 1442220618Smav (void)cam_periph_hold(periph, PRIBIO); 1443249106Smav cam_periph_unlock(periph); 1444222520Smav snprintf(announce_buf, sizeof(announce_buf), 1445222520Smav "kern.cam.ada.%d.quirks", periph->unit_number); 1446222520Smav quirks = softc->quirks; 1447222520Smav TUNABLE_INT_FETCH(announce_buf, &quirks); 1448222520Smav softc->quirks = quirks; 1449224497Smav softc->read_ahead = -1; 1450224497Smav snprintf(announce_buf, sizeof(announce_buf), 1451224497Smav "kern.cam.ada.%d.read_ahead", periph->unit_number); 1452224497Smav TUNABLE_INT_FETCH(announce_buf, &softc->read_ahead); 1453220618Smav softc->write_cache = -1; 1454220618Smav snprintf(announce_buf, sizeof(announce_buf), 1455220618Smav "kern.cam.ada.%d.write_cache", periph->unit_number); 1456220618Smav TUNABLE_INT_FETCH(announce_buf, &softc->write_cache); 1457250033Ssmh /* Disable queue sorting for non-rotational media by default. */ 1458298002Simp if (cgd->ident_data.media_rotation_rate == ATA_RATE_NON_ROTATING) { 1459298002Simp softc->rotating = 0; 1460298002Simp } else { 1461298002Simp softc->rotating = 1; 1462298002Simp } 1463298002Simp cam_iosched_set_sort_queue(softc->cam_iosched, softc->rotating ? -1 : 0); 1464198897Smav adagetparams(periph, cgd); 1465195534Sscottl softc->disk = disk_alloc(); 1466256956Ssmh softc->disk->d_rotation_rate = cgd->ident_data.media_rotation_rate; 1467220644Smav softc->disk->d_devstat = devstat_new_entry(periph->periph_name, 1468220644Smav periph->unit_number, softc->params.secsize, 1469220644Smav DEVSTAT_ALL_SUPPORTED, 1470220644Smav DEVSTAT_TYPE_DIRECT | 1471220644Smav XPORT_DEVSTAT_TYPE(cpi.transport), 1472220644Smav DEVSTAT_PRIORITY_DISK); 1473195534Sscottl softc->disk->d_open = adaopen; 1474195534Sscottl softc->disk->d_close = adaclose; 1475195534Sscottl softc->disk->d_strategy = adastrategy; 1476223089Sgibbs softc->disk->d_getattr = adagetattr; 1477195534Sscottl softc->disk->d_dump = adadump; 1478249347Sken softc->disk->d_gone = adadiskgonecb; 1479195534Sscottl softc->disk->d_name = "ada"; 1480195534Sscottl softc->disk->d_drv1 = periph; 1481195534Sscottl maxio = cpi.maxio; /* Honor max I/O size of SIM */ 1482195534Sscottl if (maxio == 0) 1483195534Sscottl maxio = DFLTPHYS; /* traditional default */ 1484195534Sscottl else if (maxio > MAXPHYS) 1485195534Sscottl maxio = MAXPHYS; /* for safety */ 1486201139Smav if (softc->flags & ADA_FLAG_CAN_48BIT) 1487198897Smav maxio = min(maxio, 65536 * softc->params.secsize); 1488195534Sscottl else /* 28bit ATA command limit */ 1489198897Smav maxio = min(maxio, 256 * softc->params.secsize); 1490195534Sscottl softc->disk->d_maxsize = maxio; 1491195534Sscottl softc->disk->d_unit = periph->unit_number; 1492256880Smav softc->disk->d_flags = DISKFLAG_DIRECT_COMPLETION; 1493195534Sscottl if (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) 1494195534Sscottl softc->disk->d_flags |= DISKFLAG_CANFLUSHCACHE; 1495249934Ssmh if (softc->flags & ADA_FLAG_CAN_TRIM) { 1496201139Smav softc->disk->d_flags |= DISKFLAG_CANDELETE; 1497249940Ssmh softc->disk->d_delmaxsize = softc->params.secsize * 1498249940Ssmh ATA_DSM_RANGE_MAX * 1499249940Ssmh softc->trim_max_ranges; 1500249934Ssmh } else if ((softc->flags & ADA_FLAG_CAN_CFA) && 1501249934Ssmh !(softc->flags & ADA_FLAG_CAN_48BIT)) { 1502249934Ssmh softc->disk->d_flags |= DISKFLAG_CANDELETE; 1503249940Ssmh softc->disk->d_delmaxsize = 256 * softc->params.secsize; 1504249940Ssmh } else 1505249940Ssmh softc->disk->d_delmaxsize = maxio; 1506298002Simp if ((cpi.hba_misc & PIM_UNMAPPED) != 0) { 1507248519Skib softc->disk->d_flags |= DISKFLAG_UNMAPPED_BIO; 1508298002Simp softc->unmappedio = 1; 1509298002Simp } 1510298002Simp /* 1511298002Simp * If we can do RCVSND_FPDMA_QUEUED commands, we may be able to do 1512298002Simp * NCQ trims, if we support trims at all. We also need support from 1513298002Simp * the sim do do things properly. Perhaps we should look at log 13 1514298002Simp * dword 0 bit 0 and dword 1 bit 0 are set too... 1515298002Simp */ 1516298002Simp if (cpi.hba_misc & PIM_NCQ_KLUDGE) 1517298002Simp softc->flags |= ADA_FLAG_PIM_CAN_NCQ_TRIM; 1518298002Simp if ((softc->quirks & ADA_Q_NCQ_TRIM_BROKEN) == 0 && 1519298002Simp (softc->flags & ADA_FLAG_PIM_CAN_NCQ_TRIM) != 0 && 1520298002Simp (cgd->ident_data.satacapabilities2 & ATA_SUPPORT_RCVSND_FPDMA_QUEUED) != 0 && 1521298002Simp (softc->flags & ADA_FLAG_CAN_TRIM) != 0) 1522298002Simp softc->flags |= ADA_FLAG_CAN_NCQ_TRIM; 1523219056Snwhitehorn strlcpy(softc->disk->d_descr, cgd->ident_data.model, 1524219056Snwhitehorn MIN(sizeof(softc->disk->d_descr), sizeof(cgd->ident_data.model))); 1525241305Savg strlcpy(softc->disk->d_ident, cgd->ident_data.serial, 1526241305Savg MIN(sizeof(softc->disk->d_ident), sizeof(cgd->ident_data.serial))); 1527210471Smav softc->disk->d_hba_vendor = cpi.hba_vendor; 1528210471Smav softc->disk->d_hba_device = cpi.hba_device; 1529210471Smav softc->disk->d_hba_subvendor = cpi.hba_subvendor; 1530210471Smav softc->disk->d_hba_subdevice = cpi.hba_subdevice; 1531195534Sscottl 1532195534Sscottl softc->disk->d_sectorsize = softc->params.secsize; 1533198897Smav softc->disk->d_mediasize = (off_t)softc->params.sectors * 1534198897Smav softc->params.secsize; 1535200969Smav if (ata_physical_sector_size(&cgd->ident_data) != 1536200969Smav softc->params.secsize) { 1537200969Smav softc->disk->d_stripesize = 1538200969Smav ata_physical_sector_size(&cgd->ident_data); 1539200969Smav softc->disk->d_stripeoffset = (softc->disk->d_stripesize - 1540200969Smav ata_logical_sector_offset(&cgd->ident_data)) % 1541200969Smav softc->disk->d_stripesize; 1542222520Smav } else if (softc->quirks & ADA_Q_4K) { 1543222520Smav softc->disk->d_stripesize = 4096; 1544222520Smav softc->disk->d_stripeoffset = 0; 1545200969Smav } 1546195534Sscottl softc->disk->d_fwsectors = softc->params.secs_per_track; 1547195534Sscottl softc->disk->d_fwheads = softc->params.heads; 1548208349Smarius ata_disk_firmware_geom_adjust(softc->disk); 1549298002Simp adasetdeletemethod(softc); 1550195534Sscottl 1551249347Sken /* 1552249347Sken * Acquire a reference to the periph before we register with GEOM. 1553249347Sken * We'll release this reference once GEOM calls us back (via 1554249347Sken * adadiskgonecb()) telling us that our provider has been freed. 1555249347Sken */ 1556249347Sken if (cam_periph_acquire(periph) != CAM_REQ_CMP) { 1557249347Sken xpt_print(periph->path, "%s: lost periph during " 1558249347Sken "registration!\n", __func__); 1559249347Sken cam_periph_lock(periph); 1560249347Sken return (CAM_REQ_CMP_ERR); 1561249347Sken } 1562195534Sscottl disk_create(softc->disk, DISK_VERSION); 1563249106Smav cam_periph_lock(periph); 1564220618Smav cam_periph_unhold(periph); 1565195534Sscottl 1566195534Sscottl dp = &softc->params; 1567195534Sscottl snprintf(announce_buf, sizeof(announce_buf), 1568289138Smav "%juMB (%ju %u byte sectors)", 1569289138Smav ((uintmax_t)dp->secsize * dp->sectors) / (1024 * 1024), 1570289138Smav (uintmax_t)dp->sectors, dp->secsize); 1571195534Sscottl xpt_announce_periph(periph, announce_buf); 1572250792Ssmh xpt_announce_quirks(periph, softc->quirks, ADA_Q_BIT_STRING); 1573220454Smav 1574195534Sscottl /* 1575220454Smav * Create our sysctl variables, now that we know 1576220454Smav * we have successfully attached. 1577220454Smav */ 1578256843Smav if (cam_periph_acquire(periph) == CAM_REQ_CMP) 1579256843Smav taskqueue_enqueue(taskqueue_thread, &softc->sysctl_task); 1580220454Smav 1581220454Smav /* 1582195534Sscottl * Add async callbacks for bus reset and 1583195534Sscottl * bus device reset calls. I don't bother 1584195534Sscottl * checking if this fails as, in most cases, 1585195534Sscottl * the system will function just fine without 1586195534Sscottl * them and the only alternative would be to 1587195534Sscottl * not attach the device on failure. 1588195534Sscottl */ 1589235897Smav xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE | 1590236393Smav AC_GETDEV_CHANGED | AC_ADVINFO_CHANGED, 1591236393Smav adaasync, periph, periph->path); 1592195534Sscottl 1593195534Sscottl /* 1594195534Sscottl * Schedule a periodic event to occasionally send an 1595195534Sscottl * ordered tag to a device. 1596195534Sscottl */ 1597256843Smav callout_init_mtx(&softc->sendordered_c, cam_periph_mtx(periph), 0); 1598195534Sscottl callout_reset(&softc->sendordered_c, 1599230921Smav (ada_default_timeout * hz) / ADA_ORDEREDTAG_INTERVAL, 1600195534Sscottl adasendorderedtag, softc); 1601195534Sscottl 1602224497Smav if (ADA_RA >= 0 && 1603224497Smav cgd->ident_data.support.command1 & ATA_SUPPORT_LOOKAHEAD) { 1604224497Smav softc->state = ADA_STATE_RAHEAD; 1605224497Smav } else if (ADA_WC >= 0 && 1606220412Smav cgd->ident_data.support.command1 & ATA_SUPPORT_WRITECACHE) { 1607220412Smav softc->state = ADA_STATE_WCACHE; 1608256843Smav } else { 1609256843Smav softc->state = ADA_STATE_NORMAL; 1610256843Smav return(CAM_REQ_CMP); 1611256843Smav } 1612256843Smav if (cam_periph_acquire(periph) != CAM_REQ_CMP) 1613256843Smav softc->state = ADA_STATE_NORMAL; 1614256843Smav else 1615220412Smav xpt_schedule(periph, CAM_PRIORITY_DEV); 1616195534Sscottl return(CAM_REQ_CMP); 1617195534Sscottl} 1618195534Sscottl 1619298002Simpstatic int 1620298002Simpada_dsmtrim_req_create(struct ada_softc *softc, struct bio *bp, struct trim_request *req) 1621268205Simp{ 1622268205Simp uint64_t lastlba = (uint64_t)-1; 1623268205Simp int c, lastcount = 0, off, ranges = 0; 1624268205Simp 1625268205Simp bzero(req, sizeof(*req)); 1626268205Simp TAILQ_INIT(&req->bps); 1627268205Simp do { 1628268205Simp uint64_t lba = bp->bio_pblkno; 1629268205Simp int count = bp->bio_bcount / softc->params.secsize; 1630268205Simp 1631268205Simp /* Try to extend the previous range. */ 1632268205Simp if (lba == lastlba) { 1633268205Simp c = min(count, ATA_DSM_RANGE_MAX - lastcount); 1634268205Simp lastcount += c; 1635268205Simp off = (ranges - 1) * ATA_DSM_RANGE_SIZE; 1636268205Simp req->data[off + 6] = lastcount & 0xff; 1637268205Simp req->data[off + 7] = 1638268205Simp (lastcount >> 8) & 0xff; 1639268205Simp count -= c; 1640268205Simp lba += c; 1641268205Simp } 1642268205Simp 1643268205Simp while (count > 0) { 1644268205Simp c = min(count, ATA_DSM_RANGE_MAX); 1645268205Simp off = ranges * ATA_DSM_RANGE_SIZE; 1646268205Simp req->data[off + 0] = lba & 0xff; 1647268205Simp req->data[off + 1] = (lba >> 8) & 0xff; 1648268205Simp req->data[off + 2] = (lba >> 16) & 0xff; 1649268205Simp req->data[off + 3] = (lba >> 24) & 0xff; 1650268205Simp req->data[off + 4] = (lba >> 32) & 0xff; 1651268205Simp req->data[off + 5] = (lba >> 40) & 0xff; 1652268205Simp req->data[off + 6] = c & 0xff; 1653268205Simp req->data[off + 7] = (c >> 8) & 0xff; 1654268205Simp lba += c; 1655268205Simp count -= c; 1656268205Simp lastcount = c; 1657268205Simp ranges++; 1658268205Simp /* 1659268205Simp * Its the caller's responsibility to ensure the 1660268205Simp * request will fit so we don't need to check for 1661268205Simp * overrun here 1662268205Simp */ 1663268205Simp } 1664268205Simp lastlba = lba; 1665268205Simp TAILQ_INSERT_TAIL(&req->bps, bp, bio_queue); 1666298002Simp 1667298002Simp bp = cam_iosched_next_trim(softc->cam_iosched); 1668298002Simp if (bp == NULL) 1669268205Simp break; 1670298002Simp if (bp->bio_bcount / softc->params.secsize > 1671298002Simp (softc->trim_max_ranges - ranges) * ATA_DSM_RANGE_MAX) { 1672298002Simp cam_iosched_put_back_trim(softc->cam_iosched, bp); 1673298002Simp break; 1674298002Simp } 1675268205Simp } while (1); 1676298002Simp 1677298002Simp return (ranges); 1678298002Simp} 1679298002Simp 1680298002Simpstatic void 1681298002Simpada_dsmtrim(struct ada_softc *softc, struct bio *bp, struct ccb_ataio *ataio) 1682298002Simp{ 1683298002Simp struct trim_request *req = &softc->trim_req; 1684298002Simp int ranges; 1685298002Simp 1686298002Simp ranges = ada_dsmtrim_req_create(softc, bp, req); 1687268205Simp cam_fill_ataio(ataio, 1688268205Simp ada_retry_count, 1689268205Simp adadone, 1690268205Simp CAM_DIR_OUT, 1691268205Simp 0, 1692268205Simp req->data, 1693268205Simp ((ranges + ATA_DSM_BLK_RANGES - 1) / 1694268205Simp ATA_DSM_BLK_RANGES) * ATA_DSM_BLK_SIZE, 1695268205Simp ada_default_timeout * 1000); 1696268205Simp ata_48bit_cmd(ataio, ATA_DATA_SET_MANAGEMENT, 1697268205Simp ATA_DSM_TRIM, 0, (ranges + ATA_DSM_BLK_RANGES - 1698268205Simp 1) / ATA_DSM_BLK_RANGES); 1699268205Simp} 1700268205Simp 1701268205Simpstatic void 1702298002Simpada_ncq_dsmtrim(struct ada_softc *softc, struct bio *bp, struct ccb_ataio *ataio) 1703298002Simp{ 1704298002Simp struct trim_request *req = &softc->trim_req; 1705298002Simp int ranges; 1706298002Simp 1707298002Simp ranges = ada_dsmtrim_req_create(softc, bp, req); 1708298002Simp cam_fill_ataio(ataio, 1709298002Simp ada_retry_count, 1710298002Simp adadone, 1711298002Simp CAM_DIR_OUT, 1712298002Simp 0, 1713298002Simp req->data, 1714298002Simp ((ranges + ATA_DSM_BLK_RANGES - 1) / 1715298002Simp ATA_DSM_BLK_RANGES) * ATA_DSM_BLK_SIZE, 1716298002Simp ada_default_timeout * 1000); 1717298002Simp ata_ncq_cmd(ataio, 1718298002Simp ATA_SEND_FPDMA_QUEUED, 1719298002Simp 0, 1720298002Simp (ranges + ATA_DSM_BLK_RANGES - 1) / ATA_DSM_BLK_RANGES); 1721298002Simp ataio->cmd.sector_count_exp = ATA_SFPDMA_DSM; 1722298002Simp ataio->cmd.flags |= CAM_ATAIO_AUX_HACK; 1723298002Simp} 1724298002Simp 1725298002Simpstatic void 1726268205Simpada_cfaerase(struct ada_softc *softc, struct bio *bp, struct ccb_ataio *ataio) 1727268205Simp{ 1728273704Ssmh struct trim_request *req = &softc->trim_req; 1729268205Simp uint64_t lba = bp->bio_pblkno; 1730268205Simp uint16_t count = bp->bio_bcount / softc->params.secsize; 1731268205Simp 1732273704Ssmh bzero(req, sizeof(*req)); 1733273704Ssmh TAILQ_INIT(&req->bps); 1734273704Ssmh TAILQ_INSERT_TAIL(&req->bps, bp, bio_queue); 1735273704Ssmh 1736268205Simp cam_fill_ataio(ataio, 1737268205Simp ada_retry_count, 1738268205Simp adadone, 1739268205Simp CAM_DIR_NONE, 1740268205Simp 0, 1741268205Simp NULL, 1742268205Simp 0, 1743268205Simp ada_default_timeout*1000); 1744268205Simp 1745268205Simp if (count >= 256) 1746268205Simp count = 0; 1747268205Simp ata_28bit_cmd(ataio, ATA_CFA_ERASE, 0, lba, count); 1748268205Simp} 1749268205Simp 1750268205Simpstatic void 1751195534Sscottladastart(struct cam_periph *periph, union ccb *start_ccb) 1752195534Sscottl{ 1753198328Smav struct ada_softc *softc = (struct ada_softc *)periph->softc; 1754198328Smav struct ccb_ataio *ataio = &start_ccb->ataio; 1755195534Sscottl 1756236602Smav CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("adastart\n")); 1757236602Smav 1758195534Sscottl switch (softc->state) { 1759195534Sscottl case ADA_STATE_NORMAL: 1760195534Sscottl { 1761195534Sscottl struct bio *bp; 1762201139Smav u_int8_t tag_code; 1763195534Sscottl 1764298002Simp bp = cam_iosched_next_bio(softc->cam_iosched); 1765201139Smav if (bp == NULL) { 1766195534Sscottl xpt_release_ccb(start_ccb); 1767201139Smav break; 1768201139Smav } 1769201139Smav 1770298002Simp if ((bp->bio_flags & BIO_ORDERED) != 0 || 1771298002Simp (bp->bio_cmd != BIO_DELETE && (softc->flags & ADA_FLAG_NEED_OTAG) != 0)) { 1772201139Smav softc->flags &= ~ADA_FLAG_NEED_OTAG; 1773257054Smav softc->flags |= ADA_FLAG_WAS_OTAG; 1774201139Smav tag_code = 0; 1775195534Sscottl } else { 1776201139Smav tag_code = 1; 1777201139Smav } 1778201139Smav switch (bp->bio_cmd) { 1779253724Smav case BIO_WRITE: 1780201139Smav case BIO_READ: 1781201139Smav { 1782201139Smav uint64_t lba = bp->bio_pblkno; 1783201139Smav uint16_t count = bp->bio_bcount / softc->params.secsize; 1784291716Sken void *data_ptr; 1785291716Sken int rw_op; 1786291716Sken 1787291716Sken if (bp->bio_cmd == BIO_WRITE) { 1788291716Sken softc->flags |= ADA_FLAG_DIRTY; 1789291716Sken rw_op = CAM_DIR_OUT; 1790291716Sken } else { 1791291716Sken rw_op = CAM_DIR_IN; 1792291716Sken } 1793291716Sken 1794291716Sken data_ptr = bp->bio_data; 1795291716Sken if ((bp->bio_flags & (BIO_UNMAPPED|BIO_VLIST)) != 0) { 1796291716Sken rw_op |= CAM_DATA_BIO; 1797291716Sken data_ptr = bp; 1798291716Sken } 1799291716Sken 1800220454Smav#ifdef ADA_TEST_FAILURE 1801220454Smav int fail = 0; 1802195534Sscottl 1803220454Smav /* 1804220454Smav * Support the failure ioctls. If the command is a 1805220454Smav * read, and there are pending forced read errors, or 1806220454Smav * if a write and pending write errors, then fail this 1807220454Smav * operation with EIO. This is useful for testing 1808220454Smav * purposes. Also, support having every Nth read fail. 1809220454Smav * 1810220454Smav * This is a rather blunt tool. 1811220454Smav */ 1812220454Smav if (bp->bio_cmd == BIO_READ) { 1813220454Smav if (softc->force_read_error) { 1814220454Smav softc->force_read_error--; 1815220454Smav fail = 1; 1816220454Smav } 1817220454Smav if (softc->periodic_read_error > 0) { 1818220454Smav if (++softc->periodic_read_count >= 1819220454Smav softc->periodic_read_error) { 1820220454Smav softc->periodic_read_count = 0; 1821220454Smav fail = 1; 1822220454Smav } 1823220454Smav } 1824220454Smav } else { 1825220454Smav if (softc->force_write_error) { 1826220454Smav softc->force_write_error--; 1827220454Smav fail = 1; 1828220454Smav } 1829220454Smav } 1830220454Smav if (fail) { 1831287025Smav biofinish(bp, NULL, EIO); 1832220454Smav xpt_release_ccb(start_ccb); 1833220454Smav adaschedule(periph); 1834220454Smav return; 1835220454Smav } 1836220454Smav#endif 1837248519Skib KASSERT((bp->bio_flags & BIO_UNMAPPED) == 0 || 1838248519Skib round_page(bp->bio_bcount + bp->bio_ma_offset) / 1839248519Skib PAGE_SIZE == bp->bio_ma_n, 1840248519Skib ("Short bio %p", bp)); 1841201139Smav cam_fill_ataio(ataio, 1842201139Smav ada_retry_count, 1843201139Smav adadone, 1844291716Sken rw_op, 1845201139Smav tag_code, 1846291716Sken data_ptr, 1847201139Smav bp->bio_bcount, 1848201139Smav ada_default_timeout*1000); 1849195534Sscottl 1850201139Smav if ((softc->flags & ADA_FLAG_CAN_NCQ) && tag_code) { 1851201139Smav if (bp->bio_cmd == BIO_READ) { 1852201139Smav ata_ncq_cmd(ataio, ATA_READ_FPDMA_QUEUED, 1853201139Smav lba, count); 1854201139Smav } else { 1855201139Smav ata_ncq_cmd(ataio, ATA_WRITE_FPDMA_QUEUED, 1856201139Smav lba, count); 1857201139Smav } 1858201139Smav } else if ((softc->flags & ADA_FLAG_CAN_48BIT) && 1859201139Smav (lba + count >= ATA_MAX_28BIT_LBA || 1860201139Smav count > 256)) { 1861249199Smarius if (softc->flags & ADA_FLAG_CAN_DMA48) { 1862195534Sscottl if (bp->bio_cmd == BIO_READ) { 1863201139Smav ata_48bit_cmd(ataio, ATA_READ_DMA48, 1864201139Smav 0, lba, count); 1865195534Sscottl } else { 1866201139Smav ata_48bit_cmd(ataio, ATA_WRITE_DMA48, 1867201139Smav 0, lba, count); 1868195534Sscottl } 1869201139Smav } else { 1870201139Smav if (bp->bio_cmd == BIO_READ) { 1871201139Smav ata_48bit_cmd(ataio, ATA_READ_MUL48, 1872201139Smav 0, lba, count); 1873195534Sscottl } else { 1874201139Smav ata_48bit_cmd(ataio, ATA_WRITE_MUL48, 1875201139Smav 0, lba, count); 1876195534Sscottl } 1877201139Smav } 1878201139Smav } else { 1879201139Smav if (count == 256) 1880201139Smav count = 0; 1881201139Smav if (softc->flags & ADA_FLAG_CAN_DMA) { 1882201139Smav if (bp->bio_cmd == BIO_READ) { 1883201139Smav ata_28bit_cmd(ataio, ATA_READ_DMA, 1884201139Smav 0, lba, count); 1885201139Smav } else { 1886201139Smav ata_28bit_cmd(ataio, ATA_WRITE_DMA, 1887201139Smav 0, lba, count); 1888201139Smav } 1889195534Sscottl } else { 1890201139Smav if (bp->bio_cmd == BIO_READ) { 1891201139Smav ata_28bit_cmd(ataio, ATA_READ_MUL, 1892201139Smav 0, lba, count); 1893195534Sscottl } else { 1894201139Smav ata_28bit_cmd(ataio, ATA_WRITE_MUL, 1895201139Smav 0, lba, count); 1896195534Sscottl } 1897195534Sscottl } 1898195534Sscottl } 1899201139Smav break; 1900201139Smav } 1901298002Simp case BIO_DELETE: 1902298002Simp switch (softc->delete_method) { 1903298002Simp case ADA_DELETE_NCQ_DSM_TRIM: 1904298002Simp ada_ncq_dsmtrim(softc, bp, ataio); 1905298002Simp break; 1906298002Simp case ADA_DELETE_DSM_TRIM: 1907298002Simp ada_dsmtrim(softc, bp, ataio); 1908298002Simp break; 1909298002Simp case ADA_DELETE_CFA_ERASE: 1910298002Simp ada_cfaerase(softc, bp, ataio); 1911298002Simp break; 1912298002Simp default: 1913298002Simp biofinish(bp, NULL, EOPNOTSUPP); 1914298002Simp xpt_release_ccb(start_ccb); 1915298002Simp adaschedule(periph); 1916298002Simp return; 1917298002Simp } 1918298002Simp start_ccb->ccb_h.ccb_state = ADA_CCB_TRIM; 1919298002Simp start_ccb->ccb_h.flags |= CAM_UNLOCKED; 1920298002Simp cam_iosched_submit_trim(softc->cam_iosched); 1921298002Simp goto out; 1922201139Smav case BIO_FLUSH: 1923201139Smav cam_fill_ataio(ataio, 1924201139Smav 1, 1925201139Smav adadone, 1926201139Smav CAM_DIR_NONE, 1927201139Smav 0, 1928201139Smav NULL, 1929201139Smav 0, 1930201139Smav ada_default_timeout*1000); 1931201139Smav 1932201139Smav if (softc->flags & ADA_FLAG_CAN_48BIT) 1933201139Smav ata_48bit_cmd(ataio, ATA_FLUSHCACHE48, 0, 0, 0); 1934201139Smav else 1935201139Smav ata_28bit_cmd(ataio, ATA_FLUSHCACHE, 0, 0, 0); 1936201139Smav break; 1937195534Sscottl } 1938201139Smav start_ccb->ccb_h.ccb_state = ADA_CCB_BUFFER_IO; 1939256843Smav start_ccb->ccb_h.flags |= CAM_UNLOCKED; 1940201139Smavout: 1941201139Smav start_ccb->ccb_h.ccb_bp = bp; 1942201139Smav softc->outstanding_cmds++; 1943256843Smav softc->refcount++; 1944256843Smav cam_periph_unlock(periph); 1945201139Smav xpt_action(start_ccb); 1946256843Smav cam_periph_lock(periph); 1947256843Smav softc->refcount--; 1948201139Smav 1949201139Smav /* May have more work to do, so ensure we stay scheduled */ 1950201139Smav adaschedule(periph); 1951195534Sscottl break; 1952195534Sscottl } 1953224497Smav case ADA_STATE_RAHEAD: 1954220412Smav case ADA_STATE_WCACHE: 1955220412Smav { 1956220412Smav cam_fill_ataio(ataio, 1957220412Smav 1, 1958220412Smav adadone, 1959220412Smav CAM_DIR_NONE, 1960220412Smav 0, 1961220412Smav NULL, 1962220412Smav 0, 1963220412Smav ada_default_timeout*1000); 1964220412Smav 1965224497Smav if (softc->state == ADA_STATE_RAHEAD) { 1966224497Smav ata_28bit_cmd(ataio, ATA_SETFEATURES, ADA_RA ? 1967224497Smav ATA_SF_ENAB_RCACHE : ATA_SF_DIS_RCACHE, 0, 0); 1968224497Smav start_ccb->ccb_h.ccb_state = ADA_CCB_RAHEAD; 1969224497Smav } else { 1970224497Smav ata_28bit_cmd(ataio, ATA_SETFEATURES, ADA_WC ? 1971224497Smav ATA_SF_ENAB_WCACHE : ATA_SF_DIS_WCACHE, 0, 0); 1972224497Smav start_ccb->ccb_h.ccb_state = ADA_CCB_WCACHE; 1973224497Smav } 1974249466Smav start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE; 1975220412Smav xpt_action(start_ccb); 1976220412Smav break; 1977195534Sscottl } 1978220412Smav } 1979195534Sscottl} 1980195534Sscottl 1981195534Sscottlstatic void 1982195534Sscottladadone(struct cam_periph *periph, union ccb *done_ccb) 1983195534Sscottl{ 1984195534Sscottl struct ada_softc *softc; 1985195534Sscottl struct ccb_ataio *ataio; 1986224497Smav struct ccb_getdev *cgd; 1987249466Smav struct cam_path *path; 1988253752Smav int state; 1989195534Sscottl 1990195534Sscottl softc = (struct ada_softc *)periph->softc; 1991195534Sscottl ataio = &done_ccb->ataio; 1992249466Smav path = done_ccb->ccb_h.path; 1993236602Smav 1994249466Smav CAM_DEBUG(path, CAM_DEBUG_TRACE, ("adadone\n")); 1995236602Smav 1996253752Smav state = ataio->ccb_h.ccb_state & ADA_CCB_TYPE_MASK; 1997253752Smav switch (state) { 1998195534Sscottl case ADA_CCB_BUFFER_IO: 1999201139Smav case ADA_CCB_TRIM: 2000195534Sscottl { 2001195534Sscottl struct bio *bp; 2002253752Smav int error; 2003195534Sscottl 2004256843Smav cam_periph_lock(periph); 2005298002Simp bp = (struct bio *)done_ccb->ccb_h.ccb_bp; 2006195534Sscottl if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 2007198328Smav error = adaerror(done_ccb, 0, 0); 2008195534Sscottl if (error == ERESTART) { 2009198328Smav /* A retry was scheduled, so just return. */ 2010256843Smav cam_periph_unlock(periph); 2011195534Sscottl return; 2012195534Sscottl } 2013195534Sscottl if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 2014249466Smav cam_release_devq(path, 2015195534Sscottl /*relsim_flags*/0, 2016195534Sscottl /*reduction*/0, 2017195534Sscottl /*timeout*/0, 2018195534Sscottl /*getcount_only*/0); 2019298002Simp /* 2020298002Simp * If we get an error on an NCQ DSM TRIM, fall back 2021298002Simp * to a non-NCQ DSM TRIM forever. Please note that if 2022298002Simp * CAN_NCQ_TRIM is set, CAN_TRIM is necessarily set too. 2023298002Simp * However, for this one trim, we treat it as advisory 2024298002Simp * and return success up the stack. 2025298002Simp */ 2026298002Simp if (state == ADA_CCB_TRIM && 2027298002Simp error != 0 && 2028298002Simp (softc->flags & ADA_FLAG_CAN_NCQ_TRIM) != 0) { 2029298002Simp softc->flags &= ~ADA_FLAG_CAN_NCQ_TRIM; 2030298002Simp error = 0; 2031298002Simp adasetdeletemethod(softc); 2032298002Simp } 2033195534Sscottl } else { 2034195534Sscottl if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 2035195534Sscottl panic("REQ_CMP with QFRZN"); 2036253752Smav error = 0; 2037253752Smav } 2038253752Smav bp->bio_error = error; 2039253752Smav if (error != 0) { 2040253752Smav bp->bio_resid = bp->bio_bcount; 2041253752Smav bp->bio_flags |= BIO_ERROR; 2042253752Smav } else { 2043253752Smav if (state == ADA_CCB_TRIM) 2044253752Smav bp->bio_resid = 0; 2045253752Smav else 2046253752Smav bp->bio_resid = ataio->resid; 2047253752Smav if (bp->bio_resid > 0) 2048195534Sscottl bp->bio_flags |= BIO_ERROR; 2049195534Sscottl } 2050195534Sscottl softc->outstanding_cmds--; 2051195534Sscottl if (softc->outstanding_cmds == 0) 2052257054Smav softc->flags |= ADA_FLAG_WAS_OTAG; 2053298002Simp 2054298002Simp cam_iosched_bio_complete(softc->cam_iosched, bp, done_ccb); 2055256843Smav xpt_release_ccb(done_ccb); 2056253752Smav if (state == ADA_CCB_TRIM) { 2057256836Smav TAILQ_HEAD(, bio) queue; 2058256836Smav struct bio *bp1; 2059195534Sscottl 2060256836Smav TAILQ_INIT(&queue); 2061256836Smav TAILQ_CONCAT(&queue, &softc->trim_req.bps, bio_queue); 2062277101Simp /* 2063277101Simp * Normally, the xpt_release_ccb() above would make sure 2064277101Simp * that when we have more work to do, that work would 2065277101Simp * get kicked off. However, we specifically keep 2066277101Simp * trim_running set to 0 before the call above to allow 2067277101Simp * other I/O to progress when many BIO_DELETE requests 2068277101Simp * are pushed down. We set trim_running to 0 and call 2069277101Simp * daschedule again so that we don't stall if there are 2070277101Simp * no other I/Os pending apart from BIO_DELETEs. 2071277101Simp */ 2072298002Simp cam_iosched_trim_done(softc->cam_iosched); 2073256843Smav adaschedule(periph); 2074256843Smav cam_periph_unlock(periph); 2075256836Smav while ((bp1 = TAILQ_FIRST(&queue)) != NULL) { 2076256836Smav TAILQ_REMOVE(&queue, bp1, bio_queue); 2077256836Smav bp1->bio_error = error; 2078256836Smav if (error != 0) { 2079201139Smav bp1->bio_flags |= BIO_ERROR; 2080253752Smav bp1->bio_resid = bp1->bio_bcount; 2081253752Smav } else 2082253752Smav bp1->bio_resid = 0; 2083201139Smav biodone(bp1); 2084201139Smav } 2085256843Smav } else { 2086298002Simp adaschedule(periph); 2087256843Smav cam_periph_unlock(periph); 2088201139Smav biodone(bp); 2089256843Smav } 2090256843Smav return; 2091195534Sscottl } 2092224497Smav case ADA_CCB_RAHEAD: 2093224497Smav { 2094224497Smav if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 2095224497Smav if (adaerror(done_ccb, 0, 0) == ERESTART) { 2096249466Smavout: 2097249466Smav /* Drop freeze taken due to CAM_DEV_QFREEZE */ 2098249466Smav cam_release_devq(path, 0, 0, 0, FALSE); 2099224497Smav return; 2100224497Smav } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 2101249466Smav cam_release_devq(path, 2102224497Smav /*relsim_flags*/0, 2103224497Smav /*reduction*/0, 2104224497Smav /*timeout*/0, 2105224497Smav /*getcount_only*/0); 2106224497Smav } 2107224497Smav } 2108224497Smav 2109224497Smav /* 2110224497Smav * Since our peripheral may be invalidated by an error 2111224497Smav * above or an external event, we must release our CCB 2112224497Smav * before releasing the reference on the peripheral. 2113224497Smav * The peripheral will only go away once the last reference 2114224497Smav * is removed, and we need it around for the CCB release 2115224497Smav * operation. 2116224497Smav */ 2117224497Smav cgd = (struct ccb_getdev *)done_ccb; 2118249466Smav xpt_setup_ccb(&cgd->ccb_h, path, CAM_PRIORITY_NORMAL); 2119224497Smav cgd->ccb_h.func_code = XPT_GDEV_TYPE; 2120224497Smav xpt_action((union ccb *)cgd); 2121224497Smav if (ADA_WC >= 0 && 2122224497Smav cgd->ident_data.support.command1 & ATA_SUPPORT_WRITECACHE) { 2123224497Smav softc->state = ADA_STATE_WCACHE; 2124224497Smav xpt_release_ccb(done_ccb); 2125224497Smav xpt_schedule(periph, CAM_PRIORITY_DEV); 2126249466Smav goto out; 2127224497Smav } 2128224497Smav softc->state = ADA_STATE_NORMAL; 2129224497Smav xpt_release_ccb(done_ccb); 2130249466Smav /* Drop freeze taken due to CAM_DEV_QFREEZE */ 2131249466Smav cam_release_devq(path, 0, 0, 0, FALSE); 2132224497Smav adaschedule(periph); 2133224497Smav cam_periph_release_locked(periph); 2134224497Smav return; 2135224497Smav } 2136220412Smav case ADA_CCB_WCACHE: 2137220412Smav { 2138220412Smav if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 2139220412Smav if (adaerror(done_ccb, 0, 0) == ERESTART) { 2140249466Smav goto out; 2141220412Smav } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 2142249466Smav cam_release_devq(path, 2143220412Smav /*relsim_flags*/0, 2144220412Smav /*reduction*/0, 2145220412Smav /*timeout*/0, 2146220412Smav /*getcount_only*/0); 2147220412Smav } 2148220412Smav } 2149220412Smav 2150220412Smav softc->state = ADA_STATE_NORMAL; 2151220412Smav /* 2152220412Smav * Since our peripheral may be invalidated by an error 2153220412Smav * above or an external event, we must release our CCB 2154220412Smav * before releasing the reference on the peripheral. 2155220412Smav * The peripheral will only go away once the last reference 2156220412Smav * is removed, and we need it around for the CCB release 2157220412Smav * operation. 2158220412Smav */ 2159220412Smav xpt_release_ccb(done_ccb); 2160249466Smav /* Drop freeze taken due to CAM_DEV_QFREEZE */ 2161249466Smav cam_release_devq(path, 0, 0, 0, FALSE); 2162220412Smav adaschedule(periph); 2163220412Smav cam_periph_release_locked(periph); 2164220412Smav return; 2165220412Smav } 2166195534Sscottl case ADA_CCB_DUMP: 2167195534Sscottl /* No-op. We're polling */ 2168195534Sscottl return; 2169195534Sscottl default: 2170195534Sscottl break; 2171195534Sscottl } 2172195534Sscottl xpt_release_ccb(done_ccb); 2173195534Sscottl} 2174195534Sscottl 2175195534Sscottlstatic int 2176195534Sscottladaerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) 2177195534Sscottl{ 2178298002Simp struct ada_softc *softc; 2179298002Simp struct cam_periph *periph; 2180195534Sscottl 2181298002Simp periph = xpt_path_periph(ccb->ccb_h.path); 2182298002Simp softc = (struct ada_softc *)periph->softc; 2183298002Simp 2184298002Simp switch (ccb->ccb_h.status & CAM_STATUS_MASK) { 2185298002Simp case CAM_CMD_TIMEOUT: 2186298002Simp#ifdef CAM_IO_STATS 2187298002Simp softc->timeouts++; 2188298002Simp#endif 2189298002Simp break; 2190298002Simp case CAM_REQ_ABORTED: 2191298002Simp case CAM_REQ_CMP_ERR: 2192298002Simp case CAM_REQ_TERMIO: 2193298002Simp case CAM_UNREC_HBA_ERROR: 2194298002Simp case CAM_DATA_RUN_ERR: 2195298002Simp case CAM_ATA_STATUS_ERROR: 2196298002Simp#ifdef CAM_IO_STATS 2197298002Simp softc->errors++; 2198298002Simp#endif 2199298002Simp break; 2200298002Simp default: 2201298002Simp break; 2202298002Simp } 2203298002Simp 2204203385Smav return(cam_periph_error(ccb, cam_flags, sense_flags, NULL)); 2205195534Sscottl} 2206195534Sscottl 2207195534Sscottlstatic void 2208198897Smavadagetparams(struct cam_periph *periph, struct ccb_getdev *cgd) 2209195534Sscottl{ 2210195534Sscottl struct ada_softc *softc = (struct ada_softc *)periph->softc; 2211195534Sscottl struct disk_params *dp = &softc->params; 2212195534Sscottl u_int64_t lbasize48; 2213195534Sscottl u_int32_t lbasize; 2214195534Sscottl 2215198897Smav dp->secsize = ata_logical_sector_size(&cgd->ident_data); 2216195534Sscottl if ((cgd->ident_data.atavalid & ATA_FLAG_54_58) && 2217195534Sscottl cgd->ident_data.current_heads && cgd->ident_data.current_sectors) { 2218195534Sscottl dp->heads = cgd->ident_data.current_heads; 2219195534Sscottl dp->secs_per_track = cgd->ident_data.current_sectors; 2220195534Sscottl dp->cylinders = cgd->ident_data.cylinders; 2221195534Sscottl dp->sectors = (u_int32_t)cgd->ident_data.current_size_1 | 2222195534Sscottl ((u_int32_t)cgd->ident_data.current_size_2 << 16); 2223195534Sscottl } else { 2224195534Sscottl dp->heads = cgd->ident_data.heads; 2225195534Sscottl dp->secs_per_track = cgd->ident_data.sectors; 2226195534Sscottl dp->cylinders = cgd->ident_data.cylinders; 2227195534Sscottl dp->sectors = cgd->ident_data.cylinders * dp->heads * dp->secs_per_track; 2228195534Sscottl } 2229195534Sscottl lbasize = (u_int32_t)cgd->ident_data.lba_size_1 | 2230195534Sscottl ((u_int32_t)cgd->ident_data.lba_size_2 << 16); 2231195534Sscottl 2232195534Sscottl /* use the 28bit LBA size if valid or bigger than the CHS mapping */ 2233195534Sscottl if (cgd->ident_data.cylinders == 16383 || dp->sectors < lbasize) 2234195534Sscottl dp->sectors = lbasize; 2235195534Sscottl 2236195534Sscottl /* use the 48bit LBA size if valid */ 2237195534Sscottl lbasize48 = ((u_int64_t)cgd->ident_data.lba_size48_1) | 2238195534Sscottl ((u_int64_t)cgd->ident_data.lba_size48_2 << 16) | 2239195534Sscottl ((u_int64_t)cgd->ident_data.lba_size48_3 << 32) | 2240195534Sscottl ((u_int64_t)cgd->ident_data.lba_size48_4 << 48); 2241195534Sscottl if ((cgd->ident_data.support.command2 & ATA_SUPPORT_ADDRESS48) && 2242195534Sscottl lbasize48 > ATA_MAX_28BIT_LBA) 2243195534Sscottl dp->sectors = lbasize48; 2244195534Sscottl} 2245195534Sscottl 2246195534Sscottlstatic void 2247195534Sscottladasendorderedtag(void *arg) 2248195534Sscottl{ 2249195534Sscottl struct ada_softc *softc = arg; 2250195534Sscottl 2251195534Sscottl if (ada_send_ordered) { 2252257054Smav if (softc->outstanding_cmds > 0) { 2253257054Smav if ((softc->flags & ADA_FLAG_WAS_OTAG) == 0) 2254257054Smav softc->flags |= ADA_FLAG_NEED_OTAG; 2255257054Smav softc->flags &= ~ADA_FLAG_WAS_OTAG; 2256195534Sscottl } 2257195534Sscottl } 2258195534Sscottl /* Queue us up again */ 2259195534Sscottl callout_reset(&softc->sendordered_c, 2260230921Smav (ada_default_timeout * hz) / ADA_ORDEREDTAG_INTERVAL, 2261195534Sscottl adasendorderedtag, softc); 2262195534Sscottl} 2263195534Sscottl 2264195534Sscottl/* 2265195534Sscottl * Step through all ADA peripheral drivers, and if the device is still open, 2266195534Sscottl * sync the disk cache to physical media. 2267195534Sscottl */ 2268195534Sscottlstatic void 2269220650Smavadaflush(void) 2270195534Sscottl{ 2271195534Sscottl struct cam_periph *periph; 2272195534Sscottl struct ada_softc *softc; 2273248872Smav union ccb *ccb; 2274236814Smav int error; 2275195534Sscottl 2276248868Smav CAM_PERIPH_FOREACH(periph, &adadriver) { 2277251792Smav softc = (struct ada_softc *)periph->softc; 2278251792Smav if (SCHEDULER_STOPPED()) { 2279251792Smav /* If we paniced with the lock held, do not recurse. */ 2280251792Smav if (!cam_periph_owned(periph) && 2281251792Smav (softc->flags & ADA_FLAG_OPEN)) { 2282251792Smav adadump(softc->disk, NULL, 0, 0, 0); 2283251792Smav } 2284200180Smav continue; 2285251792Smav } 2286195534Sscottl cam_periph_lock(periph); 2287195534Sscottl /* 2288195534Sscottl * We only sync the cache if the drive is still open, and 2289195534Sscottl * if the drive is capable of it.. 2290195534Sscottl */ 2291195534Sscottl if (((softc->flags & ADA_FLAG_OPEN) == 0) || 2292195534Sscottl (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) == 0) { 2293195534Sscottl cam_periph_unlock(periph); 2294195534Sscottl continue; 2295195534Sscottl } 2296195534Sscottl 2297248872Smav ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 2298248872Smav cam_fill_ataio(&ccb->ataio, 2299236814Smav 0, 2300195534Sscottl adadone, 2301195534Sscottl CAM_DIR_NONE, 2302195534Sscottl 0, 2303195534Sscottl NULL, 2304195534Sscottl 0, 2305195534Sscottl ada_default_timeout*1000); 2306195534Sscottl if (softc->flags & ADA_FLAG_CAN_48BIT) 2307248872Smav ata_48bit_cmd(&ccb->ataio, ATA_FLUSHCACHE48, 0, 0, 0); 2308195534Sscottl else 2309248872Smav ata_28bit_cmd(&ccb->ataio, ATA_FLUSHCACHE, 0, 0, 0); 2310195534Sscottl 2311248872Smav error = cam_periph_runccb(ccb, adaerror, /*cam_flags*/0, 2312248872Smav /*sense_flags*/ SF_NO_RECOVERY | SF_NO_RETRY, 2313248872Smav softc->disk->d_devstat); 2314236814Smav if (error != 0) 2315195534Sscottl xpt_print(periph->path, "Synchronize cache failed\n"); 2316249048Smav xpt_release_ccb(ccb); 2317195534Sscottl cam_periph_unlock(periph); 2318195534Sscottl } 2319220650Smav} 2320214279Sbrucec 2321220650Smavstatic void 2322220650Smavadaspindown(uint8_t cmd, int flags) 2323220650Smav{ 2324220650Smav struct cam_periph *periph; 2325220650Smav struct ada_softc *softc; 2326248872Smav union ccb *ccb; 2327236814Smav int error; 2328214279Sbrucec 2329248868Smav CAM_PERIPH_FOREACH(periph, &adadriver) { 2330214279Sbrucec /* If we paniced with lock held - not recurse here. */ 2331214279Sbrucec if (cam_periph_owned(periph)) 2332214279Sbrucec continue; 2333214279Sbrucec cam_periph_lock(periph); 2334214279Sbrucec softc = (struct ada_softc *)periph->softc; 2335214279Sbrucec /* 2336214279Sbrucec * We only spin-down the drive if it is capable of it.. 2337214279Sbrucec */ 2338214279Sbrucec if ((softc->flags & ADA_FLAG_CAN_POWERMGT) == 0) { 2339214279Sbrucec cam_periph_unlock(periph); 2340214279Sbrucec continue; 2341214279Sbrucec } 2342214279Sbrucec 2343214279Sbrucec if (bootverbose) 2344214279Sbrucec xpt_print(periph->path, "spin-down\n"); 2345214279Sbrucec 2346248872Smav ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 2347248872Smav cam_fill_ataio(&ccb->ataio, 2348236814Smav 0, 2349214279Sbrucec adadone, 2350220650Smav CAM_DIR_NONE | flags, 2351214279Sbrucec 0, 2352214279Sbrucec NULL, 2353214279Sbrucec 0, 2354214279Sbrucec ada_default_timeout*1000); 2355248872Smav ata_28bit_cmd(&ccb->ataio, cmd, 0, 0, 0); 2356214279Sbrucec 2357248872Smav error = cam_periph_runccb(ccb, adaerror, /*cam_flags*/0, 2358248872Smav /*sense_flags*/ SF_NO_RECOVERY | SF_NO_RETRY, 2359248872Smav softc->disk->d_devstat); 2360236814Smav if (error != 0) 2361214279Sbrucec xpt_print(periph->path, "Spin-down disk failed\n"); 2362249048Smav xpt_release_ccb(ccb); 2363214279Sbrucec cam_periph_unlock(periph); 2364214279Sbrucec } 2365195534Sscottl} 2366195534Sscottl 2367220650Smavstatic void 2368220650Smavadashutdown(void *arg, int howto) 2369220650Smav{ 2370220650Smav 2371220650Smav adaflush(); 2372220650Smav if (ada_spindown_shutdown != 0 && 2373220650Smav (howto & (RB_HALT | RB_POWEROFF)) != 0) 2374220650Smav adaspindown(ATA_STANDBY_IMMEDIATE, 0); 2375220650Smav} 2376220650Smav 2377220650Smavstatic void 2378220650Smavadasuspend(void *arg) 2379220650Smav{ 2380220650Smav 2381220650Smav adaflush(); 2382220650Smav if (ada_spindown_suspend != 0) 2383220650Smav adaspindown(ATA_SLEEP, CAM_DEV_QFREEZE); 2384220650Smav} 2385220650Smav 2386220650Smavstatic void 2387220650Smavadaresume(void *arg) 2388220650Smav{ 2389220650Smav struct cam_periph *periph; 2390220650Smav struct ada_softc *softc; 2391220650Smav 2392220650Smav if (ada_spindown_suspend == 0) 2393220650Smav return; 2394220650Smav 2395248868Smav CAM_PERIPH_FOREACH(periph, &adadriver) { 2396220650Smav cam_periph_lock(periph); 2397220650Smav softc = (struct ada_softc *)periph->softc; 2398220650Smav /* 2399220650Smav * We only spin-down the drive if it is capable of it.. 2400220650Smav */ 2401220650Smav if ((softc->flags & ADA_FLAG_CAN_POWERMGT) == 0) { 2402220650Smav cam_periph_unlock(periph); 2403220650Smav continue; 2404220650Smav } 2405220650Smav 2406220650Smav if (bootverbose) 2407220650Smav xpt_print(periph->path, "resume\n"); 2408220650Smav 2409220650Smav /* 2410220650Smav * Drop freeze taken due to CAM_DEV_QFREEZE flag set on 2411220650Smav * sleep request. 2412220650Smav */ 2413220650Smav cam_release_devq(periph->path, 2414220650Smav /*relsim_flags*/0, 2415220650Smav /*openings*/0, 2416220650Smav /*timeout*/0, 2417220650Smav /*getcount_only*/0); 2418220650Smav 2419220650Smav cam_periph_unlock(periph); 2420220650Smav } 2421220650Smav} 2422220650Smav 2423195534Sscottl#endif /* _KERNEL */ 2424