ata_da.c revision 224283
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 224283 2011-07-23 22:11:40Z mav $"); 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 { 72220412Smav ADA_STATE_WCACHE, 73198708Smav ADA_STATE_NORMAL 74195534Sscottl} ada_state; 75195534Sscottl 76195534Sscottltypedef enum { 77195534Sscottl ADA_FLAG_PACK_INVALID = 0x001, 78195534Sscottl ADA_FLAG_CAN_48BIT = 0x002, 79195534Sscottl ADA_FLAG_CAN_FLUSHCACHE = 0x004, 80198328Smav ADA_FLAG_CAN_NCQ = 0x008, 81198328Smav ADA_FLAG_CAN_DMA = 0x010, 82195534Sscottl ADA_FLAG_NEED_OTAG = 0x020, 83195534Sscottl ADA_FLAG_WENT_IDLE = 0x040, 84201139Smav ADA_FLAG_CAN_TRIM = 0x080, 85195534Sscottl ADA_FLAG_OPEN = 0x100, 86201139Smav ADA_FLAG_SCTX_INIT = 0x200, 87214279Sbrucec ADA_FLAG_CAN_CFA = 0x400, 88214279Sbrucec ADA_FLAG_CAN_POWERMGT = 0x800 89195534Sscottl} ada_flags; 90195534Sscottl 91195534Sscottltypedef enum { 92222520Smav ADA_Q_NONE = 0x00, 93222520Smav ADA_Q_4K = 0x01, 94195534Sscottl} ada_quirks; 95195534Sscottl 96195534Sscottltypedef enum { 97220412Smav ADA_CCB_WCACHE = 0x01, 98195534Sscottl ADA_CCB_BUFFER_IO = 0x03, 99195534Sscottl ADA_CCB_WAITING = 0x04, 100195534Sscottl ADA_CCB_DUMP = 0x05, 101201139Smav ADA_CCB_TRIM = 0x06, 102195534Sscottl ADA_CCB_TYPE_MASK = 0x0F, 103195534Sscottl} ada_ccb_state; 104195534Sscottl 105195534Sscottl/* Offsets into our private area for storing information */ 106195534Sscottl#define ccb_state ppriv_field0 107195534Sscottl#define ccb_bp ppriv_ptr1 108195534Sscottl 109195534Sscottlstruct disk_params { 110195534Sscottl u_int8_t heads; 111198897Smav u_int8_t secs_per_track; 112195534Sscottl u_int32_t cylinders; 113198897Smav u_int32_t secsize; /* Number of bytes/logical sector */ 114198897Smav u_int64_t sectors; /* Total number sectors */ 115195534Sscottl}; 116195534Sscottl 117222643Smav#define TRIM_MAX_BLOCKS 8 118222628Smav#define TRIM_MAX_RANGES (TRIM_MAX_BLOCKS * 64) 119222643Smav#define TRIM_MAX_BIOS (TRIM_MAX_RANGES * 4) 120201139Smavstruct trim_request { 121201139Smav uint8_t data[TRIM_MAX_RANGES * 8]; 122222628Smav struct bio *bps[TRIM_MAX_BIOS]; 123201139Smav}; 124201139Smav 125195534Sscottlstruct ada_softc { 126195534Sscottl struct bio_queue_head bio_queue; 127201139Smav struct bio_queue_head trim_queue; 128195534Sscottl ada_state state; 129195534Sscottl ada_flags flags; 130195534Sscottl ada_quirks quirks; 131195534Sscottl int ordered_tag_count; 132195534Sscottl int outstanding_cmds; 133201139Smav int trim_max_ranges; 134201139Smav int trim_running; 135220454Smav int write_cache; 136220454Smav#ifdef ADA_TEST_FAILURE 137220454Smav int force_read_error; 138220454Smav int force_write_error; 139220454Smav int periodic_read_error; 140220454Smav int periodic_read_count; 141220454Smav#endif 142195534Sscottl struct disk_params params; 143195534Sscottl struct disk *disk; 144195534Sscottl struct task sysctl_task; 145195534Sscottl struct sysctl_ctx_list sysctl_ctx; 146195534Sscottl struct sysctl_oid *sysctl_tree; 147195534Sscottl struct callout sendordered_c; 148201139Smav struct trim_request trim_req; 149195534Sscottl}; 150195534Sscottl 151195534Sscottlstruct ada_quirk_entry { 152195534Sscottl struct scsi_inquiry_pattern inq_pat; 153195534Sscottl ada_quirks quirks; 154195534Sscottl}; 155195534Sscottl 156199178Smavstatic struct ada_quirk_entry ada_quirk_table[] = 157199178Smav{ 158199178Smav { 159222520Smav /* Hitachi Advanced Format (4k) drives */ 160222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "Hitachi H??????????E3*", "*" }, 161222520Smav /*quirks*/ADA_Q_4K 162222520Smav }, 163222520Smav { 164222520Smav /* Samsung Advanced Format (4k) drives */ 165222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "SAMSUNG HD204UI*", "*" }, 166222520Smav /*quirks*/ADA_Q_4K 167222520Smav }, 168222520Smav { 169222520Smav /* Seagate Barracuda Green Advanced Format (4k) drives */ 170222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST????DL*", "*" }, 171222520Smav /*quirks*/ADA_Q_4K 172222520Smav }, 173222520Smav { 174222520Smav /* Seagate Momentus Advanced Format (4k) drives */ 175222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9500423AS*", "*" }, 176222520Smav /*quirks*/ADA_Q_4K 177222520Smav }, 178222520Smav { 179222520Smav /* Seagate Momentus Advanced Format (4k) drives */ 180222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9500424AS*", "*" }, 181222520Smav /*quirks*/ADA_Q_4K 182222520Smav }, 183222520Smav { 184222520Smav /* Seagate Momentus Advanced Format (4k) drives */ 185222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9750420AS*", "*" }, 186222520Smav /*quirks*/ADA_Q_4K 187222520Smav }, 188222520Smav { 189222520Smav /* Seagate Momentus Advanced Format (4k) drives */ 190222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9750422AS*", "*" }, 191222520Smav /*quirks*/ADA_Q_4K 192222520Smav }, 193222520Smav { 194222520Smav /* Seagate Momentus Thin Advanced Format (4k) drives */ 195222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST???LT*", "*" }, 196222520Smav /*quirks*/ADA_Q_4K 197222520Smav }, 198222520Smav { 199222520Smav /* WDC Caviar Green Advanced Format (4k) drives */ 200222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD????RS*", "*" }, 201222520Smav /*quirks*/ADA_Q_4K 202222520Smav }, 203222520Smav { 204222520Smav /* WDC Caviar Green Advanced Format (4k) drives */ 205222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD????RX*", "*" }, 206222520Smav /*quirks*/ADA_Q_4K 207222520Smav }, 208222520Smav { 209222520Smav /* WDC Caviar Green Advanced Format (4k) drives */ 210222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD??????RS*", "*" }, 211222520Smav /*quirks*/ADA_Q_4K 212222520Smav }, 213222520Smav { 214222520Smav /* WDC Caviar Green Advanced Format (4k) drives */ 215222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD??????RX*", "*" }, 216222520Smav /*quirks*/ADA_Q_4K 217222520Smav }, 218222520Smav { 219222520Smav /* WDC Scorpio Black Advanced Format (4k) drives */ 220222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD???PKT*", "*" }, 221222520Smav /*quirks*/ADA_Q_4K 222222520Smav }, 223222520Smav { 224222520Smav /* WDC Scorpio Black Advanced Format (4k) drives */ 225222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD?????PKT*", "*" }, 226222520Smav /*quirks*/ADA_Q_4K 227222520Smav }, 228222520Smav { 229222520Smav /* WDC Scorpio Blue Advanced Format (4k) drives */ 230222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD???PVT*", "*" }, 231222520Smav /*quirks*/ADA_Q_4K 232222520Smav }, 233222520Smav { 234222520Smav /* WDC Scorpio Blue Advanced Format (4k) drives */ 235222520Smav { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD?????PVT*", "*" }, 236222520Smav /*quirks*/ADA_Q_4K 237222520Smav }, 238222520Smav { 239199178Smav /* Default */ 240199178Smav { 241199178Smav T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED, 242199178Smav /*vendor*/"*", /*product*/"*", /*revision*/"*" 243199178Smav }, 244199178Smav /*quirks*/0 245199178Smav }, 246199178Smav}; 247195534Sscottl 248195534Sscottlstatic disk_strategy_t adastrategy; 249195534Sscottlstatic dumper_t adadump; 250195534Sscottlstatic periph_init_t adainit; 251195534Sscottlstatic void adaasync(void *callback_arg, u_int32_t code, 252195534Sscottl struct cam_path *path, void *arg); 253195534Sscottlstatic void adasysctlinit(void *context, int pending); 254195534Sscottlstatic periph_ctor_t adaregister; 255195534Sscottlstatic periph_dtor_t adacleanup; 256195534Sscottlstatic periph_start_t adastart; 257195534Sscottlstatic periph_oninv_t adaoninvalidate; 258195534Sscottlstatic void adadone(struct cam_periph *periph, 259195534Sscottl union ccb *done_ccb); 260195534Sscottlstatic int adaerror(union ccb *ccb, u_int32_t cam_flags, 261195534Sscottl u_int32_t sense_flags); 262198897Smavstatic void adagetparams(struct cam_periph *periph, 263195534Sscottl struct ccb_getdev *cgd); 264195534Sscottlstatic timeout_t adasendorderedtag; 265195534Sscottlstatic void adashutdown(void *arg, int howto); 266220650Smavstatic void adasuspend(void *arg); 267220650Smavstatic void adaresume(void *arg); 268195534Sscottl 269221071Smav#ifndef ADA_DEFAULT_LEGACY_ALIASES 270221071Smav#ifdef ATA_CAM 271221071Smav#define ADA_DEFAULT_LEGACY_ALIASES 1 272221071Smav#else 273221071Smav#define ADA_DEFAULT_LEGACY_ALIASES 0 274221071Smav#endif 275221071Smav#endif 276221071Smav 277195534Sscottl#ifndef ADA_DEFAULT_TIMEOUT 278195534Sscottl#define ADA_DEFAULT_TIMEOUT 30 /* Timeout in seconds */ 279195534Sscottl#endif 280195534Sscottl 281195534Sscottl#ifndef ADA_DEFAULT_RETRY 282195534Sscottl#define ADA_DEFAULT_RETRY 4 283195534Sscottl#endif 284195534Sscottl 285195534Sscottl#ifndef ADA_DEFAULT_SEND_ORDERED 286195534Sscottl#define ADA_DEFAULT_SEND_ORDERED 1 287195534Sscottl#endif 288195534Sscottl 289214279Sbrucec#ifndef ADA_DEFAULT_SPINDOWN_SHUTDOWN 290214279Sbrucec#define ADA_DEFAULT_SPINDOWN_SHUTDOWN 1 291214279Sbrucec#endif 292214279Sbrucec 293220650Smav#ifndef ADA_DEFAULT_SPINDOWN_SUSPEND 294220650Smav#define ADA_DEFAULT_SPINDOWN_SUSPEND 1 295220650Smav#endif 296220650Smav 297220412Smav#ifndef ADA_DEFAULT_WRITE_CACHE 298220412Smav#define ADA_DEFAULT_WRITE_CACHE 1 299220412Smav#endif 300220412Smav 301208349Smarius/* 302208349Smarius * Most platforms map firmware geometry to actual, but some don't. If 303208349Smarius * not overridden, default to nothing. 304208349Smarius */ 305208349Smarius#ifndef ata_disk_firmware_geom_adjust 306208349Smarius#define ata_disk_firmware_geom_adjust(disk) 307208349Smarius#endif 308195534Sscottl 309221071Smavstatic int ada_legacy_aliases = ADA_DEFAULT_LEGACY_ALIASES; 310195534Sscottlstatic int ada_retry_count = ADA_DEFAULT_RETRY; 311195534Sscottlstatic int ada_default_timeout = ADA_DEFAULT_TIMEOUT; 312195534Sscottlstatic int ada_send_ordered = ADA_DEFAULT_SEND_ORDERED; 313214279Sbrucecstatic int ada_spindown_shutdown = ADA_DEFAULT_SPINDOWN_SHUTDOWN; 314220650Smavstatic int ada_spindown_suspend = ADA_DEFAULT_SPINDOWN_SUSPEND; 315220412Smavstatic int ada_write_cache = ADA_DEFAULT_WRITE_CACHE; 316195534Sscottl 317195534SscottlSYSCTL_NODE(_kern_cam, OID_AUTO, ada, CTLFLAG_RD, 0, 318195534Sscottl "CAM Direct Access Disk driver"); 319221071SmavSYSCTL_INT(_kern_cam_ada, OID_AUTO, legacy_aliases, CTLFLAG_RW, 320221071Smav &ada_legacy_aliases, 0, "Create legacy-like device aliases"); 321221071SmavTUNABLE_INT("kern.cam.ada.legacy_aliases", &ada_legacy_aliases); 322195534SscottlSYSCTL_INT(_kern_cam_ada, OID_AUTO, retry_count, CTLFLAG_RW, 323195534Sscottl &ada_retry_count, 0, "Normal I/O retry count"); 324195534SscottlTUNABLE_INT("kern.cam.ada.retry_count", &ada_retry_count); 325195534SscottlSYSCTL_INT(_kern_cam_ada, OID_AUTO, default_timeout, CTLFLAG_RW, 326195534Sscottl &ada_default_timeout, 0, "Normal I/O timeout (in seconds)"); 327195534SscottlTUNABLE_INT("kern.cam.ada.default_timeout", &ada_default_timeout); 328195534SscottlSYSCTL_INT(_kern_cam_ada, OID_AUTO, ada_send_ordered, CTLFLAG_RW, 329195534Sscottl &ada_send_ordered, 0, "Send Ordered Tags"); 330195534SscottlTUNABLE_INT("kern.cam.ada.ada_send_ordered", &ada_send_ordered); 331214279SbrucecSYSCTL_INT(_kern_cam_ada, OID_AUTO, spindown_shutdown, CTLFLAG_RW, 332214279Sbrucec &ada_spindown_shutdown, 0, "Spin down upon shutdown"); 333214279SbrucecTUNABLE_INT("kern.cam.ada.spindown_shutdown", &ada_spindown_shutdown); 334220650SmavSYSCTL_INT(_kern_cam_ada, OID_AUTO, spindown_suspend, CTLFLAG_RW, 335220650Smav &ada_spindown_suspend, 0, "Spin down upon suspend"); 336220650SmavTUNABLE_INT("kern.cam.ada.spindown_suspend", &ada_spindown_suspend); 337220412SmavSYSCTL_INT(_kern_cam_ada, OID_AUTO, write_cache, CTLFLAG_RW, 338220412Smav &ada_write_cache, 0, "Enable disk write cache"); 339220412SmavTUNABLE_INT("kern.cam.ada.write_cache", &ada_write_cache); 340195534Sscottl 341195534Sscottl/* 342195534Sscottl * ADA_ORDEREDTAG_INTERVAL determines how often, relative 343195534Sscottl * to the default timeout, we check to see whether an ordered 344195534Sscottl * tagged transaction is appropriate to prevent simple tag 345195534Sscottl * starvation. Since we'd like to ensure that there is at least 346195534Sscottl * 1/2 of the timeout length left for a starved transaction to 347195534Sscottl * complete after we've sent an ordered tag, we must poll at least 348195534Sscottl * four times in every timeout period. This takes care of the worst 349195534Sscottl * case where a starved transaction starts during an interval that 350195534Sscottl * meets the requirement "don't send an ordered tag" test so it takes 351195534Sscottl * us two intervals to determine that a tag must be sent. 352195534Sscottl */ 353195534Sscottl#ifndef ADA_ORDEREDTAG_INTERVAL 354195534Sscottl#define ADA_ORDEREDTAG_INTERVAL 4 355195534Sscottl#endif 356195534Sscottl 357195534Sscottlstatic struct periph_driver adadriver = 358195534Sscottl{ 359195534Sscottl adainit, "ada", 360195534Sscottl TAILQ_HEAD_INITIALIZER(adadriver.units), /* generation */ 0 361195534Sscottl}; 362195534Sscottl 363195534SscottlPERIPHDRIVER_DECLARE(ada, adadriver); 364195534Sscottl 365195534SscottlMALLOC_DEFINE(M_ATADA, "ata_da", "ata_da buffers"); 366195534Sscottl 367195534Sscottlstatic int 368195534Sscottladaopen(struct disk *dp) 369195534Sscottl{ 370195534Sscottl struct cam_periph *periph; 371195534Sscottl struct ada_softc *softc; 372195534Sscottl int error; 373195534Sscottl 374195534Sscottl periph = (struct cam_periph *)dp->d_drv1; 375195534Sscottl if (periph == NULL) { 376195534Sscottl return (ENXIO); 377195534Sscottl } 378195534Sscottl 379195534Sscottl if (cam_periph_acquire(periph) != CAM_REQ_CMP) { 380195534Sscottl return(ENXIO); 381195534Sscottl } 382195534Sscottl 383195534Sscottl cam_periph_lock(periph); 384195534Sscottl if ((error = cam_periph_hold(periph, PRIBIO|PCATCH)) != 0) { 385195534Sscottl cam_periph_unlock(periph); 386195534Sscottl cam_periph_release(periph); 387195534Sscottl return (error); 388195534Sscottl } 389195534Sscottl 390195534Sscottl softc = (struct ada_softc *)periph->softc; 391195534Sscottl softc->flags |= ADA_FLAG_OPEN; 392195534Sscottl 393195534Sscottl CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, 394195534Sscottl ("adaopen: disk=%s%d (unit %d)\n", dp->d_name, dp->d_unit, 395220778Smav periph->unit_number)); 396195534Sscottl 397195534Sscottl if ((softc->flags & ADA_FLAG_PACK_INVALID) != 0) { 398195534Sscottl /* Invalidate our pack information. */ 399195534Sscottl softc->flags &= ~ADA_FLAG_PACK_INVALID; 400195534Sscottl } 401195534Sscottl 402195534Sscottl cam_periph_unhold(periph); 403195534Sscottl cam_periph_unlock(periph); 404195534Sscottl return (0); 405195534Sscottl} 406195534Sscottl 407195534Sscottlstatic int 408195534Sscottladaclose(struct disk *dp) 409195534Sscottl{ 410195534Sscottl struct cam_periph *periph; 411195534Sscottl struct ada_softc *softc; 412195534Sscottl union ccb *ccb; 413195534Sscottl int error; 414195534Sscottl 415195534Sscottl periph = (struct cam_periph *)dp->d_drv1; 416195534Sscottl if (periph == NULL) 417195534Sscottl return (ENXIO); 418195534Sscottl 419195534Sscottl cam_periph_lock(periph); 420195534Sscottl if ((error = cam_periph_hold(periph, PRIBIO)) != 0) { 421195534Sscottl cam_periph_unlock(periph); 422195534Sscottl cam_periph_release(periph); 423195534Sscottl return (error); 424195534Sscottl } 425195534Sscottl 426195534Sscottl softc = (struct ada_softc *)periph->softc; 427195534Sscottl /* We only sync the cache if the drive is capable of it. */ 428224283Smav if ((softc->flags & ADA_FLAG_CAN_FLUSHCACHE) != 0 && 429224283Smav (softc->flags & ADA_FLAG_PACK_INVALID) == 0) { 430195534Sscottl 431198382Smav ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 432195534Sscottl cam_fill_ataio(&ccb->ataio, 433195534Sscottl 1, 434195534Sscottl adadone, 435195534Sscottl CAM_DIR_NONE, 436195534Sscottl 0, 437195534Sscottl NULL, 438195534Sscottl 0, 439195534Sscottl ada_default_timeout*1000); 440195534Sscottl 441195534Sscottl if (softc->flags & ADA_FLAG_CAN_48BIT) 442195534Sscottl ata_48bit_cmd(&ccb->ataio, ATA_FLUSHCACHE48, 0, 0, 0); 443195534Sscottl else 444196659Smav ata_28bit_cmd(&ccb->ataio, ATA_FLUSHCACHE, 0, 0, 0); 445195748Smav cam_periph_runccb(ccb, /*error_routine*/NULL, /*cam_flags*/0, 446198328Smav /*sense_flags*/0, softc->disk->d_devstat); 447195534Sscottl 448195534Sscottl if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) 449195534Sscottl xpt_print(periph->path, "Synchronize cache failed\n"); 450195534Sscottl 451195534Sscottl if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 452195534Sscottl cam_release_devq(ccb->ccb_h.path, 453195534Sscottl /*relsim_flags*/0, 454195534Sscottl /*reduction*/0, 455195534Sscottl /*timeout*/0, 456195534Sscottl /*getcount_only*/0); 457195534Sscottl xpt_release_ccb(ccb); 458195534Sscottl } 459195534Sscottl 460195534Sscottl softc->flags &= ~ADA_FLAG_OPEN; 461195534Sscottl cam_periph_unhold(periph); 462195534Sscottl cam_periph_unlock(periph); 463195534Sscottl cam_periph_release(periph); 464195534Sscottl return (0); 465195534Sscottl} 466195534Sscottl 467201139Smavstatic void 468201139Smavadaschedule(struct cam_periph *periph) 469201139Smav{ 470201139Smav struct ada_softc *softc = (struct ada_softc *)periph->softc; 471201139Smav 472201139Smav if (bioq_first(&softc->bio_queue) || 473201139Smav (!softc->trim_running && bioq_first(&softc->trim_queue))) { 474201139Smav /* Have more work to do, so ensure we stay scheduled */ 475201139Smav xpt_schedule(periph, CAM_PRIORITY_NORMAL); 476201139Smav } 477201139Smav} 478201139Smav 479195534Sscottl/* 480195534Sscottl * Actually translate the requested transfer into one the physical driver 481195534Sscottl * can understand. The transfer is described by a buf and will include 482195534Sscottl * only one physical transfer. 483195534Sscottl */ 484195534Sscottlstatic void 485195534Sscottladastrategy(struct bio *bp) 486195534Sscottl{ 487195534Sscottl struct cam_periph *periph; 488195534Sscottl struct ada_softc *softc; 489195534Sscottl 490195534Sscottl periph = (struct cam_periph *)bp->bio_disk->d_drv1; 491195534Sscottl if (periph == NULL) { 492195534Sscottl biofinish(bp, NULL, ENXIO); 493195534Sscottl return; 494195534Sscottl } 495195534Sscottl softc = (struct ada_softc *)periph->softc; 496195534Sscottl 497195534Sscottl cam_periph_lock(periph); 498195534Sscottl 499195534Sscottl /* 500195534Sscottl * If the device has been made invalid, error out 501195534Sscottl */ 502195534Sscottl if ((softc->flags & ADA_FLAG_PACK_INVALID)) { 503195534Sscottl cam_periph_unlock(periph); 504195534Sscottl biofinish(bp, NULL, ENXIO); 505195534Sscottl return; 506195534Sscottl } 507195534Sscottl 508195534Sscottl /* 509195534Sscottl * Place it in the queue of disk activities for this disk 510195534Sscottl */ 511201139Smav if (bp->bio_cmd == BIO_DELETE && 512201139Smav (softc->flags & ADA_FLAG_CAN_TRIM)) 513201139Smav bioq_disksort(&softc->trim_queue, bp); 514201139Smav else 515201139Smav bioq_disksort(&softc->bio_queue, bp); 516195534Sscottl 517195534Sscottl /* 518195534Sscottl * Schedule ourselves for performing the work. 519195534Sscottl */ 520201139Smav adaschedule(periph); 521195534Sscottl cam_periph_unlock(periph); 522195534Sscottl 523195534Sscottl return; 524195534Sscottl} 525195534Sscottl 526195534Sscottlstatic int 527195534Sscottladadump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t length) 528195534Sscottl{ 529195534Sscottl struct cam_periph *periph; 530195534Sscottl struct ada_softc *softc; 531195534Sscottl u_int secsize; 532195534Sscottl union ccb ccb; 533195534Sscottl struct disk *dp; 534195534Sscottl uint64_t lba; 535195534Sscottl uint16_t count; 536195534Sscottl 537195534Sscottl dp = arg; 538195534Sscottl periph = dp->d_drv1; 539195534Sscottl if (periph == NULL) 540195534Sscottl return (ENXIO); 541195534Sscottl softc = (struct ada_softc *)periph->softc; 542195534Sscottl cam_periph_lock(periph); 543195534Sscottl secsize = softc->params.secsize; 544195534Sscottl lba = offset / secsize; 545195534Sscottl count = length / secsize; 546195534Sscottl 547195534Sscottl if ((softc->flags & ADA_FLAG_PACK_INVALID) != 0) { 548195534Sscottl cam_periph_unlock(periph); 549195534Sscottl return (ENXIO); 550195534Sscottl } 551195534Sscottl 552195534Sscottl if (length > 0) { 553198382Smav xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 554195534Sscottl ccb.ccb_h.ccb_state = ADA_CCB_DUMP; 555195534Sscottl cam_fill_ataio(&ccb.ataio, 556195534Sscottl 0, 557195534Sscottl adadone, 558195534Sscottl CAM_DIR_OUT, 559195534Sscottl 0, 560195534Sscottl (u_int8_t *) virtual, 561195534Sscottl length, 562195534Sscottl ada_default_timeout*1000); 563195534Sscottl if ((softc->flags & ADA_FLAG_CAN_48BIT) && 564195534Sscottl (lba + count >= ATA_MAX_28BIT_LBA || 565195534Sscottl count >= 256)) { 566195534Sscottl ata_48bit_cmd(&ccb.ataio, ATA_WRITE_DMA48, 567195534Sscottl 0, lba, count); 568195534Sscottl } else { 569196659Smav ata_28bit_cmd(&ccb.ataio, ATA_WRITE_DMA, 570195534Sscottl 0, lba, count); 571195534Sscottl } 572195534Sscottl xpt_polled_action(&ccb); 573195534Sscottl 574195534Sscottl if ((ccb.ataio.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 575195534Sscottl printf("Aborting dump due to I/O error.\n"); 576195534Sscottl cam_periph_unlock(periph); 577195534Sscottl return(EIO); 578195534Sscottl } 579195534Sscottl cam_periph_unlock(periph); 580195534Sscottl return(0); 581195534Sscottl } 582195534Sscottl 583195534Sscottl if (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) { 584198382Smav xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 585195534Sscottl 586195534Sscottl ccb.ccb_h.ccb_state = ADA_CCB_DUMP; 587195534Sscottl cam_fill_ataio(&ccb.ataio, 588195534Sscottl 1, 589195534Sscottl adadone, 590195534Sscottl CAM_DIR_NONE, 591195534Sscottl 0, 592195534Sscottl NULL, 593195534Sscottl 0, 594195534Sscottl ada_default_timeout*1000); 595195534Sscottl 596195534Sscottl if (softc->flags & ADA_FLAG_CAN_48BIT) 597195534Sscottl ata_48bit_cmd(&ccb.ataio, ATA_FLUSHCACHE48, 0, 0, 0); 598195534Sscottl else 599196659Smav ata_28bit_cmd(&ccb.ataio, ATA_FLUSHCACHE, 0, 0, 0); 600195534Sscottl xpt_polled_action(&ccb); 601195534Sscottl 602195534Sscottl if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) 603195534Sscottl xpt_print(periph->path, "Synchronize cache failed\n"); 604195534Sscottl 605195534Sscottl if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0) 606195534Sscottl cam_release_devq(ccb.ccb_h.path, 607195534Sscottl /*relsim_flags*/0, 608195534Sscottl /*reduction*/0, 609195534Sscottl /*timeout*/0, 610195534Sscottl /*getcount_only*/0); 611195534Sscottl } 612195534Sscottl cam_periph_unlock(periph); 613195534Sscottl return (0); 614195534Sscottl} 615195534Sscottl 616195534Sscottlstatic void 617195534Sscottladainit(void) 618195534Sscottl{ 619195534Sscottl cam_status status; 620195534Sscottl 621195534Sscottl /* 622195534Sscottl * Install a global async callback. This callback will 623195534Sscottl * receive async callbacks like "new device found". 624195534Sscottl */ 625195534Sscottl status = xpt_register_async(AC_FOUND_DEVICE, adaasync, NULL, NULL); 626195534Sscottl 627195534Sscottl if (status != CAM_REQ_CMP) { 628195534Sscottl printf("ada: Failed to attach master async callback " 629195534Sscottl "due to status 0x%x!\n", status); 630195534Sscottl } else if (ada_send_ordered) { 631195534Sscottl 632220650Smav /* Register our event handlers */ 633220650Smav if ((EVENTHANDLER_REGISTER(power_suspend, adasuspend, 634220650Smav NULL, EVENTHANDLER_PRI_LAST)) == NULL) 635220650Smav printf("adainit: power event registration failed!\n"); 636220650Smav if ((EVENTHANDLER_REGISTER(power_resume, adaresume, 637220650Smav NULL, EVENTHANDLER_PRI_LAST)) == NULL) 638220650Smav printf("adainit: power event registration failed!\n"); 639220650Smav if ((EVENTHANDLER_REGISTER(shutdown_post_sync, adashutdown, 640195534Sscottl NULL, SHUTDOWN_PRI_DEFAULT)) == NULL) 641195534Sscottl printf("adainit: shutdown event registration failed!\n"); 642195534Sscottl } 643195534Sscottl} 644195534Sscottl 645195534Sscottlstatic void 646195534Sscottladaoninvalidate(struct cam_periph *periph) 647195534Sscottl{ 648195534Sscottl struct ada_softc *softc; 649195534Sscottl 650195534Sscottl softc = (struct ada_softc *)periph->softc; 651195534Sscottl 652195534Sscottl /* 653195534Sscottl * De-register any async callbacks. 654195534Sscottl */ 655195534Sscottl xpt_register_async(0, adaasync, periph, periph->path); 656195534Sscottl 657195534Sscottl softc->flags |= ADA_FLAG_PACK_INVALID; 658195534Sscottl 659195534Sscottl /* 660195534Sscottl * Return all queued I/O with ENXIO. 661195534Sscottl * XXX Handle any transactions queued to the card 662195534Sscottl * with XPT_ABORT_CCB. 663195534Sscottl */ 664195534Sscottl bioq_flush(&softc->bio_queue, NULL, ENXIO); 665201139Smav bioq_flush(&softc->trim_queue, NULL, ENXIO); 666195534Sscottl 667195534Sscottl disk_gone(softc->disk); 668195534Sscottl xpt_print(periph->path, "lost device\n"); 669195534Sscottl} 670195534Sscottl 671195534Sscottlstatic void 672195534Sscottladacleanup(struct cam_periph *periph) 673195534Sscottl{ 674195534Sscottl struct ada_softc *softc; 675195534Sscottl 676195534Sscottl softc = (struct ada_softc *)periph->softc; 677195534Sscottl 678195534Sscottl xpt_print(periph->path, "removing device entry\n"); 679195534Sscottl cam_periph_unlock(periph); 680195534Sscottl 681195534Sscottl /* 682195534Sscottl * If we can't free the sysctl tree, oh well... 683195534Sscottl */ 684195534Sscottl if ((softc->flags & ADA_FLAG_SCTX_INIT) != 0 685195534Sscottl && sysctl_ctx_free(&softc->sysctl_ctx) != 0) { 686195534Sscottl xpt_print(periph->path, "can't remove sysctl context\n"); 687195534Sscottl } 688195534Sscottl 689195534Sscottl disk_destroy(softc->disk); 690195534Sscottl callout_drain(&softc->sendordered_c); 691195534Sscottl free(softc, M_DEVBUF); 692195534Sscottl cam_periph_lock(periph); 693195534Sscottl} 694195534Sscottl 695195534Sscottlstatic void 696195534Sscottladaasync(void *callback_arg, u_int32_t code, 697195534Sscottl struct cam_path *path, void *arg) 698195534Sscottl{ 699195534Sscottl struct cam_periph *periph; 700220412Smav struct ada_softc *softc; 701195534Sscottl 702195534Sscottl periph = (struct cam_periph *)callback_arg; 703195534Sscottl switch (code) { 704195534Sscottl case AC_FOUND_DEVICE: 705195534Sscottl { 706195534Sscottl struct ccb_getdev *cgd; 707195534Sscottl cam_status status; 708195534Sscottl 709195534Sscottl cgd = (struct ccb_getdev *)arg; 710195534Sscottl if (cgd == NULL) 711195534Sscottl break; 712195534Sscottl 713195534Sscottl if (cgd->protocol != PROTO_ATA) 714195534Sscottl break; 715195534Sscottl 716195534Sscottl /* 717195534Sscottl * Allocate a peripheral instance for 718195534Sscottl * this device and start the probe 719195534Sscottl * process. 720195534Sscottl */ 721195534Sscottl status = cam_periph_alloc(adaregister, adaoninvalidate, 722195534Sscottl adacleanup, adastart, 723195534Sscottl "ada", CAM_PERIPH_BIO, 724195534Sscottl cgd->ccb_h.path, adaasync, 725195534Sscottl AC_FOUND_DEVICE, cgd); 726195534Sscottl 727195534Sscottl if (status != CAM_REQ_CMP 728195534Sscottl && status != CAM_REQ_INPROG) 729195534Sscottl printf("adaasync: Unable to attach to new device " 730195534Sscottl "due to status 0x%x\n", status); 731195534Sscottl break; 732195534Sscottl } 733220412Smav case AC_SENT_BDR: 734220412Smav case AC_BUS_RESET: 735220412Smav { 736220412Smav struct ccb_getdev cgd; 737220412Smav 738220412Smav softc = (struct ada_softc *)periph->softc; 739220412Smav cam_periph_async(periph, code, path, arg); 740220454Smav if (ada_write_cache < 0 && softc->write_cache < 0) 741220412Smav break; 742220412Smav if (softc->state != ADA_STATE_NORMAL) 743220412Smav break; 744220454Smav xpt_setup_ccb(&cgd.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 745220412Smav cgd.ccb_h.func_code = XPT_GDEV_TYPE; 746220412Smav xpt_action((union ccb *)&cgd); 747220412Smav if ((cgd.ident_data.support.command1 & ATA_SUPPORT_WRITECACHE) == 0) 748220412Smav break; 749220412Smav softc->state = ADA_STATE_WCACHE; 750220412Smav cam_periph_acquire(periph); 751220412Smav cam_freeze_devq_arg(periph->path, 752220412Smav RELSIM_RELEASE_RUNLEVEL, CAM_RL_DEV + 1); 753220412Smav xpt_schedule(periph, CAM_PRIORITY_DEV); 754220412Smav } 755195534Sscottl default: 756195534Sscottl cam_periph_async(periph, code, path, arg); 757195534Sscottl break; 758195534Sscottl } 759195534Sscottl} 760195534Sscottl 761195534Sscottlstatic void 762195534Sscottladasysctlinit(void *context, int pending) 763195534Sscottl{ 764195534Sscottl struct cam_periph *periph; 765195534Sscottl struct ada_softc *softc; 766195534Sscottl char tmpstr[80], tmpstr2[80]; 767195534Sscottl 768195534Sscottl periph = (struct cam_periph *)context; 769220454Smav 770220454Smav /* periph was held for us when this task was enqueued */ 771220454Smav if (periph->flags & CAM_PERIPH_INVALID) { 772220454Smav cam_periph_release(periph); 773195534Sscottl return; 774220454Smav } 775195534Sscottl 776195534Sscottl softc = (struct ada_softc *)periph->softc; 777195534Sscottl snprintf(tmpstr, sizeof(tmpstr), "CAM ADA unit %d", periph->unit_number); 778195534Sscottl snprintf(tmpstr2, sizeof(tmpstr2), "%d", periph->unit_number); 779195534Sscottl 780195534Sscottl sysctl_ctx_init(&softc->sysctl_ctx); 781195534Sscottl softc->flags |= ADA_FLAG_SCTX_INIT; 782195534Sscottl softc->sysctl_tree = SYSCTL_ADD_NODE(&softc->sysctl_ctx, 783195534Sscottl SYSCTL_STATIC_CHILDREN(_kern_cam_ada), OID_AUTO, tmpstr2, 784195534Sscottl CTLFLAG_RD, 0, tmpstr); 785195534Sscottl if (softc->sysctl_tree == NULL) { 786195534Sscottl printf("adasysctlinit: unable to allocate sysctl tree\n"); 787195534Sscottl cam_periph_release(periph); 788195534Sscottl return; 789195534Sscottl } 790195534Sscottl 791220454Smav SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 792220454Smav OID_AUTO, "write_cache", CTLFLAG_RW | CTLFLAG_MPSAFE, 793220454Smav &softc->write_cache, 0, "Enable disk write cache."); 794220454Smav#ifdef ADA_TEST_FAILURE 795220454Smav /* 796220454Smav * Add a 'door bell' sysctl which allows one to set it from userland 797220454Smav * and cause something bad to happen. For the moment, we only allow 798220454Smav * whacking the next read or write. 799220454Smav */ 800220454Smav SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 801220454Smav OID_AUTO, "force_read_error", CTLFLAG_RW | CTLFLAG_MPSAFE, 802220454Smav &softc->force_read_error, 0, 803220454Smav "Force a read error for the next N reads."); 804220454Smav SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 805220454Smav OID_AUTO, "force_write_error", CTLFLAG_RW | CTLFLAG_MPSAFE, 806220454Smav &softc->force_write_error, 0, 807220454Smav "Force a write error for the next N writes."); 808220454Smav SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 809220454Smav OID_AUTO, "periodic_read_error", CTLFLAG_RW | CTLFLAG_MPSAFE, 810220454Smav &softc->periodic_read_error, 0, 811220454Smav "Force a read error every N reads (don't set too low)."); 812220454Smav#endif 813195534Sscottl cam_periph_release(periph); 814195534Sscottl} 815195534Sscottl 816223089Sgibbsstatic int 817223089Sgibbsadagetattr(struct bio *bp) 818223089Sgibbs{ 819223089Sgibbs int ret = -1; 820223089Sgibbs struct cam_periph *periph; 821223089Sgibbs 822223277Skib if (bp->bio_disk == NULL || bp->bio_disk->d_drv1 == NULL) 823223089Sgibbs return ENXIO; 824223089Sgibbs periph = (struct cam_periph *)bp->bio_disk->d_drv1; 825223089Sgibbs if (periph->path == NULL) 826223089Sgibbs return ENXIO; 827223089Sgibbs 828223089Sgibbs ret = xpt_getattr(bp->bio_data, bp->bio_length, bp->bio_attribute, 829223089Sgibbs periph->path); 830223089Sgibbs if (ret == 0) 831223089Sgibbs bp->bio_completed = bp->bio_length; 832223089Sgibbs return ret; 833223089Sgibbs} 834223089Sgibbs 835195534Sscottlstatic cam_status 836195534Sscottladaregister(struct cam_periph *periph, void *arg) 837195534Sscottl{ 838195534Sscottl struct ada_softc *softc; 839195534Sscottl struct ccb_pathinq cpi; 840195534Sscottl struct ccb_getdev *cgd; 841221071Smav char announce_buf[80], buf1[32]; 842195534Sscottl struct disk_params *dp; 843195534Sscottl caddr_t match; 844195534Sscottl u_int maxio; 845222520Smav int legacy_id, quirks; 846195534Sscottl 847195534Sscottl cgd = (struct ccb_getdev *)arg; 848195534Sscottl if (periph == NULL) { 849195534Sscottl printf("adaregister: periph was NULL!!\n"); 850195534Sscottl return(CAM_REQ_CMP_ERR); 851195534Sscottl } 852195534Sscottl 853195534Sscottl if (cgd == NULL) { 854195534Sscottl printf("adaregister: no getdev CCB, can't register device\n"); 855195534Sscottl return(CAM_REQ_CMP_ERR); 856195534Sscottl } 857195534Sscottl 858195534Sscottl softc = (struct ada_softc *)malloc(sizeof(*softc), M_DEVBUF, 859195534Sscottl M_NOWAIT|M_ZERO); 860195534Sscottl 861195534Sscottl if (softc == NULL) { 862195534Sscottl printf("adaregister: Unable to probe new device. " 863198328Smav "Unable to allocate softc\n"); 864195534Sscottl return(CAM_REQ_CMP_ERR); 865195534Sscottl } 866195534Sscottl 867195534Sscottl bioq_init(&softc->bio_queue); 868201139Smav bioq_init(&softc->trim_queue); 869195534Sscottl 870220886Smav if (cgd->ident_data.capabilities1 & ATA_SUPPORT_DMA && 871220886Smav (cgd->inq_flags & SID_DMA)) 872198328Smav softc->flags |= ADA_FLAG_CAN_DMA; 873195534Sscottl if (cgd->ident_data.support.command2 & ATA_SUPPORT_ADDRESS48) 874195534Sscottl softc->flags |= ADA_FLAG_CAN_48BIT; 875195534Sscottl if (cgd->ident_data.support.command2 & ATA_SUPPORT_FLUSHCACHE) 876195534Sscottl softc->flags |= ADA_FLAG_CAN_FLUSHCACHE; 877214279Sbrucec if (cgd->ident_data.support.command1 & ATA_SUPPORT_POWERMGT) 878214279Sbrucec softc->flags |= ADA_FLAG_CAN_POWERMGT; 879195534Sscottl if (cgd->ident_data.satacapabilities & ATA_SUPPORT_NCQ && 880220886Smav (cgd->inq_flags & SID_DMA) && (cgd->inq_flags & SID_CmdQue)) 881195534Sscottl softc->flags |= ADA_FLAG_CAN_NCQ; 882201139Smav if (cgd->ident_data.support_dsm & ATA_SUPPORT_DSM_TRIM) { 883201139Smav softc->flags |= ADA_FLAG_CAN_TRIM; 884201139Smav softc->trim_max_ranges = TRIM_MAX_RANGES; 885201139Smav if (cgd->ident_data.max_dsm_blocks != 0) { 886201139Smav softc->trim_max_ranges = 887201139Smav min(cgd->ident_data.max_dsm_blocks * 64, 888201139Smav softc->trim_max_ranges); 889201139Smav } 890201139Smav } 891201139Smav if (cgd->ident_data.support.command2 & ATA_SUPPORT_CFA) 892201139Smav softc->flags |= ADA_FLAG_CAN_CFA; 893195534Sscottl 894195534Sscottl periph->softc = softc; 895195534Sscottl 896195534Sscottl /* 897195534Sscottl * See if this device has any quirks. 898195534Sscottl */ 899199178Smav match = cam_quirkmatch((caddr_t)&cgd->ident_data, 900199178Smav (caddr_t)ada_quirk_table, 901199178Smav sizeof(ada_quirk_table)/sizeof(*ada_quirk_table), 902199178Smav sizeof(*ada_quirk_table), ata_identify_match); 903195534Sscottl if (match != NULL) 904195534Sscottl softc->quirks = ((struct ada_quirk_entry *)match)->quirks; 905195534Sscottl else 906195534Sscottl softc->quirks = ADA_Q_NONE; 907195534Sscottl 908195534Sscottl bzero(&cpi, sizeof(cpi)); 909203108Smav xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NONE); 910195534Sscottl cpi.ccb_h.func_code = XPT_PATH_INQ; 911195534Sscottl xpt_action((union ccb *)&cpi); 912195534Sscottl 913195534Sscottl TASK_INIT(&softc->sysctl_task, 0, adasysctlinit, periph); 914195534Sscottl 915195534Sscottl /* 916195534Sscottl * Register this media as a disk 917195534Sscottl */ 918220618Smav (void)cam_periph_hold(periph, PRIBIO); 919195534Sscottl mtx_unlock(periph->sim->mtx); 920222520Smav snprintf(announce_buf, sizeof(announce_buf), 921222520Smav "kern.cam.ada.%d.quirks", periph->unit_number); 922222520Smav quirks = softc->quirks; 923222520Smav TUNABLE_INT_FETCH(announce_buf, &quirks); 924222520Smav softc->quirks = quirks; 925220618Smav softc->write_cache = -1; 926220618Smav snprintf(announce_buf, sizeof(announce_buf), 927220618Smav "kern.cam.ada.%d.write_cache", periph->unit_number); 928220618Smav TUNABLE_INT_FETCH(announce_buf, &softc->write_cache); 929198897Smav adagetparams(periph, cgd); 930195534Sscottl softc->disk = disk_alloc(); 931220644Smav softc->disk->d_devstat = devstat_new_entry(periph->periph_name, 932220644Smav periph->unit_number, softc->params.secsize, 933220644Smav DEVSTAT_ALL_SUPPORTED, 934220644Smav DEVSTAT_TYPE_DIRECT | 935220644Smav XPORT_DEVSTAT_TYPE(cpi.transport), 936220644Smav DEVSTAT_PRIORITY_DISK); 937195534Sscottl softc->disk->d_open = adaopen; 938195534Sscottl softc->disk->d_close = adaclose; 939195534Sscottl softc->disk->d_strategy = adastrategy; 940223089Sgibbs softc->disk->d_getattr = adagetattr; 941195534Sscottl softc->disk->d_dump = adadump; 942195534Sscottl softc->disk->d_name = "ada"; 943195534Sscottl softc->disk->d_drv1 = periph; 944195534Sscottl maxio = cpi.maxio; /* Honor max I/O size of SIM */ 945195534Sscottl if (maxio == 0) 946195534Sscottl maxio = DFLTPHYS; /* traditional default */ 947195534Sscottl else if (maxio > MAXPHYS) 948195534Sscottl maxio = MAXPHYS; /* for safety */ 949201139Smav if (softc->flags & ADA_FLAG_CAN_48BIT) 950198897Smav maxio = min(maxio, 65536 * softc->params.secsize); 951195534Sscottl else /* 28bit ATA command limit */ 952198897Smav maxio = min(maxio, 256 * softc->params.secsize); 953195534Sscottl softc->disk->d_maxsize = maxio; 954195534Sscottl softc->disk->d_unit = periph->unit_number; 955195534Sscottl softc->disk->d_flags = 0; 956195534Sscottl if (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) 957195534Sscottl softc->disk->d_flags |= DISKFLAG_CANFLUSHCACHE; 958201139Smav if ((softc->flags & ADA_FLAG_CAN_TRIM) || 959201139Smav ((softc->flags & ADA_FLAG_CAN_CFA) && 960201139Smav !(softc->flags & ADA_FLAG_CAN_48BIT))) 961201139Smav softc->disk->d_flags |= DISKFLAG_CANDELETE; 962219056Snwhitehorn strlcpy(softc->disk->d_descr, cgd->ident_data.model, 963219056Snwhitehorn MIN(sizeof(softc->disk->d_descr), sizeof(cgd->ident_data.model))); 964210471Smav softc->disk->d_hba_vendor = cpi.hba_vendor; 965210471Smav softc->disk->d_hba_device = cpi.hba_device; 966210471Smav softc->disk->d_hba_subvendor = cpi.hba_subvendor; 967210471Smav softc->disk->d_hba_subdevice = cpi.hba_subdevice; 968195534Sscottl 969195534Sscottl softc->disk->d_sectorsize = softc->params.secsize; 970198897Smav softc->disk->d_mediasize = (off_t)softc->params.sectors * 971198897Smav softc->params.secsize; 972200969Smav if (ata_physical_sector_size(&cgd->ident_data) != 973200969Smav softc->params.secsize) { 974200969Smav softc->disk->d_stripesize = 975200969Smav ata_physical_sector_size(&cgd->ident_data); 976200969Smav softc->disk->d_stripeoffset = (softc->disk->d_stripesize - 977200969Smav ata_logical_sector_offset(&cgd->ident_data)) % 978200969Smav softc->disk->d_stripesize; 979222520Smav } else if (softc->quirks & ADA_Q_4K) { 980222520Smav softc->disk->d_stripesize = 4096; 981222520Smav softc->disk->d_stripeoffset = 0; 982200969Smav } 983195534Sscottl softc->disk->d_fwsectors = softc->params.secs_per_track; 984195534Sscottl softc->disk->d_fwheads = softc->params.heads; 985208349Smarius ata_disk_firmware_geom_adjust(softc->disk); 986195534Sscottl 987221071Smav if (ada_legacy_aliases) { 988221071Smav#ifdef ATA_STATIC_ID 989221071Smav legacy_id = xpt_path_legacy_ata_id(periph->path); 990221071Smav#else 991221071Smav legacy_id = softc->disk->d_unit; 992221071Smav#endif 993221071Smav if (legacy_id >= 0) { 994221071Smav snprintf(announce_buf, sizeof(announce_buf), 995221071Smav "kern.devalias.%s%d", 996221071Smav softc->disk->d_name, softc->disk->d_unit); 997221071Smav snprintf(buf1, sizeof(buf1), 998221071Smav "ad%d", legacy_id); 999221071Smav setenv(announce_buf, buf1); 1000221071Smav } 1001221071Smav } else 1002221071Smav legacy_id = -1; 1003195534Sscottl disk_create(softc->disk, DISK_VERSION); 1004195534Sscottl mtx_lock(periph->sim->mtx); 1005220618Smav cam_periph_unhold(periph); 1006195534Sscottl 1007195534Sscottl dp = &softc->params; 1008195534Sscottl snprintf(announce_buf, sizeof(announce_buf), 1009195534Sscottl "%juMB (%ju %u byte sectors: %dH %dS/T %dC)", 1010195534Sscottl (uintmax_t)(((uintmax_t)dp->secsize * 1011195534Sscottl dp->sectors) / (1024*1024)), 1012195534Sscottl (uintmax_t)dp->sectors, 1013195534Sscottl dp->secsize, dp->heads, 1014195534Sscottl dp->secs_per_track, dp->cylinders); 1015195534Sscottl xpt_announce_periph(periph, announce_buf); 1016221071Smav if (legacy_id >= 0) 1017221071Smav printf("%s%d: Previously was known as ad%d\n", 1018221071Smav periph->periph_name, periph->unit_number, legacy_id); 1019220454Smav 1020195534Sscottl /* 1021220454Smav * Create our sysctl variables, now that we know 1022220454Smav * we have successfully attached. 1023220454Smav */ 1024220454Smav cam_periph_acquire(periph); 1025220454Smav taskqueue_enqueue(taskqueue_thread, &softc->sysctl_task); 1026220454Smav 1027220454Smav /* 1028195534Sscottl * Add async callbacks for bus reset and 1029195534Sscottl * bus device reset calls. I don't bother 1030195534Sscottl * checking if this fails as, in most cases, 1031195534Sscottl * the system will function just fine without 1032195534Sscottl * them and the only alternative would be to 1033195534Sscottl * not attach the device on failure. 1034195534Sscottl */ 1035220412Smav xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE, 1036195534Sscottl adaasync, periph, periph->path); 1037195534Sscottl 1038195534Sscottl /* 1039195534Sscottl * Schedule a periodic event to occasionally send an 1040195534Sscottl * ordered tag to a device. 1041195534Sscottl */ 1042195534Sscottl callout_init_mtx(&softc->sendordered_c, periph->sim->mtx, 0); 1043195534Sscottl callout_reset(&softc->sendordered_c, 1044195534Sscottl (ADA_DEFAULT_TIMEOUT * hz) / ADA_ORDEREDTAG_INTERVAL, 1045195534Sscottl adasendorderedtag, softc); 1046195534Sscottl 1047220454Smav if ((ada_write_cache >= 0 || softc->write_cache >= 0) && 1048220412Smav cgd->ident_data.support.command1 & ATA_SUPPORT_WRITECACHE) { 1049220412Smav softc->state = ADA_STATE_WCACHE; 1050220412Smav cam_periph_acquire(periph); 1051220412Smav cam_freeze_devq_arg(periph->path, 1052220412Smav RELSIM_RELEASE_RUNLEVEL, CAM_RL_DEV + 1); 1053220412Smav xpt_schedule(periph, CAM_PRIORITY_DEV); 1054220412Smav } else 1055220412Smav softc->state = ADA_STATE_NORMAL; 1056220412Smav 1057195534Sscottl return(CAM_REQ_CMP); 1058195534Sscottl} 1059195534Sscottl 1060195534Sscottlstatic void 1061195534Sscottladastart(struct cam_periph *periph, union ccb *start_ccb) 1062195534Sscottl{ 1063198328Smav struct ada_softc *softc = (struct ada_softc *)periph->softc; 1064198328Smav struct ccb_ataio *ataio = &start_ccb->ataio; 1065195534Sscottl 1066195534Sscottl switch (softc->state) { 1067195534Sscottl case ADA_STATE_NORMAL: 1068195534Sscottl { 1069195534Sscottl struct bio *bp; 1070201139Smav u_int8_t tag_code; 1071195534Sscottl 1072201139Smav /* Execute immediate CCB if waiting. */ 1073195534Sscottl if (periph->immediate_priority <= periph->pinfo.priority) { 1074195534Sscottl CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE, 1075195534Sscottl ("queuing for immediate ccb\n")); 1076195534Sscottl start_ccb->ccb_h.ccb_state = ADA_CCB_WAITING; 1077195534Sscottl SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, 1078195534Sscottl periph_links.sle); 1079195534Sscottl periph->immediate_priority = CAM_PRIORITY_NONE; 1080195534Sscottl wakeup(&periph->ccb_list); 1081201139Smav /* Have more work to do, so ensure we stay scheduled */ 1082201139Smav adaschedule(periph); 1083201139Smav break; 1084201139Smav } 1085201139Smav /* Run TRIM if not running yet. */ 1086201139Smav if (!softc->trim_running && 1087201139Smav (bp = bioq_first(&softc->trim_queue)) != 0) { 1088201139Smav struct trim_request *req = &softc->trim_req; 1089201139Smav struct bio *bp1; 1090222628Smav uint64_t lastlba = (uint64_t)-1; 1091222628Smav int bps = 0, c, lastcount = 0, off, ranges = 0; 1092201139Smav 1093201139Smav softc->trim_running = 1; 1094201139Smav bzero(req, sizeof(*req)); 1095201139Smav bp1 = bp; 1096201139Smav do { 1097201139Smav uint64_t lba = bp1->bio_pblkno; 1098201139Smav int count = bp1->bio_bcount / 1099201139Smav softc->params.secsize; 1100201139Smav 1101201139Smav bioq_remove(&softc->trim_queue, bp1); 1102222628Smav 1103222628Smav /* Try to extend the previous range. */ 1104222628Smav if (lba == lastlba) { 1105222628Smav c = min(count, 0xffff - lastcount); 1106222628Smav lastcount += c; 1107222628Smav off = (ranges - 1) * 8; 1108222628Smav req->data[off + 6] = lastcount & 0xff; 1109222628Smav req->data[off + 7] = 1110222628Smav (lastcount >> 8) & 0xff; 1111222628Smav count -= c; 1112222628Smav lba += c; 1113222628Smav } 1114222628Smav 1115201139Smav while (count > 0) { 1116222628Smav c = min(count, 0xffff); 1117222628Smav off = ranges * 8; 1118201139Smav req->data[off + 0] = lba & 0xff; 1119201139Smav req->data[off + 1] = (lba >> 8) & 0xff; 1120201139Smav req->data[off + 2] = (lba >> 16) & 0xff; 1121201139Smav req->data[off + 3] = (lba >> 24) & 0xff; 1122201139Smav req->data[off + 4] = (lba >> 32) & 0xff; 1123201139Smav req->data[off + 5] = (lba >> 40) & 0xff; 1124201139Smav req->data[off + 6] = c & 0xff; 1125201139Smav req->data[off + 7] = (c >> 8) & 0xff; 1126201139Smav lba += c; 1127201139Smav count -= c; 1128222628Smav lastcount = c; 1129201139Smav ranges++; 1130201139Smav } 1131222628Smav lastlba = lba; 1132201139Smav req->bps[bps++] = bp1; 1133201139Smav bp1 = bioq_first(&softc->trim_queue); 1134222628Smav if (bps >= TRIM_MAX_BIOS || 1135222628Smav bp1 == NULL || 1136201139Smav bp1->bio_bcount / softc->params.secsize > 1137201139Smav (softc->trim_max_ranges - ranges) * 0xffff) 1138201139Smav break; 1139201139Smav } while (1); 1140201139Smav cam_fill_ataio(ataio, 1141201139Smav ada_retry_count, 1142201139Smav adadone, 1143201139Smav CAM_DIR_OUT, 1144201139Smav 0, 1145201139Smav req->data, 1146201139Smav ((ranges + 63) / 64) * 512, 1147201139Smav ada_default_timeout * 1000); 1148201139Smav ata_48bit_cmd(ataio, ATA_DATA_SET_MANAGEMENT, 1149201139Smav ATA_DSM_TRIM, 0, (ranges + 63) / 64); 1150201139Smav start_ccb->ccb_h.ccb_state = ADA_CCB_TRIM; 1151201139Smav goto out; 1152201139Smav } 1153201139Smav /* Run regular command. */ 1154201139Smav bp = bioq_first(&softc->bio_queue); 1155201139Smav if (bp == NULL) { 1156195534Sscottl xpt_release_ccb(start_ccb); 1157201139Smav break; 1158201139Smav } 1159201139Smav bioq_remove(&softc->bio_queue, bp); 1160201139Smav 1161212160Sgibbs if ((bp->bio_flags & BIO_ORDERED) != 0 1162212160Sgibbs || (softc->flags & ADA_FLAG_NEED_OTAG) != 0) { 1163201139Smav softc->flags &= ~ADA_FLAG_NEED_OTAG; 1164201139Smav softc->ordered_tag_count++; 1165201139Smav tag_code = 0; 1166195534Sscottl } else { 1167201139Smav tag_code = 1; 1168201139Smav } 1169201139Smav switch (bp->bio_cmd) { 1170201139Smav case BIO_READ: 1171201139Smav case BIO_WRITE: 1172201139Smav { 1173201139Smav uint64_t lba = bp->bio_pblkno; 1174201139Smav uint16_t count = bp->bio_bcount / softc->params.secsize; 1175220454Smav#ifdef ADA_TEST_FAILURE 1176220454Smav int fail = 0; 1177195534Sscottl 1178220454Smav /* 1179220454Smav * Support the failure ioctls. If the command is a 1180220454Smav * read, and there are pending forced read errors, or 1181220454Smav * if a write and pending write errors, then fail this 1182220454Smav * operation with EIO. This is useful for testing 1183220454Smav * purposes. Also, support having every Nth read fail. 1184220454Smav * 1185220454Smav * This is a rather blunt tool. 1186220454Smav */ 1187220454Smav if (bp->bio_cmd == BIO_READ) { 1188220454Smav if (softc->force_read_error) { 1189220454Smav softc->force_read_error--; 1190220454Smav fail = 1; 1191220454Smav } 1192220454Smav if (softc->periodic_read_error > 0) { 1193220454Smav if (++softc->periodic_read_count >= 1194220454Smav softc->periodic_read_error) { 1195220454Smav softc->periodic_read_count = 0; 1196220454Smav fail = 1; 1197220454Smav } 1198220454Smav } 1199220454Smav } else { 1200220454Smav if (softc->force_write_error) { 1201220454Smav softc->force_write_error--; 1202220454Smav fail = 1; 1203220454Smav } 1204220454Smav } 1205220454Smav if (fail) { 1206220454Smav bp->bio_error = EIO; 1207220454Smav bp->bio_flags |= BIO_ERROR; 1208220454Smav biodone(bp); 1209220454Smav xpt_release_ccb(start_ccb); 1210220454Smav adaschedule(periph); 1211220454Smav return; 1212220454Smav } 1213220454Smav#endif 1214201139Smav cam_fill_ataio(ataio, 1215201139Smav ada_retry_count, 1216201139Smav adadone, 1217201139Smav bp->bio_cmd == BIO_READ ? 1218201139Smav CAM_DIR_IN : CAM_DIR_OUT, 1219201139Smav tag_code, 1220201139Smav bp->bio_data, 1221201139Smav bp->bio_bcount, 1222201139Smav ada_default_timeout*1000); 1223195534Sscottl 1224201139Smav if ((softc->flags & ADA_FLAG_CAN_NCQ) && tag_code) { 1225201139Smav if (bp->bio_cmd == BIO_READ) { 1226201139Smav ata_ncq_cmd(ataio, ATA_READ_FPDMA_QUEUED, 1227201139Smav lba, count); 1228201139Smav } else { 1229201139Smav ata_ncq_cmd(ataio, ATA_WRITE_FPDMA_QUEUED, 1230201139Smav lba, count); 1231201139Smav } 1232201139Smav } else if ((softc->flags & ADA_FLAG_CAN_48BIT) && 1233201139Smav (lba + count >= ATA_MAX_28BIT_LBA || 1234201139Smav count > 256)) { 1235201139Smav if (softc->flags & ADA_FLAG_CAN_DMA) { 1236195534Sscottl if (bp->bio_cmd == BIO_READ) { 1237201139Smav ata_48bit_cmd(ataio, ATA_READ_DMA48, 1238201139Smav 0, lba, count); 1239195534Sscottl } else { 1240201139Smav ata_48bit_cmd(ataio, ATA_WRITE_DMA48, 1241201139Smav 0, lba, count); 1242195534Sscottl } 1243201139Smav } else { 1244201139Smav if (bp->bio_cmd == BIO_READ) { 1245201139Smav ata_48bit_cmd(ataio, ATA_READ_MUL48, 1246201139Smav 0, lba, count); 1247195534Sscottl } else { 1248201139Smav ata_48bit_cmd(ataio, ATA_WRITE_MUL48, 1249201139Smav 0, lba, count); 1250195534Sscottl } 1251201139Smav } 1252201139Smav } else { 1253201139Smav if (count == 256) 1254201139Smav count = 0; 1255201139Smav if (softc->flags & ADA_FLAG_CAN_DMA) { 1256201139Smav if (bp->bio_cmd == BIO_READ) { 1257201139Smav ata_28bit_cmd(ataio, ATA_READ_DMA, 1258201139Smav 0, lba, count); 1259201139Smav } else { 1260201139Smav ata_28bit_cmd(ataio, ATA_WRITE_DMA, 1261201139Smav 0, lba, count); 1262201139Smav } 1263195534Sscottl } else { 1264201139Smav if (bp->bio_cmd == BIO_READ) { 1265201139Smav ata_28bit_cmd(ataio, ATA_READ_MUL, 1266201139Smav 0, lba, count); 1267195534Sscottl } else { 1268201139Smav ata_28bit_cmd(ataio, ATA_WRITE_MUL, 1269201139Smav 0, lba, count); 1270195534Sscottl } 1271195534Sscottl } 1272195534Sscottl } 1273201139Smav break; 1274201139Smav } 1275201139Smav case BIO_DELETE: 1276201139Smav { 1277201139Smav uint64_t lba = bp->bio_pblkno; 1278201139Smav uint16_t count = bp->bio_bcount / softc->params.secsize; 1279195534Sscottl 1280201139Smav cam_fill_ataio(ataio, 1281201139Smav ada_retry_count, 1282201139Smav adadone, 1283201139Smav CAM_DIR_NONE, 1284201139Smav 0, 1285201139Smav NULL, 1286201139Smav 0, 1287201139Smav ada_default_timeout*1000); 1288201139Smav 1289201139Smav if (count >= 256) 1290201139Smav count = 0; 1291201139Smav ata_28bit_cmd(ataio, ATA_CFA_ERASE, 0, lba, count); 1292201139Smav break; 1293195534Sscottl } 1294201139Smav case BIO_FLUSH: 1295201139Smav cam_fill_ataio(ataio, 1296201139Smav 1, 1297201139Smav adadone, 1298201139Smav CAM_DIR_NONE, 1299201139Smav 0, 1300201139Smav NULL, 1301201139Smav 0, 1302201139Smav ada_default_timeout*1000); 1303201139Smav 1304201139Smav if (softc->flags & ADA_FLAG_CAN_48BIT) 1305201139Smav ata_48bit_cmd(ataio, ATA_FLUSHCACHE48, 0, 0, 0); 1306201139Smav else 1307201139Smav ata_28bit_cmd(ataio, ATA_FLUSHCACHE, 0, 0, 0); 1308201139Smav break; 1309195534Sscottl } 1310201139Smav start_ccb->ccb_h.ccb_state = ADA_CCB_BUFFER_IO; 1311201139Smavout: 1312201139Smav start_ccb->ccb_h.ccb_bp = bp; 1313201139Smav softc->outstanding_cmds++; 1314201139Smav xpt_action(start_ccb); 1315201139Smav 1316201139Smav /* May have more work to do, so ensure we stay scheduled */ 1317201139Smav adaschedule(periph); 1318195534Sscottl break; 1319195534Sscottl } 1320220412Smav case ADA_STATE_WCACHE: 1321220412Smav { 1322220412Smav cam_fill_ataio(ataio, 1323220412Smav 1, 1324220412Smav adadone, 1325220412Smav CAM_DIR_NONE, 1326220412Smav 0, 1327220412Smav NULL, 1328220412Smav 0, 1329220412Smav ada_default_timeout*1000); 1330220412Smav 1331220454Smav ata_28bit_cmd(ataio, ATA_SETFEATURES, (softc->write_cache > 0 || 1332220454Smav (softc->write_cache < 0 && ada_write_cache)) ? 1333220412Smav ATA_SF_ENAB_WCACHE : ATA_SF_DIS_WCACHE, 0, 0); 1334220412Smav start_ccb->ccb_h.ccb_state = ADA_CCB_WCACHE; 1335220412Smav xpt_action(start_ccb); 1336220412Smav break; 1337195534Sscottl } 1338220412Smav } 1339195534Sscottl} 1340195534Sscottl 1341195534Sscottlstatic void 1342195534Sscottladadone(struct cam_periph *periph, union ccb *done_ccb) 1343195534Sscottl{ 1344195534Sscottl struct ada_softc *softc; 1345195534Sscottl struct ccb_ataio *ataio; 1346195534Sscottl 1347195534Sscottl softc = (struct ada_softc *)periph->softc; 1348195534Sscottl ataio = &done_ccb->ataio; 1349195534Sscottl switch (ataio->ccb_h.ccb_state & ADA_CCB_TYPE_MASK) { 1350195534Sscottl case ADA_CCB_BUFFER_IO: 1351201139Smav case ADA_CCB_TRIM: 1352195534Sscottl { 1353195534Sscottl struct bio *bp; 1354195534Sscottl 1355195534Sscottl bp = (struct bio *)done_ccb->ccb_h.ccb_bp; 1356195534Sscottl if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 1357195534Sscottl int error; 1358195534Sscottl 1359198328Smav error = adaerror(done_ccb, 0, 0); 1360195534Sscottl if (error == ERESTART) { 1361198328Smav /* A retry was scheduled, so just return. */ 1362195534Sscottl return; 1363195534Sscottl } 1364195534Sscottl if (error != 0) { 1365224283Smav if (error == ENXIO && 1366224283Smav (softc->flags & ADA_FLAG_PACK_INVALID) == 0) { 1367195534Sscottl /* 1368195534Sscottl * Catastrophic error. Mark our pack as 1369195534Sscottl * invalid. 1370195534Sscottl */ 1371195534Sscottl /* 1372195534Sscottl * XXX See if this is really a media 1373195534Sscottl * XXX change first? 1374195534Sscottl */ 1375195534Sscottl xpt_print(periph->path, 1376195534Sscottl "Invalidating pack\n"); 1377195534Sscottl softc->flags |= ADA_FLAG_PACK_INVALID; 1378195534Sscottl } 1379195534Sscottl bp->bio_error = error; 1380195534Sscottl bp->bio_resid = bp->bio_bcount; 1381195534Sscottl bp->bio_flags |= BIO_ERROR; 1382195534Sscottl } else { 1383195534Sscottl bp->bio_resid = ataio->resid; 1384195534Sscottl bp->bio_error = 0; 1385195534Sscottl if (bp->bio_resid != 0) 1386195534Sscottl bp->bio_flags |= BIO_ERROR; 1387195534Sscottl } 1388195534Sscottl if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 1389195534Sscottl cam_release_devq(done_ccb->ccb_h.path, 1390195534Sscottl /*relsim_flags*/0, 1391195534Sscottl /*reduction*/0, 1392195534Sscottl /*timeout*/0, 1393195534Sscottl /*getcount_only*/0); 1394195534Sscottl } else { 1395195534Sscottl if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 1396195534Sscottl panic("REQ_CMP with QFRZN"); 1397195534Sscottl bp->bio_resid = ataio->resid; 1398195534Sscottl if (ataio->resid > 0) 1399195534Sscottl bp->bio_flags |= BIO_ERROR; 1400195534Sscottl } 1401195534Sscottl softc->outstanding_cmds--; 1402195534Sscottl if (softc->outstanding_cmds == 0) 1403195534Sscottl softc->flags |= ADA_FLAG_WENT_IDLE; 1404201139Smav if ((ataio->ccb_h.ccb_state & ADA_CCB_TYPE_MASK) == 1405201139Smav ADA_CCB_TRIM) { 1406201139Smav struct trim_request *req = 1407201139Smav (struct trim_request *)ataio->data_ptr; 1408201139Smav int i; 1409195534Sscottl 1410222628Smav for (i = 1; i < TRIM_MAX_BIOS && req->bps[i]; i++) { 1411201139Smav struct bio *bp1 = req->bps[i]; 1412201139Smav 1413201139Smav bp1->bio_resid = bp->bio_resid; 1414201139Smav bp1->bio_error = bp->bio_error; 1415201139Smav if (bp->bio_flags & BIO_ERROR) 1416201139Smav bp1->bio_flags |= BIO_ERROR; 1417201139Smav biodone(bp1); 1418201139Smav } 1419201139Smav softc->trim_running = 0; 1420201139Smav biodone(bp); 1421201139Smav adaschedule(periph); 1422201139Smav } else 1423201139Smav biodone(bp); 1424195534Sscottl break; 1425195534Sscottl } 1426220412Smav case ADA_CCB_WCACHE: 1427220412Smav { 1428220412Smav if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 1429220412Smav if (adaerror(done_ccb, 0, 0) == ERESTART) { 1430220412Smav return; 1431220412Smav } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 1432220412Smav cam_release_devq(done_ccb->ccb_h.path, 1433220412Smav /*relsim_flags*/0, 1434220412Smav /*reduction*/0, 1435220412Smav /*timeout*/0, 1436220412Smav /*getcount_only*/0); 1437220412Smav } 1438220412Smav } 1439220412Smav 1440220412Smav softc->state = ADA_STATE_NORMAL; 1441220412Smav /* 1442220412Smav * Since our peripheral may be invalidated by an error 1443220412Smav * above or an external event, we must release our CCB 1444220412Smav * before releasing the reference on the peripheral. 1445220412Smav * The peripheral will only go away once the last reference 1446220412Smav * is removed, and we need it around for the CCB release 1447220412Smav * operation. 1448220412Smav */ 1449220412Smav xpt_release_ccb(done_ccb); 1450220412Smav cam_release_devq(periph->path, 1451220412Smav RELSIM_RELEASE_RUNLEVEL, 0, CAM_RL_DEV + 1, FALSE); 1452220412Smav adaschedule(periph); 1453220412Smav cam_periph_release_locked(periph); 1454220412Smav return; 1455220412Smav } 1456195534Sscottl case ADA_CCB_WAITING: 1457195534Sscottl { 1458195534Sscottl /* Caller will release the CCB */ 1459195534Sscottl wakeup(&done_ccb->ccb_h.cbfcnp); 1460195534Sscottl return; 1461195534Sscottl } 1462195534Sscottl case ADA_CCB_DUMP: 1463195534Sscottl /* No-op. We're polling */ 1464195534Sscottl return; 1465195534Sscottl default: 1466195534Sscottl break; 1467195534Sscottl } 1468195534Sscottl xpt_release_ccb(done_ccb); 1469195534Sscottl} 1470195534Sscottl 1471195534Sscottlstatic int 1472195534Sscottladaerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) 1473195534Sscottl{ 1474195534Sscottl 1475203385Smav return(cam_periph_error(ccb, cam_flags, sense_flags, NULL)); 1476195534Sscottl} 1477195534Sscottl 1478195534Sscottlstatic void 1479198897Smavadagetparams(struct cam_periph *periph, struct ccb_getdev *cgd) 1480195534Sscottl{ 1481195534Sscottl struct ada_softc *softc = (struct ada_softc *)periph->softc; 1482195534Sscottl struct disk_params *dp = &softc->params; 1483195534Sscottl u_int64_t lbasize48; 1484195534Sscottl u_int32_t lbasize; 1485195534Sscottl 1486198897Smav dp->secsize = ata_logical_sector_size(&cgd->ident_data); 1487195534Sscottl if ((cgd->ident_data.atavalid & ATA_FLAG_54_58) && 1488195534Sscottl cgd->ident_data.current_heads && cgd->ident_data.current_sectors) { 1489195534Sscottl dp->heads = cgd->ident_data.current_heads; 1490195534Sscottl dp->secs_per_track = cgd->ident_data.current_sectors; 1491195534Sscottl dp->cylinders = cgd->ident_data.cylinders; 1492195534Sscottl dp->sectors = (u_int32_t)cgd->ident_data.current_size_1 | 1493195534Sscottl ((u_int32_t)cgd->ident_data.current_size_2 << 16); 1494195534Sscottl } else { 1495195534Sscottl dp->heads = cgd->ident_data.heads; 1496195534Sscottl dp->secs_per_track = cgd->ident_data.sectors; 1497195534Sscottl dp->cylinders = cgd->ident_data.cylinders; 1498195534Sscottl dp->sectors = cgd->ident_data.cylinders * dp->heads * dp->secs_per_track; 1499195534Sscottl } 1500195534Sscottl lbasize = (u_int32_t)cgd->ident_data.lba_size_1 | 1501195534Sscottl ((u_int32_t)cgd->ident_data.lba_size_2 << 16); 1502195534Sscottl 1503195534Sscottl /* use the 28bit LBA size if valid or bigger than the CHS mapping */ 1504195534Sscottl if (cgd->ident_data.cylinders == 16383 || dp->sectors < lbasize) 1505195534Sscottl dp->sectors = lbasize; 1506195534Sscottl 1507195534Sscottl /* use the 48bit LBA size if valid */ 1508195534Sscottl lbasize48 = ((u_int64_t)cgd->ident_data.lba_size48_1) | 1509195534Sscottl ((u_int64_t)cgd->ident_data.lba_size48_2 << 16) | 1510195534Sscottl ((u_int64_t)cgd->ident_data.lba_size48_3 << 32) | 1511195534Sscottl ((u_int64_t)cgd->ident_data.lba_size48_4 << 48); 1512195534Sscottl if ((cgd->ident_data.support.command2 & ATA_SUPPORT_ADDRESS48) && 1513195534Sscottl lbasize48 > ATA_MAX_28BIT_LBA) 1514195534Sscottl dp->sectors = lbasize48; 1515195534Sscottl} 1516195534Sscottl 1517195534Sscottlstatic void 1518195534Sscottladasendorderedtag(void *arg) 1519195534Sscottl{ 1520195534Sscottl struct ada_softc *softc = arg; 1521195534Sscottl 1522195534Sscottl if (ada_send_ordered) { 1523195534Sscottl if ((softc->ordered_tag_count == 0) 1524195534Sscottl && ((softc->flags & ADA_FLAG_WENT_IDLE) == 0)) { 1525195534Sscottl softc->flags |= ADA_FLAG_NEED_OTAG; 1526195534Sscottl } 1527195534Sscottl if (softc->outstanding_cmds > 0) 1528195534Sscottl softc->flags &= ~ADA_FLAG_WENT_IDLE; 1529195534Sscottl 1530195534Sscottl softc->ordered_tag_count = 0; 1531195534Sscottl } 1532195534Sscottl /* Queue us up again */ 1533195534Sscottl callout_reset(&softc->sendordered_c, 1534195534Sscottl (ADA_DEFAULT_TIMEOUT * hz) / ADA_ORDEREDTAG_INTERVAL, 1535195534Sscottl adasendorderedtag, softc); 1536195534Sscottl} 1537195534Sscottl 1538195534Sscottl/* 1539195534Sscottl * Step through all ADA peripheral drivers, and if the device is still open, 1540195534Sscottl * sync the disk cache to physical media. 1541195534Sscottl */ 1542195534Sscottlstatic void 1543220650Smavadaflush(void) 1544195534Sscottl{ 1545195534Sscottl struct cam_periph *periph; 1546195534Sscottl struct ada_softc *softc; 1547195534Sscottl 1548195534Sscottl TAILQ_FOREACH(periph, &adadriver.units, unit_links) { 1549195534Sscottl union ccb ccb; 1550195534Sscottl 1551200180Smav /* If we paniced with lock held - not recurse here. */ 1552200180Smav if (cam_periph_owned(periph)) 1553200180Smav continue; 1554195534Sscottl cam_periph_lock(periph); 1555195534Sscottl softc = (struct ada_softc *)periph->softc; 1556195534Sscottl /* 1557195534Sscottl * We only sync the cache if the drive is still open, and 1558195534Sscottl * if the drive is capable of it.. 1559195534Sscottl */ 1560195534Sscottl if (((softc->flags & ADA_FLAG_OPEN) == 0) || 1561195534Sscottl (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) == 0) { 1562195534Sscottl cam_periph_unlock(periph); 1563195534Sscottl continue; 1564195534Sscottl } 1565195534Sscottl 1566198382Smav xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 1567195534Sscottl 1568195534Sscottl ccb.ccb_h.ccb_state = ADA_CCB_DUMP; 1569195534Sscottl cam_fill_ataio(&ccb.ataio, 1570195534Sscottl 1, 1571195534Sscottl adadone, 1572195534Sscottl CAM_DIR_NONE, 1573195534Sscottl 0, 1574195534Sscottl NULL, 1575195534Sscottl 0, 1576195534Sscottl ada_default_timeout*1000); 1577195534Sscottl 1578195534Sscottl if (softc->flags & ADA_FLAG_CAN_48BIT) 1579195534Sscottl ata_48bit_cmd(&ccb.ataio, ATA_FLUSHCACHE48, 0, 0, 0); 1580195534Sscottl else 1581196659Smav ata_28bit_cmd(&ccb.ataio, ATA_FLUSHCACHE, 0, 0, 0); 1582195534Sscottl xpt_polled_action(&ccb); 1583195534Sscottl 1584195534Sscottl if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) 1585195534Sscottl xpt_print(periph->path, "Synchronize cache failed\n"); 1586195534Sscottl 1587195534Sscottl if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0) 1588195534Sscottl cam_release_devq(ccb.ccb_h.path, 1589195534Sscottl /*relsim_flags*/0, 1590195534Sscottl /*reduction*/0, 1591195534Sscottl /*timeout*/0, 1592195534Sscottl /*getcount_only*/0); 1593195534Sscottl cam_periph_unlock(periph); 1594195534Sscottl } 1595220650Smav} 1596214279Sbrucec 1597220650Smavstatic void 1598220650Smavadaspindown(uint8_t cmd, int flags) 1599220650Smav{ 1600220650Smav struct cam_periph *periph; 1601220650Smav struct ada_softc *softc; 1602214279Sbrucec 1603214279Sbrucec TAILQ_FOREACH(periph, &adadriver.units, unit_links) { 1604214279Sbrucec union ccb ccb; 1605214279Sbrucec 1606214279Sbrucec /* If we paniced with lock held - not recurse here. */ 1607214279Sbrucec if (cam_periph_owned(periph)) 1608214279Sbrucec continue; 1609214279Sbrucec cam_periph_lock(periph); 1610214279Sbrucec softc = (struct ada_softc *)periph->softc; 1611214279Sbrucec /* 1612214279Sbrucec * We only spin-down the drive if it is capable of it.. 1613214279Sbrucec */ 1614214279Sbrucec if ((softc->flags & ADA_FLAG_CAN_POWERMGT) == 0) { 1615214279Sbrucec cam_periph_unlock(periph); 1616214279Sbrucec continue; 1617214279Sbrucec } 1618214279Sbrucec 1619214279Sbrucec if (bootverbose) 1620214279Sbrucec xpt_print(periph->path, "spin-down\n"); 1621214279Sbrucec 1622214279Sbrucec xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 1623214279Sbrucec 1624214279Sbrucec ccb.ccb_h.ccb_state = ADA_CCB_DUMP; 1625214279Sbrucec cam_fill_ataio(&ccb.ataio, 1626214279Sbrucec 1, 1627214279Sbrucec adadone, 1628220650Smav CAM_DIR_NONE | flags, 1629214279Sbrucec 0, 1630214279Sbrucec NULL, 1631214279Sbrucec 0, 1632214279Sbrucec ada_default_timeout*1000); 1633214279Sbrucec 1634220650Smav ata_28bit_cmd(&ccb.ataio, cmd, 0, 0, 0); 1635214279Sbrucec xpt_polled_action(&ccb); 1636214279Sbrucec 1637214279Sbrucec if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) 1638214279Sbrucec xpt_print(periph->path, "Spin-down disk failed\n"); 1639214279Sbrucec 1640214279Sbrucec if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0) 1641214279Sbrucec cam_release_devq(ccb.ccb_h.path, 1642214279Sbrucec /*relsim_flags*/0, 1643214279Sbrucec /*reduction*/0, 1644214279Sbrucec /*timeout*/0, 1645214279Sbrucec /*getcount_only*/0); 1646214279Sbrucec cam_periph_unlock(periph); 1647214279Sbrucec } 1648195534Sscottl} 1649195534Sscottl 1650220650Smavstatic void 1651220650Smavadashutdown(void *arg, int howto) 1652220650Smav{ 1653220650Smav 1654220650Smav adaflush(); 1655220650Smav if (ada_spindown_shutdown != 0 && 1656220650Smav (howto & (RB_HALT | RB_POWEROFF)) != 0) 1657220650Smav adaspindown(ATA_STANDBY_IMMEDIATE, 0); 1658220650Smav} 1659220650Smav 1660220650Smavstatic void 1661220650Smavadasuspend(void *arg) 1662220650Smav{ 1663220650Smav 1664220650Smav adaflush(); 1665220650Smav if (ada_spindown_suspend != 0) 1666220650Smav adaspindown(ATA_SLEEP, CAM_DEV_QFREEZE); 1667220650Smav} 1668220650Smav 1669220650Smavstatic void 1670220650Smavadaresume(void *arg) 1671220650Smav{ 1672220650Smav struct cam_periph *periph; 1673220650Smav struct ada_softc *softc; 1674220650Smav 1675220650Smav if (ada_spindown_suspend == 0) 1676220650Smav return; 1677220650Smav 1678220650Smav TAILQ_FOREACH(periph, &adadriver.units, unit_links) { 1679220650Smav cam_periph_lock(periph); 1680220650Smav softc = (struct ada_softc *)periph->softc; 1681220650Smav /* 1682220650Smav * We only spin-down the drive if it is capable of it.. 1683220650Smav */ 1684220650Smav if ((softc->flags & ADA_FLAG_CAN_POWERMGT) == 0) { 1685220650Smav cam_periph_unlock(periph); 1686220650Smav continue; 1687220650Smav } 1688220650Smav 1689220650Smav if (bootverbose) 1690220650Smav xpt_print(periph->path, "resume\n"); 1691220650Smav 1692220650Smav /* 1693220650Smav * Drop freeze taken due to CAM_DEV_QFREEZE flag set on 1694220650Smav * sleep request. 1695220650Smav */ 1696220650Smav cam_release_devq(periph->path, 1697220650Smav /*relsim_flags*/0, 1698220650Smav /*openings*/0, 1699220650Smav /*timeout*/0, 1700220650Smav /*getcount_only*/0); 1701220650Smav 1702220650Smav cam_periph_unlock(periph); 1703220650Smav } 1704220650Smav} 1705220650Smav 1706195534Sscottl#endif /* _KERNEL */ 1707