ata_da.c revision 238382
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 238382 2012-07-11 23:22:09Z brueffer $"); 29195534Sscottl 30220454Smav#include "opt_ada.h" 31221071Smav#include "opt_ata.h" 32220454Smav 33195534Sscottl#include <sys/param.h> 34195534Sscottl 35195534Sscottl#ifdef _KERNEL 36195534Sscottl#include <sys/systm.h> 37195534Sscottl#include <sys/kernel.h> 38195534Sscottl#include <sys/bio.h> 39195534Sscottl#include <sys/sysctl.h> 40195534Sscottl#include <sys/taskqueue.h> 41195534Sscottl#include <sys/lock.h> 42195534Sscottl#include <sys/mutex.h> 43195534Sscottl#include <sys/conf.h> 44195534Sscottl#include <sys/devicestat.h> 45195534Sscottl#include <sys/eventhandler.h> 46195534Sscottl#include <sys/malloc.h> 47195534Sscottl#include <sys/cons.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> 62195534Sscottl 63195534Sscottl#include <cam/ata/ata_all.h> 64195534Sscottl 65208349Smarius#include <machine/md_var.h> /* geometry translation */ 66208349Smarius 67195534Sscottl#ifdef _KERNEL 68195534Sscottl 69195534Sscottl#define ATA_MAX_28BIT_LBA 268435455UL 70195534Sscottl 71195534Sscottltypedef enum { 72224497Smav ADA_STATE_RAHEAD, 73220412Smav ADA_STATE_WCACHE, 74198708Smav ADA_STATE_NORMAL 75195534Sscottl} ada_state; 76195534Sscottl 77195534Sscottltypedef enum { 78195534Sscottl ADA_FLAG_PACK_INVALID = 0x001, 79195534Sscottl ADA_FLAG_CAN_48BIT = 0x002, 80195534Sscottl ADA_FLAG_CAN_FLUSHCACHE = 0x004, 81198328Smav ADA_FLAG_CAN_NCQ = 0x008, 82198328Smav ADA_FLAG_CAN_DMA = 0x010, 83195534Sscottl ADA_FLAG_NEED_OTAG = 0x020, 84195534Sscottl ADA_FLAG_WENT_IDLE = 0x040, 85201139Smav ADA_FLAG_CAN_TRIM = 0x080, 86195534Sscottl ADA_FLAG_OPEN = 0x100, 87201139Smav ADA_FLAG_SCTX_INIT = 0x200, 88214279Sbrucec ADA_FLAG_CAN_CFA = 0x400, 89214279Sbrucec ADA_FLAG_CAN_POWERMGT = 0x800 90195534Sscottl} ada_flags; 91195534Sscottl 92195534Sscottltypedef enum { 93222520Smav ADA_Q_NONE = 0x00, 94222520Smav ADA_Q_4K = 0x01, 95195534Sscottl} ada_quirks; 96195534Sscottl 97195534Sscottltypedef enum { 98224497Smav ADA_CCB_RAHEAD = 0x01, 99224497Smav ADA_CCB_WCACHE = 0x02, 100195534Sscottl ADA_CCB_BUFFER_IO = 0x03, 101195534Sscottl ADA_CCB_WAITING = 0x04, 102195534Sscottl ADA_CCB_DUMP = 0x05, 103201139Smav ADA_CCB_TRIM = 0x06, 104195534Sscottl ADA_CCB_TYPE_MASK = 0x0F, 105195534Sscottl} ada_ccb_state; 106195534Sscottl 107195534Sscottl/* Offsets into our private area for storing information */ 108195534Sscottl#define ccb_state ppriv_field0 109195534Sscottl#define ccb_bp ppriv_ptr1 110195534Sscottl 111195534Sscottlstruct disk_params { 112195534Sscottl u_int8_t heads; 113198897Smav u_int8_t secs_per_track; 114195534Sscottl u_int32_t cylinders; 115198897Smav u_int32_t secsize; /* Number of bytes/logical sector */ 116198897Smav u_int64_t sectors; /* Total number sectors */ 117195534Sscottl}; 118195534Sscottl 119222643Smav#define TRIM_MAX_BLOCKS 8 120222628Smav#define TRIM_MAX_RANGES (TRIM_MAX_BLOCKS * 64) 121222643Smav#define TRIM_MAX_BIOS (TRIM_MAX_RANGES * 4) 122201139Smavstruct trim_request { 123201139Smav uint8_t data[TRIM_MAX_RANGES * 8]; 124222628Smav struct bio *bps[TRIM_MAX_BIOS]; 125201139Smav}; 126201139Smav 127195534Sscottlstruct ada_softc { 128195534Sscottl struct bio_queue_head bio_queue; 129201139Smav struct bio_queue_head trim_queue; 130195534Sscottl ada_state state; 131195534Sscottl ada_flags flags; 132195534Sscottl ada_quirks quirks; 133195534Sscottl int ordered_tag_count; 134195534Sscottl int outstanding_cmds; 135201139Smav int trim_max_ranges; 136201139Smav int trim_running; 137224497Smav int read_ahead; 138220454Smav int write_cache; 139220454Smav#ifdef ADA_TEST_FAILURE 140220454Smav int force_read_error; 141220454Smav int force_write_error; 142220454Smav int periodic_read_error; 143220454Smav int periodic_read_count; 144220454Smav#endif 145195534Sscottl struct disk_params params; 146195534Sscottl struct disk *disk; 147195534Sscottl struct task sysctl_task; 148195534Sscottl struct sysctl_ctx_list sysctl_ctx; 149195534Sscottl struct sysctl_oid *sysctl_tree; 150195534Sscottl struct callout sendordered_c; 151201139Smav struct trim_request trim_req; 152195534Sscottl}; 153195534Sscottl 154195534Sscottlstruct ada_quirk_entry { 155195534Sscottl struct scsi_inquiry_pattern inq_pat; 156195534Sscottl ada_quirks quirks; 157195534Sscottl}; 158195534Sscottl 159199178Smavstatic struct ada_quirk_entry ada_quirk_table[] = 160199178Smav{ 161199178Smav { 162222520Smav /* Hitachi Advanced Format (4k) drives */ 163222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "Hitachi H??????????E3*", "*" }, 164222520Smav /*quirks*/ADA_Q_4K 165222520Smav }, 166222520Smav { 167222520Smav /* Samsung Advanced Format (4k) drives */ 168228819Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "SAMSUNG HD155UI*", "*" }, 169228819Smav /*quirks*/ADA_Q_4K 170228819Smav }, 171228819Smav { 172228819Smav /* Samsung Advanced Format (4k) drives */ 173222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "SAMSUNG HD204UI*", "*" }, 174222520Smav /*quirks*/ADA_Q_4K 175222520Smav }, 176222520Smav { 177222520Smav /* Seagate Barracuda Green Advanced Format (4k) drives */ 178222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST????DL*", "*" }, 179222520Smav /*quirks*/ADA_Q_4K 180222520Smav }, 181222520Smav { 182228819Smav /* Seagate Barracuda Advanced Format (4k) drives */ 183228819Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST???DM*", "*" }, 184228819Smav /*quirks*/ADA_Q_4K 185228819Smav }, 186228819Smav { 187228819Smav /* Seagate Barracuda Advanced Format (4k) drives */ 188228819Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST????DM*", "*" }, 189228819Smav /*quirks*/ADA_Q_4K 190228819Smav }, 191228819Smav { 192222520Smav /* Seagate Momentus Advanced Format (4k) drives */ 193222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9500423AS*", "*" }, 194222520Smav /*quirks*/ADA_Q_4K 195222520Smav }, 196222520Smav { 197222520Smav /* Seagate Momentus Advanced Format (4k) drives */ 198222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9500424AS*", "*" }, 199222520Smav /*quirks*/ADA_Q_4K 200222520Smav }, 201222520Smav { 202222520Smav /* Seagate Momentus Advanced Format (4k) drives */ 203228819Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9640423AS*", "*" }, 204228819Smav /*quirks*/ADA_Q_4K 205228819Smav }, 206228819Smav { 207228819Smav /* Seagate Momentus Advanced Format (4k) drives */ 208228819Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9640424AS*", "*" }, 209228819Smav /*quirks*/ADA_Q_4K 210228819Smav }, 211228819Smav { 212228819Smav /* Seagate Momentus Advanced Format (4k) drives */ 213222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9750420AS*", "*" }, 214222520Smav /*quirks*/ADA_Q_4K 215222520Smav }, 216222520Smav { 217222520Smav /* Seagate Momentus Advanced Format (4k) drives */ 218222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9750422AS*", "*" }, 219222520Smav /*quirks*/ADA_Q_4K 220222520Smav }, 221222520Smav { 222228819Smav /* Seagate Momentus Advanced Format (4k) drives */ 223228819Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9750423AS*", "*" }, 224228819Smav /*quirks*/ADA_Q_4K 225228819Smav }, 226228819Smav { 227222520Smav /* Seagate Momentus Thin Advanced Format (4k) drives */ 228222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST???LT*", "*" }, 229222520Smav /*quirks*/ADA_Q_4K 230222520Smav }, 231222520Smav { 232222520Smav /* WDC Caviar Green Advanced Format (4k) drives */ 233222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD????RS*", "*" }, 234222520Smav /*quirks*/ADA_Q_4K 235222520Smav }, 236222520Smav { 237222520Smav /* WDC Caviar Green Advanced Format (4k) drives */ 238222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD????RX*", "*" }, 239222520Smav /*quirks*/ADA_Q_4K 240222520Smav }, 241222520Smav { 242222520Smav /* WDC Caviar Green Advanced Format (4k) drives */ 243222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD??????RS*", "*" }, 244222520Smav /*quirks*/ADA_Q_4K 245222520Smav }, 246222520Smav { 247222520Smav /* WDC Caviar Green Advanced Format (4k) drives */ 248222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD??????RX*", "*" }, 249222520Smav /*quirks*/ADA_Q_4K 250222520Smav }, 251222520Smav { 252222520Smav /* WDC Scorpio Black Advanced Format (4k) drives */ 253222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD???PKT*", "*" }, 254222520Smav /*quirks*/ADA_Q_4K 255222520Smav }, 256222520Smav { 257222520Smav /* WDC Scorpio Black Advanced Format (4k) drives */ 258222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD?????PKT*", "*" }, 259222520Smav /*quirks*/ADA_Q_4K 260222520Smav }, 261222520Smav { 262222520Smav /* WDC Scorpio Blue Advanced Format (4k) drives */ 263222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD???PVT*", "*" }, 264222520Smav /*quirks*/ADA_Q_4K 265222520Smav }, 266222520Smav { 267222520Smav /* WDC Scorpio Blue Advanced Format (4k) drives */ 268222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD?????PVT*", "*" }, 269222520Smav /*quirks*/ADA_Q_4K 270222520Smav }, 271222520Smav { 272199178Smav /* Default */ 273199178Smav { 274199178Smav T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED, 275199178Smav /*vendor*/"*", /*product*/"*", /*revision*/"*" 276199178Smav }, 277199178Smav /*quirks*/0 278199178Smav }, 279199178Smav}; 280195534Sscottl 281195534Sscottlstatic disk_strategy_t adastrategy; 282195534Sscottlstatic dumper_t adadump; 283195534Sscottlstatic periph_init_t adainit; 284195534Sscottlstatic void adaasync(void *callback_arg, u_int32_t code, 285195534Sscottl struct cam_path *path, void *arg); 286195534Sscottlstatic void adasysctlinit(void *context, int pending); 287195534Sscottlstatic periph_ctor_t adaregister; 288195534Sscottlstatic periph_dtor_t adacleanup; 289195534Sscottlstatic periph_start_t adastart; 290195534Sscottlstatic periph_oninv_t adaoninvalidate; 291195534Sscottlstatic void adadone(struct cam_periph *periph, 292195534Sscottl union ccb *done_ccb); 293195534Sscottlstatic int adaerror(union ccb *ccb, u_int32_t cam_flags, 294195534Sscottl u_int32_t sense_flags); 295198897Smavstatic void adagetparams(struct cam_periph *periph, 296195534Sscottl struct ccb_getdev *cgd); 297195534Sscottlstatic timeout_t adasendorderedtag; 298195534Sscottlstatic void adashutdown(void *arg, int howto); 299220650Smavstatic void adasuspend(void *arg); 300220650Smavstatic void adaresume(void *arg); 301195534Sscottl 302221071Smav#ifndef ADA_DEFAULT_LEGACY_ALIASES 303221071Smav#ifdef ATA_CAM 304221071Smav#define ADA_DEFAULT_LEGACY_ALIASES 1 305221071Smav#else 306221071Smav#define ADA_DEFAULT_LEGACY_ALIASES 0 307221071Smav#endif 308221071Smav#endif 309221071Smav 310195534Sscottl#ifndef ADA_DEFAULT_TIMEOUT 311195534Sscottl#define ADA_DEFAULT_TIMEOUT 30 /* Timeout in seconds */ 312195534Sscottl#endif 313195534Sscottl 314195534Sscottl#ifndef ADA_DEFAULT_RETRY 315195534Sscottl#define ADA_DEFAULT_RETRY 4 316195534Sscottl#endif 317195534Sscottl 318195534Sscottl#ifndef ADA_DEFAULT_SEND_ORDERED 319195534Sscottl#define ADA_DEFAULT_SEND_ORDERED 1 320195534Sscottl#endif 321195534Sscottl 322214279Sbrucec#ifndef ADA_DEFAULT_SPINDOWN_SHUTDOWN 323214279Sbrucec#define ADA_DEFAULT_SPINDOWN_SHUTDOWN 1 324214279Sbrucec#endif 325214279Sbrucec 326220650Smav#ifndef ADA_DEFAULT_SPINDOWN_SUSPEND 327220650Smav#define ADA_DEFAULT_SPINDOWN_SUSPEND 1 328220650Smav#endif 329220650Smav 330224497Smav#ifndef ADA_DEFAULT_READ_AHEAD 331224497Smav#define ADA_DEFAULT_READ_AHEAD 1 332224497Smav#endif 333224497Smav 334220412Smav#ifndef ADA_DEFAULT_WRITE_CACHE 335220412Smav#define ADA_DEFAULT_WRITE_CACHE 1 336220412Smav#endif 337220412Smav 338224497Smav#define ADA_RA (softc->read_ahead >= 0 ? \ 339224497Smav softc->read_ahead : ada_read_ahead) 340224497Smav#define ADA_WC (softc->write_cache >= 0 ? \ 341224497Smav softc->write_cache : ada_write_cache) 342224497Smav 343208349Smarius/* 344208349Smarius * Most platforms map firmware geometry to actual, but some don't. If 345208349Smarius * not overridden, default to nothing. 346208349Smarius */ 347208349Smarius#ifndef ata_disk_firmware_geom_adjust 348208349Smarius#define ata_disk_firmware_geom_adjust(disk) 349208349Smarius#endif 350195534Sscottl 351221071Smavstatic int ada_legacy_aliases = ADA_DEFAULT_LEGACY_ALIASES; 352195534Sscottlstatic int ada_retry_count = ADA_DEFAULT_RETRY; 353195534Sscottlstatic int ada_default_timeout = ADA_DEFAULT_TIMEOUT; 354195534Sscottlstatic int ada_send_ordered = ADA_DEFAULT_SEND_ORDERED; 355214279Sbrucecstatic int ada_spindown_shutdown = ADA_DEFAULT_SPINDOWN_SHUTDOWN; 356220650Smavstatic int ada_spindown_suspend = ADA_DEFAULT_SPINDOWN_SUSPEND; 357224497Smavstatic int ada_read_ahead = ADA_DEFAULT_READ_AHEAD; 358220412Smavstatic int ada_write_cache = ADA_DEFAULT_WRITE_CACHE; 359195534Sscottl 360227309Sedstatic SYSCTL_NODE(_kern_cam, OID_AUTO, ada, CTLFLAG_RD, 0, 361195534Sscottl "CAM Direct Access Disk driver"); 362221071SmavSYSCTL_INT(_kern_cam_ada, OID_AUTO, legacy_aliases, CTLFLAG_RW, 363221071Smav &ada_legacy_aliases, 0, "Create legacy-like device aliases"); 364221071SmavTUNABLE_INT("kern.cam.ada.legacy_aliases", &ada_legacy_aliases); 365195534SscottlSYSCTL_INT(_kern_cam_ada, OID_AUTO, retry_count, CTLFLAG_RW, 366195534Sscottl &ada_retry_count, 0, "Normal I/O retry count"); 367195534SscottlTUNABLE_INT("kern.cam.ada.retry_count", &ada_retry_count); 368195534SscottlSYSCTL_INT(_kern_cam_ada, OID_AUTO, default_timeout, CTLFLAG_RW, 369195534Sscottl &ada_default_timeout, 0, "Normal I/O timeout (in seconds)"); 370195534SscottlTUNABLE_INT("kern.cam.ada.default_timeout", &ada_default_timeout); 371238382SbruefferSYSCTL_INT(_kern_cam_ada, OID_AUTO, send_ordered, CTLFLAG_RW, 372195534Sscottl &ada_send_ordered, 0, "Send Ordered Tags"); 373238382SbruefferTUNABLE_INT("kern.cam.ada.send_ordered", &ada_send_ordered); 374214279SbrucecSYSCTL_INT(_kern_cam_ada, OID_AUTO, spindown_shutdown, CTLFLAG_RW, 375214279Sbrucec &ada_spindown_shutdown, 0, "Spin down upon shutdown"); 376214279SbrucecTUNABLE_INT("kern.cam.ada.spindown_shutdown", &ada_spindown_shutdown); 377220650SmavSYSCTL_INT(_kern_cam_ada, OID_AUTO, spindown_suspend, CTLFLAG_RW, 378220650Smav &ada_spindown_suspend, 0, "Spin down upon suspend"); 379220650SmavTUNABLE_INT("kern.cam.ada.spindown_suspend", &ada_spindown_suspend); 380224497SmavSYSCTL_INT(_kern_cam_ada, OID_AUTO, read_ahead, CTLFLAG_RW, 381224497Smav &ada_read_ahead, 0, "Enable disk read-ahead"); 382224497SmavTUNABLE_INT("kern.cam.ada.read_ahead", &ada_read_ahead); 383220412SmavSYSCTL_INT(_kern_cam_ada, OID_AUTO, write_cache, CTLFLAG_RW, 384220412Smav &ada_write_cache, 0, "Enable disk write cache"); 385220412SmavTUNABLE_INT("kern.cam.ada.write_cache", &ada_write_cache); 386195534Sscottl 387195534Sscottl/* 388195534Sscottl * ADA_ORDEREDTAG_INTERVAL determines how often, relative 389195534Sscottl * to the default timeout, we check to see whether an ordered 390195534Sscottl * tagged transaction is appropriate to prevent simple tag 391195534Sscottl * starvation. Since we'd like to ensure that there is at least 392195534Sscottl * 1/2 of the timeout length left for a starved transaction to 393195534Sscottl * complete after we've sent an ordered tag, we must poll at least 394195534Sscottl * four times in every timeout period. This takes care of the worst 395195534Sscottl * case where a starved transaction starts during an interval that 396195534Sscottl * meets the requirement "don't send an ordered tag" test so it takes 397195534Sscottl * us two intervals to determine that a tag must be sent. 398195534Sscottl */ 399195534Sscottl#ifndef ADA_ORDEREDTAG_INTERVAL 400195534Sscottl#define ADA_ORDEREDTAG_INTERVAL 4 401195534Sscottl#endif 402195534Sscottl 403195534Sscottlstatic struct periph_driver adadriver = 404195534Sscottl{ 405195534Sscottl adainit, "ada", 406195534Sscottl TAILQ_HEAD_INITIALIZER(adadriver.units), /* generation */ 0 407195534Sscottl}; 408195534Sscottl 409195534SscottlPERIPHDRIVER_DECLARE(ada, adadriver); 410195534Sscottl 411227293Sedstatic MALLOC_DEFINE(M_ATADA, "ata_da", "ata_da buffers"); 412195534Sscottl 413195534Sscottlstatic int 414195534Sscottladaopen(struct disk *dp) 415195534Sscottl{ 416195534Sscottl struct cam_periph *periph; 417195534Sscottl struct ada_softc *softc; 418195534Sscottl int error; 419195534Sscottl 420195534Sscottl periph = (struct cam_periph *)dp->d_drv1; 421195534Sscottl if (periph == NULL) { 422195534Sscottl return (ENXIO); 423195534Sscottl } 424195534Sscottl 425195534Sscottl if (cam_periph_acquire(periph) != CAM_REQ_CMP) { 426195534Sscottl return(ENXIO); 427195534Sscottl } 428195534Sscottl 429195534Sscottl cam_periph_lock(periph); 430195534Sscottl if ((error = cam_periph_hold(periph, PRIBIO|PCATCH)) != 0) { 431195534Sscottl cam_periph_unlock(periph); 432195534Sscottl cam_periph_release(periph); 433195534Sscottl return (error); 434195534Sscottl } 435195534Sscottl 436195534Sscottl softc = (struct ada_softc *)periph->softc; 437195534Sscottl softc->flags |= ADA_FLAG_OPEN; 438195534Sscottl 439236602Smav CAM_DEBUG(periph->path, CAM_DEBUG_TRACE | CAM_DEBUG_PERIPH, 440236602Smav ("adaopen\n")); 441195534Sscottl 442195534Sscottl if ((softc->flags & ADA_FLAG_PACK_INVALID) != 0) { 443195534Sscottl /* Invalidate our pack information. */ 444195534Sscottl softc->flags &= ~ADA_FLAG_PACK_INVALID; 445195534Sscottl } 446195534Sscottl 447195534Sscottl cam_periph_unhold(periph); 448195534Sscottl cam_periph_unlock(periph); 449195534Sscottl return (0); 450195534Sscottl} 451195534Sscottl 452195534Sscottlstatic int 453195534Sscottladaclose(struct disk *dp) 454195534Sscottl{ 455195534Sscottl struct cam_periph *periph; 456195534Sscottl struct ada_softc *softc; 457195534Sscottl union ccb *ccb; 458195534Sscottl 459195534Sscottl periph = (struct cam_periph *)dp->d_drv1; 460195534Sscottl if (periph == NULL) 461195534Sscottl return (ENXIO); 462195534Sscottl 463195534Sscottl cam_periph_lock(periph); 464234414Smav if (cam_periph_hold(periph, PRIBIO) != 0) { 465195534Sscottl cam_periph_unlock(periph); 466195534Sscottl cam_periph_release(periph); 467234414Smav return (0); 468195534Sscottl } 469195534Sscottl 470195534Sscottl softc = (struct ada_softc *)periph->softc; 471236602Smav 472236602Smav CAM_DEBUG(periph->path, CAM_DEBUG_TRACE | CAM_DEBUG_PERIPH, 473236602Smav ("adaclose\n")); 474236602Smav 475195534Sscottl /* We only sync the cache if the drive is capable of it. */ 476224283Smav if ((softc->flags & ADA_FLAG_CAN_FLUSHCACHE) != 0 && 477224283Smav (softc->flags & ADA_FLAG_PACK_INVALID) == 0) { 478195534Sscottl 479198382Smav ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 480195534Sscottl cam_fill_ataio(&ccb->ataio, 481195534Sscottl 1, 482195534Sscottl adadone, 483195534Sscottl CAM_DIR_NONE, 484195534Sscottl 0, 485195534Sscottl NULL, 486195534Sscottl 0, 487195534Sscottl ada_default_timeout*1000); 488195534Sscottl 489195534Sscottl if (softc->flags & ADA_FLAG_CAN_48BIT) 490195534Sscottl ata_48bit_cmd(&ccb->ataio, ATA_FLUSHCACHE48, 0, 0, 0); 491195534Sscottl else 492196659Smav ata_28bit_cmd(&ccb->ataio, ATA_FLUSHCACHE, 0, 0, 0); 493236639Smav cam_periph_runccb(ccb, adaerror, /*cam_flags*/0, 494198328Smav /*sense_flags*/0, softc->disk->d_devstat); 495195534Sscottl 496195534Sscottl if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) 497195534Sscottl xpt_print(periph->path, "Synchronize cache failed\n"); 498195534Sscottl xpt_release_ccb(ccb); 499195534Sscottl } 500195534Sscottl 501195534Sscottl softc->flags &= ~ADA_FLAG_OPEN; 502195534Sscottl cam_periph_unhold(periph); 503195534Sscottl cam_periph_unlock(periph); 504195534Sscottl cam_periph_release(periph); 505195534Sscottl return (0); 506195534Sscottl} 507195534Sscottl 508201139Smavstatic void 509201139Smavadaschedule(struct cam_periph *periph) 510201139Smav{ 511201139Smav struct ada_softc *softc = (struct ada_softc *)periph->softc; 512224531Smav uint32_t prio; 513201139Smav 514224531Smav /* Check if cam_periph_getccb() was called. */ 515224531Smav prio = periph->immediate_priority; 516224531Smav 517224531Smav /* Check if we have more work to do. */ 518201139Smav if (bioq_first(&softc->bio_queue) || 519201139Smav (!softc->trim_running && bioq_first(&softc->trim_queue))) { 520224531Smav prio = CAM_PRIORITY_NORMAL; 521201139Smav } 522224531Smav 523224531Smav /* Schedule CCB if any of above is true. */ 524224531Smav if (prio != CAM_PRIORITY_NONE) 525224531Smav xpt_schedule(periph, prio); 526201139Smav} 527201139Smav 528195534Sscottl/* 529195534Sscottl * Actually translate the requested transfer into one the physical driver 530195534Sscottl * can understand. The transfer is described by a buf and will include 531195534Sscottl * only one physical transfer. 532195534Sscottl */ 533195534Sscottlstatic void 534195534Sscottladastrategy(struct bio *bp) 535195534Sscottl{ 536195534Sscottl struct cam_periph *periph; 537195534Sscottl struct ada_softc *softc; 538195534Sscottl 539195534Sscottl periph = (struct cam_periph *)bp->bio_disk->d_drv1; 540195534Sscottl if (periph == NULL) { 541195534Sscottl biofinish(bp, NULL, ENXIO); 542195534Sscottl return; 543195534Sscottl } 544195534Sscottl softc = (struct ada_softc *)periph->softc; 545195534Sscottl 546195534Sscottl cam_periph_lock(periph); 547195534Sscottl 548236602Smav CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("adastrategy(%p)\n", bp)); 549236602Smav 550195534Sscottl /* 551195534Sscottl * If the device has been made invalid, error out 552195534Sscottl */ 553195534Sscottl if ((softc->flags & ADA_FLAG_PACK_INVALID)) { 554195534Sscottl cam_periph_unlock(periph); 555195534Sscottl biofinish(bp, NULL, ENXIO); 556195534Sscottl return; 557195534Sscottl } 558195534Sscottl 559195534Sscottl /* 560195534Sscottl * Place it in the queue of disk activities for this disk 561195534Sscottl */ 562201139Smav if (bp->bio_cmd == BIO_DELETE && 563201139Smav (softc->flags & ADA_FLAG_CAN_TRIM)) 564201139Smav bioq_disksort(&softc->trim_queue, bp); 565201139Smav else 566201139Smav bioq_disksort(&softc->bio_queue, bp); 567195534Sscottl 568195534Sscottl /* 569195534Sscottl * Schedule ourselves for performing the work. 570195534Sscottl */ 571201139Smav adaschedule(periph); 572195534Sscottl cam_periph_unlock(periph); 573195534Sscottl 574195534Sscottl return; 575195534Sscottl} 576195534Sscottl 577195534Sscottlstatic int 578195534Sscottladadump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t length) 579195534Sscottl{ 580195534Sscottl struct cam_periph *periph; 581195534Sscottl struct ada_softc *softc; 582195534Sscottl u_int secsize; 583195534Sscottl union ccb ccb; 584195534Sscottl struct disk *dp; 585195534Sscottl uint64_t lba; 586195534Sscottl uint16_t count; 587236814Smav int error = 0; 588195534Sscottl 589195534Sscottl dp = arg; 590195534Sscottl periph = dp->d_drv1; 591195534Sscottl if (periph == NULL) 592195534Sscottl return (ENXIO); 593195534Sscottl softc = (struct ada_softc *)periph->softc; 594195534Sscottl cam_periph_lock(periph); 595195534Sscottl secsize = softc->params.secsize; 596195534Sscottl lba = offset / secsize; 597195534Sscottl count = length / secsize; 598195534Sscottl 599195534Sscottl if ((softc->flags & ADA_FLAG_PACK_INVALID) != 0) { 600195534Sscottl cam_periph_unlock(periph); 601195534Sscottl return (ENXIO); 602195534Sscottl } 603195534Sscottl 604195534Sscottl if (length > 0) { 605198382Smav xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 606195534Sscottl ccb.ccb_h.ccb_state = ADA_CCB_DUMP; 607195534Sscottl cam_fill_ataio(&ccb.ataio, 608195534Sscottl 0, 609195534Sscottl adadone, 610195534Sscottl CAM_DIR_OUT, 611195534Sscottl 0, 612195534Sscottl (u_int8_t *) virtual, 613195534Sscottl length, 614195534Sscottl ada_default_timeout*1000); 615195534Sscottl if ((softc->flags & ADA_FLAG_CAN_48BIT) && 616195534Sscottl (lba + count >= ATA_MAX_28BIT_LBA || 617195534Sscottl count >= 256)) { 618195534Sscottl ata_48bit_cmd(&ccb.ataio, ATA_WRITE_DMA48, 619195534Sscottl 0, lba, count); 620195534Sscottl } else { 621196659Smav ata_28bit_cmd(&ccb.ataio, ATA_WRITE_DMA, 622195534Sscottl 0, lba, count); 623195534Sscottl } 624195534Sscottl xpt_polled_action(&ccb); 625195534Sscottl 626236814Smav error = cam_periph_error(&ccb, 627236814Smav 0, SF_NO_RECOVERY | SF_NO_RETRY, NULL); 628236814Smav if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0) 629236814Smav cam_release_devq(ccb.ccb_h.path, /*relsim_flags*/0, 630236814Smav /*reduction*/0, /*timeout*/0, /*getcount_only*/0); 631236814Smav if (error != 0) 632195534Sscottl printf("Aborting dump due to I/O error.\n"); 633236814Smav 634195534Sscottl cam_periph_unlock(periph); 635236814Smav return (error); 636195534Sscottl } 637195534Sscottl 638195534Sscottl if (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) { 639198382Smav xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 640195534Sscottl 641195534Sscottl ccb.ccb_h.ccb_state = ADA_CCB_DUMP; 642195534Sscottl cam_fill_ataio(&ccb.ataio, 643236814Smav 0, 644195534Sscottl adadone, 645195534Sscottl CAM_DIR_NONE, 646195534Sscottl 0, 647195534Sscottl NULL, 648195534Sscottl 0, 649195534Sscottl ada_default_timeout*1000); 650195534Sscottl 651195534Sscottl if (softc->flags & ADA_FLAG_CAN_48BIT) 652195534Sscottl ata_48bit_cmd(&ccb.ataio, ATA_FLUSHCACHE48, 0, 0, 0); 653195534Sscottl else 654196659Smav ata_28bit_cmd(&ccb.ataio, ATA_FLUSHCACHE, 0, 0, 0); 655195534Sscottl xpt_polled_action(&ccb); 656195534Sscottl 657236814Smav error = cam_periph_error(&ccb, 658236814Smav 0, SF_NO_RECOVERY | SF_NO_RETRY, NULL); 659236814Smav if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0) 660236814Smav cam_release_devq(ccb.ccb_h.path, /*relsim_flags*/0, 661236814Smav /*reduction*/0, /*timeout*/0, /*getcount_only*/0); 662236814Smav if (error != 0) 663195534Sscottl xpt_print(periph->path, "Synchronize cache failed\n"); 664195534Sscottl } 665195534Sscottl cam_periph_unlock(periph); 666236814Smav return (error); 667195534Sscottl} 668195534Sscottl 669195534Sscottlstatic void 670195534Sscottladainit(void) 671195534Sscottl{ 672195534Sscottl cam_status status; 673195534Sscottl 674195534Sscottl /* 675195534Sscottl * Install a global async callback. This callback will 676195534Sscottl * receive async callbacks like "new device found". 677195534Sscottl */ 678195534Sscottl status = xpt_register_async(AC_FOUND_DEVICE, adaasync, NULL, NULL); 679195534Sscottl 680195534Sscottl if (status != CAM_REQ_CMP) { 681195534Sscottl printf("ada: Failed to attach master async callback " 682195534Sscottl "due to status 0x%x!\n", status); 683195534Sscottl } else if (ada_send_ordered) { 684195534Sscottl 685220650Smav /* Register our event handlers */ 686220650Smav if ((EVENTHANDLER_REGISTER(power_suspend, adasuspend, 687220650Smav NULL, EVENTHANDLER_PRI_LAST)) == NULL) 688220650Smav printf("adainit: power event registration failed!\n"); 689220650Smav if ((EVENTHANDLER_REGISTER(power_resume, adaresume, 690220650Smav NULL, EVENTHANDLER_PRI_LAST)) == NULL) 691220650Smav printf("adainit: power event registration failed!\n"); 692220650Smav if ((EVENTHANDLER_REGISTER(shutdown_post_sync, adashutdown, 693195534Sscottl NULL, SHUTDOWN_PRI_DEFAULT)) == NULL) 694195534Sscottl printf("adainit: shutdown event registration failed!\n"); 695195534Sscottl } 696195534Sscottl} 697195534Sscottl 698195534Sscottlstatic void 699195534Sscottladaoninvalidate(struct cam_periph *periph) 700195534Sscottl{ 701195534Sscottl struct ada_softc *softc; 702195534Sscottl 703195534Sscottl softc = (struct ada_softc *)periph->softc; 704195534Sscottl 705195534Sscottl /* 706195534Sscottl * De-register any async callbacks. 707195534Sscottl */ 708195534Sscottl xpt_register_async(0, adaasync, periph, periph->path); 709195534Sscottl 710195534Sscottl softc->flags |= ADA_FLAG_PACK_INVALID; 711195534Sscottl 712195534Sscottl /* 713195534Sscottl * Return all queued I/O with ENXIO. 714195534Sscottl * XXX Handle any transactions queued to the card 715195534Sscottl * with XPT_ABORT_CCB. 716195534Sscottl */ 717195534Sscottl bioq_flush(&softc->bio_queue, NULL, ENXIO); 718201139Smav bioq_flush(&softc->trim_queue, NULL, ENXIO); 719195534Sscottl 720195534Sscottl disk_gone(softc->disk); 721195534Sscottl xpt_print(periph->path, "lost device\n"); 722195534Sscottl} 723195534Sscottl 724195534Sscottlstatic void 725195534Sscottladacleanup(struct cam_periph *periph) 726195534Sscottl{ 727195534Sscottl struct ada_softc *softc; 728195534Sscottl 729195534Sscottl softc = (struct ada_softc *)periph->softc; 730195534Sscottl 731195534Sscottl xpt_print(periph->path, "removing device entry\n"); 732195534Sscottl cam_periph_unlock(periph); 733195534Sscottl 734195534Sscottl /* 735195534Sscottl * If we can't free the sysctl tree, oh well... 736195534Sscottl */ 737195534Sscottl if ((softc->flags & ADA_FLAG_SCTX_INIT) != 0 738195534Sscottl && sysctl_ctx_free(&softc->sysctl_ctx) != 0) { 739195534Sscottl xpt_print(periph->path, "can't remove sysctl context\n"); 740195534Sscottl } 741195534Sscottl 742195534Sscottl disk_destroy(softc->disk); 743195534Sscottl callout_drain(&softc->sendordered_c); 744195534Sscottl free(softc, M_DEVBUF); 745195534Sscottl cam_periph_lock(periph); 746195534Sscottl} 747195534Sscottl 748195534Sscottlstatic void 749195534Sscottladaasync(void *callback_arg, u_int32_t code, 750195534Sscottl struct cam_path *path, void *arg) 751195534Sscottl{ 752236393Smav struct ccb_getdev cgd; 753195534Sscottl struct cam_periph *periph; 754220412Smav struct ada_softc *softc; 755195534Sscottl 756195534Sscottl periph = (struct cam_periph *)callback_arg; 757195534Sscottl switch (code) { 758195534Sscottl case AC_FOUND_DEVICE: 759195534Sscottl { 760195534Sscottl struct ccb_getdev *cgd; 761195534Sscottl cam_status status; 762195534Sscottl 763195534Sscottl cgd = (struct ccb_getdev *)arg; 764195534Sscottl if (cgd == NULL) 765195534Sscottl break; 766195534Sscottl 767195534Sscottl if (cgd->protocol != PROTO_ATA) 768195534Sscottl break; 769195534Sscottl 770195534Sscottl /* 771195534Sscottl * Allocate a peripheral instance for 772195534Sscottl * this device and start the probe 773195534Sscottl * process. 774195534Sscottl */ 775195534Sscottl status = cam_periph_alloc(adaregister, adaoninvalidate, 776195534Sscottl adacleanup, adastart, 777195534Sscottl "ada", CAM_PERIPH_BIO, 778195534Sscottl cgd->ccb_h.path, adaasync, 779195534Sscottl AC_FOUND_DEVICE, cgd); 780195534Sscottl 781195534Sscottl if (status != CAM_REQ_CMP 782195534Sscottl && status != CAM_REQ_INPROG) 783195534Sscottl printf("adaasync: Unable to attach to new device " 784195534Sscottl "due to status 0x%x\n", status); 785195534Sscottl break; 786195534Sscottl } 787236393Smav case AC_GETDEV_CHANGED: 788236393Smav { 789236393Smav softc = (struct ada_softc *)periph->softc; 790236393Smav xpt_setup_ccb(&cgd.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 791236393Smav cgd.ccb_h.func_code = XPT_GDEV_TYPE; 792236393Smav xpt_action((union ccb *)&cgd); 793236393Smav 794236393Smav if ((cgd.ident_data.capabilities1 & ATA_SUPPORT_DMA) && 795236393Smav (cgd.inq_flags & SID_DMA)) 796236393Smav softc->flags |= ADA_FLAG_CAN_DMA; 797236393Smav else 798236393Smav softc->flags &= ~ADA_FLAG_CAN_DMA; 799236393Smav if ((cgd.ident_data.satacapabilities & ATA_SUPPORT_NCQ) && 800236393Smav (cgd.inq_flags & SID_DMA) && (cgd.inq_flags & SID_CmdQue)) 801236393Smav softc->flags |= ADA_FLAG_CAN_NCQ; 802236393Smav else 803236393Smav softc->flags &= ~ADA_FLAG_CAN_NCQ; 804236393Smav if ((cgd.ident_data.support_dsm & ATA_SUPPORT_DSM_TRIM) && 805236393Smav (cgd.inq_flags & SID_DMA)) 806236393Smav softc->flags |= ADA_FLAG_CAN_TRIM; 807236393Smav else 808236393Smav softc->flags &= ~ADA_FLAG_CAN_TRIM; 809236393Smav 810236393Smav cam_periph_async(periph, code, path, arg); 811236393Smav break; 812236393Smav } 813235897Smav case AC_ADVINFO_CHANGED: 814235897Smav { 815235897Smav uintptr_t buftype; 816235897Smav 817235897Smav buftype = (uintptr_t)arg; 818235897Smav if (buftype == CDAI_TYPE_PHYS_PATH) { 819235897Smav struct ada_softc *softc; 820235897Smav 821235897Smav softc = periph->softc; 822235897Smav disk_attr_changed(softc->disk, "GEOM::physpath", 823235897Smav M_NOWAIT); 824235897Smav } 825235897Smav break; 826235897Smav } 827220412Smav case AC_SENT_BDR: 828220412Smav case AC_BUS_RESET: 829220412Smav { 830220412Smav softc = (struct ada_softc *)periph->softc; 831220412Smav cam_periph_async(periph, code, path, arg); 832220412Smav if (softc->state != ADA_STATE_NORMAL) 833220412Smav break; 834220454Smav xpt_setup_ccb(&cgd.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 835220412Smav cgd.ccb_h.func_code = XPT_GDEV_TYPE; 836220412Smav xpt_action((union ccb *)&cgd); 837224497Smav if (ADA_RA >= 0 && 838224497Smav cgd.ident_data.support.command1 & ATA_SUPPORT_LOOKAHEAD) 839224497Smav softc->state = ADA_STATE_RAHEAD; 840224497Smav else if (ADA_WC >= 0 && 841224497Smav cgd.ident_data.support.command1 & ATA_SUPPORT_WRITECACHE) 842224497Smav softc->state = ADA_STATE_WCACHE; 843224497Smav else 844224497Smav break; 845220412Smav cam_periph_acquire(periph); 846220412Smav cam_freeze_devq_arg(periph->path, 847220412Smav RELSIM_RELEASE_RUNLEVEL, CAM_RL_DEV + 1); 848220412Smav xpt_schedule(periph, CAM_PRIORITY_DEV); 849220412Smav } 850195534Sscottl default: 851195534Sscottl cam_periph_async(periph, code, path, arg); 852195534Sscottl break; 853195534Sscottl } 854195534Sscottl} 855195534Sscottl 856195534Sscottlstatic void 857195534Sscottladasysctlinit(void *context, int pending) 858195534Sscottl{ 859195534Sscottl struct cam_periph *periph; 860195534Sscottl struct ada_softc *softc; 861195534Sscottl char tmpstr[80], tmpstr2[80]; 862195534Sscottl 863195534Sscottl periph = (struct cam_periph *)context; 864220454Smav 865220454Smav /* periph was held for us when this task was enqueued */ 866220454Smav if (periph->flags & CAM_PERIPH_INVALID) { 867220454Smav cam_periph_release(periph); 868195534Sscottl return; 869220454Smav } 870195534Sscottl 871195534Sscottl softc = (struct ada_softc *)periph->softc; 872195534Sscottl snprintf(tmpstr, sizeof(tmpstr), "CAM ADA unit %d", periph->unit_number); 873195534Sscottl snprintf(tmpstr2, sizeof(tmpstr2), "%d", periph->unit_number); 874195534Sscottl 875195534Sscottl sysctl_ctx_init(&softc->sysctl_ctx); 876195534Sscottl softc->flags |= ADA_FLAG_SCTX_INIT; 877195534Sscottl softc->sysctl_tree = SYSCTL_ADD_NODE(&softc->sysctl_ctx, 878195534Sscottl SYSCTL_STATIC_CHILDREN(_kern_cam_ada), OID_AUTO, tmpstr2, 879195534Sscottl CTLFLAG_RD, 0, tmpstr); 880195534Sscottl if (softc->sysctl_tree == NULL) { 881195534Sscottl printf("adasysctlinit: unable to allocate sysctl tree\n"); 882195534Sscottl cam_periph_release(periph); 883195534Sscottl return; 884195534Sscottl } 885195534Sscottl 886220454Smav SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 887224497Smav OID_AUTO, "read_ahead", CTLFLAG_RW | CTLFLAG_MPSAFE, 888224497Smav &softc->read_ahead, 0, "Enable disk read ahead."); 889224497Smav SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 890220454Smav OID_AUTO, "write_cache", CTLFLAG_RW | CTLFLAG_MPSAFE, 891220454Smav &softc->write_cache, 0, "Enable disk write cache."); 892220454Smav#ifdef ADA_TEST_FAILURE 893220454Smav /* 894220454Smav * Add a 'door bell' sysctl which allows one to set it from userland 895220454Smav * and cause something bad to happen. For the moment, we only allow 896220454Smav * whacking the next read or write. 897220454Smav */ 898220454Smav SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 899220454Smav OID_AUTO, "force_read_error", CTLFLAG_RW | CTLFLAG_MPSAFE, 900220454Smav &softc->force_read_error, 0, 901220454Smav "Force a read error for the next N reads."); 902220454Smav SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 903220454Smav OID_AUTO, "force_write_error", CTLFLAG_RW | CTLFLAG_MPSAFE, 904220454Smav &softc->force_write_error, 0, 905220454Smav "Force a write error for the next N writes."); 906220454Smav SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 907220454Smav OID_AUTO, "periodic_read_error", CTLFLAG_RW | CTLFLAG_MPSAFE, 908220454Smav &softc->periodic_read_error, 0, 909220454Smav "Force a read error every N reads (don't set too low)."); 910220454Smav#endif 911195534Sscottl cam_periph_release(periph); 912195534Sscottl} 913195534Sscottl 914223089Sgibbsstatic int 915223089Sgibbsadagetattr(struct bio *bp) 916223089Sgibbs{ 917223089Sgibbs int ret = -1; 918223089Sgibbs struct cam_periph *periph; 919223089Sgibbs 920223277Skib if (bp->bio_disk == NULL || bp->bio_disk->d_drv1 == NULL) 921223089Sgibbs return ENXIO; 922223089Sgibbs periph = (struct cam_periph *)bp->bio_disk->d_drv1; 923223089Sgibbs if (periph->path == NULL) 924223089Sgibbs return ENXIO; 925223089Sgibbs 926223089Sgibbs ret = xpt_getattr(bp->bio_data, bp->bio_length, bp->bio_attribute, 927223089Sgibbs periph->path); 928223089Sgibbs if (ret == 0) 929223089Sgibbs bp->bio_completed = bp->bio_length; 930223089Sgibbs return ret; 931223089Sgibbs} 932223089Sgibbs 933195534Sscottlstatic cam_status 934195534Sscottladaregister(struct cam_periph *periph, void *arg) 935195534Sscottl{ 936195534Sscottl struct ada_softc *softc; 937195534Sscottl struct ccb_pathinq cpi; 938195534Sscottl struct ccb_getdev *cgd; 939221071Smav char announce_buf[80], buf1[32]; 940195534Sscottl struct disk_params *dp; 941195534Sscottl caddr_t match; 942195534Sscottl u_int maxio; 943222520Smav int legacy_id, quirks; 944195534Sscottl 945195534Sscottl cgd = (struct ccb_getdev *)arg; 946195534Sscottl if (periph == NULL) { 947195534Sscottl printf("adaregister: periph was NULL!!\n"); 948195534Sscottl return(CAM_REQ_CMP_ERR); 949195534Sscottl } 950195534Sscottl 951195534Sscottl if (cgd == NULL) { 952195534Sscottl printf("adaregister: no getdev CCB, can't register device\n"); 953195534Sscottl return(CAM_REQ_CMP_ERR); 954195534Sscottl } 955195534Sscottl 956195534Sscottl softc = (struct ada_softc *)malloc(sizeof(*softc), M_DEVBUF, 957195534Sscottl M_NOWAIT|M_ZERO); 958195534Sscottl 959195534Sscottl if (softc == NULL) { 960195534Sscottl printf("adaregister: Unable to probe new device. " 961198328Smav "Unable to allocate softc\n"); 962195534Sscottl return(CAM_REQ_CMP_ERR); 963195534Sscottl } 964195534Sscottl 965195534Sscottl bioq_init(&softc->bio_queue); 966201139Smav bioq_init(&softc->trim_queue); 967195534Sscottl 968236393Smav if ((cgd->ident_data.capabilities1 & ATA_SUPPORT_DMA) && 969220886Smav (cgd->inq_flags & SID_DMA)) 970198328Smav softc->flags |= ADA_FLAG_CAN_DMA; 971195534Sscottl if (cgd->ident_data.support.command2 & ATA_SUPPORT_ADDRESS48) 972195534Sscottl softc->flags |= ADA_FLAG_CAN_48BIT; 973195534Sscottl if (cgd->ident_data.support.command2 & ATA_SUPPORT_FLUSHCACHE) 974195534Sscottl softc->flags |= ADA_FLAG_CAN_FLUSHCACHE; 975214279Sbrucec if (cgd->ident_data.support.command1 & ATA_SUPPORT_POWERMGT) 976214279Sbrucec softc->flags |= ADA_FLAG_CAN_POWERMGT; 977236393Smav if ((cgd->ident_data.satacapabilities & ATA_SUPPORT_NCQ) && 978220886Smav (cgd->inq_flags & SID_DMA) && (cgd->inq_flags & SID_CmdQue)) 979195534Sscottl softc->flags |= ADA_FLAG_CAN_NCQ; 980236393Smav if ((cgd->ident_data.support_dsm & ATA_SUPPORT_DSM_TRIM) && 981236393Smav (cgd->inq_flags & SID_DMA)) { 982201139Smav softc->flags |= ADA_FLAG_CAN_TRIM; 983201139Smav softc->trim_max_ranges = TRIM_MAX_RANGES; 984201139Smav if (cgd->ident_data.max_dsm_blocks != 0) { 985201139Smav softc->trim_max_ranges = 986201139Smav min(cgd->ident_data.max_dsm_blocks * 64, 987201139Smav softc->trim_max_ranges); 988201139Smav } 989201139Smav } 990201139Smav if (cgd->ident_data.support.command2 & ATA_SUPPORT_CFA) 991201139Smav softc->flags |= ADA_FLAG_CAN_CFA; 992195534Sscottl 993195534Sscottl periph->softc = softc; 994195534Sscottl 995195534Sscottl /* 996195534Sscottl * See if this device has any quirks. 997195534Sscottl */ 998199178Smav match = cam_quirkmatch((caddr_t)&cgd->ident_data, 999199178Smav (caddr_t)ada_quirk_table, 1000199178Smav sizeof(ada_quirk_table)/sizeof(*ada_quirk_table), 1001199178Smav sizeof(*ada_quirk_table), ata_identify_match); 1002195534Sscottl if (match != NULL) 1003195534Sscottl softc->quirks = ((struct ada_quirk_entry *)match)->quirks; 1004195534Sscottl else 1005195534Sscottl softc->quirks = ADA_Q_NONE; 1006195534Sscottl 1007195534Sscottl bzero(&cpi, sizeof(cpi)); 1008203108Smav xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NONE); 1009195534Sscottl cpi.ccb_h.func_code = XPT_PATH_INQ; 1010195534Sscottl xpt_action((union ccb *)&cpi); 1011195534Sscottl 1012195534Sscottl TASK_INIT(&softc->sysctl_task, 0, adasysctlinit, periph); 1013195534Sscottl 1014195534Sscottl /* 1015195534Sscottl * Register this media as a disk 1016195534Sscottl */ 1017220618Smav (void)cam_periph_hold(periph, PRIBIO); 1018195534Sscottl mtx_unlock(periph->sim->mtx); 1019222520Smav snprintf(announce_buf, sizeof(announce_buf), 1020222520Smav "kern.cam.ada.%d.quirks", periph->unit_number); 1021222520Smav quirks = softc->quirks; 1022222520Smav TUNABLE_INT_FETCH(announce_buf, &quirks); 1023222520Smav softc->quirks = quirks; 1024224497Smav softc->read_ahead = -1; 1025224497Smav snprintf(announce_buf, sizeof(announce_buf), 1026224497Smav "kern.cam.ada.%d.read_ahead", periph->unit_number); 1027224497Smav TUNABLE_INT_FETCH(announce_buf, &softc->read_ahead); 1028220618Smav softc->write_cache = -1; 1029220618Smav snprintf(announce_buf, sizeof(announce_buf), 1030220618Smav "kern.cam.ada.%d.write_cache", periph->unit_number); 1031220618Smav TUNABLE_INT_FETCH(announce_buf, &softc->write_cache); 1032198897Smav adagetparams(periph, cgd); 1033195534Sscottl softc->disk = disk_alloc(); 1034220644Smav softc->disk->d_devstat = devstat_new_entry(periph->periph_name, 1035220644Smav periph->unit_number, softc->params.secsize, 1036220644Smav DEVSTAT_ALL_SUPPORTED, 1037220644Smav DEVSTAT_TYPE_DIRECT | 1038220644Smav XPORT_DEVSTAT_TYPE(cpi.transport), 1039220644Smav DEVSTAT_PRIORITY_DISK); 1040195534Sscottl softc->disk->d_open = adaopen; 1041195534Sscottl softc->disk->d_close = adaclose; 1042195534Sscottl softc->disk->d_strategy = adastrategy; 1043223089Sgibbs softc->disk->d_getattr = adagetattr; 1044195534Sscottl softc->disk->d_dump = adadump; 1045195534Sscottl softc->disk->d_name = "ada"; 1046195534Sscottl softc->disk->d_drv1 = periph; 1047195534Sscottl maxio = cpi.maxio; /* Honor max I/O size of SIM */ 1048195534Sscottl if (maxio == 0) 1049195534Sscottl maxio = DFLTPHYS; /* traditional default */ 1050195534Sscottl else if (maxio > MAXPHYS) 1051195534Sscottl maxio = MAXPHYS; /* for safety */ 1052201139Smav if (softc->flags & ADA_FLAG_CAN_48BIT) 1053198897Smav maxio = min(maxio, 65536 * softc->params.secsize); 1054195534Sscottl else /* 28bit ATA command limit */ 1055198897Smav maxio = min(maxio, 256 * softc->params.secsize); 1056195534Sscottl softc->disk->d_maxsize = maxio; 1057195534Sscottl softc->disk->d_unit = periph->unit_number; 1058195534Sscottl softc->disk->d_flags = 0; 1059195534Sscottl if (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) 1060195534Sscottl softc->disk->d_flags |= DISKFLAG_CANFLUSHCACHE; 1061201139Smav if ((softc->flags & ADA_FLAG_CAN_TRIM) || 1062201139Smav ((softc->flags & ADA_FLAG_CAN_CFA) && 1063201139Smav !(softc->flags & ADA_FLAG_CAN_48BIT))) 1064201139Smav softc->disk->d_flags |= DISKFLAG_CANDELETE; 1065219056Snwhitehorn strlcpy(softc->disk->d_descr, cgd->ident_data.model, 1066219056Snwhitehorn MIN(sizeof(softc->disk->d_descr), sizeof(cgd->ident_data.model))); 1067210471Smav softc->disk->d_hba_vendor = cpi.hba_vendor; 1068210471Smav softc->disk->d_hba_device = cpi.hba_device; 1069210471Smav softc->disk->d_hba_subvendor = cpi.hba_subvendor; 1070210471Smav softc->disk->d_hba_subdevice = cpi.hba_subdevice; 1071195534Sscottl 1072195534Sscottl softc->disk->d_sectorsize = softc->params.secsize; 1073198897Smav softc->disk->d_mediasize = (off_t)softc->params.sectors * 1074198897Smav softc->params.secsize; 1075200969Smav if (ata_physical_sector_size(&cgd->ident_data) != 1076200969Smav softc->params.secsize) { 1077200969Smav softc->disk->d_stripesize = 1078200969Smav ata_physical_sector_size(&cgd->ident_data); 1079200969Smav softc->disk->d_stripeoffset = (softc->disk->d_stripesize - 1080200969Smav ata_logical_sector_offset(&cgd->ident_data)) % 1081200969Smav softc->disk->d_stripesize; 1082222520Smav } else if (softc->quirks & ADA_Q_4K) { 1083222520Smav softc->disk->d_stripesize = 4096; 1084222520Smav softc->disk->d_stripeoffset = 0; 1085200969Smav } 1086195534Sscottl softc->disk->d_fwsectors = softc->params.secs_per_track; 1087195534Sscottl softc->disk->d_fwheads = softc->params.heads; 1088208349Smarius ata_disk_firmware_geom_adjust(softc->disk); 1089195534Sscottl 1090221071Smav if (ada_legacy_aliases) { 1091221071Smav#ifdef ATA_STATIC_ID 1092221071Smav legacy_id = xpt_path_legacy_ata_id(periph->path); 1093221071Smav#else 1094221071Smav legacy_id = softc->disk->d_unit; 1095221071Smav#endif 1096221071Smav if (legacy_id >= 0) { 1097221071Smav snprintf(announce_buf, sizeof(announce_buf), 1098221071Smav "kern.devalias.%s%d", 1099221071Smav softc->disk->d_name, softc->disk->d_unit); 1100221071Smav snprintf(buf1, sizeof(buf1), 1101221071Smav "ad%d", legacy_id); 1102221071Smav setenv(announce_buf, buf1); 1103221071Smav } 1104221071Smav } else 1105221071Smav legacy_id = -1; 1106195534Sscottl disk_create(softc->disk, DISK_VERSION); 1107195534Sscottl mtx_lock(periph->sim->mtx); 1108220618Smav cam_periph_unhold(periph); 1109195534Sscottl 1110195534Sscottl dp = &softc->params; 1111195534Sscottl snprintf(announce_buf, sizeof(announce_buf), 1112195534Sscottl "%juMB (%ju %u byte sectors: %dH %dS/T %dC)", 1113195534Sscottl (uintmax_t)(((uintmax_t)dp->secsize * 1114195534Sscottl dp->sectors) / (1024*1024)), 1115195534Sscottl (uintmax_t)dp->sectors, 1116195534Sscottl dp->secsize, dp->heads, 1117195534Sscottl dp->secs_per_track, dp->cylinders); 1118195534Sscottl xpt_announce_periph(periph, announce_buf); 1119221071Smav if (legacy_id >= 0) 1120221071Smav printf("%s%d: Previously was known as ad%d\n", 1121221071Smav periph->periph_name, periph->unit_number, legacy_id); 1122220454Smav 1123195534Sscottl /* 1124220454Smav * Create our sysctl variables, now that we know 1125220454Smav * we have successfully attached. 1126220454Smav */ 1127220454Smav cam_periph_acquire(periph); 1128220454Smav taskqueue_enqueue(taskqueue_thread, &softc->sysctl_task); 1129220454Smav 1130220454Smav /* 1131195534Sscottl * Add async callbacks for bus reset and 1132195534Sscottl * bus device reset calls. I don't bother 1133195534Sscottl * checking if this fails as, in most cases, 1134195534Sscottl * the system will function just fine without 1135195534Sscottl * them and the only alternative would be to 1136195534Sscottl * not attach the device on failure. 1137195534Sscottl */ 1138235897Smav xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE | 1139236393Smav AC_GETDEV_CHANGED | AC_ADVINFO_CHANGED, 1140236393Smav adaasync, periph, periph->path); 1141195534Sscottl 1142195534Sscottl /* 1143195534Sscottl * Schedule a periodic event to occasionally send an 1144195534Sscottl * ordered tag to a device. 1145195534Sscottl */ 1146195534Sscottl callout_init_mtx(&softc->sendordered_c, periph->sim->mtx, 0); 1147195534Sscottl callout_reset(&softc->sendordered_c, 1148230921Smav (ada_default_timeout * hz) / ADA_ORDEREDTAG_INTERVAL, 1149195534Sscottl adasendorderedtag, softc); 1150195534Sscottl 1151224497Smav if (ADA_RA >= 0 && 1152224497Smav cgd->ident_data.support.command1 & ATA_SUPPORT_LOOKAHEAD) { 1153224497Smav softc->state = ADA_STATE_RAHEAD; 1154224497Smav cam_periph_acquire(periph); 1155224497Smav cam_freeze_devq_arg(periph->path, 1156224497Smav RELSIM_RELEASE_RUNLEVEL, CAM_RL_DEV + 1); 1157224497Smav xpt_schedule(periph, CAM_PRIORITY_DEV); 1158224497Smav } else if (ADA_WC >= 0 && 1159220412Smav cgd->ident_data.support.command1 & ATA_SUPPORT_WRITECACHE) { 1160220412Smav softc->state = ADA_STATE_WCACHE; 1161220412Smav cam_periph_acquire(periph); 1162220412Smav cam_freeze_devq_arg(periph->path, 1163220412Smav RELSIM_RELEASE_RUNLEVEL, CAM_RL_DEV + 1); 1164220412Smav xpt_schedule(periph, CAM_PRIORITY_DEV); 1165220412Smav } else 1166220412Smav softc->state = ADA_STATE_NORMAL; 1167220412Smav 1168195534Sscottl return(CAM_REQ_CMP); 1169195534Sscottl} 1170195534Sscottl 1171195534Sscottlstatic void 1172195534Sscottladastart(struct cam_periph *periph, union ccb *start_ccb) 1173195534Sscottl{ 1174198328Smav struct ada_softc *softc = (struct ada_softc *)periph->softc; 1175198328Smav struct ccb_ataio *ataio = &start_ccb->ataio; 1176195534Sscottl 1177236602Smav CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("adastart\n")); 1178236602Smav 1179195534Sscottl switch (softc->state) { 1180195534Sscottl case ADA_STATE_NORMAL: 1181195534Sscottl { 1182195534Sscottl struct bio *bp; 1183201139Smav u_int8_t tag_code; 1184195534Sscottl 1185201139Smav /* Execute immediate CCB if waiting. */ 1186195534Sscottl if (periph->immediate_priority <= periph->pinfo.priority) { 1187236602Smav CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 1188195534Sscottl ("queuing for immediate ccb\n")); 1189195534Sscottl start_ccb->ccb_h.ccb_state = ADA_CCB_WAITING; 1190195534Sscottl SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, 1191195534Sscottl periph_links.sle); 1192195534Sscottl periph->immediate_priority = CAM_PRIORITY_NONE; 1193195534Sscottl wakeup(&periph->ccb_list); 1194201139Smav /* Have more work to do, so ensure we stay scheduled */ 1195201139Smav adaschedule(periph); 1196201139Smav break; 1197201139Smav } 1198201139Smav /* Run TRIM if not running yet. */ 1199201139Smav if (!softc->trim_running && 1200201139Smav (bp = bioq_first(&softc->trim_queue)) != 0) { 1201201139Smav struct trim_request *req = &softc->trim_req; 1202201139Smav struct bio *bp1; 1203222628Smav uint64_t lastlba = (uint64_t)-1; 1204222628Smav int bps = 0, c, lastcount = 0, off, ranges = 0; 1205201139Smav 1206201139Smav softc->trim_running = 1; 1207201139Smav bzero(req, sizeof(*req)); 1208201139Smav bp1 = bp; 1209201139Smav do { 1210201139Smav uint64_t lba = bp1->bio_pblkno; 1211201139Smav int count = bp1->bio_bcount / 1212201139Smav softc->params.secsize; 1213201139Smav 1214201139Smav bioq_remove(&softc->trim_queue, bp1); 1215222628Smav 1216222628Smav /* Try to extend the previous range. */ 1217222628Smav if (lba == lastlba) { 1218222628Smav c = min(count, 0xffff - lastcount); 1219222628Smav lastcount += c; 1220222628Smav off = (ranges - 1) * 8; 1221222628Smav req->data[off + 6] = lastcount & 0xff; 1222222628Smav req->data[off + 7] = 1223222628Smav (lastcount >> 8) & 0xff; 1224222628Smav count -= c; 1225222628Smav lba += c; 1226222628Smav } 1227222628Smav 1228201139Smav while (count > 0) { 1229222628Smav c = min(count, 0xffff); 1230222628Smav off = ranges * 8; 1231201139Smav req->data[off + 0] = lba & 0xff; 1232201139Smav req->data[off + 1] = (lba >> 8) & 0xff; 1233201139Smav req->data[off + 2] = (lba >> 16) & 0xff; 1234201139Smav req->data[off + 3] = (lba >> 24) & 0xff; 1235201139Smav req->data[off + 4] = (lba >> 32) & 0xff; 1236201139Smav req->data[off + 5] = (lba >> 40) & 0xff; 1237201139Smav req->data[off + 6] = c & 0xff; 1238201139Smav req->data[off + 7] = (c >> 8) & 0xff; 1239201139Smav lba += c; 1240201139Smav count -= c; 1241222628Smav lastcount = c; 1242201139Smav ranges++; 1243201139Smav } 1244222628Smav lastlba = lba; 1245201139Smav req->bps[bps++] = bp1; 1246201139Smav bp1 = bioq_first(&softc->trim_queue); 1247222628Smav if (bps >= TRIM_MAX_BIOS || 1248222628Smav bp1 == NULL || 1249201139Smav bp1->bio_bcount / softc->params.secsize > 1250201139Smav (softc->trim_max_ranges - ranges) * 0xffff) 1251201139Smav break; 1252201139Smav } while (1); 1253201139Smav cam_fill_ataio(ataio, 1254201139Smav ada_retry_count, 1255201139Smav adadone, 1256201139Smav CAM_DIR_OUT, 1257201139Smav 0, 1258201139Smav req->data, 1259201139Smav ((ranges + 63) / 64) * 512, 1260201139Smav ada_default_timeout * 1000); 1261201139Smav ata_48bit_cmd(ataio, ATA_DATA_SET_MANAGEMENT, 1262201139Smav ATA_DSM_TRIM, 0, (ranges + 63) / 64); 1263201139Smav start_ccb->ccb_h.ccb_state = ADA_CCB_TRIM; 1264201139Smav goto out; 1265201139Smav } 1266201139Smav /* Run regular command. */ 1267201139Smav bp = bioq_first(&softc->bio_queue); 1268201139Smav if (bp == NULL) { 1269195534Sscottl xpt_release_ccb(start_ccb); 1270201139Smav break; 1271201139Smav } 1272201139Smav bioq_remove(&softc->bio_queue, bp); 1273201139Smav 1274212160Sgibbs if ((bp->bio_flags & BIO_ORDERED) != 0 1275212160Sgibbs || (softc->flags & ADA_FLAG_NEED_OTAG) != 0) { 1276201139Smav softc->flags &= ~ADA_FLAG_NEED_OTAG; 1277201139Smav softc->ordered_tag_count++; 1278201139Smav tag_code = 0; 1279195534Sscottl } else { 1280201139Smav tag_code = 1; 1281201139Smav } 1282201139Smav switch (bp->bio_cmd) { 1283201139Smav case BIO_READ: 1284201139Smav case BIO_WRITE: 1285201139Smav { 1286201139Smav uint64_t lba = bp->bio_pblkno; 1287201139Smav uint16_t count = bp->bio_bcount / softc->params.secsize; 1288220454Smav#ifdef ADA_TEST_FAILURE 1289220454Smav int fail = 0; 1290195534Sscottl 1291220454Smav /* 1292220454Smav * Support the failure ioctls. If the command is a 1293220454Smav * read, and there are pending forced read errors, or 1294220454Smav * if a write and pending write errors, then fail this 1295220454Smav * operation with EIO. This is useful for testing 1296220454Smav * purposes. Also, support having every Nth read fail. 1297220454Smav * 1298220454Smav * This is a rather blunt tool. 1299220454Smav */ 1300220454Smav if (bp->bio_cmd == BIO_READ) { 1301220454Smav if (softc->force_read_error) { 1302220454Smav softc->force_read_error--; 1303220454Smav fail = 1; 1304220454Smav } 1305220454Smav if (softc->periodic_read_error > 0) { 1306220454Smav if (++softc->periodic_read_count >= 1307220454Smav softc->periodic_read_error) { 1308220454Smav softc->periodic_read_count = 0; 1309220454Smav fail = 1; 1310220454Smav } 1311220454Smav } 1312220454Smav } else { 1313220454Smav if (softc->force_write_error) { 1314220454Smav softc->force_write_error--; 1315220454Smav fail = 1; 1316220454Smav } 1317220454Smav } 1318220454Smav if (fail) { 1319220454Smav bp->bio_error = EIO; 1320220454Smav bp->bio_flags |= BIO_ERROR; 1321220454Smav biodone(bp); 1322220454Smav xpt_release_ccb(start_ccb); 1323220454Smav adaschedule(periph); 1324220454Smav return; 1325220454Smav } 1326220454Smav#endif 1327201139Smav cam_fill_ataio(ataio, 1328201139Smav ada_retry_count, 1329201139Smav adadone, 1330201139Smav bp->bio_cmd == BIO_READ ? 1331201139Smav CAM_DIR_IN : CAM_DIR_OUT, 1332201139Smav tag_code, 1333201139Smav bp->bio_data, 1334201139Smav bp->bio_bcount, 1335201139Smav ada_default_timeout*1000); 1336195534Sscottl 1337201139Smav if ((softc->flags & ADA_FLAG_CAN_NCQ) && tag_code) { 1338201139Smav if (bp->bio_cmd == BIO_READ) { 1339201139Smav ata_ncq_cmd(ataio, ATA_READ_FPDMA_QUEUED, 1340201139Smav lba, count); 1341201139Smav } else { 1342201139Smav ata_ncq_cmd(ataio, ATA_WRITE_FPDMA_QUEUED, 1343201139Smav lba, count); 1344201139Smav } 1345201139Smav } else if ((softc->flags & ADA_FLAG_CAN_48BIT) && 1346201139Smav (lba + count >= ATA_MAX_28BIT_LBA || 1347201139Smav count > 256)) { 1348201139Smav if (softc->flags & ADA_FLAG_CAN_DMA) { 1349195534Sscottl if (bp->bio_cmd == BIO_READ) { 1350201139Smav ata_48bit_cmd(ataio, ATA_READ_DMA48, 1351201139Smav 0, lba, count); 1352195534Sscottl } else { 1353201139Smav ata_48bit_cmd(ataio, ATA_WRITE_DMA48, 1354201139Smav 0, lba, count); 1355195534Sscottl } 1356201139Smav } else { 1357201139Smav if (bp->bio_cmd == BIO_READ) { 1358201139Smav ata_48bit_cmd(ataio, ATA_READ_MUL48, 1359201139Smav 0, lba, count); 1360195534Sscottl } else { 1361201139Smav ata_48bit_cmd(ataio, ATA_WRITE_MUL48, 1362201139Smav 0, lba, count); 1363195534Sscottl } 1364201139Smav } 1365201139Smav } else { 1366201139Smav if (count == 256) 1367201139Smav count = 0; 1368201139Smav if (softc->flags & ADA_FLAG_CAN_DMA) { 1369201139Smav if (bp->bio_cmd == BIO_READ) { 1370201139Smav ata_28bit_cmd(ataio, ATA_READ_DMA, 1371201139Smav 0, lba, count); 1372201139Smav } else { 1373201139Smav ata_28bit_cmd(ataio, ATA_WRITE_DMA, 1374201139Smav 0, lba, count); 1375201139Smav } 1376195534Sscottl } else { 1377201139Smav if (bp->bio_cmd == BIO_READ) { 1378201139Smav ata_28bit_cmd(ataio, ATA_READ_MUL, 1379201139Smav 0, lba, count); 1380195534Sscottl } else { 1381201139Smav ata_28bit_cmd(ataio, ATA_WRITE_MUL, 1382201139Smav 0, lba, count); 1383195534Sscottl } 1384195534Sscottl } 1385195534Sscottl } 1386201139Smav break; 1387201139Smav } 1388201139Smav case BIO_DELETE: 1389201139Smav { 1390201139Smav uint64_t lba = bp->bio_pblkno; 1391201139Smav uint16_t count = bp->bio_bcount / softc->params.secsize; 1392195534Sscottl 1393201139Smav cam_fill_ataio(ataio, 1394201139Smav ada_retry_count, 1395201139Smav adadone, 1396201139Smav CAM_DIR_NONE, 1397201139Smav 0, 1398201139Smav NULL, 1399201139Smav 0, 1400201139Smav ada_default_timeout*1000); 1401201139Smav 1402201139Smav if (count >= 256) 1403201139Smav count = 0; 1404201139Smav ata_28bit_cmd(ataio, ATA_CFA_ERASE, 0, lba, count); 1405201139Smav break; 1406195534Sscottl } 1407201139Smav case BIO_FLUSH: 1408201139Smav cam_fill_ataio(ataio, 1409201139Smav 1, 1410201139Smav adadone, 1411201139Smav CAM_DIR_NONE, 1412201139Smav 0, 1413201139Smav NULL, 1414201139Smav 0, 1415201139Smav ada_default_timeout*1000); 1416201139Smav 1417201139Smav if (softc->flags & ADA_FLAG_CAN_48BIT) 1418201139Smav ata_48bit_cmd(ataio, ATA_FLUSHCACHE48, 0, 0, 0); 1419201139Smav else 1420201139Smav ata_28bit_cmd(ataio, ATA_FLUSHCACHE, 0, 0, 0); 1421201139Smav break; 1422195534Sscottl } 1423201139Smav start_ccb->ccb_h.ccb_state = ADA_CCB_BUFFER_IO; 1424201139Smavout: 1425201139Smav start_ccb->ccb_h.ccb_bp = bp; 1426201139Smav softc->outstanding_cmds++; 1427201139Smav xpt_action(start_ccb); 1428201139Smav 1429201139Smav /* May have more work to do, so ensure we stay scheduled */ 1430201139Smav adaschedule(periph); 1431195534Sscottl break; 1432195534Sscottl } 1433224497Smav case ADA_STATE_RAHEAD: 1434220412Smav case ADA_STATE_WCACHE: 1435220412Smav { 1436224497Smav if (softc->flags & ADA_FLAG_PACK_INVALID) { 1437224497Smav softc->state = ADA_STATE_NORMAL; 1438224497Smav xpt_release_ccb(start_ccb); 1439224497Smav cam_release_devq(periph->path, 1440224497Smav RELSIM_RELEASE_RUNLEVEL, 0, CAM_RL_DEV + 1, FALSE); 1441224497Smav adaschedule(periph); 1442224497Smav cam_periph_release_locked(periph); 1443224497Smav return; 1444224497Smav } 1445224497Smav 1446220412Smav cam_fill_ataio(ataio, 1447220412Smav 1, 1448220412Smav adadone, 1449220412Smav CAM_DIR_NONE, 1450220412Smav 0, 1451220412Smav NULL, 1452220412Smav 0, 1453220412Smav ada_default_timeout*1000); 1454220412Smav 1455224497Smav if (softc->state == ADA_STATE_RAHEAD) { 1456224497Smav ata_28bit_cmd(ataio, ATA_SETFEATURES, ADA_RA ? 1457224497Smav ATA_SF_ENAB_RCACHE : ATA_SF_DIS_RCACHE, 0, 0); 1458224497Smav start_ccb->ccb_h.ccb_state = ADA_CCB_RAHEAD; 1459224497Smav } else { 1460224497Smav ata_28bit_cmd(ataio, ATA_SETFEATURES, ADA_WC ? 1461224497Smav ATA_SF_ENAB_WCACHE : ATA_SF_DIS_WCACHE, 0, 0); 1462224497Smav start_ccb->ccb_h.ccb_state = ADA_CCB_WCACHE; 1463224497Smav } 1464220412Smav xpt_action(start_ccb); 1465220412Smav break; 1466195534Sscottl } 1467220412Smav } 1468195534Sscottl} 1469195534Sscottl 1470195534Sscottlstatic void 1471195534Sscottladadone(struct cam_periph *periph, union ccb *done_ccb) 1472195534Sscottl{ 1473195534Sscottl struct ada_softc *softc; 1474195534Sscottl struct ccb_ataio *ataio; 1475224497Smav struct ccb_getdev *cgd; 1476195534Sscottl 1477195534Sscottl softc = (struct ada_softc *)periph->softc; 1478195534Sscottl ataio = &done_ccb->ataio; 1479236602Smav 1480236602Smav CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("adadone\n")); 1481236602Smav 1482195534Sscottl switch (ataio->ccb_h.ccb_state & ADA_CCB_TYPE_MASK) { 1483195534Sscottl case ADA_CCB_BUFFER_IO: 1484201139Smav case ADA_CCB_TRIM: 1485195534Sscottl { 1486195534Sscottl struct bio *bp; 1487195534Sscottl 1488195534Sscottl bp = (struct bio *)done_ccb->ccb_h.ccb_bp; 1489195534Sscottl if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 1490195534Sscottl int error; 1491195534Sscottl 1492198328Smav error = adaerror(done_ccb, 0, 0); 1493195534Sscottl if (error == ERESTART) { 1494198328Smav /* A retry was scheduled, so just return. */ 1495195534Sscottl return; 1496195534Sscottl } 1497195534Sscottl if (error != 0) { 1498224283Smav if (error == ENXIO && 1499224283Smav (softc->flags & ADA_FLAG_PACK_INVALID) == 0) { 1500195534Sscottl /* 1501195534Sscottl * Catastrophic error. Mark our pack as 1502195534Sscottl * invalid. 1503195534Sscottl */ 1504195534Sscottl /* 1505195534Sscottl * XXX See if this is really a media 1506195534Sscottl * XXX change first? 1507195534Sscottl */ 1508195534Sscottl xpt_print(periph->path, 1509195534Sscottl "Invalidating pack\n"); 1510195534Sscottl softc->flags |= ADA_FLAG_PACK_INVALID; 1511195534Sscottl } 1512195534Sscottl bp->bio_error = error; 1513195534Sscottl bp->bio_resid = bp->bio_bcount; 1514195534Sscottl bp->bio_flags |= BIO_ERROR; 1515195534Sscottl } else { 1516195534Sscottl bp->bio_resid = ataio->resid; 1517195534Sscottl bp->bio_error = 0; 1518195534Sscottl if (bp->bio_resid != 0) 1519195534Sscottl bp->bio_flags |= BIO_ERROR; 1520195534Sscottl } 1521195534Sscottl if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 1522195534Sscottl cam_release_devq(done_ccb->ccb_h.path, 1523195534Sscottl /*relsim_flags*/0, 1524195534Sscottl /*reduction*/0, 1525195534Sscottl /*timeout*/0, 1526195534Sscottl /*getcount_only*/0); 1527195534Sscottl } else { 1528195534Sscottl if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 1529195534Sscottl panic("REQ_CMP with QFRZN"); 1530195534Sscottl bp->bio_resid = ataio->resid; 1531195534Sscottl if (ataio->resid > 0) 1532195534Sscottl bp->bio_flags |= BIO_ERROR; 1533195534Sscottl } 1534195534Sscottl softc->outstanding_cmds--; 1535195534Sscottl if (softc->outstanding_cmds == 0) 1536195534Sscottl softc->flags |= ADA_FLAG_WENT_IDLE; 1537201139Smav if ((ataio->ccb_h.ccb_state & ADA_CCB_TYPE_MASK) == 1538201139Smav ADA_CCB_TRIM) { 1539201139Smav struct trim_request *req = 1540201139Smav (struct trim_request *)ataio->data_ptr; 1541201139Smav int i; 1542195534Sscottl 1543222628Smav for (i = 1; i < TRIM_MAX_BIOS && req->bps[i]; i++) { 1544201139Smav struct bio *bp1 = req->bps[i]; 1545201139Smav 1546201139Smav bp1->bio_resid = bp->bio_resid; 1547201139Smav bp1->bio_error = bp->bio_error; 1548201139Smav if (bp->bio_flags & BIO_ERROR) 1549201139Smav bp1->bio_flags |= BIO_ERROR; 1550201139Smav biodone(bp1); 1551201139Smav } 1552201139Smav softc->trim_running = 0; 1553201139Smav biodone(bp); 1554201139Smav adaschedule(periph); 1555201139Smav } else 1556201139Smav biodone(bp); 1557195534Sscottl break; 1558195534Sscottl } 1559224497Smav case ADA_CCB_RAHEAD: 1560224497Smav { 1561224497Smav if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 1562224497Smav if (adaerror(done_ccb, 0, 0) == ERESTART) { 1563224497Smav return; 1564224497Smav } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 1565224497Smav cam_release_devq(done_ccb->ccb_h.path, 1566224497Smav /*relsim_flags*/0, 1567224497Smav /*reduction*/0, 1568224497Smav /*timeout*/0, 1569224497Smav /*getcount_only*/0); 1570224497Smav } 1571224497Smav } 1572224497Smav 1573224497Smav /* 1574224497Smav * Since our peripheral may be invalidated by an error 1575224497Smav * above or an external event, we must release our CCB 1576224497Smav * before releasing the reference on the peripheral. 1577224497Smav * The peripheral will only go away once the last reference 1578224497Smav * is removed, and we need it around for the CCB release 1579224497Smav * operation. 1580224497Smav */ 1581224497Smav cgd = (struct ccb_getdev *)done_ccb; 1582224497Smav xpt_setup_ccb(&cgd->ccb_h, periph->path, CAM_PRIORITY_NORMAL); 1583224497Smav cgd->ccb_h.func_code = XPT_GDEV_TYPE; 1584224497Smav xpt_action((union ccb *)cgd); 1585224497Smav if (ADA_WC >= 0 && 1586224497Smav cgd->ident_data.support.command1 & ATA_SUPPORT_WRITECACHE) { 1587224497Smav softc->state = ADA_STATE_WCACHE; 1588224497Smav xpt_release_ccb(done_ccb); 1589224497Smav xpt_schedule(periph, CAM_PRIORITY_DEV); 1590224497Smav return; 1591224497Smav } 1592224497Smav softc->state = ADA_STATE_NORMAL; 1593224497Smav xpt_release_ccb(done_ccb); 1594224497Smav cam_release_devq(periph->path, 1595224497Smav RELSIM_RELEASE_RUNLEVEL, 0, CAM_RL_DEV + 1, FALSE); 1596224497Smav adaschedule(periph); 1597224497Smav cam_periph_release_locked(periph); 1598224497Smav return; 1599224497Smav } 1600220412Smav case ADA_CCB_WCACHE: 1601220412Smav { 1602220412Smav if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 1603220412Smav if (adaerror(done_ccb, 0, 0) == ERESTART) { 1604220412Smav return; 1605220412Smav } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 1606220412Smav cam_release_devq(done_ccb->ccb_h.path, 1607220412Smav /*relsim_flags*/0, 1608220412Smav /*reduction*/0, 1609220412Smav /*timeout*/0, 1610220412Smav /*getcount_only*/0); 1611220412Smav } 1612220412Smav } 1613220412Smav 1614220412Smav softc->state = ADA_STATE_NORMAL; 1615220412Smav /* 1616220412Smav * Since our peripheral may be invalidated by an error 1617220412Smav * above or an external event, we must release our CCB 1618220412Smav * before releasing the reference on the peripheral. 1619220412Smav * The peripheral will only go away once the last reference 1620220412Smav * is removed, and we need it around for the CCB release 1621220412Smav * operation. 1622220412Smav */ 1623220412Smav xpt_release_ccb(done_ccb); 1624220412Smav cam_release_devq(periph->path, 1625220412Smav RELSIM_RELEASE_RUNLEVEL, 0, CAM_RL_DEV + 1, FALSE); 1626220412Smav adaschedule(periph); 1627220412Smav cam_periph_release_locked(periph); 1628220412Smav return; 1629220412Smav } 1630195534Sscottl case ADA_CCB_WAITING: 1631195534Sscottl { 1632195534Sscottl /* Caller will release the CCB */ 1633195534Sscottl wakeup(&done_ccb->ccb_h.cbfcnp); 1634195534Sscottl return; 1635195534Sscottl } 1636195534Sscottl case ADA_CCB_DUMP: 1637195534Sscottl /* No-op. We're polling */ 1638195534Sscottl return; 1639195534Sscottl default: 1640195534Sscottl break; 1641195534Sscottl } 1642195534Sscottl xpt_release_ccb(done_ccb); 1643195534Sscottl} 1644195534Sscottl 1645195534Sscottlstatic int 1646195534Sscottladaerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) 1647195534Sscottl{ 1648195534Sscottl 1649203385Smav return(cam_periph_error(ccb, cam_flags, sense_flags, NULL)); 1650195534Sscottl} 1651195534Sscottl 1652195534Sscottlstatic void 1653198897Smavadagetparams(struct cam_periph *periph, struct ccb_getdev *cgd) 1654195534Sscottl{ 1655195534Sscottl struct ada_softc *softc = (struct ada_softc *)periph->softc; 1656195534Sscottl struct disk_params *dp = &softc->params; 1657195534Sscottl u_int64_t lbasize48; 1658195534Sscottl u_int32_t lbasize; 1659195534Sscottl 1660198897Smav dp->secsize = ata_logical_sector_size(&cgd->ident_data); 1661195534Sscottl if ((cgd->ident_data.atavalid & ATA_FLAG_54_58) && 1662195534Sscottl cgd->ident_data.current_heads && cgd->ident_data.current_sectors) { 1663195534Sscottl dp->heads = cgd->ident_data.current_heads; 1664195534Sscottl dp->secs_per_track = cgd->ident_data.current_sectors; 1665195534Sscottl dp->cylinders = cgd->ident_data.cylinders; 1666195534Sscottl dp->sectors = (u_int32_t)cgd->ident_data.current_size_1 | 1667195534Sscottl ((u_int32_t)cgd->ident_data.current_size_2 << 16); 1668195534Sscottl } else { 1669195534Sscottl dp->heads = cgd->ident_data.heads; 1670195534Sscottl dp->secs_per_track = cgd->ident_data.sectors; 1671195534Sscottl dp->cylinders = cgd->ident_data.cylinders; 1672195534Sscottl dp->sectors = cgd->ident_data.cylinders * dp->heads * dp->secs_per_track; 1673195534Sscottl } 1674195534Sscottl lbasize = (u_int32_t)cgd->ident_data.lba_size_1 | 1675195534Sscottl ((u_int32_t)cgd->ident_data.lba_size_2 << 16); 1676195534Sscottl 1677195534Sscottl /* use the 28bit LBA size if valid or bigger than the CHS mapping */ 1678195534Sscottl if (cgd->ident_data.cylinders == 16383 || dp->sectors < lbasize) 1679195534Sscottl dp->sectors = lbasize; 1680195534Sscottl 1681195534Sscottl /* use the 48bit LBA size if valid */ 1682195534Sscottl lbasize48 = ((u_int64_t)cgd->ident_data.lba_size48_1) | 1683195534Sscottl ((u_int64_t)cgd->ident_data.lba_size48_2 << 16) | 1684195534Sscottl ((u_int64_t)cgd->ident_data.lba_size48_3 << 32) | 1685195534Sscottl ((u_int64_t)cgd->ident_data.lba_size48_4 << 48); 1686195534Sscottl if ((cgd->ident_data.support.command2 & ATA_SUPPORT_ADDRESS48) && 1687195534Sscottl lbasize48 > ATA_MAX_28BIT_LBA) 1688195534Sscottl dp->sectors = lbasize48; 1689195534Sscottl} 1690195534Sscottl 1691195534Sscottlstatic void 1692195534Sscottladasendorderedtag(void *arg) 1693195534Sscottl{ 1694195534Sscottl struct ada_softc *softc = arg; 1695195534Sscottl 1696195534Sscottl if (ada_send_ordered) { 1697195534Sscottl if ((softc->ordered_tag_count == 0) 1698195534Sscottl && ((softc->flags & ADA_FLAG_WENT_IDLE) == 0)) { 1699195534Sscottl softc->flags |= ADA_FLAG_NEED_OTAG; 1700195534Sscottl } 1701195534Sscottl if (softc->outstanding_cmds > 0) 1702195534Sscottl softc->flags &= ~ADA_FLAG_WENT_IDLE; 1703195534Sscottl 1704195534Sscottl softc->ordered_tag_count = 0; 1705195534Sscottl } 1706195534Sscottl /* Queue us up again */ 1707195534Sscottl callout_reset(&softc->sendordered_c, 1708230921Smav (ada_default_timeout * hz) / ADA_ORDEREDTAG_INTERVAL, 1709195534Sscottl adasendorderedtag, softc); 1710195534Sscottl} 1711195534Sscottl 1712195534Sscottl/* 1713195534Sscottl * Step through all ADA peripheral drivers, and if the device is still open, 1714195534Sscottl * sync the disk cache to physical media. 1715195534Sscottl */ 1716195534Sscottlstatic void 1717220650Smavadaflush(void) 1718195534Sscottl{ 1719195534Sscottl struct cam_periph *periph; 1720195534Sscottl struct ada_softc *softc; 1721236814Smav int error; 1722195534Sscottl 1723195534Sscottl TAILQ_FOREACH(periph, &adadriver.units, unit_links) { 1724195534Sscottl union ccb ccb; 1725195534Sscottl 1726200180Smav /* If we paniced with lock held - not recurse here. */ 1727200180Smav if (cam_periph_owned(periph)) 1728200180Smav continue; 1729195534Sscottl cam_periph_lock(periph); 1730195534Sscottl softc = (struct ada_softc *)periph->softc; 1731195534Sscottl /* 1732195534Sscottl * We only sync the cache if the drive is still open, and 1733195534Sscottl * if the drive is capable of it.. 1734195534Sscottl */ 1735195534Sscottl if (((softc->flags & ADA_FLAG_OPEN) == 0) || 1736195534Sscottl (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) == 0) { 1737195534Sscottl cam_periph_unlock(periph); 1738195534Sscottl continue; 1739195534Sscottl } 1740195534Sscottl 1741198382Smav xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 1742195534Sscottl 1743195534Sscottl ccb.ccb_h.ccb_state = ADA_CCB_DUMP; 1744195534Sscottl cam_fill_ataio(&ccb.ataio, 1745236814Smav 0, 1746195534Sscottl adadone, 1747195534Sscottl CAM_DIR_NONE, 1748195534Sscottl 0, 1749195534Sscottl NULL, 1750195534Sscottl 0, 1751195534Sscottl ada_default_timeout*1000); 1752195534Sscottl 1753195534Sscottl if (softc->flags & ADA_FLAG_CAN_48BIT) 1754195534Sscottl ata_48bit_cmd(&ccb.ataio, ATA_FLUSHCACHE48, 0, 0, 0); 1755195534Sscottl else 1756196659Smav ata_28bit_cmd(&ccb.ataio, ATA_FLUSHCACHE, 0, 0, 0); 1757195534Sscottl xpt_polled_action(&ccb); 1758195534Sscottl 1759236814Smav error = cam_periph_error(&ccb, 1760236814Smav 0, SF_NO_RECOVERY | SF_NO_RETRY, NULL); 1761236814Smav if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0) 1762236814Smav cam_release_devq(ccb.ccb_h.path, /*relsim_flags*/0, 1763236814Smav /*reduction*/0, /*timeout*/0, /*getcount_only*/0); 1764236814Smav if (error != 0) 1765195534Sscottl xpt_print(periph->path, "Synchronize cache failed\n"); 1766195534Sscottl cam_periph_unlock(periph); 1767195534Sscottl } 1768220650Smav} 1769214279Sbrucec 1770220650Smavstatic void 1771220650Smavadaspindown(uint8_t cmd, int flags) 1772220650Smav{ 1773220650Smav struct cam_periph *periph; 1774220650Smav struct ada_softc *softc; 1775236814Smav int error; 1776214279Sbrucec 1777214279Sbrucec TAILQ_FOREACH(periph, &adadriver.units, unit_links) { 1778214279Sbrucec union ccb ccb; 1779214279Sbrucec 1780214279Sbrucec /* If we paniced with lock held - not recurse here. */ 1781214279Sbrucec if (cam_periph_owned(periph)) 1782214279Sbrucec continue; 1783214279Sbrucec cam_periph_lock(periph); 1784214279Sbrucec softc = (struct ada_softc *)periph->softc; 1785214279Sbrucec /* 1786214279Sbrucec * We only spin-down the drive if it is capable of it.. 1787214279Sbrucec */ 1788214279Sbrucec if ((softc->flags & ADA_FLAG_CAN_POWERMGT) == 0) { 1789214279Sbrucec cam_periph_unlock(periph); 1790214279Sbrucec continue; 1791214279Sbrucec } 1792214279Sbrucec 1793214279Sbrucec if (bootverbose) 1794214279Sbrucec xpt_print(periph->path, "spin-down\n"); 1795214279Sbrucec 1796214279Sbrucec xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 1797214279Sbrucec 1798214279Sbrucec ccb.ccb_h.ccb_state = ADA_CCB_DUMP; 1799214279Sbrucec cam_fill_ataio(&ccb.ataio, 1800236814Smav 0, 1801214279Sbrucec adadone, 1802220650Smav CAM_DIR_NONE | flags, 1803214279Sbrucec 0, 1804214279Sbrucec NULL, 1805214279Sbrucec 0, 1806214279Sbrucec ada_default_timeout*1000); 1807214279Sbrucec 1808220650Smav ata_28bit_cmd(&ccb.ataio, cmd, 0, 0, 0); 1809214279Sbrucec xpt_polled_action(&ccb); 1810214279Sbrucec 1811236814Smav error = cam_periph_error(&ccb, 1812236814Smav 0, SF_NO_RECOVERY | SF_NO_RETRY, NULL); 1813236814Smav if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0) 1814236814Smav cam_release_devq(ccb.ccb_h.path, /*relsim_flags*/0, 1815236814Smav /*reduction*/0, /*timeout*/0, /*getcount_only*/0); 1816236814Smav if (error != 0) 1817214279Sbrucec xpt_print(periph->path, "Spin-down disk failed\n"); 1818214279Sbrucec cam_periph_unlock(periph); 1819214279Sbrucec } 1820195534Sscottl} 1821195534Sscottl 1822220650Smavstatic void 1823220650Smavadashutdown(void *arg, int howto) 1824220650Smav{ 1825220650Smav 1826220650Smav adaflush(); 1827220650Smav if (ada_spindown_shutdown != 0 && 1828220650Smav (howto & (RB_HALT | RB_POWEROFF)) != 0) 1829220650Smav adaspindown(ATA_STANDBY_IMMEDIATE, 0); 1830220650Smav} 1831220650Smav 1832220650Smavstatic void 1833220650Smavadasuspend(void *arg) 1834220650Smav{ 1835220650Smav 1836220650Smav adaflush(); 1837220650Smav if (ada_spindown_suspend != 0) 1838220650Smav adaspindown(ATA_SLEEP, CAM_DEV_QFREEZE); 1839220650Smav} 1840220650Smav 1841220650Smavstatic void 1842220650Smavadaresume(void *arg) 1843220650Smav{ 1844220650Smav struct cam_periph *periph; 1845220650Smav struct ada_softc *softc; 1846220650Smav 1847220650Smav if (ada_spindown_suspend == 0) 1848220650Smav return; 1849220650Smav 1850220650Smav TAILQ_FOREACH(periph, &adadriver.units, unit_links) { 1851220650Smav cam_periph_lock(periph); 1852220650Smav softc = (struct ada_softc *)periph->softc; 1853220650Smav /* 1854220650Smav * We only spin-down the drive if it is capable of it.. 1855220650Smav */ 1856220650Smav if ((softc->flags & ADA_FLAG_CAN_POWERMGT) == 0) { 1857220650Smav cam_periph_unlock(periph); 1858220650Smav continue; 1859220650Smav } 1860220650Smav 1861220650Smav if (bootverbose) 1862220650Smav xpt_print(periph->path, "resume\n"); 1863220650Smav 1864220650Smav /* 1865220650Smav * Drop freeze taken due to CAM_DEV_QFREEZE flag set on 1866220650Smav * sleep request. 1867220650Smav */ 1868220650Smav cam_release_devq(periph->path, 1869220650Smav /*relsim_flags*/0, 1870220650Smav /*openings*/0, 1871220650Smav /*timeout*/0, 1872220650Smav /*getcount_only*/0); 1873220650Smav 1874220650Smav cam_periph_unlock(periph); 1875220650Smav } 1876220650Smav} 1877220650Smav 1878195534Sscottl#endif /* _KERNEL */ 1879