ata_da.c revision 227293
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 227293 2011-11-07 06:44:47Z ed $"); 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 */ 168222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "SAMSUNG HD204UI*", "*" }, 169222520Smav /*quirks*/ADA_Q_4K 170222520Smav }, 171222520Smav { 172222520Smav /* Seagate Barracuda Green Advanced Format (4k) drives */ 173222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST????DL*", "*" }, 174222520Smav /*quirks*/ADA_Q_4K 175222520Smav }, 176222520Smav { 177222520Smav /* Seagate Momentus Advanced Format (4k) drives */ 178222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9500423AS*", "*" }, 179222520Smav /*quirks*/ADA_Q_4K 180222520Smav }, 181222520Smav { 182222520Smav /* Seagate Momentus Advanced Format (4k) drives */ 183222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9500424AS*", "*" }, 184222520Smav /*quirks*/ADA_Q_4K 185222520Smav }, 186222520Smav { 187222520Smav /* Seagate Momentus Advanced Format (4k) drives */ 188222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9750420AS*", "*" }, 189222520Smav /*quirks*/ADA_Q_4K 190222520Smav }, 191222520Smav { 192222520Smav /* Seagate Momentus Advanced Format (4k) drives */ 193222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9750422AS*", "*" }, 194222520Smav /*quirks*/ADA_Q_4K 195222520Smav }, 196222520Smav { 197222520Smav /* Seagate Momentus Thin Advanced Format (4k) drives */ 198222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST???LT*", "*" }, 199222520Smav /*quirks*/ADA_Q_4K 200222520Smav }, 201222520Smav { 202222520Smav /* WDC Caviar Green Advanced Format (4k) drives */ 203222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD????RS*", "*" }, 204222520Smav /*quirks*/ADA_Q_4K 205222520Smav }, 206222520Smav { 207222520Smav /* WDC Caviar Green Advanced Format (4k) drives */ 208222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD????RX*", "*" }, 209222520Smav /*quirks*/ADA_Q_4K 210222520Smav }, 211222520Smav { 212222520Smav /* WDC Caviar Green Advanced Format (4k) drives */ 213222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD??????RS*", "*" }, 214222520Smav /*quirks*/ADA_Q_4K 215222520Smav }, 216222520Smav { 217222520Smav /* WDC Caviar Green Advanced Format (4k) drives */ 218222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD??????RX*", "*" }, 219222520Smav /*quirks*/ADA_Q_4K 220222520Smav }, 221222520Smav { 222222520Smav /* WDC Scorpio Black Advanced Format (4k) drives */ 223222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD???PKT*", "*" }, 224222520Smav /*quirks*/ADA_Q_4K 225222520Smav }, 226222520Smav { 227222520Smav /* WDC Scorpio Black Advanced Format (4k) drives */ 228222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD?????PKT*", "*" }, 229222520Smav /*quirks*/ADA_Q_4K 230222520Smav }, 231222520Smav { 232222520Smav /* WDC Scorpio Blue Advanced Format (4k) drives */ 233222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD???PVT*", "*" }, 234222520Smav /*quirks*/ADA_Q_4K 235222520Smav }, 236222520Smav { 237222520Smav /* WDC Scorpio Blue Advanced Format (4k) drives */ 238222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD?????PVT*", "*" }, 239222520Smav /*quirks*/ADA_Q_4K 240222520Smav }, 241222520Smav { 242199178Smav /* Default */ 243199178Smav { 244199178Smav T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED, 245199178Smav /*vendor*/"*", /*product*/"*", /*revision*/"*" 246199178Smav }, 247199178Smav /*quirks*/0 248199178Smav }, 249199178Smav}; 250195534Sscottl 251195534Sscottlstatic disk_strategy_t adastrategy; 252195534Sscottlstatic dumper_t adadump; 253195534Sscottlstatic periph_init_t adainit; 254195534Sscottlstatic void adaasync(void *callback_arg, u_int32_t code, 255195534Sscottl struct cam_path *path, void *arg); 256195534Sscottlstatic void adasysctlinit(void *context, int pending); 257195534Sscottlstatic periph_ctor_t adaregister; 258195534Sscottlstatic periph_dtor_t adacleanup; 259195534Sscottlstatic periph_start_t adastart; 260195534Sscottlstatic periph_oninv_t adaoninvalidate; 261195534Sscottlstatic void adadone(struct cam_periph *periph, 262195534Sscottl union ccb *done_ccb); 263195534Sscottlstatic int adaerror(union ccb *ccb, u_int32_t cam_flags, 264195534Sscottl u_int32_t sense_flags); 265198897Smavstatic void adagetparams(struct cam_periph *periph, 266195534Sscottl struct ccb_getdev *cgd); 267195534Sscottlstatic timeout_t adasendorderedtag; 268195534Sscottlstatic void adashutdown(void *arg, int howto); 269220650Smavstatic void adasuspend(void *arg); 270220650Smavstatic void adaresume(void *arg); 271195534Sscottl 272221071Smav#ifndef ADA_DEFAULT_LEGACY_ALIASES 273221071Smav#ifdef ATA_CAM 274221071Smav#define ADA_DEFAULT_LEGACY_ALIASES 1 275221071Smav#else 276221071Smav#define ADA_DEFAULT_LEGACY_ALIASES 0 277221071Smav#endif 278221071Smav#endif 279221071Smav 280195534Sscottl#ifndef ADA_DEFAULT_TIMEOUT 281195534Sscottl#define ADA_DEFAULT_TIMEOUT 30 /* Timeout in seconds */ 282195534Sscottl#endif 283195534Sscottl 284195534Sscottl#ifndef ADA_DEFAULT_RETRY 285195534Sscottl#define ADA_DEFAULT_RETRY 4 286195534Sscottl#endif 287195534Sscottl 288195534Sscottl#ifndef ADA_DEFAULT_SEND_ORDERED 289195534Sscottl#define ADA_DEFAULT_SEND_ORDERED 1 290195534Sscottl#endif 291195534Sscottl 292214279Sbrucec#ifndef ADA_DEFAULT_SPINDOWN_SHUTDOWN 293214279Sbrucec#define ADA_DEFAULT_SPINDOWN_SHUTDOWN 1 294214279Sbrucec#endif 295214279Sbrucec 296220650Smav#ifndef ADA_DEFAULT_SPINDOWN_SUSPEND 297220650Smav#define ADA_DEFAULT_SPINDOWN_SUSPEND 1 298220650Smav#endif 299220650Smav 300224497Smav#ifndef ADA_DEFAULT_READ_AHEAD 301224497Smav#define ADA_DEFAULT_READ_AHEAD 1 302224497Smav#endif 303224497Smav 304220412Smav#ifndef ADA_DEFAULT_WRITE_CACHE 305220412Smav#define ADA_DEFAULT_WRITE_CACHE 1 306220412Smav#endif 307220412Smav 308224497Smav#define ADA_RA (softc->read_ahead >= 0 ? \ 309224497Smav softc->read_ahead : ada_read_ahead) 310224497Smav#define ADA_WC (softc->write_cache >= 0 ? \ 311224497Smav softc->write_cache : ada_write_cache) 312224497Smav 313208349Smarius/* 314208349Smarius * Most platforms map firmware geometry to actual, but some don't. If 315208349Smarius * not overridden, default to nothing. 316208349Smarius */ 317208349Smarius#ifndef ata_disk_firmware_geom_adjust 318208349Smarius#define ata_disk_firmware_geom_adjust(disk) 319208349Smarius#endif 320195534Sscottl 321221071Smavstatic int ada_legacy_aliases = ADA_DEFAULT_LEGACY_ALIASES; 322195534Sscottlstatic int ada_retry_count = ADA_DEFAULT_RETRY; 323195534Sscottlstatic int ada_default_timeout = ADA_DEFAULT_TIMEOUT; 324195534Sscottlstatic int ada_send_ordered = ADA_DEFAULT_SEND_ORDERED; 325214279Sbrucecstatic int ada_spindown_shutdown = ADA_DEFAULT_SPINDOWN_SHUTDOWN; 326220650Smavstatic int ada_spindown_suspend = ADA_DEFAULT_SPINDOWN_SUSPEND; 327224497Smavstatic int ada_read_ahead = ADA_DEFAULT_READ_AHEAD; 328220412Smavstatic int ada_write_cache = ADA_DEFAULT_WRITE_CACHE; 329195534Sscottl 330195534SscottlSYSCTL_NODE(_kern_cam, OID_AUTO, ada, CTLFLAG_RD, 0, 331195534Sscottl "CAM Direct Access Disk driver"); 332221071SmavSYSCTL_INT(_kern_cam_ada, OID_AUTO, legacy_aliases, CTLFLAG_RW, 333221071Smav &ada_legacy_aliases, 0, "Create legacy-like device aliases"); 334221071SmavTUNABLE_INT("kern.cam.ada.legacy_aliases", &ada_legacy_aliases); 335195534SscottlSYSCTL_INT(_kern_cam_ada, OID_AUTO, retry_count, CTLFLAG_RW, 336195534Sscottl &ada_retry_count, 0, "Normal I/O retry count"); 337195534SscottlTUNABLE_INT("kern.cam.ada.retry_count", &ada_retry_count); 338195534SscottlSYSCTL_INT(_kern_cam_ada, OID_AUTO, default_timeout, CTLFLAG_RW, 339195534Sscottl &ada_default_timeout, 0, "Normal I/O timeout (in seconds)"); 340195534SscottlTUNABLE_INT("kern.cam.ada.default_timeout", &ada_default_timeout); 341195534SscottlSYSCTL_INT(_kern_cam_ada, OID_AUTO, ada_send_ordered, CTLFLAG_RW, 342195534Sscottl &ada_send_ordered, 0, "Send Ordered Tags"); 343195534SscottlTUNABLE_INT("kern.cam.ada.ada_send_ordered", &ada_send_ordered); 344214279SbrucecSYSCTL_INT(_kern_cam_ada, OID_AUTO, spindown_shutdown, CTLFLAG_RW, 345214279Sbrucec &ada_spindown_shutdown, 0, "Spin down upon shutdown"); 346214279SbrucecTUNABLE_INT("kern.cam.ada.spindown_shutdown", &ada_spindown_shutdown); 347220650SmavSYSCTL_INT(_kern_cam_ada, OID_AUTO, spindown_suspend, CTLFLAG_RW, 348220650Smav &ada_spindown_suspend, 0, "Spin down upon suspend"); 349220650SmavTUNABLE_INT("kern.cam.ada.spindown_suspend", &ada_spindown_suspend); 350224497SmavSYSCTL_INT(_kern_cam_ada, OID_AUTO, read_ahead, CTLFLAG_RW, 351224497Smav &ada_read_ahead, 0, "Enable disk read-ahead"); 352224497SmavTUNABLE_INT("kern.cam.ada.read_ahead", &ada_read_ahead); 353220412SmavSYSCTL_INT(_kern_cam_ada, OID_AUTO, write_cache, CTLFLAG_RW, 354220412Smav &ada_write_cache, 0, "Enable disk write cache"); 355220412SmavTUNABLE_INT("kern.cam.ada.write_cache", &ada_write_cache); 356195534Sscottl 357195534Sscottl/* 358195534Sscottl * ADA_ORDEREDTAG_INTERVAL determines how often, relative 359195534Sscottl * to the default timeout, we check to see whether an ordered 360195534Sscottl * tagged transaction is appropriate to prevent simple tag 361195534Sscottl * starvation. Since we'd like to ensure that there is at least 362195534Sscottl * 1/2 of the timeout length left for a starved transaction to 363195534Sscottl * complete after we've sent an ordered tag, we must poll at least 364195534Sscottl * four times in every timeout period. This takes care of the worst 365195534Sscottl * case where a starved transaction starts during an interval that 366195534Sscottl * meets the requirement "don't send an ordered tag" test so it takes 367195534Sscottl * us two intervals to determine that a tag must be sent. 368195534Sscottl */ 369195534Sscottl#ifndef ADA_ORDEREDTAG_INTERVAL 370195534Sscottl#define ADA_ORDEREDTAG_INTERVAL 4 371195534Sscottl#endif 372195534Sscottl 373195534Sscottlstatic struct periph_driver adadriver = 374195534Sscottl{ 375195534Sscottl adainit, "ada", 376195534Sscottl TAILQ_HEAD_INITIALIZER(adadriver.units), /* generation */ 0 377195534Sscottl}; 378195534Sscottl 379195534SscottlPERIPHDRIVER_DECLARE(ada, adadriver); 380195534Sscottl 381227293Sedstatic MALLOC_DEFINE(M_ATADA, "ata_da", "ata_da buffers"); 382195534Sscottl 383195534Sscottlstatic int 384195534Sscottladaopen(struct disk *dp) 385195534Sscottl{ 386195534Sscottl struct cam_periph *periph; 387195534Sscottl struct ada_softc *softc; 388195534Sscottl int error; 389195534Sscottl 390195534Sscottl periph = (struct cam_periph *)dp->d_drv1; 391195534Sscottl if (periph == NULL) { 392195534Sscottl return (ENXIO); 393195534Sscottl } 394195534Sscottl 395195534Sscottl if (cam_periph_acquire(periph) != CAM_REQ_CMP) { 396195534Sscottl return(ENXIO); 397195534Sscottl } 398195534Sscottl 399195534Sscottl cam_periph_lock(periph); 400195534Sscottl if ((error = cam_periph_hold(periph, PRIBIO|PCATCH)) != 0) { 401195534Sscottl cam_periph_unlock(periph); 402195534Sscottl cam_periph_release(periph); 403195534Sscottl return (error); 404195534Sscottl } 405195534Sscottl 406195534Sscottl softc = (struct ada_softc *)periph->softc; 407195534Sscottl softc->flags |= ADA_FLAG_OPEN; 408195534Sscottl 409195534Sscottl CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, 410195534Sscottl ("adaopen: disk=%s%d (unit %d)\n", dp->d_name, dp->d_unit, 411220778Smav periph->unit_number)); 412195534Sscottl 413195534Sscottl if ((softc->flags & ADA_FLAG_PACK_INVALID) != 0) { 414195534Sscottl /* Invalidate our pack information. */ 415195534Sscottl softc->flags &= ~ADA_FLAG_PACK_INVALID; 416195534Sscottl } 417195534Sscottl 418195534Sscottl cam_periph_unhold(periph); 419195534Sscottl cam_periph_unlock(periph); 420195534Sscottl return (0); 421195534Sscottl} 422195534Sscottl 423195534Sscottlstatic int 424195534Sscottladaclose(struct disk *dp) 425195534Sscottl{ 426195534Sscottl struct cam_periph *periph; 427195534Sscottl struct ada_softc *softc; 428195534Sscottl union ccb *ccb; 429195534Sscottl int error; 430195534Sscottl 431195534Sscottl periph = (struct cam_periph *)dp->d_drv1; 432195534Sscottl if (periph == NULL) 433195534Sscottl return (ENXIO); 434195534Sscottl 435195534Sscottl cam_periph_lock(periph); 436195534Sscottl if ((error = cam_periph_hold(periph, PRIBIO)) != 0) { 437195534Sscottl cam_periph_unlock(periph); 438195534Sscottl cam_periph_release(periph); 439195534Sscottl return (error); 440195534Sscottl } 441195534Sscottl 442195534Sscottl softc = (struct ada_softc *)periph->softc; 443195534Sscottl /* We only sync the cache if the drive is capable of it. */ 444224283Smav if ((softc->flags & ADA_FLAG_CAN_FLUSHCACHE) != 0 && 445224283Smav (softc->flags & ADA_FLAG_PACK_INVALID) == 0) { 446195534Sscottl 447198382Smav ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 448195534Sscottl cam_fill_ataio(&ccb->ataio, 449195534Sscottl 1, 450195534Sscottl adadone, 451195534Sscottl CAM_DIR_NONE, 452195534Sscottl 0, 453195534Sscottl NULL, 454195534Sscottl 0, 455195534Sscottl ada_default_timeout*1000); 456195534Sscottl 457195534Sscottl if (softc->flags & ADA_FLAG_CAN_48BIT) 458195534Sscottl ata_48bit_cmd(&ccb->ataio, ATA_FLUSHCACHE48, 0, 0, 0); 459195534Sscottl else 460196659Smav ata_28bit_cmd(&ccb->ataio, ATA_FLUSHCACHE, 0, 0, 0); 461195748Smav cam_periph_runccb(ccb, /*error_routine*/NULL, /*cam_flags*/0, 462198328Smav /*sense_flags*/0, softc->disk->d_devstat); 463195534Sscottl 464195534Sscottl if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) 465195534Sscottl xpt_print(periph->path, "Synchronize cache failed\n"); 466195534Sscottl 467195534Sscottl if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 468195534Sscottl cam_release_devq(ccb->ccb_h.path, 469195534Sscottl /*relsim_flags*/0, 470195534Sscottl /*reduction*/0, 471195534Sscottl /*timeout*/0, 472195534Sscottl /*getcount_only*/0); 473195534Sscottl xpt_release_ccb(ccb); 474195534Sscottl } 475195534Sscottl 476195534Sscottl softc->flags &= ~ADA_FLAG_OPEN; 477195534Sscottl cam_periph_unhold(periph); 478195534Sscottl cam_periph_unlock(periph); 479195534Sscottl cam_periph_release(periph); 480195534Sscottl return (0); 481195534Sscottl} 482195534Sscottl 483201139Smavstatic void 484201139Smavadaschedule(struct cam_periph *periph) 485201139Smav{ 486201139Smav struct ada_softc *softc = (struct ada_softc *)periph->softc; 487224531Smav uint32_t prio; 488201139Smav 489224531Smav /* Check if cam_periph_getccb() was called. */ 490224531Smav prio = periph->immediate_priority; 491224531Smav 492224531Smav /* Check if we have more work to do. */ 493201139Smav if (bioq_first(&softc->bio_queue) || 494201139Smav (!softc->trim_running && bioq_first(&softc->trim_queue))) { 495224531Smav prio = CAM_PRIORITY_NORMAL; 496201139Smav } 497224531Smav 498224531Smav /* Schedule CCB if any of above is true. */ 499224531Smav if (prio != CAM_PRIORITY_NONE) 500224531Smav xpt_schedule(periph, prio); 501201139Smav} 502201139Smav 503195534Sscottl/* 504195534Sscottl * Actually translate the requested transfer into one the physical driver 505195534Sscottl * can understand. The transfer is described by a buf and will include 506195534Sscottl * only one physical transfer. 507195534Sscottl */ 508195534Sscottlstatic void 509195534Sscottladastrategy(struct bio *bp) 510195534Sscottl{ 511195534Sscottl struct cam_periph *periph; 512195534Sscottl struct ada_softc *softc; 513195534Sscottl 514195534Sscottl periph = (struct cam_periph *)bp->bio_disk->d_drv1; 515195534Sscottl if (periph == NULL) { 516195534Sscottl biofinish(bp, NULL, ENXIO); 517195534Sscottl return; 518195534Sscottl } 519195534Sscottl softc = (struct ada_softc *)periph->softc; 520195534Sscottl 521195534Sscottl cam_periph_lock(periph); 522195534Sscottl 523195534Sscottl /* 524195534Sscottl * If the device has been made invalid, error out 525195534Sscottl */ 526195534Sscottl if ((softc->flags & ADA_FLAG_PACK_INVALID)) { 527195534Sscottl cam_periph_unlock(periph); 528195534Sscottl biofinish(bp, NULL, ENXIO); 529195534Sscottl return; 530195534Sscottl } 531195534Sscottl 532195534Sscottl /* 533195534Sscottl * Place it in the queue of disk activities for this disk 534195534Sscottl */ 535201139Smav if (bp->bio_cmd == BIO_DELETE && 536201139Smav (softc->flags & ADA_FLAG_CAN_TRIM)) 537201139Smav bioq_disksort(&softc->trim_queue, bp); 538201139Smav else 539201139Smav bioq_disksort(&softc->bio_queue, bp); 540195534Sscottl 541195534Sscottl /* 542195534Sscottl * Schedule ourselves for performing the work. 543195534Sscottl */ 544201139Smav adaschedule(periph); 545195534Sscottl cam_periph_unlock(periph); 546195534Sscottl 547195534Sscottl return; 548195534Sscottl} 549195534Sscottl 550195534Sscottlstatic int 551195534Sscottladadump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t length) 552195534Sscottl{ 553195534Sscottl struct cam_periph *periph; 554195534Sscottl struct ada_softc *softc; 555195534Sscottl u_int secsize; 556195534Sscottl union ccb ccb; 557195534Sscottl struct disk *dp; 558195534Sscottl uint64_t lba; 559195534Sscottl uint16_t count; 560195534Sscottl 561195534Sscottl dp = arg; 562195534Sscottl periph = dp->d_drv1; 563195534Sscottl if (periph == NULL) 564195534Sscottl return (ENXIO); 565195534Sscottl softc = (struct ada_softc *)periph->softc; 566195534Sscottl cam_periph_lock(periph); 567195534Sscottl secsize = softc->params.secsize; 568195534Sscottl lba = offset / secsize; 569195534Sscottl count = length / secsize; 570195534Sscottl 571195534Sscottl if ((softc->flags & ADA_FLAG_PACK_INVALID) != 0) { 572195534Sscottl cam_periph_unlock(periph); 573195534Sscottl return (ENXIO); 574195534Sscottl } 575195534Sscottl 576195534Sscottl if (length > 0) { 577198382Smav xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 578195534Sscottl ccb.ccb_h.ccb_state = ADA_CCB_DUMP; 579195534Sscottl cam_fill_ataio(&ccb.ataio, 580195534Sscottl 0, 581195534Sscottl adadone, 582195534Sscottl CAM_DIR_OUT, 583195534Sscottl 0, 584195534Sscottl (u_int8_t *) virtual, 585195534Sscottl length, 586195534Sscottl ada_default_timeout*1000); 587195534Sscottl if ((softc->flags & ADA_FLAG_CAN_48BIT) && 588195534Sscottl (lba + count >= ATA_MAX_28BIT_LBA || 589195534Sscottl count >= 256)) { 590195534Sscottl ata_48bit_cmd(&ccb.ataio, ATA_WRITE_DMA48, 591195534Sscottl 0, lba, count); 592195534Sscottl } else { 593196659Smav ata_28bit_cmd(&ccb.ataio, ATA_WRITE_DMA, 594195534Sscottl 0, lba, count); 595195534Sscottl } 596195534Sscottl xpt_polled_action(&ccb); 597195534Sscottl 598195534Sscottl if ((ccb.ataio.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 599195534Sscottl printf("Aborting dump due to I/O error.\n"); 600195534Sscottl cam_periph_unlock(periph); 601195534Sscottl return(EIO); 602195534Sscottl } 603195534Sscottl cam_periph_unlock(periph); 604195534Sscottl return(0); 605195534Sscottl } 606195534Sscottl 607195534Sscottl if (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) { 608198382Smav xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 609195534Sscottl 610195534Sscottl ccb.ccb_h.ccb_state = ADA_CCB_DUMP; 611195534Sscottl cam_fill_ataio(&ccb.ataio, 612195534Sscottl 1, 613195534Sscottl adadone, 614195534Sscottl CAM_DIR_NONE, 615195534Sscottl 0, 616195534Sscottl NULL, 617195534Sscottl 0, 618195534Sscottl ada_default_timeout*1000); 619195534Sscottl 620195534Sscottl if (softc->flags & ADA_FLAG_CAN_48BIT) 621195534Sscottl ata_48bit_cmd(&ccb.ataio, ATA_FLUSHCACHE48, 0, 0, 0); 622195534Sscottl else 623196659Smav ata_28bit_cmd(&ccb.ataio, ATA_FLUSHCACHE, 0, 0, 0); 624195534Sscottl xpt_polled_action(&ccb); 625195534Sscottl 626195534Sscottl if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) 627195534Sscottl xpt_print(periph->path, "Synchronize cache failed\n"); 628195534Sscottl 629195534Sscottl if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0) 630195534Sscottl cam_release_devq(ccb.ccb_h.path, 631195534Sscottl /*relsim_flags*/0, 632195534Sscottl /*reduction*/0, 633195534Sscottl /*timeout*/0, 634195534Sscottl /*getcount_only*/0); 635195534Sscottl } 636195534Sscottl cam_periph_unlock(periph); 637195534Sscottl return (0); 638195534Sscottl} 639195534Sscottl 640195534Sscottlstatic void 641195534Sscottladainit(void) 642195534Sscottl{ 643195534Sscottl cam_status status; 644195534Sscottl 645195534Sscottl /* 646195534Sscottl * Install a global async callback. This callback will 647195534Sscottl * receive async callbacks like "new device found". 648195534Sscottl */ 649195534Sscottl status = xpt_register_async(AC_FOUND_DEVICE, adaasync, NULL, NULL); 650195534Sscottl 651195534Sscottl if (status != CAM_REQ_CMP) { 652195534Sscottl printf("ada: Failed to attach master async callback " 653195534Sscottl "due to status 0x%x!\n", status); 654195534Sscottl } else if (ada_send_ordered) { 655195534Sscottl 656220650Smav /* Register our event handlers */ 657220650Smav if ((EVENTHANDLER_REGISTER(power_suspend, adasuspend, 658220650Smav NULL, EVENTHANDLER_PRI_LAST)) == NULL) 659220650Smav printf("adainit: power event registration failed!\n"); 660220650Smav if ((EVENTHANDLER_REGISTER(power_resume, adaresume, 661220650Smav NULL, EVENTHANDLER_PRI_LAST)) == NULL) 662220650Smav printf("adainit: power event registration failed!\n"); 663220650Smav if ((EVENTHANDLER_REGISTER(shutdown_post_sync, adashutdown, 664195534Sscottl NULL, SHUTDOWN_PRI_DEFAULT)) == NULL) 665195534Sscottl printf("adainit: shutdown event registration failed!\n"); 666195534Sscottl } 667195534Sscottl} 668195534Sscottl 669195534Sscottlstatic void 670195534Sscottladaoninvalidate(struct cam_periph *periph) 671195534Sscottl{ 672195534Sscottl struct ada_softc *softc; 673195534Sscottl 674195534Sscottl softc = (struct ada_softc *)periph->softc; 675195534Sscottl 676195534Sscottl /* 677195534Sscottl * De-register any async callbacks. 678195534Sscottl */ 679195534Sscottl xpt_register_async(0, adaasync, periph, periph->path); 680195534Sscottl 681195534Sscottl softc->flags |= ADA_FLAG_PACK_INVALID; 682195534Sscottl 683195534Sscottl /* 684195534Sscottl * Return all queued I/O with ENXIO. 685195534Sscottl * XXX Handle any transactions queued to the card 686195534Sscottl * with XPT_ABORT_CCB. 687195534Sscottl */ 688195534Sscottl bioq_flush(&softc->bio_queue, NULL, ENXIO); 689201139Smav bioq_flush(&softc->trim_queue, NULL, ENXIO); 690195534Sscottl 691195534Sscottl disk_gone(softc->disk); 692195534Sscottl xpt_print(periph->path, "lost device\n"); 693195534Sscottl} 694195534Sscottl 695195534Sscottlstatic void 696195534Sscottladacleanup(struct cam_periph *periph) 697195534Sscottl{ 698195534Sscottl struct ada_softc *softc; 699195534Sscottl 700195534Sscottl softc = (struct ada_softc *)periph->softc; 701195534Sscottl 702195534Sscottl xpt_print(periph->path, "removing device entry\n"); 703195534Sscottl cam_periph_unlock(periph); 704195534Sscottl 705195534Sscottl /* 706195534Sscottl * If we can't free the sysctl tree, oh well... 707195534Sscottl */ 708195534Sscottl if ((softc->flags & ADA_FLAG_SCTX_INIT) != 0 709195534Sscottl && sysctl_ctx_free(&softc->sysctl_ctx) != 0) { 710195534Sscottl xpt_print(periph->path, "can't remove sysctl context\n"); 711195534Sscottl } 712195534Sscottl 713195534Sscottl disk_destroy(softc->disk); 714195534Sscottl callout_drain(&softc->sendordered_c); 715195534Sscottl free(softc, M_DEVBUF); 716195534Sscottl cam_periph_lock(periph); 717195534Sscottl} 718195534Sscottl 719195534Sscottlstatic void 720195534Sscottladaasync(void *callback_arg, u_int32_t code, 721195534Sscottl struct cam_path *path, void *arg) 722195534Sscottl{ 723195534Sscottl struct cam_periph *periph; 724220412Smav struct ada_softc *softc; 725195534Sscottl 726195534Sscottl periph = (struct cam_periph *)callback_arg; 727195534Sscottl switch (code) { 728195534Sscottl case AC_FOUND_DEVICE: 729195534Sscottl { 730195534Sscottl struct ccb_getdev *cgd; 731195534Sscottl cam_status status; 732195534Sscottl 733195534Sscottl cgd = (struct ccb_getdev *)arg; 734195534Sscottl if (cgd == NULL) 735195534Sscottl break; 736195534Sscottl 737195534Sscottl if (cgd->protocol != PROTO_ATA) 738195534Sscottl break; 739195534Sscottl 740195534Sscottl /* 741195534Sscottl * Allocate a peripheral instance for 742195534Sscottl * this device and start the probe 743195534Sscottl * process. 744195534Sscottl */ 745195534Sscottl status = cam_periph_alloc(adaregister, adaoninvalidate, 746195534Sscottl adacleanup, adastart, 747195534Sscottl "ada", CAM_PERIPH_BIO, 748195534Sscottl cgd->ccb_h.path, adaasync, 749195534Sscottl AC_FOUND_DEVICE, cgd); 750195534Sscottl 751195534Sscottl if (status != CAM_REQ_CMP 752195534Sscottl && status != CAM_REQ_INPROG) 753195534Sscottl printf("adaasync: Unable to attach to new device " 754195534Sscottl "due to status 0x%x\n", status); 755195534Sscottl break; 756195534Sscottl } 757220412Smav case AC_SENT_BDR: 758220412Smav case AC_BUS_RESET: 759220412Smav { 760220412Smav struct ccb_getdev cgd; 761220412Smav 762220412Smav softc = (struct ada_softc *)periph->softc; 763220412Smav cam_periph_async(periph, code, path, arg); 764220412Smav if (softc->state != ADA_STATE_NORMAL) 765220412Smav break; 766220454Smav xpt_setup_ccb(&cgd.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 767220412Smav cgd.ccb_h.func_code = XPT_GDEV_TYPE; 768220412Smav xpt_action((union ccb *)&cgd); 769224497Smav if (ADA_RA >= 0 && 770224497Smav cgd.ident_data.support.command1 & ATA_SUPPORT_LOOKAHEAD) 771224497Smav softc->state = ADA_STATE_RAHEAD; 772224497Smav else if (ADA_WC >= 0 && 773224497Smav cgd.ident_data.support.command1 & ATA_SUPPORT_WRITECACHE) 774224497Smav softc->state = ADA_STATE_WCACHE; 775224497Smav else 776224497Smav break; 777220412Smav cam_periph_acquire(periph); 778220412Smav cam_freeze_devq_arg(periph->path, 779220412Smav RELSIM_RELEASE_RUNLEVEL, CAM_RL_DEV + 1); 780220412Smav xpt_schedule(periph, CAM_PRIORITY_DEV); 781220412Smav } 782195534Sscottl default: 783195534Sscottl cam_periph_async(periph, code, path, arg); 784195534Sscottl break; 785195534Sscottl } 786195534Sscottl} 787195534Sscottl 788195534Sscottlstatic void 789195534Sscottladasysctlinit(void *context, int pending) 790195534Sscottl{ 791195534Sscottl struct cam_periph *periph; 792195534Sscottl struct ada_softc *softc; 793195534Sscottl char tmpstr[80], tmpstr2[80]; 794195534Sscottl 795195534Sscottl periph = (struct cam_periph *)context; 796220454Smav 797220454Smav /* periph was held for us when this task was enqueued */ 798220454Smav if (periph->flags & CAM_PERIPH_INVALID) { 799220454Smav cam_periph_release(periph); 800195534Sscottl return; 801220454Smav } 802195534Sscottl 803195534Sscottl softc = (struct ada_softc *)periph->softc; 804195534Sscottl snprintf(tmpstr, sizeof(tmpstr), "CAM ADA unit %d", periph->unit_number); 805195534Sscottl snprintf(tmpstr2, sizeof(tmpstr2), "%d", periph->unit_number); 806195534Sscottl 807195534Sscottl sysctl_ctx_init(&softc->sysctl_ctx); 808195534Sscottl softc->flags |= ADA_FLAG_SCTX_INIT; 809195534Sscottl softc->sysctl_tree = SYSCTL_ADD_NODE(&softc->sysctl_ctx, 810195534Sscottl SYSCTL_STATIC_CHILDREN(_kern_cam_ada), OID_AUTO, tmpstr2, 811195534Sscottl CTLFLAG_RD, 0, tmpstr); 812195534Sscottl if (softc->sysctl_tree == NULL) { 813195534Sscottl printf("adasysctlinit: unable to allocate sysctl tree\n"); 814195534Sscottl cam_periph_release(periph); 815195534Sscottl return; 816195534Sscottl } 817195534Sscottl 818220454Smav SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 819224497Smav OID_AUTO, "read_ahead", CTLFLAG_RW | CTLFLAG_MPSAFE, 820224497Smav &softc->read_ahead, 0, "Enable disk read ahead."); 821224497Smav SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 822220454Smav OID_AUTO, "write_cache", CTLFLAG_RW | CTLFLAG_MPSAFE, 823220454Smav &softc->write_cache, 0, "Enable disk write cache."); 824220454Smav#ifdef ADA_TEST_FAILURE 825220454Smav /* 826220454Smav * Add a 'door bell' sysctl which allows one to set it from userland 827220454Smav * and cause something bad to happen. For the moment, we only allow 828220454Smav * whacking the next read or write. 829220454Smav */ 830220454Smav SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 831220454Smav OID_AUTO, "force_read_error", CTLFLAG_RW | CTLFLAG_MPSAFE, 832220454Smav &softc->force_read_error, 0, 833220454Smav "Force a read error for the next N reads."); 834220454Smav SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 835220454Smav OID_AUTO, "force_write_error", CTLFLAG_RW | CTLFLAG_MPSAFE, 836220454Smav &softc->force_write_error, 0, 837220454Smav "Force a write error for the next N writes."); 838220454Smav SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 839220454Smav OID_AUTO, "periodic_read_error", CTLFLAG_RW | CTLFLAG_MPSAFE, 840220454Smav &softc->periodic_read_error, 0, 841220454Smav "Force a read error every N reads (don't set too low)."); 842220454Smav#endif 843195534Sscottl cam_periph_release(periph); 844195534Sscottl} 845195534Sscottl 846223089Sgibbsstatic int 847223089Sgibbsadagetattr(struct bio *bp) 848223089Sgibbs{ 849223089Sgibbs int ret = -1; 850223089Sgibbs struct cam_periph *periph; 851223089Sgibbs 852223277Skib if (bp->bio_disk == NULL || bp->bio_disk->d_drv1 == NULL) 853223089Sgibbs return ENXIO; 854223089Sgibbs periph = (struct cam_periph *)bp->bio_disk->d_drv1; 855223089Sgibbs if (periph->path == NULL) 856223089Sgibbs return ENXIO; 857223089Sgibbs 858223089Sgibbs ret = xpt_getattr(bp->bio_data, bp->bio_length, bp->bio_attribute, 859223089Sgibbs periph->path); 860223089Sgibbs if (ret == 0) 861223089Sgibbs bp->bio_completed = bp->bio_length; 862223089Sgibbs return ret; 863223089Sgibbs} 864223089Sgibbs 865195534Sscottlstatic cam_status 866195534Sscottladaregister(struct cam_periph *periph, void *arg) 867195534Sscottl{ 868195534Sscottl struct ada_softc *softc; 869195534Sscottl struct ccb_pathinq cpi; 870195534Sscottl struct ccb_getdev *cgd; 871221071Smav char announce_buf[80], buf1[32]; 872195534Sscottl struct disk_params *dp; 873195534Sscottl caddr_t match; 874195534Sscottl u_int maxio; 875222520Smav int legacy_id, quirks; 876195534Sscottl 877195534Sscottl cgd = (struct ccb_getdev *)arg; 878195534Sscottl if (periph == NULL) { 879195534Sscottl printf("adaregister: periph was NULL!!\n"); 880195534Sscottl return(CAM_REQ_CMP_ERR); 881195534Sscottl } 882195534Sscottl 883195534Sscottl if (cgd == NULL) { 884195534Sscottl printf("adaregister: no getdev CCB, can't register device\n"); 885195534Sscottl return(CAM_REQ_CMP_ERR); 886195534Sscottl } 887195534Sscottl 888195534Sscottl softc = (struct ada_softc *)malloc(sizeof(*softc), M_DEVBUF, 889195534Sscottl M_NOWAIT|M_ZERO); 890195534Sscottl 891195534Sscottl if (softc == NULL) { 892195534Sscottl printf("adaregister: Unable to probe new device. " 893198328Smav "Unable to allocate softc\n"); 894195534Sscottl return(CAM_REQ_CMP_ERR); 895195534Sscottl } 896195534Sscottl 897195534Sscottl bioq_init(&softc->bio_queue); 898201139Smav bioq_init(&softc->trim_queue); 899195534Sscottl 900220886Smav if (cgd->ident_data.capabilities1 & ATA_SUPPORT_DMA && 901220886Smav (cgd->inq_flags & SID_DMA)) 902198328Smav softc->flags |= ADA_FLAG_CAN_DMA; 903195534Sscottl if (cgd->ident_data.support.command2 & ATA_SUPPORT_ADDRESS48) 904195534Sscottl softc->flags |= ADA_FLAG_CAN_48BIT; 905195534Sscottl if (cgd->ident_data.support.command2 & ATA_SUPPORT_FLUSHCACHE) 906195534Sscottl softc->flags |= ADA_FLAG_CAN_FLUSHCACHE; 907214279Sbrucec if (cgd->ident_data.support.command1 & ATA_SUPPORT_POWERMGT) 908214279Sbrucec softc->flags |= ADA_FLAG_CAN_POWERMGT; 909195534Sscottl if (cgd->ident_data.satacapabilities & ATA_SUPPORT_NCQ && 910220886Smav (cgd->inq_flags & SID_DMA) && (cgd->inq_flags & SID_CmdQue)) 911195534Sscottl softc->flags |= ADA_FLAG_CAN_NCQ; 912201139Smav if (cgd->ident_data.support_dsm & ATA_SUPPORT_DSM_TRIM) { 913201139Smav softc->flags |= ADA_FLAG_CAN_TRIM; 914201139Smav softc->trim_max_ranges = TRIM_MAX_RANGES; 915201139Smav if (cgd->ident_data.max_dsm_blocks != 0) { 916201139Smav softc->trim_max_ranges = 917201139Smav min(cgd->ident_data.max_dsm_blocks * 64, 918201139Smav softc->trim_max_ranges); 919201139Smav } 920201139Smav } 921201139Smav if (cgd->ident_data.support.command2 & ATA_SUPPORT_CFA) 922201139Smav softc->flags |= ADA_FLAG_CAN_CFA; 923195534Sscottl 924195534Sscottl periph->softc = softc; 925195534Sscottl 926195534Sscottl /* 927195534Sscottl * See if this device has any quirks. 928195534Sscottl */ 929199178Smav match = cam_quirkmatch((caddr_t)&cgd->ident_data, 930199178Smav (caddr_t)ada_quirk_table, 931199178Smav sizeof(ada_quirk_table)/sizeof(*ada_quirk_table), 932199178Smav sizeof(*ada_quirk_table), ata_identify_match); 933195534Sscottl if (match != NULL) 934195534Sscottl softc->quirks = ((struct ada_quirk_entry *)match)->quirks; 935195534Sscottl else 936195534Sscottl softc->quirks = ADA_Q_NONE; 937195534Sscottl 938195534Sscottl bzero(&cpi, sizeof(cpi)); 939203108Smav xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NONE); 940195534Sscottl cpi.ccb_h.func_code = XPT_PATH_INQ; 941195534Sscottl xpt_action((union ccb *)&cpi); 942195534Sscottl 943195534Sscottl TASK_INIT(&softc->sysctl_task, 0, adasysctlinit, periph); 944195534Sscottl 945195534Sscottl /* 946195534Sscottl * Register this media as a disk 947195534Sscottl */ 948220618Smav (void)cam_periph_hold(periph, PRIBIO); 949195534Sscottl mtx_unlock(periph->sim->mtx); 950222520Smav snprintf(announce_buf, sizeof(announce_buf), 951222520Smav "kern.cam.ada.%d.quirks", periph->unit_number); 952222520Smav quirks = softc->quirks; 953222520Smav TUNABLE_INT_FETCH(announce_buf, &quirks); 954222520Smav softc->quirks = quirks; 955224497Smav softc->read_ahead = -1; 956224497Smav snprintf(announce_buf, sizeof(announce_buf), 957224497Smav "kern.cam.ada.%d.read_ahead", periph->unit_number); 958224497Smav TUNABLE_INT_FETCH(announce_buf, &softc->read_ahead); 959220618Smav softc->write_cache = -1; 960220618Smav snprintf(announce_buf, sizeof(announce_buf), 961220618Smav "kern.cam.ada.%d.write_cache", periph->unit_number); 962220618Smav TUNABLE_INT_FETCH(announce_buf, &softc->write_cache); 963198897Smav adagetparams(periph, cgd); 964195534Sscottl softc->disk = disk_alloc(); 965220644Smav softc->disk->d_devstat = devstat_new_entry(periph->periph_name, 966220644Smav periph->unit_number, softc->params.secsize, 967220644Smav DEVSTAT_ALL_SUPPORTED, 968220644Smav DEVSTAT_TYPE_DIRECT | 969220644Smav XPORT_DEVSTAT_TYPE(cpi.transport), 970220644Smav DEVSTAT_PRIORITY_DISK); 971195534Sscottl softc->disk->d_open = adaopen; 972195534Sscottl softc->disk->d_close = adaclose; 973195534Sscottl softc->disk->d_strategy = adastrategy; 974223089Sgibbs softc->disk->d_getattr = adagetattr; 975195534Sscottl softc->disk->d_dump = adadump; 976195534Sscottl softc->disk->d_name = "ada"; 977195534Sscottl softc->disk->d_drv1 = periph; 978195534Sscottl maxio = cpi.maxio; /* Honor max I/O size of SIM */ 979195534Sscottl if (maxio == 0) 980195534Sscottl maxio = DFLTPHYS; /* traditional default */ 981195534Sscottl else if (maxio > MAXPHYS) 982195534Sscottl maxio = MAXPHYS; /* for safety */ 983201139Smav if (softc->flags & ADA_FLAG_CAN_48BIT) 984198897Smav maxio = min(maxio, 65536 * softc->params.secsize); 985195534Sscottl else /* 28bit ATA command limit */ 986198897Smav maxio = min(maxio, 256 * softc->params.secsize); 987195534Sscottl softc->disk->d_maxsize = maxio; 988195534Sscottl softc->disk->d_unit = periph->unit_number; 989195534Sscottl softc->disk->d_flags = 0; 990195534Sscottl if (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) 991195534Sscottl softc->disk->d_flags |= DISKFLAG_CANFLUSHCACHE; 992201139Smav if ((softc->flags & ADA_FLAG_CAN_TRIM) || 993201139Smav ((softc->flags & ADA_FLAG_CAN_CFA) && 994201139Smav !(softc->flags & ADA_FLAG_CAN_48BIT))) 995201139Smav softc->disk->d_flags |= DISKFLAG_CANDELETE; 996219056Snwhitehorn strlcpy(softc->disk->d_descr, cgd->ident_data.model, 997219056Snwhitehorn MIN(sizeof(softc->disk->d_descr), sizeof(cgd->ident_data.model))); 998210471Smav softc->disk->d_hba_vendor = cpi.hba_vendor; 999210471Smav softc->disk->d_hba_device = cpi.hba_device; 1000210471Smav softc->disk->d_hba_subvendor = cpi.hba_subvendor; 1001210471Smav softc->disk->d_hba_subdevice = cpi.hba_subdevice; 1002195534Sscottl 1003195534Sscottl softc->disk->d_sectorsize = softc->params.secsize; 1004198897Smav softc->disk->d_mediasize = (off_t)softc->params.sectors * 1005198897Smav softc->params.secsize; 1006200969Smav if (ata_physical_sector_size(&cgd->ident_data) != 1007200969Smav softc->params.secsize) { 1008200969Smav softc->disk->d_stripesize = 1009200969Smav ata_physical_sector_size(&cgd->ident_data); 1010200969Smav softc->disk->d_stripeoffset = (softc->disk->d_stripesize - 1011200969Smav ata_logical_sector_offset(&cgd->ident_data)) % 1012200969Smav softc->disk->d_stripesize; 1013222520Smav } else if (softc->quirks & ADA_Q_4K) { 1014222520Smav softc->disk->d_stripesize = 4096; 1015222520Smav softc->disk->d_stripeoffset = 0; 1016200969Smav } 1017195534Sscottl softc->disk->d_fwsectors = softc->params.secs_per_track; 1018195534Sscottl softc->disk->d_fwheads = softc->params.heads; 1019208349Smarius ata_disk_firmware_geom_adjust(softc->disk); 1020195534Sscottl 1021221071Smav if (ada_legacy_aliases) { 1022221071Smav#ifdef ATA_STATIC_ID 1023221071Smav legacy_id = xpt_path_legacy_ata_id(periph->path); 1024221071Smav#else 1025221071Smav legacy_id = softc->disk->d_unit; 1026221071Smav#endif 1027221071Smav if (legacy_id >= 0) { 1028221071Smav snprintf(announce_buf, sizeof(announce_buf), 1029221071Smav "kern.devalias.%s%d", 1030221071Smav softc->disk->d_name, softc->disk->d_unit); 1031221071Smav snprintf(buf1, sizeof(buf1), 1032221071Smav "ad%d", legacy_id); 1033221071Smav setenv(announce_buf, buf1); 1034221071Smav } 1035221071Smav } else 1036221071Smav legacy_id = -1; 1037195534Sscottl disk_create(softc->disk, DISK_VERSION); 1038195534Sscottl mtx_lock(periph->sim->mtx); 1039220618Smav cam_periph_unhold(periph); 1040195534Sscottl 1041195534Sscottl dp = &softc->params; 1042195534Sscottl snprintf(announce_buf, sizeof(announce_buf), 1043195534Sscottl "%juMB (%ju %u byte sectors: %dH %dS/T %dC)", 1044195534Sscottl (uintmax_t)(((uintmax_t)dp->secsize * 1045195534Sscottl dp->sectors) / (1024*1024)), 1046195534Sscottl (uintmax_t)dp->sectors, 1047195534Sscottl dp->secsize, dp->heads, 1048195534Sscottl dp->secs_per_track, dp->cylinders); 1049195534Sscottl xpt_announce_periph(periph, announce_buf); 1050221071Smav if (legacy_id >= 0) 1051221071Smav printf("%s%d: Previously was known as ad%d\n", 1052221071Smav periph->periph_name, periph->unit_number, legacy_id); 1053220454Smav 1054195534Sscottl /* 1055220454Smav * Create our sysctl variables, now that we know 1056220454Smav * we have successfully attached. 1057220454Smav */ 1058220454Smav cam_periph_acquire(periph); 1059220454Smav taskqueue_enqueue(taskqueue_thread, &softc->sysctl_task); 1060220454Smav 1061220454Smav /* 1062195534Sscottl * Add async callbacks for bus reset and 1063195534Sscottl * bus device reset calls. I don't bother 1064195534Sscottl * checking if this fails as, in most cases, 1065195534Sscottl * the system will function just fine without 1066195534Sscottl * them and the only alternative would be to 1067195534Sscottl * not attach the device on failure. 1068195534Sscottl */ 1069220412Smav xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE, 1070195534Sscottl adaasync, periph, periph->path); 1071195534Sscottl 1072195534Sscottl /* 1073195534Sscottl * Schedule a periodic event to occasionally send an 1074195534Sscottl * ordered tag to a device. 1075195534Sscottl */ 1076195534Sscottl callout_init_mtx(&softc->sendordered_c, periph->sim->mtx, 0); 1077195534Sscottl callout_reset(&softc->sendordered_c, 1078195534Sscottl (ADA_DEFAULT_TIMEOUT * hz) / ADA_ORDEREDTAG_INTERVAL, 1079195534Sscottl adasendorderedtag, softc); 1080195534Sscottl 1081224497Smav if (ADA_RA >= 0 && 1082224497Smav cgd->ident_data.support.command1 & ATA_SUPPORT_LOOKAHEAD) { 1083224497Smav softc->state = ADA_STATE_RAHEAD; 1084224497Smav cam_periph_acquire(periph); 1085224497Smav cam_freeze_devq_arg(periph->path, 1086224497Smav RELSIM_RELEASE_RUNLEVEL, CAM_RL_DEV + 1); 1087224497Smav xpt_schedule(periph, CAM_PRIORITY_DEV); 1088224497Smav } else if (ADA_WC >= 0 && 1089220412Smav cgd->ident_data.support.command1 & ATA_SUPPORT_WRITECACHE) { 1090220412Smav softc->state = ADA_STATE_WCACHE; 1091220412Smav cam_periph_acquire(periph); 1092220412Smav cam_freeze_devq_arg(periph->path, 1093220412Smav RELSIM_RELEASE_RUNLEVEL, CAM_RL_DEV + 1); 1094220412Smav xpt_schedule(periph, CAM_PRIORITY_DEV); 1095220412Smav } else 1096220412Smav softc->state = ADA_STATE_NORMAL; 1097220412Smav 1098195534Sscottl return(CAM_REQ_CMP); 1099195534Sscottl} 1100195534Sscottl 1101195534Sscottlstatic void 1102195534Sscottladastart(struct cam_periph *periph, union ccb *start_ccb) 1103195534Sscottl{ 1104198328Smav struct ada_softc *softc = (struct ada_softc *)periph->softc; 1105198328Smav struct ccb_ataio *ataio = &start_ccb->ataio; 1106195534Sscottl 1107195534Sscottl switch (softc->state) { 1108195534Sscottl case ADA_STATE_NORMAL: 1109195534Sscottl { 1110195534Sscottl struct bio *bp; 1111201139Smav u_int8_t tag_code; 1112195534Sscottl 1113201139Smav /* Execute immediate CCB if waiting. */ 1114195534Sscottl if (periph->immediate_priority <= periph->pinfo.priority) { 1115195534Sscottl CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE, 1116195534Sscottl ("queuing for immediate ccb\n")); 1117195534Sscottl start_ccb->ccb_h.ccb_state = ADA_CCB_WAITING; 1118195534Sscottl SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, 1119195534Sscottl periph_links.sle); 1120195534Sscottl periph->immediate_priority = CAM_PRIORITY_NONE; 1121195534Sscottl wakeup(&periph->ccb_list); 1122201139Smav /* Have more work to do, so ensure we stay scheduled */ 1123201139Smav adaschedule(periph); 1124201139Smav break; 1125201139Smav } 1126201139Smav /* Run TRIM if not running yet. */ 1127201139Smav if (!softc->trim_running && 1128201139Smav (bp = bioq_first(&softc->trim_queue)) != 0) { 1129201139Smav struct trim_request *req = &softc->trim_req; 1130201139Smav struct bio *bp1; 1131222628Smav uint64_t lastlba = (uint64_t)-1; 1132222628Smav int bps = 0, c, lastcount = 0, off, ranges = 0; 1133201139Smav 1134201139Smav softc->trim_running = 1; 1135201139Smav bzero(req, sizeof(*req)); 1136201139Smav bp1 = bp; 1137201139Smav do { 1138201139Smav uint64_t lba = bp1->bio_pblkno; 1139201139Smav int count = bp1->bio_bcount / 1140201139Smav softc->params.secsize; 1141201139Smav 1142201139Smav bioq_remove(&softc->trim_queue, bp1); 1143222628Smav 1144222628Smav /* Try to extend the previous range. */ 1145222628Smav if (lba == lastlba) { 1146222628Smav c = min(count, 0xffff - lastcount); 1147222628Smav lastcount += c; 1148222628Smav off = (ranges - 1) * 8; 1149222628Smav req->data[off + 6] = lastcount & 0xff; 1150222628Smav req->data[off + 7] = 1151222628Smav (lastcount >> 8) & 0xff; 1152222628Smav count -= c; 1153222628Smav lba += c; 1154222628Smav } 1155222628Smav 1156201139Smav while (count > 0) { 1157222628Smav c = min(count, 0xffff); 1158222628Smav off = ranges * 8; 1159201139Smav req->data[off + 0] = lba & 0xff; 1160201139Smav req->data[off + 1] = (lba >> 8) & 0xff; 1161201139Smav req->data[off + 2] = (lba >> 16) & 0xff; 1162201139Smav req->data[off + 3] = (lba >> 24) & 0xff; 1163201139Smav req->data[off + 4] = (lba >> 32) & 0xff; 1164201139Smav req->data[off + 5] = (lba >> 40) & 0xff; 1165201139Smav req->data[off + 6] = c & 0xff; 1166201139Smav req->data[off + 7] = (c >> 8) & 0xff; 1167201139Smav lba += c; 1168201139Smav count -= c; 1169222628Smav lastcount = c; 1170201139Smav ranges++; 1171201139Smav } 1172222628Smav lastlba = lba; 1173201139Smav req->bps[bps++] = bp1; 1174201139Smav bp1 = bioq_first(&softc->trim_queue); 1175222628Smav if (bps >= TRIM_MAX_BIOS || 1176222628Smav bp1 == NULL || 1177201139Smav bp1->bio_bcount / softc->params.secsize > 1178201139Smav (softc->trim_max_ranges - ranges) * 0xffff) 1179201139Smav break; 1180201139Smav } while (1); 1181201139Smav cam_fill_ataio(ataio, 1182201139Smav ada_retry_count, 1183201139Smav adadone, 1184201139Smav CAM_DIR_OUT, 1185201139Smav 0, 1186201139Smav req->data, 1187201139Smav ((ranges + 63) / 64) * 512, 1188201139Smav ada_default_timeout * 1000); 1189201139Smav ata_48bit_cmd(ataio, ATA_DATA_SET_MANAGEMENT, 1190201139Smav ATA_DSM_TRIM, 0, (ranges + 63) / 64); 1191201139Smav start_ccb->ccb_h.ccb_state = ADA_CCB_TRIM; 1192201139Smav goto out; 1193201139Smav } 1194201139Smav /* Run regular command. */ 1195201139Smav bp = bioq_first(&softc->bio_queue); 1196201139Smav if (bp == NULL) { 1197195534Sscottl xpt_release_ccb(start_ccb); 1198201139Smav break; 1199201139Smav } 1200201139Smav bioq_remove(&softc->bio_queue, bp); 1201201139Smav 1202212160Sgibbs if ((bp->bio_flags & BIO_ORDERED) != 0 1203212160Sgibbs || (softc->flags & ADA_FLAG_NEED_OTAG) != 0) { 1204201139Smav softc->flags &= ~ADA_FLAG_NEED_OTAG; 1205201139Smav softc->ordered_tag_count++; 1206201139Smav tag_code = 0; 1207195534Sscottl } else { 1208201139Smav tag_code = 1; 1209201139Smav } 1210201139Smav switch (bp->bio_cmd) { 1211201139Smav case BIO_READ: 1212201139Smav case BIO_WRITE: 1213201139Smav { 1214201139Smav uint64_t lba = bp->bio_pblkno; 1215201139Smav uint16_t count = bp->bio_bcount / softc->params.secsize; 1216220454Smav#ifdef ADA_TEST_FAILURE 1217220454Smav int fail = 0; 1218195534Sscottl 1219220454Smav /* 1220220454Smav * Support the failure ioctls. If the command is a 1221220454Smav * read, and there are pending forced read errors, or 1222220454Smav * if a write and pending write errors, then fail this 1223220454Smav * operation with EIO. This is useful for testing 1224220454Smav * purposes. Also, support having every Nth read fail. 1225220454Smav * 1226220454Smav * This is a rather blunt tool. 1227220454Smav */ 1228220454Smav if (bp->bio_cmd == BIO_READ) { 1229220454Smav if (softc->force_read_error) { 1230220454Smav softc->force_read_error--; 1231220454Smav fail = 1; 1232220454Smav } 1233220454Smav if (softc->periodic_read_error > 0) { 1234220454Smav if (++softc->periodic_read_count >= 1235220454Smav softc->periodic_read_error) { 1236220454Smav softc->periodic_read_count = 0; 1237220454Smav fail = 1; 1238220454Smav } 1239220454Smav } 1240220454Smav } else { 1241220454Smav if (softc->force_write_error) { 1242220454Smav softc->force_write_error--; 1243220454Smav fail = 1; 1244220454Smav } 1245220454Smav } 1246220454Smav if (fail) { 1247220454Smav bp->bio_error = EIO; 1248220454Smav bp->bio_flags |= BIO_ERROR; 1249220454Smav biodone(bp); 1250220454Smav xpt_release_ccb(start_ccb); 1251220454Smav adaschedule(periph); 1252220454Smav return; 1253220454Smav } 1254220454Smav#endif 1255201139Smav cam_fill_ataio(ataio, 1256201139Smav ada_retry_count, 1257201139Smav adadone, 1258201139Smav bp->bio_cmd == BIO_READ ? 1259201139Smav CAM_DIR_IN : CAM_DIR_OUT, 1260201139Smav tag_code, 1261201139Smav bp->bio_data, 1262201139Smav bp->bio_bcount, 1263201139Smav ada_default_timeout*1000); 1264195534Sscottl 1265201139Smav if ((softc->flags & ADA_FLAG_CAN_NCQ) && tag_code) { 1266201139Smav if (bp->bio_cmd == BIO_READ) { 1267201139Smav ata_ncq_cmd(ataio, ATA_READ_FPDMA_QUEUED, 1268201139Smav lba, count); 1269201139Smav } else { 1270201139Smav ata_ncq_cmd(ataio, ATA_WRITE_FPDMA_QUEUED, 1271201139Smav lba, count); 1272201139Smav } 1273201139Smav } else if ((softc->flags & ADA_FLAG_CAN_48BIT) && 1274201139Smav (lba + count >= ATA_MAX_28BIT_LBA || 1275201139Smav count > 256)) { 1276201139Smav if (softc->flags & ADA_FLAG_CAN_DMA) { 1277195534Sscottl if (bp->bio_cmd == BIO_READ) { 1278201139Smav ata_48bit_cmd(ataio, ATA_READ_DMA48, 1279201139Smav 0, lba, count); 1280195534Sscottl } else { 1281201139Smav ata_48bit_cmd(ataio, ATA_WRITE_DMA48, 1282201139Smav 0, lba, count); 1283195534Sscottl } 1284201139Smav } else { 1285201139Smav if (bp->bio_cmd == BIO_READ) { 1286201139Smav ata_48bit_cmd(ataio, ATA_READ_MUL48, 1287201139Smav 0, lba, count); 1288195534Sscottl } else { 1289201139Smav ata_48bit_cmd(ataio, ATA_WRITE_MUL48, 1290201139Smav 0, lba, count); 1291195534Sscottl } 1292201139Smav } 1293201139Smav } else { 1294201139Smav if (count == 256) 1295201139Smav count = 0; 1296201139Smav if (softc->flags & ADA_FLAG_CAN_DMA) { 1297201139Smav if (bp->bio_cmd == BIO_READ) { 1298201139Smav ata_28bit_cmd(ataio, ATA_READ_DMA, 1299201139Smav 0, lba, count); 1300201139Smav } else { 1301201139Smav ata_28bit_cmd(ataio, ATA_WRITE_DMA, 1302201139Smav 0, lba, count); 1303201139Smav } 1304195534Sscottl } else { 1305201139Smav if (bp->bio_cmd == BIO_READ) { 1306201139Smav ata_28bit_cmd(ataio, ATA_READ_MUL, 1307201139Smav 0, lba, count); 1308195534Sscottl } else { 1309201139Smav ata_28bit_cmd(ataio, ATA_WRITE_MUL, 1310201139Smav 0, lba, count); 1311195534Sscottl } 1312195534Sscottl } 1313195534Sscottl } 1314201139Smav break; 1315201139Smav } 1316201139Smav case BIO_DELETE: 1317201139Smav { 1318201139Smav uint64_t lba = bp->bio_pblkno; 1319201139Smav uint16_t count = bp->bio_bcount / softc->params.secsize; 1320195534Sscottl 1321201139Smav cam_fill_ataio(ataio, 1322201139Smav ada_retry_count, 1323201139Smav adadone, 1324201139Smav CAM_DIR_NONE, 1325201139Smav 0, 1326201139Smav NULL, 1327201139Smav 0, 1328201139Smav ada_default_timeout*1000); 1329201139Smav 1330201139Smav if (count >= 256) 1331201139Smav count = 0; 1332201139Smav ata_28bit_cmd(ataio, ATA_CFA_ERASE, 0, lba, count); 1333201139Smav break; 1334195534Sscottl } 1335201139Smav case BIO_FLUSH: 1336201139Smav cam_fill_ataio(ataio, 1337201139Smav 1, 1338201139Smav adadone, 1339201139Smav CAM_DIR_NONE, 1340201139Smav 0, 1341201139Smav NULL, 1342201139Smav 0, 1343201139Smav ada_default_timeout*1000); 1344201139Smav 1345201139Smav if (softc->flags & ADA_FLAG_CAN_48BIT) 1346201139Smav ata_48bit_cmd(ataio, ATA_FLUSHCACHE48, 0, 0, 0); 1347201139Smav else 1348201139Smav ata_28bit_cmd(ataio, ATA_FLUSHCACHE, 0, 0, 0); 1349201139Smav break; 1350195534Sscottl } 1351201139Smav start_ccb->ccb_h.ccb_state = ADA_CCB_BUFFER_IO; 1352201139Smavout: 1353201139Smav start_ccb->ccb_h.ccb_bp = bp; 1354201139Smav softc->outstanding_cmds++; 1355201139Smav xpt_action(start_ccb); 1356201139Smav 1357201139Smav /* May have more work to do, so ensure we stay scheduled */ 1358201139Smav adaschedule(periph); 1359195534Sscottl break; 1360195534Sscottl } 1361224497Smav case ADA_STATE_RAHEAD: 1362220412Smav case ADA_STATE_WCACHE: 1363220412Smav { 1364224497Smav if (softc->flags & ADA_FLAG_PACK_INVALID) { 1365224497Smav softc->state = ADA_STATE_NORMAL; 1366224497Smav xpt_release_ccb(start_ccb); 1367224497Smav cam_release_devq(periph->path, 1368224497Smav RELSIM_RELEASE_RUNLEVEL, 0, CAM_RL_DEV + 1, FALSE); 1369224497Smav adaschedule(periph); 1370224497Smav cam_periph_release_locked(periph); 1371224497Smav return; 1372224497Smav } 1373224497Smav 1374220412Smav cam_fill_ataio(ataio, 1375220412Smav 1, 1376220412Smav adadone, 1377220412Smav CAM_DIR_NONE, 1378220412Smav 0, 1379220412Smav NULL, 1380220412Smav 0, 1381220412Smav ada_default_timeout*1000); 1382220412Smav 1383224497Smav if (softc->state == ADA_STATE_RAHEAD) { 1384224497Smav ata_28bit_cmd(ataio, ATA_SETFEATURES, ADA_RA ? 1385224497Smav ATA_SF_ENAB_RCACHE : ATA_SF_DIS_RCACHE, 0, 0); 1386224497Smav start_ccb->ccb_h.ccb_state = ADA_CCB_RAHEAD; 1387224497Smav } else { 1388224497Smav ata_28bit_cmd(ataio, ATA_SETFEATURES, ADA_WC ? 1389224497Smav ATA_SF_ENAB_WCACHE : ATA_SF_DIS_WCACHE, 0, 0); 1390224497Smav start_ccb->ccb_h.ccb_state = ADA_CCB_WCACHE; 1391224497Smav } 1392220412Smav xpt_action(start_ccb); 1393220412Smav break; 1394195534Sscottl } 1395220412Smav } 1396195534Sscottl} 1397195534Sscottl 1398195534Sscottlstatic void 1399195534Sscottladadone(struct cam_periph *periph, union ccb *done_ccb) 1400195534Sscottl{ 1401195534Sscottl struct ada_softc *softc; 1402195534Sscottl struct ccb_ataio *ataio; 1403224497Smav struct ccb_getdev *cgd; 1404195534Sscottl 1405195534Sscottl softc = (struct ada_softc *)periph->softc; 1406195534Sscottl ataio = &done_ccb->ataio; 1407195534Sscottl switch (ataio->ccb_h.ccb_state & ADA_CCB_TYPE_MASK) { 1408195534Sscottl case ADA_CCB_BUFFER_IO: 1409201139Smav case ADA_CCB_TRIM: 1410195534Sscottl { 1411195534Sscottl struct bio *bp; 1412195534Sscottl 1413195534Sscottl bp = (struct bio *)done_ccb->ccb_h.ccb_bp; 1414195534Sscottl if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 1415195534Sscottl int error; 1416195534Sscottl 1417198328Smav error = adaerror(done_ccb, 0, 0); 1418195534Sscottl if (error == ERESTART) { 1419198328Smav /* A retry was scheduled, so just return. */ 1420195534Sscottl return; 1421195534Sscottl } 1422195534Sscottl if (error != 0) { 1423224283Smav if (error == ENXIO && 1424224283Smav (softc->flags & ADA_FLAG_PACK_INVALID) == 0) { 1425195534Sscottl /* 1426195534Sscottl * Catastrophic error. Mark our pack as 1427195534Sscottl * invalid. 1428195534Sscottl */ 1429195534Sscottl /* 1430195534Sscottl * XXX See if this is really a media 1431195534Sscottl * XXX change first? 1432195534Sscottl */ 1433195534Sscottl xpt_print(periph->path, 1434195534Sscottl "Invalidating pack\n"); 1435195534Sscottl softc->flags |= ADA_FLAG_PACK_INVALID; 1436195534Sscottl } 1437195534Sscottl bp->bio_error = error; 1438195534Sscottl bp->bio_resid = bp->bio_bcount; 1439195534Sscottl bp->bio_flags |= BIO_ERROR; 1440195534Sscottl } else { 1441195534Sscottl bp->bio_resid = ataio->resid; 1442195534Sscottl bp->bio_error = 0; 1443195534Sscottl if (bp->bio_resid != 0) 1444195534Sscottl bp->bio_flags |= BIO_ERROR; 1445195534Sscottl } 1446195534Sscottl if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 1447195534Sscottl cam_release_devq(done_ccb->ccb_h.path, 1448195534Sscottl /*relsim_flags*/0, 1449195534Sscottl /*reduction*/0, 1450195534Sscottl /*timeout*/0, 1451195534Sscottl /*getcount_only*/0); 1452195534Sscottl } else { 1453195534Sscottl if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 1454195534Sscottl panic("REQ_CMP with QFRZN"); 1455195534Sscottl bp->bio_resid = ataio->resid; 1456195534Sscottl if (ataio->resid > 0) 1457195534Sscottl bp->bio_flags |= BIO_ERROR; 1458195534Sscottl } 1459195534Sscottl softc->outstanding_cmds--; 1460195534Sscottl if (softc->outstanding_cmds == 0) 1461195534Sscottl softc->flags |= ADA_FLAG_WENT_IDLE; 1462201139Smav if ((ataio->ccb_h.ccb_state & ADA_CCB_TYPE_MASK) == 1463201139Smav ADA_CCB_TRIM) { 1464201139Smav struct trim_request *req = 1465201139Smav (struct trim_request *)ataio->data_ptr; 1466201139Smav int i; 1467195534Sscottl 1468222628Smav for (i = 1; i < TRIM_MAX_BIOS && req->bps[i]; i++) { 1469201139Smav struct bio *bp1 = req->bps[i]; 1470201139Smav 1471201139Smav bp1->bio_resid = bp->bio_resid; 1472201139Smav bp1->bio_error = bp->bio_error; 1473201139Smav if (bp->bio_flags & BIO_ERROR) 1474201139Smav bp1->bio_flags |= BIO_ERROR; 1475201139Smav biodone(bp1); 1476201139Smav } 1477201139Smav softc->trim_running = 0; 1478201139Smav biodone(bp); 1479201139Smav adaschedule(periph); 1480201139Smav } else 1481201139Smav biodone(bp); 1482195534Sscottl break; 1483195534Sscottl } 1484224497Smav case ADA_CCB_RAHEAD: 1485224497Smav { 1486224497Smav if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 1487224497Smav if (adaerror(done_ccb, 0, 0) == ERESTART) { 1488224497Smav return; 1489224497Smav } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 1490224497Smav cam_release_devq(done_ccb->ccb_h.path, 1491224497Smav /*relsim_flags*/0, 1492224497Smav /*reduction*/0, 1493224497Smav /*timeout*/0, 1494224497Smav /*getcount_only*/0); 1495224497Smav } 1496224497Smav } 1497224497Smav 1498224497Smav /* 1499224497Smav * Since our peripheral may be invalidated by an error 1500224497Smav * above or an external event, we must release our CCB 1501224497Smav * before releasing the reference on the peripheral. 1502224497Smav * The peripheral will only go away once the last reference 1503224497Smav * is removed, and we need it around for the CCB release 1504224497Smav * operation. 1505224497Smav */ 1506224497Smav cgd = (struct ccb_getdev *)done_ccb; 1507224497Smav xpt_setup_ccb(&cgd->ccb_h, periph->path, CAM_PRIORITY_NORMAL); 1508224497Smav cgd->ccb_h.func_code = XPT_GDEV_TYPE; 1509224497Smav xpt_action((union ccb *)cgd); 1510224497Smav if (ADA_WC >= 0 && 1511224497Smav cgd->ident_data.support.command1 & ATA_SUPPORT_WRITECACHE) { 1512224497Smav softc->state = ADA_STATE_WCACHE; 1513224497Smav xpt_release_ccb(done_ccb); 1514224497Smav xpt_schedule(periph, CAM_PRIORITY_DEV); 1515224497Smav return; 1516224497Smav } 1517224497Smav softc->state = ADA_STATE_NORMAL; 1518224497Smav xpt_release_ccb(done_ccb); 1519224497Smav cam_release_devq(periph->path, 1520224497Smav RELSIM_RELEASE_RUNLEVEL, 0, CAM_RL_DEV + 1, FALSE); 1521224497Smav adaschedule(periph); 1522224497Smav cam_periph_release_locked(periph); 1523224497Smav return; 1524224497Smav } 1525220412Smav case ADA_CCB_WCACHE: 1526220412Smav { 1527220412Smav if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 1528220412Smav if (adaerror(done_ccb, 0, 0) == ERESTART) { 1529220412Smav return; 1530220412Smav } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 1531220412Smav cam_release_devq(done_ccb->ccb_h.path, 1532220412Smav /*relsim_flags*/0, 1533220412Smav /*reduction*/0, 1534220412Smav /*timeout*/0, 1535220412Smav /*getcount_only*/0); 1536220412Smav } 1537220412Smav } 1538220412Smav 1539220412Smav softc->state = ADA_STATE_NORMAL; 1540220412Smav /* 1541220412Smav * Since our peripheral may be invalidated by an error 1542220412Smav * above or an external event, we must release our CCB 1543220412Smav * before releasing the reference on the peripheral. 1544220412Smav * The peripheral will only go away once the last reference 1545220412Smav * is removed, and we need it around for the CCB release 1546220412Smav * operation. 1547220412Smav */ 1548220412Smav xpt_release_ccb(done_ccb); 1549220412Smav cam_release_devq(periph->path, 1550220412Smav RELSIM_RELEASE_RUNLEVEL, 0, CAM_RL_DEV + 1, FALSE); 1551220412Smav adaschedule(periph); 1552220412Smav cam_periph_release_locked(periph); 1553220412Smav return; 1554220412Smav } 1555195534Sscottl case ADA_CCB_WAITING: 1556195534Sscottl { 1557195534Sscottl /* Caller will release the CCB */ 1558195534Sscottl wakeup(&done_ccb->ccb_h.cbfcnp); 1559195534Sscottl return; 1560195534Sscottl } 1561195534Sscottl case ADA_CCB_DUMP: 1562195534Sscottl /* No-op. We're polling */ 1563195534Sscottl return; 1564195534Sscottl default: 1565195534Sscottl break; 1566195534Sscottl } 1567195534Sscottl xpt_release_ccb(done_ccb); 1568195534Sscottl} 1569195534Sscottl 1570195534Sscottlstatic int 1571195534Sscottladaerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) 1572195534Sscottl{ 1573195534Sscottl 1574203385Smav return(cam_periph_error(ccb, cam_flags, sense_flags, NULL)); 1575195534Sscottl} 1576195534Sscottl 1577195534Sscottlstatic void 1578198897Smavadagetparams(struct cam_periph *periph, struct ccb_getdev *cgd) 1579195534Sscottl{ 1580195534Sscottl struct ada_softc *softc = (struct ada_softc *)periph->softc; 1581195534Sscottl struct disk_params *dp = &softc->params; 1582195534Sscottl u_int64_t lbasize48; 1583195534Sscottl u_int32_t lbasize; 1584195534Sscottl 1585198897Smav dp->secsize = ata_logical_sector_size(&cgd->ident_data); 1586195534Sscottl if ((cgd->ident_data.atavalid & ATA_FLAG_54_58) && 1587195534Sscottl cgd->ident_data.current_heads && cgd->ident_data.current_sectors) { 1588195534Sscottl dp->heads = cgd->ident_data.current_heads; 1589195534Sscottl dp->secs_per_track = cgd->ident_data.current_sectors; 1590195534Sscottl dp->cylinders = cgd->ident_data.cylinders; 1591195534Sscottl dp->sectors = (u_int32_t)cgd->ident_data.current_size_1 | 1592195534Sscottl ((u_int32_t)cgd->ident_data.current_size_2 << 16); 1593195534Sscottl } else { 1594195534Sscottl dp->heads = cgd->ident_data.heads; 1595195534Sscottl dp->secs_per_track = cgd->ident_data.sectors; 1596195534Sscottl dp->cylinders = cgd->ident_data.cylinders; 1597195534Sscottl dp->sectors = cgd->ident_data.cylinders * dp->heads * dp->secs_per_track; 1598195534Sscottl } 1599195534Sscottl lbasize = (u_int32_t)cgd->ident_data.lba_size_1 | 1600195534Sscottl ((u_int32_t)cgd->ident_data.lba_size_2 << 16); 1601195534Sscottl 1602195534Sscottl /* use the 28bit LBA size if valid or bigger than the CHS mapping */ 1603195534Sscottl if (cgd->ident_data.cylinders == 16383 || dp->sectors < lbasize) 1604195534Sscottl dp->sectors = lbasize; 1605195534Sscottl 1606195534Sscottl /* use the 48bit LBA size if valid */ 1607195534Sscottl lbasize48 = ((u_int64_t)cgd->ident_data.lba_size48_1) | 1608195534Sscottl ((u_int64_t)cgd->ident_data.lba_size48_2 << 16) | 1609195534Sscottl ((u_int64_t)cgd->ident_data.lba_size48_3 << 32) | 1610195534Sscottl ((u_int64_t)cgd->ident_data.lba_size48_4 << 48); 1611195534Sscottl if ((cgd->ident_data.support.command2 & ATA_SUPPORT_ADDRESS48) && 1612195534Sscottl lbasize48 > ATA_MAX_28BIT_LBA) 1613195534Sscottl dp->sectors = lbasize48; 1614195534Sscottl} 1615195534Sscottl 1616195534Sscottlstatic void 1617195534Sscottladasendorderedtag(void *arg) 1618195534Sscottl{ 1619195534Sscottl struct ada_softc *softc = arg; 1620195534Sscottl 1621195534Sscottl if (ada_send_ordered) { 1622195534Sscottl if ((softc->ordered_tag_count == 0) 1623195534Sscottl && ((softc->flags & ADA_FLAG_WENT_IDLE) == 0)) { 1624195534Sscottl softc->flags |= ADA_FLAG_NEED_OTAG; 1625195534Sscottl } 1626195534Sscottl if (softc->outstanding_cmds > 0) 1627195534Sscottl softc->flags &= ~ADA_FLAG_WENT_IDLE; 1628195534Sscottl 1629195534Sscottl softc->ordered_tag_count = 0; 1630195534Sscottl } 1631195534Sscottl /* Queue us up again */ 1632195534Sscottl callout_reset(&softc->sendordered_c, 1633195534Sscottl (ADA_DEFAULT_TIMEOUT * hz) / ADA_ORDEREDTAG_INTERVAL, 1634195534Sscottl adasendorderedtag, softc); 1635195534Sscottl} 1636195534Sscottl 1637195534Sscottl/* 1638195534Sscottl * Step through all ADA peripheral drivers, and if the device is still open, 1639195534Sscottl * sync the disk cache to physical media. 1640195534Sscottl */ 1641195534Sscottlstatic void 1642220650Smavadaflush(void) 1643195534Sscottl{ 1644195534Sscottl struct cam_periph *periph; 1645195534Sscottl struct ada_softc *softc; 1646195534Sscottl 1647195534Sscottl TAILQ_FOREACH(periph, &adadriver.units, unit_links) { 1648195534Sscottl union ccb ccb; 1649195534Sscottl 1650200180Smav /* If we paniced with lock held - not recurse here. */ 1651200180Smav if (cam_periph_owned(periph)) 1652200180Smav continue; 1653195534Sscottl cam_periph_lock(periph); 1654195534Sscottl softc = (struct ada_softc *)periph->softc; 1655195534Sscottl /* 1656195534Sscottl * We only sync the cache if the drive is still open, and 1657195534Sscottl * if the drive is capable of it.. 1658195534Sscottl */ 1659195534Sscottl if (((softc->flags & ADA_FLAG_OPEN) == 0) || 1660195534Sscottl (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) == 0) { 1661195534Sscottl cam_periph_unlock(periph); 1662195534Sscottl continue; 1663195534Sscottl } 1664195534Sscottl 1665198382Smav xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 1666195534Sscottl 1667195534Sscottl ccb.ccb_h.ccb_state = ADA_CCB_DUMP; 1668195534Sscottl cam_fill_ataio(&ccb.ataio, 1669195534Sscottl 1, 1670195534Sscottl adadone, 1671195534Sscottl CAM_DIR_NONE, 1672195534Sscottl 0, 1673195534Sscottl NULL, 1674195534Sscottl 0, 1675195534Sscottl ada_default_timeout*1000); 1676195534Sscottl 1677195534Sscottl if (softc->flags & ADA_FLAG_CAN_48BIT) 1678195534Sscottl ata_48bit_cmd(&ccb.ataio, ATA_FLUSHCACHE48, 0, 0, 0); 1679195534Sscottl else 1680196659Smav ata_28bit_cmd(&ccb.ataio, ATA_FLUSHCACHE, 0, 0, 0); 1681195534Sscottl xpt_polled_action(&ccb); 1682195534Sscottl 1683195534Sscottl if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) 1684195534Sscottl xpt_print(periph->path, "Synchronize cache failed\n"); 1685195534Sscottl 1686195534Sscottl if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0) 1687195534Sscottl cam_release_devq(ccb.ccb_h.path, 1688195534Sscottl /*relsim_flags*/0, 1689195534Sscottl /*reduction*/0, 1690195534Sscottl /*timeout*/0, 1691195534Sscottl /*getcount_only*/0); 1692195534Sscottl cam_periph_unlock(periph); 1693195534Sscottl } 1694220650Smav} 1695214279Sbrucec 1696220650Smavstatic void 1697220650Smavadaspindown(uint8_t cmd, int flags) 1698220650Smav{ 1699220650Smav struct cam_periph *periph; 1700220650Smav struct ada_softc *softc; 1701214279Sbrucec 1702214279Sbrucec TAILQ_FOREACH(periph, &adadriver.units, unit_links) { 1703214279Sbrucec union ccb ccb; 1704214279Sbrucec 1705214279Sbrucec /* If we paniced with lock held - not recurse here. */ 1706214279Sbrucec if (cam_periph_owned(periph)) 1707214279Sbrucec continue; 1708214279Sbrucec cam_periph_lock(periph); 1709214279Sbrucec softc = (struct ada_softc *)periph->softc; 1710214279Sbrucec /* 1711214279Sbrucec * We only spin-down the drive if it is capable of it.. 1712214279Sbrucec */ 1713214279Sbrucec if ((softc->flags & ADA_FLAG_CAN_POWERMGT) == 0) { 1714214279Sbrucec cam_periph_unlock(periph); 1715214279Sbrucec continue; 1716214279Sbrucec } 1717214279Sbrucec 1718214279Sbrucec if (bootverbose) 1719214279Sbrucec xpt_print(periph->path, "spin-down\n"); 1720214279Sbrucec 1721214279Sbrucec xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 1722214279Sbrucec 1723214279Sbrucec ccb.ccb_h.ccb_state = ADA_CCB_DUMP; 1724214279Sbrucec cam_fill_ataio(&ccb.ataio, 1725214279Sbrucec 1, 1726214279Sbrucec adadone, 1727220650Smav CAM_DIR_NONE | flags, 1728214279Sbrucec 0, 1729214279Sbrucec NULL, 1730214279Sbrucec 0, 1731214279Sbrucec ada_default_timeout*1000); 1732214279Sbrucec 1733220650Smav ata_28bit_cmd(&ccb.ataio, cmd, 0, 0, 0); 1734214279Sbrucec xpt_polled_action(&ccb); 1735214279Sbrucec 1736214279Sbrucec if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) 1737214279Sbrucec xpt_print(periph->path, "Spin-down disk failed\n"); 1738214279Sbrucec 1739214279Sbrucec if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0) 1740214279Sbrucec cam_release_devq(ccb.ccb_h.path, 1741214279Sbrucec /*relsim_flags*/0, 1742214279Sbrucec /*reduction*/0, 1743214279Sbrucec /*timeout*/0, 1744214279Sbrucec /*getcount_only*/0); 1745214279Sbrucec cam_periph_unlock(periph); 1746214279Sbrucec } 1747195534Sscottl} 1748195534Sscottl 1749220650Smavstatic void 1750220650Smavadashutdown(void *arg, int howto) 1751220650Smav{ 1752220650Smav 1753220650Smav adaflush(); 1754220650Smav if (ada_spindown_shutdown != 0 && 1755220650Smav (howto & (RB_HALT | RB_POWEROFF)) != 0) 1756220650Smav adaspindown(ATA_STANDBY_IMMEDIATE, 0); 1757220650Smav} 1758220650Smav 1759220650Smavstatic void 1760220650Smavadasuspend(void *arg) 1761220650Smav{ 1762220650Smav 1763220650Smav adaflush(); 1764220650Smav if (ada_spindown_suspend != 0) 1765220650Smav adaspindown(ATA_SLEEP, CAM_DEV_QFREEZE); 1766220650Smav} 1767220650Smav 1768220650Smavstatic void 1769220650Smavadaresume(void *arg) 1770220650Smav{ 1771220650Smav struct cam_periph *periph; 1772220650Smav struct ada_softc *softc; 1773220650Smav 1774220650Smav if (ada_spindown_suspend == 0) 1775220650Smav return; 1776220650Smav 1777220650Smav TAILQ_FOREACH(periph, &adadriver.units, unit_links) { 1778220650Smav cam_periph_lock(periph); 1779220650Smav softc = (struct ada_softc *)periph->softc; 1780220650Smav /* 1781220650Smav * We only spin-down the drive if it is capable of it.. 1782220650Smav */ 1783220650Smav if ((softc->flags & ADA_FLAG_CAN_POWERMGT) == 0) { 1784220650Smav cam_periph_unlock(periph); 1785220650Smav continue; 1786220650Smav } 1787220650Smav 1788220650Smav if (bootverbose) 1789220650Smav xpt_print(periph->path, "resume\n"); 1790220650Smav 1791220650Smav /* 1792220650Smav * Drop freeze taken due to CAM_DEV_QFREEZE flag set on 1793220650Smav * sleep request. 1794220650Smav */ 1795220650Smav cam_release_devq(periph->path, 1796220650Smav /*relsim_flags*/0, 1797220650Smav /*openings*/0, 1798220650Smav /*timeout*/0, 1799220650Smav /*getcount_only*/0); 1800220650Smav 1801220650Smav cam_periph_unlock(periph); 1802220650Smav } 1803220650Smav} 1804220650Smav 1805195534Sscottl#endif /* _KERNEL */ 1806