ata_da.c revision 214279
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 214279 2010-10-24 16:31:57Z brucec $"); 29195534Sscottl 30195534Sscottl#include <sys/param.h> 31195534Sscottl 32195534Sscottl#ifdef _KERNEL 33195534Sscottl#include <sys/systm.h> 34195534Sscottl#include <sys/kernel.h> 35195534Sscottl#include <sys/bio.h> 36195534Sscottl#include <sys/sysctl.h> 37195534Sscottl#include <sys/taskqueue.h> 38195534Sscottl#include <sys/lock.h> 39195534Sscottl#include <sys/mutex.h> 40195534Sscottl#include <sys/conf.h> 41195534Sscottl#include <sys/devicestat.h> 42195534Sscottl#include <sys/eventhandler.h> 43195534Sscottl#include <sys/malloc.h> 44195534Sscottl#include <sys/cons.h> 45214279Sbrucec#include <sys/reboot.h> 46195534Sscottl#include <geom/geom_disk.h> 47195534Sscottl#endif /* _KERNEL */ 48195534Sscottl 49195534Sscottl#ifndef _KERNEL 50195534Sscottl#include <stdio.h> 51195534Sscottl#include <string.h> 52195534Sscottl#endif /* _KERNEL */ 53195534Sscottl 54195534Sscottl#include <cam/cam.h> 55195534Sscottl#include <cam/cam_ccb.h> 56195534Sscottl#include <cam/cam_periph.h> 57195534Sscottl#include <cam/cam_xpt_periph.h> 58195534Sscottl#include <cam/cam_sim.h> 59195534Sscottl 60195534Sscottl#include <cam/ata/ata_all.h> 61195534Sscottl 62208349Smarius#include <machine/md_var.h> /* geometry translation */ 63208349Smarius 64195534Sscottl#ifdef _KERNEL 65195534Sscottl 66195534Sscottl#define ATA_MAX_28BIT_LBA 268435455UL 67195534Sscottl 68195534Sscottltypedef enum { 69198708Smav ADA_STATE_NORMAL 70195534Sscottl} ada_state; 71195534Sscottl 72195534Sscottltypedef enum { 73195534Sscottl ADA_FLAG_PACK_INVALID = 0x001, 74195534Sscottl ADA_FLAG_CAN_48BIT = 0x002, 75195534Sscottl ADA_FLAG_CAN_FLUSHCACHE = 0x004, 76198328Smav ADA_FLAG_CAN_NCQ = 0x008, 77198328Smav ADA_FLAG_CAN_DMA = 0x010, 78195534Sscottl ADA_FLAG_NEED_OTAG = 0x020, 79195534Sscottl ADA_FLAG_WENT_IDLE = 0x040, 80201139Smav ADA_FLAG_CAN_TRIM = 0x080, 81195534Sscottl ADA_FLAG_OPEN = 0x100, 82201139Smav ADA_FLAG_SCTX_INIT = 0x200, 83214279Sbrucec ADA_FLAG_CAN_CFA = 0x400, 84214279Sbrucec ADA_FLAG_CAN_POWERMGT = 0x800 85195534Sscottl} ada_flags; 86195534Sscottl 87195534Sscottltypedef enum { 88198328Smav ADA_Q_NONE = 0x00 89195534Sscottl} ada_quirks; 90195534Sscottl 91195534Sscottltypedef enum { 92195534Sscottl ADA_CCB_BUFFER_IO = 0x03, 93195534Sscottl ADA_CCB_WAITING = 0x04, 94195534Sscottl ADA_CCB_DUMP = 0x05, 95201139Smav ADA_CCB_TRIM = 0x06, 96195534Sscottl ADA_CCB_TYPE_MASK = 0x0F, 97195534Sscottl} ada_ccb_state; 98195534Sscottl 99195534Sscottl/* Offsets into our private area for storing information */ 100195534Sscottl#define ccb_state ppriv_field0 101195534Sscottl#define ccb_bp ppriv_ptr1 102195534Sscottl 103195534Sscottlstruct disk_params { 104195534Sscottl u_int8_t heads; 105198897Smav u_int8_t secs_per_track; 106195534Sscottl u_int32_t cylinders; 107198897Smav u_int32_t secsize; /* Number of bytes/logical sector */ 108198897Smav u_int64_t sectors; /* Total number sectors */ 109195534Sscottl}; 110195534Sscottl 111201139Smav#define TRIM_MAX_BLOCKS 4 112201139Smav#define TRIM_MAX_RANGES TRIM_MAX_BLOCKS * 64 113201139Smavstruct trim_request { 114201139Smav uint8_t data[TRIM_MAX_RANGES * 8]; 115201139Smav struct bio *bps[TRIM_MAX_RANGES]; 116201139Smav}; 117201139Smav 118195534Sscottlstruct ada_softc { 119195534Sscottl struct bio_queue_head bio_queue; 120201139Smav struct bio_queue_head trim_queue; 121195534Sscottl ada_state state; 122195534Sscottl ada_flags flags; 123195534Sscottl ada_quirks quirks; 124195534Sscottl int ordered_tag_count; 125195534Sscottl int outstanding_cmds; 126201139Smav int trim_max_ranges; 127201139Smav int trim_running; 128195534Sscottl struct disk_params params; 129195534Sscottl struct disk *disk; 130195534Sscottl struct task sysctl_task; 131195534Sscottl struct sysctl_ctx_list sysctl_ctx; 132195534Sscottl struct sysctl_oid *sysctl_tree; 133195534Sscottl struct callout sendordered_c; 134201139Smav struct trim_request trim_req; 135195534Sscottl}; 136195534Sscottl 137195534Sscottlstruct ada_quirk_entry { 138195534Sscottl struct scsi_inquiry_pattern inq_pat; 139195534Sscottl ada_quirks quirks; 140195534Sscottl}; 141195534Sscottl 142199178Smavstatic struct ada_quirk_entry ada_quirk_table[] = 143199178Smav{ 144199178Smav { 145199178Smav /* Default */ 146199178Smav { 147199178Smav T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED, 148199178Smav /*vendor*/"*", /*product*/"*", /*revision*/"*" 149199178Smav }, 150199178Smav /*quirks*/0 151199178Smav }, 152199178Smav}; 153195534Sscottl 154195534Sscottlstatic disk_strategy_t adastrategy; 155195534Sscottlstatic dumper_t adadump; 156195534Sscottlstatic periph_init_t adainit; 157195534Sscottlstatic void adaasync(void *callback_arg, u_int32_t code, 158195534Sscottl struct cam_path *path, void *arg); 159195534Sscottlstatic void adasysctlinit(void *context, int pending); 160195534Sscottlstatic periph_ctor_t adaregister; 161195534Sscottlstatic periph_dtor_t adacleanup; 162195534Sscottlstatic periph_start_t adastart; 163195534Sscottlstatic periph_oninv_t adaoninvalidate; 164195534Sscottlstatic void adadone(struct cam_periph *periph, 165195534Sscottl union ccb *done_ccb); 166195534Sscottlstatic int adaerror(union ccb *ccb, u_int32_t cam_flags, 167195534Sscottl u_int32_t sense_flags); 168198897Smavstatic void adagetparams(struct cam_periph *periph, 169195534Sscottl struct ccb_getdev *cgd); 170195534Sscottlstatic timeout_t adasendorderedtag; 171195534Sscottlstatic void adashutdown(void *arg, int howto); 172195534Sscottl 173195534Sscottl#ifndef ADA_DEFAULT_TIMEOUT 174195534Sscottl#define ADA_DEFAULT_TIMEOUT 30 /* Timeout in seconds */ 175195534Sscottl#endif 176195534Sscottl 177195534Sscottl#ifndef ADA_DEFAULT_RETRY 178195534Sscottl#define ADA_DEFAULT_RETRY 4 179195534Sscottl#endif 180195534Sscottl 181195534Sscottl#ifndef ADA_DEFAULT_SEND_ORDERED 182195534Sscottl#define ADA_DEFAULT_SEND_ORDERED 1 183195534Sscottl#endif 184195534Sscottl 185214279Sbrucec#ifndef ADA_DEFAULT_SPINDOWN_SHUTDOWN 186214279Sbrucec#define ADA_DEFAULT_SPINDOWN_SHUTDOWN 1 187214279Sbrucec#endif 188214279Sbrucec 189208349Smarius/* 190208349Smarius * Most platforms map firmware geometry to actual, but some don't. If 191208349Smarius * not overridden, default to nothing. 192208349Smarius */ 193208349Smarius#ifndef ata_disk_firmware_geom_adjust 194208349Smarius#define ata_disk_firmware_geom_adjust(disk) 195208349Smarius#endif 196195534Sscottl 197195534Sscottlstatic int ada_retry_count = ADA_DEFAULT_RETRY; 198195534Sscottlstatic int ada_default_timeout = ADA_DEFAULT_TIMEOUT; 199195534Sscottlstatic int ada_send_ordered = ADA_DEFAULT_SEND_ORDERED; 200214279Sbrucecstatic int ada_spindown_shutdown = ADA_DEFAULT_SPINDOWN_SHUTDOWN; 201195534Sscottl 202195534SscottlSYSCTL_NODE(_kern_cam, OID_AUTO, ada, CTLFLAG_RD, 0, 203195534Sscottl "CAM Direct Access Disk driver"); 204195534SscottlSYSCTL_INT(_kern_cam_ada, OID_AUTO, retry_count, CTLFLAG_RW, 205195534Sscottl &ada_retry_count, 0, "Normal I/O retry count"); 206195534SscottlTUNABLE_INT("kern.cam.ada.retry_count", &ada_retry_count); 207195534SscottlSYSCTL_INT(_kern_cam_ada, OID_AUTO, default_timeout, CTLFLAG_RW, 208195534Sscottl &ada_default_timeout, 0, "Normal I/O timeout (in seconds)"); 209195534SscottlTUNABLE_INT("kern.cam.ada.default_timeout", &ada_default_timeout); 210195534SscottlSYSCTL_INT(_kern_cam_ada, OID_AUTO, ada_send_ordered, CTLFLAG_RW, 211195534Sscottl &ada_send_ordered, 0, "Send Ordered Tags"); 212195534SscottlTUNABLE_INT("kern.cam.ada.ada_send_ordered", &ada_send_ordered); 213214279SbrucecSYSCTL_INT(_kern_cam_ada, OID_AUTO, spindown_shutdown, CTLFLAG_RW, 214214279Sbrucec &ada_spindown_shutdown, 0, "Spin down upon shutdown"); 215214279SbrucecTUNABLE_INT("kern.cam.ada.spindown_shutdown", &ada_spindown_shutdown); 216195534Sscottl 217195534Sscottl/* 218195534Sscottl * ADA_ORDEREDTAG_INTERVAL determines how often, relative 219195534Sscottl * to the default timeout, we check to see whether an ordered 220195534Sscottl * tagged transaction is appropriate to prevent simple tag 221195534Sscottl * starvation. Since we'd like to ensure that there is at least 222195534Sscottl * 1/2 of the timeout length left for a starved transaction to 223195534Sscottl * complete after we've sent an ordered tag, we must poll at least 224195534Sscottl * four times in every timeout period. This takes care of the worst 225195534Sscottl * case where a starved transaction starts during an interval that 226195534Sscottl * meets the requirement "don't send an ordered tag" test so it takes 227195534Sscottl * us two intervals to determine that a tag must be sent. 228195534Sscottl */ 229195534Sscottl#ifndef ADA_ORDEREDTAG_INTERVAL 230195534Sscottl#define ADA_ORDEREDTAG_INTERVAL 4 231195534Sscottl#endif 232195534Sscottl 233195534Sscottlstatic struct periph_driver adadriver = 234195534Sscottl{ 235195534Sscottl adainit, "ada", 236195534Sscottl TAILQ_HEAD_INITIALIZER(adadriver.units), /* generation */ 0 237195534Sscottl}; 238195534Sscottl 239195534SscottlPERIPHDRIVER_DECLARE(ada, adadriver); 240195534Sscottl 241195534SscottlMALLOC_DEFINE(M_ATADA, "ata_da", "ata_da buffers"); 242195534Sscottl 243195534Sscottlstatic int 244195534Sscottladaopen(struct disk *dp) 245195534Sscottl{ 246195534Sscottl struct cam_periph *periph; 247195534Sscottl struct ada_softc *softc; 248195534Sscottl int unit; 249195534Sscottl int error; 250195534Sscottl 251195534Sscottl periph = (struct cam_periph *)dp->d_drv1; 252195534Sscottl if (periph == NULL) { 253195534Sscottl return (ENXIO); 254195534Sscottl } 255195534Sscottl 256195534Sscottl if (cam_periph_acquire(periph) != CAM_REQ_CMP) { 257195534Sscottl return(ENXIO); 258195534Sscottl } 259195534Sscottl 260195534Sscottl cam_periph_lock(periph); 261195534Sscottl if ((error = cam_periph_hold(periph, PRIBIO|PCATCH)) != 0) { 262195534Sscottl cam_periph_unlock(periph); 263195534Sscottl cam_periph_release(periph); 264195534Sscottl return (error); 265195534Sscottl } 266195534Sscottl 267195534Sscottl unit = periph->unit_number; 268195534Sscottl softc = (struct ada_softc *)periph->softc; 269195534Sscottl softc->flags |= ADA_FLAG_OPEN; 270195534Sscottl 271195534Sscottl CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, 272195534Sscottl ("adaopen: disk=%s%d (unit %d)\n", dp->d_name, dp->d_unit, 273195534Sscottl unit)); 274195534Sscottl 275195534Sscottl if ((softc->flags & ADA_FLAG_PACK_INVALID) != 0) { 276195534Sscottl /* Invalidate our pack information. */ 277195534Sscottl softc->flags &= ~ADA_FLAG_PACK_INVALID; 278195534Sscottl } 279195534Sscottl 280195534Sscottl cam_periph_unhold(periph); 281195534Sscottl cam_periph_unlock(periph); 282195534Sscottl return (0); 283195534Sscottl} 284195534Sscottl 285195534Sscottlstatic int 286195534Sscottladaclose(struct disk *dp) 287195534Sscottl{ 288195534Sscottl struct cam_periph *periph; 289195534Sscottl struct ada_softc *softc; 290195534Sscottl union ccb *ccb; 291195534Sscottl int error; 292195534Sscottl 293195534Sscottl periph = (struct cam_periph *)dp->d_drv1; 294195534Sscottl if (periph == NULL) 295195534Sscottl return (ENXIO); 296195534Sscottl 297195534Sscottl cam_periph_lock(periph); 298195534Sscottl if ((error = cam_periph_hold(periph, PRIBIO)) != 0) { 299195534Sscottl cam_periph_unlock(periph); 300195534Sscottl cam_periph_release(periph); 301195534Sscottl return (error); 302195534Sscottl } 303195534Sscottl 304195534Sscottl softc = (struct ada_softc *)periph->softc; 305195534Sscottl /* We only sync the cache if the drive is capable of it. */ 306195534Sscottl if (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) { 307195534Sscottl 308198382Smav ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 309195534Sscottl cam_fill_ataio(&ccb->ataio, 310195534Sscottl 1, 311195534Sscottl adadone, 312195534Sscottl CAM_DIR_NONE, 313195534Sscottl 0, 314195534Sscottl NULL, 315195534Sscottl 0, 316195534Sscottl ada_default_timeout*1000); 317195534Sscottl 318195534Sscottl if (softc->flags & ADA_FLAG_CAN_48BIT) 319195534Sscottl ata_48bit_cmd(&ccb->ataio, ATA_FLUSHCACHE48, 0, 0, 0); 320195534Sscottl else 321196659Smav ata_28bit_cmd(&ccb->ataio, ATA_FLUSHCACHE, 0, 0, 0); 322195748Smav cam_periph_runccb(ccb, /*error_routine*/NULL, /*cam_flags*/0, 323198328Smav /*sense_flags*/0, softc->disk->d_devstat); 324195534Sscottl 325195534Sscottl if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) 326195534Sscottl xpt_print(periph->path, "Synchronize cache failed\n"); 327195534Sscottl 328195534Sscottl if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 329195534Sscottl cam_release_devq(ccb->ccb_h.path, 330195534Sscottl /*relsim_flags*/0, 331195534Sscottl /*reduction*/0, 332195534Sscottl /*timeout*/0, 333195534Sscottl /*getcount_only*/0); 334195534Sscottl xpt_release_ccb(ccb); 335195534Sscottl } 336195534Sscottl 337195534Sscottl softc->flags &= ~ADA_FLAG_OPEN; 338195534Sscottl cam_periph_unhold(periph); 339195534Sscottl cam_periph_unlock(periph); 340195534Sscottl cam_periph_release(periph); 341195534Sscottl return (0); 342195534Sscottl} 343195534Sscottl 344201139Smavstatic void 345201139Smavadaschedule(struct cam_periph *periph) 346201139Smav{ 347201139Smav struct ada_softc *softc = (struct ada_softc *)periph->softc; 348201139Smav 349201139Smav if (bioq_first(&softc->bio_queue) || 350201139Smav (!softc->trim_running && bioq_first(&softc->trim_queue))) { 351201139Smav /* Have more work to do, so ensure we stay scheduled */ 352201139Smav xpt_schedule(periph, CAM_PRIORITY_NORMAL); 353201139Smav } 354201139Smav} 355201139Smav 356195534Sscottl/* 357195534Sscottl * Actually translate the requested transfer into one the physical driver 358195534Sscottl * can understand. The transfer is described by a buf and will include 359195534Sscottl * only one physical transfer. 360195534Sscottl */ 361195534Sscottlstatic void 362195534Sscottladastrategy(struct bio *bp) 363195534Sscottl{ 364195534Sscottl struct cam_periph *periph; 365195534Sscottl struct ada_softc *softc; 366195534Sscottl 367195534Sscottl periph = (struct cam_periph *)bp->bio_disk->d_drv1; 368195534Sscottl if (periph == NULL) { 369195534Sscottl biofinish(bp, NULL, ENXIO); 370195534Sscottl return; 371195534Sscottl } 372195534Sscottl softc = (struct ada_softc *)periph->softc; 373195534Sscottl 374195534Sscottl cam_periph_lock(periph); 375195534Sscottl 376195534Sscottl /* 377195534Sscottl * If the device has been made invalid, error out 378195534Sscottl */ 379195534Sscottl if ((softc->flags & ADA_FLAG_PACK_INVALID)) { 380195534Sscottl cam_periph_unlock(periph); 381195534Sscottl biofinish(bp, NULL, ENXIO); 382195534Sscottl return; 383195534Sscottl } 384195534Sscottl 385195534Sscottl /* 386195534Sscottl * Place it in the queue of disk activities for this disk 387195534Sscottl */ 388201139Smav if (bp->bio_cmd == BIO_DELETE && 389201139Smav (softc->flags & ADA_FLAG_CAN_TRIM)) 390201139Smav bioq_disksort(&softc->trim_queue, bp); 391201139Smav else 392201139Smav bioq_disksort(&softc->bio_queue, bp); 393195534Sscottl 394195534Sscottl /* 395195534Sscottl * Schedule ourselves for performing the work. 396195534Sscottl */ 397201139Smav adaschedule(periph); 398195534Sscottl cam_periph_unlock(periph); 399195534Sscottl 400195534Sscottl return; 401195534Sscottl} 402195534Sscottl 403195534Sscottlstatic int 404195534Sscottladadump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t length) 405195534Sscottl{ 406195534Sscottl struct cam_periph *periph; 407195534Sscottl struct ada_softc *softc; 408195534Sscottl u_int secsize; 409195534Sscottl union ccb ccb; 410195534Sscottl struct disk *dp; 411195534Sscottl uint64_t lba; 412195534Sscottl uint16_t count; 413195534Sscottl 414195534Sscottl dp = arg; 415195534Sscottl periph = dp->d_drv1; 416195534Sscottl if (periph == NULL) 417195534Sscottl return (ENXIO); 418195534Sscottl softc = (struct ada_softc *)periph->softc; 419195534Sscottl cam_periph_lock(periph); 420195534Sscottl secsize = softc->params.secsize; 421195534Sscottl lba = offset / secsize; 422195534Sscottl count = length / secsize; 423195534Sscottl 424195534Sscottl if ((softc->flags & ADA_FLAG_PACK_INVALID) != 0) { 425195534Sscottl cam_periph_unlock(periph); 426195534Sscottl return (ENXIO); 427195534Sscottl } 428195534Sscottl 429195534Sscottl if (length > 0) { 430198382Smav xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 431195534Sscottl ccb.ccb_h.ccb_state = ADA_CCB_DUMP; 432195534Sscottl cam_fill_ataio(&ccb.ataio, 433195534Sscottl 0, 434195534Sscottl adadone, 435195534Sscottl CAM_DIR_OUT, 436195534Sscottl 0, 437195534Sscottl (u_int8_t *) virtual, 438195534Sscottl length, 439195534Sscottl ada_default_timeout*1000); 440195534Sscottl if ((softc->flags & ADA_FLAG_CAN_48BIT) && 441195534Sscottl (lba + count >= ATA_MAX_28BIT_LBA || 442195534Sscottl count >= 256)) { 443195534Sscottl ata_48bit_cmd(&ccb.ataio, ATA_WRITE_DMA48, 444195534Sscottl 0, lba, count); 445195534Sscottl } else { 446196659Smav ata_28bit_cmd(&ccb.ataio, ATA_WRITE_DMA, 447195534Sscottl 0, lba, count); 448195534Sscottl } 449195534Sscottl xpt_polled_action(&ccb); 450195534Sscottl 451195534Sscottl if ((ccb.ataio.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 452195534Sscottl printf("Aborting dump due to I/O error.\n"); 453195534Sscottl cam_periph_unlock(periph); 454195534Sscottl return(EIO); 455195534Sscottl } 456195534Sscottl cam_periph_unlock(periph); 457195534Sscottl return(0); 458195534Sscottl } 459195534Sscottl 460195534Sscottl if (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) { 461198382Smav xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 462195534Sscottl 463195534Sscottl ccb.ccb_h.ccb_state = ADA_CCB_DUMP; 464195534Sscottl cam_fill_ataio(&ccb.ataio, 465195534Sscottl 1, 466195534Sscottl adadone, 467195534Sscottl CAM_DIR_NONE, 468195534Sscottl 0, 469195534Sscottl NULL, 470195534Sscottl 0, 471195534Sscottl ada_default_timeout*1000); 472195534Sscottl 473195534Sscottl if (softc->flags & ADA_FLAG_CAN_48BIT) 474195534Sscottl ata_48bit_cmd(&ccb.ataio, ATA_FLUSHCACHE48, 0, 0, 0); 475195534Sscottl else 476196659Smav ata_28bit_cmd(&ccb.ataio, ATA_FLUSHCACHE, 0, 0, 0); 477195534Sscottl xpt_polled_action(&ccb); 478195534Sscottl 479195534Sscottl if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) 480195534Sscottl xpt_print(periph->path, "Synchronize cache failed\n"); 481195534Sscottl 482195534Sscottl if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0) 483195534Sscottl cam_release_devq(ccb.ccb_h.path, 484195534Sscottl /*relsim_flags*/0, 485195534Sscottl /*reduction*/0, 486195534Sscottl /*timeout*/0, 487195534Sscottl /*getcount_only*/0); 488195534Sscottl } 489195534Sscottl cam_periph_unlock(periph); 490195534Sscottl return (0); 491195534Sscottl} 492195534Sscottl 493195534Sscottlstatic void 494195534Sscottladainit(void) 495195534Sscottl{ 496195534Sscottl cam_status status; 497195534Sscottl 498195534Sscottl /* 499195534Sscottl * Install a global async callback. This callback will 500195534Sscottl * receive async callbacks like "new device found". 501195534Sscottl */ 502195534Sscottl status = xpt_register_async(AC_FOUND_DEVICE, adaasync, NULL, NULL); 503195534Sscottl 504195534Sscottl if (status != CAM_REQ_CMP) { 505195534Sscottl printf("ada: Failed to attach master async callback " 506195534Sscottl "due to status 0x%x!\n", status); 507195534Sscottl } else if (ada_send_ordered) { 508195534Sscottl 509195534Sscottl /* Register our shutdown event handler */ 510195534Sscottl if ((EVENTHANDLER_REGISTER(shutdown_post_sync, adashutdown, 511195534Sscottl NULL, SHUTDOWN_PRI_DEFAULT)) == NULL) 512195534Sscottl printf("adainit: shutdown event registration failed!\n"); 513195534Sscottl } 514195534Sscottl} 515195534Sscottl 516195534Sscottlstatic void 517195534Sscottladaoninvalidate(struct cam_periph *periph) 518195534Sscottl{ 519195534Sscottl struct ada_softc *softc; 520195534Sscottl 521195534Sscottl softc = (struct ada_softc *)periph->softc; 522195534Sscottl 523195534Sscottl /* 524195534Sscottl * De-register any async callbacks. 525195534Sscottl */ 526195534Sscottl xpt_register_async(0, adaasync, periph, periph->path); 527195534Sscottl 528195534Sscottl softc->flags |= ADA_FLAG_PACK_INVALID; 529195534Sscottl 530195534Sscottl /* 531195534Sscottl * Return all queued I/O with ENXIO. 532195534Sscottl * XXX Handle any transactions queued to the card 533195534Sscottl * with XPT_ABORT_CCB. 534195534Sscottl */ 535195534Sscottl bioq_flush(&softc->bio_queue, NULL, ENXIO); 536201139Smav bioq_flush(&softc->trim_queue, NULL, ENXIO); 537195534Sscottl 538195534Sscottl disk_gone(softc->disk); 539195534Sscottl xpt_print(periph->path, "lost device\n"); 540195534Sscottl} 541195534Sscottl 542195534Sscottlstatic void 543195534Sscottladacleanup(struct cam_periph *periph) 544195534Sscottl{ 545195534Sscottl struct ada_softc *softc; 546195534Sscottl 547195534Sscottl softc = (struct ada_softc *)periph->softc; 548195534Sscottl 549195534Sscottl xpt_print(periph->path, "removing device entry\n"); 550195534Sscottl cam_periph_unlock(periph); 551195534Sscottl 552195534Sscottl /* 553195534Sscottl * If we can't free the sysctl tree, oh well... 554195534Sscottl */ 555195534Sscottl if ((softc->flags & ADA_FLAG_SCTX_INIT) != 0 556195534Sscottl && sysctl_ctx_free(&softc->sysctl_ctx) != 0) { 557195534Sscottl xpt_print(periph->path, "can't remove sysctl context\n"); 558195534Sscottl } 559195534Sscottl 560195534Sscottl disk_destroy(softc->disk); 561195534Sscottl callout_drain(&softc->sendordered_c); 562195534Sscottl free(softc, M_DEVBUF); 563195534Sscottl cam_periph_lock(periph); 564195534Sscottl} 565195534Sscottl 566195534Sscottlstatic void 567195534Sscottladaasync(void *callback_arg, u_int32_t code, 568195534Sscottl struct cam_path *path, void *arg) 569195534Sscottl{ 570195534Sscottl struct cam_periph *periph; 571195534Sscottl 572195534Sscottl periph = (struct cam_periph *)callback_arg; 573195534Sscottl switch (code) { 574195534Sscottl case AC_FOUND_DEVICE: 575195534Sscottl { 576195534Sscottl struct ccb_getdev *cgd; 577195534Sscottl cam_status status; 578195534Sscottl 579195534Sscottl cgd = (struct ccb_getdev *)arg; 580195534Sscottl if (cgd == NULL) 581195534Sscottl break; 582195534Sscottl 583195534Sscottl if (cgd->protocol != PROTO_ATA) 584195534Sscottl break; 585195534Sscottl 586195534Sscottl /* 587195534Sscottl * Allocate a peripheral instance for 588195534Sscottl * this device and start the probe 589195534Sscottl * process. 590195534Sscottl */ 591195534Sscottl status = cam_periph_alloc(adaregister, adaoninvalidate, 592195534Sscottl adacleanup, adastart, 593195534Sscottl "ada", CAM_PERIPH_BIO, 594195534Sscottl cgd->ccb_h.path, adaasync, 595195534Sscottl AC_FOUND_DEVICE, cgd); 596195534Sscottl 597195534Sscottl if (status != CAM_REQ_CMP 598195534Sscottl && status != CAM_REQ_INPROG) 599195534Sscottl printf("adaasync: Unable to attach to new device " 600195534Sscottl "due to status 0x%x\n", status); 601195534Sscottl break; 602195534Sscottl } 603195534Sscottl default: 604195534Sscottl cam_periph_async(periph, code, path, arg); 605195534Sscottl break; 606195534Sscottl } 607195534Sscottl} 608195534Sscottl 609195534Sscottlstatic void 610195534Sscottladasysctlinit(void *context, int pending) 611195534Sscottl{ 612195534Sscottl struct cam_periph *periph; 613195534Sscottl struct ada_softc *softc; 614195534Sscottl char tmpstr[80], tmpstr2[80]; 615195534Sscottl 616195534Sscottl periph = (struct cam_periph *)context; 617195534Sscottl if (cam_periph_acquire(periph) != CAM_REQ_CMP) 618195534Sscottl return; 619195534Sscottl 620195534Sscottl softc = (struct ada_softc *)periph->softc; 621195534Sscottl snprintf(tmpstr, sizeof(tmpstr), "CAM ADA unit %d", periph->unit_number); 622195534Sscottl snprintf(tmpstr2, sizeof(tmpstr2), "%d", periph->unit_number); 623195534Sscottl 624195534Sscottl sysctl_ctx_init(&softc->sysctl_ctx); 625195534Sscottl softc->flags |= ADA_FLAG_SCTX_INIT; 626195534Sscottl softc->sysctl_tree = SYSCTL_ADD_NODE(&softc->sysctl_ctx, 627195534Sscottl SYSCTL_STATIC_CHILDREN(_kern_cam_ada), OID_AUTO, tmpstr2, 628195534Sscottl CTLFLAG_RD, 0, tmpstr); 629195534Sscottl if (softc->sysctl_tree == NULL) { 630195534Sscottl printf("adasysctlinit: unable to allocate sysctl tree\n"); 631195534Sscottl cam_periph_release(periph); 632195534Sscottl return; 633195534Sscottl } 634195534Sscottl 635195534Sscottl cam_periph_release(periph); 636195534Sscottl} 637195534Sscottl 638195534Sscottlstatic cam_status 639195534Sscottladaregister(struct cam_periph *periph, void *arg) 640195534Sscottl{ 641195534Sscottl struct ada_softc *softc; 642195534Sscottl struct ccb_pathinq cpi; 643195534Sscottl struct ccb_getdev *cgd; 644195534Sscottl char announce_buf[80]; 645195534Sscottl struct disk_params *dp; 646195534Sscottl caddr_t match; 647195534Sscottl u_int maxio; 648195534Sscottl 649195534Sscottl cgd = (struct ccb_getdev *)arg; 650195534Sscottl if (periph == NULL) { 651195534Sscottl printf("adaregister: periph was NULL!!\n"); 652195534Sscottl return(CAM_REQ_CMP_ERR); 653195534Sscottl } 654195534Sscottl 655195534Sscottl if (cgd == NULL) { 656195534Sscottl printf("adaregister: no getdev CCB, can't register device\n"); 657195534Sscottl return(CAM_REQ_CMP_ERR); 658195534Sscottl } 659195534Sscottl 660195534Sscottl softc = (struct ada_softc *)malloc(sizeof(*softc), M_DEVBUF, 661195534Sscottl M_NOWAIT|M_ZERO); 662195534Sscottl 663195534Sscottl if (softc == NULL) { 664195534Sscottl printf("adaregister: Unable to probe new device. " 665198328Smav "Unable to allocate softc\n"); 666195534Sscottl return(CAM_REQ_CMP_ERR); 667195534Sscottl } 668195534Sscottl 669195534Sscottl bioq_init(&softc->bio_queue); 670201139Smav bioq_init(&softc->trim_queue); 671195534Sscottl 672198328Smav if (cgd->ident_data.capabilities1 & ATA_SUPPORT_DMA) 673198328Smav softc->flags |= ADA_FLAG_CAN_DMA; 674195534Sscottl if (cgd->ident_data.support.command2 & ATA_SUPPORT_ADDRESS48) 675195534Sscottl softc->flags |= ADA_FLAG_CAN_48BIT; 676195534Sscottl if (cgd->ident_data.support.command2 & ATA_SUPPORT_FLUSHCACHE) 677195534Sscottl softc->flags |= ADA_FLAG_CAN_FLUSHCACHE; 678214279Sbrucec if (cgd->ident_data.support.command1 & ATA_SUPPORT_POWERMGT) 679214279Sbrucec softc->flags |= ADA_FLAG_CAN_POWERMGT; 680195534Sscottl if (cgd->ident_data.satacapabilities & ATA_SUPPORT_NCQ && 681199178Smav cgd->inq_flags & SID_CmdQue) 682195534Sscottl softc->flags |= ADA_FLAG_CAN_NCQ; 683201139Smav if (cgd->ident_data.support_dsm & ATA_SUPPORT_DSM_TRIM) { 684201139Smav softc->flags |= ADA_FLAG_CAN_TRIM; 685201139Smav softc->trim_max_ranges = TRIM_MAX_RANGES; 686201139Smav if (cgd->ident_data.max_dsm_blocks != 0) { 687201139Smav softc->trim_max_ranges = 688201139Smav min(cgd->ident_data.max_dsm_blocks * 64, 689201139Smav softc->trim_max_ranges); 690201139Smav } 691201139Smav } 692201139Smav if (cgd->ident_data.support.command2 & ATA_SUPPORT_CFA) 693201139Smav softc->flags |= ADA_FLAG_CAN_CFA; 694198708Smav softc->state = ADA_STATE_NORMAL; 695195534Sscottl 696195534Sscottl periph->softc = softc; 697195534Sscottl 698195534Sscottl /* 699195534Sscottl * See if this device has any quirks. 700195534Sscottl */ 701199178Smav match = cam_quirkmatch((caddr_t)&cgd->ident_data, 702199178Smav (caddr_t)ada_quirk_table, 703199178Smav sizeof(ada_quirk_table)/sizeof(*ada_quirk_table), 704199178Smav sizeof(*ada_quirk_table), ata_identify_match); 705195534Sscottl if (match != NULL) 706195534Sscottl softc->quirks = ((struct ada_quirk_entry *)match)->quirks; 707195534Sscottl else 708195534Sscottl softc->quirks = ADA_Q_NONE; 709195534Sscottl 710195534Sscottl bzero(&cpi, sizeof(cpi)); 711203108Smav xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NONE); 712195534Sscottl cpi.ccb_h.func_code = XPT_PATH_INQ; 713195534Sscottl xpt_action((union ccb *)&cpi); 714195534Sscottl 715195534Sscottl TASK_INIT(&softc->sysctl_task, 0, adasysctlinit, periph); 716195534Sscottl 717195534Sscottl /* 718195534Sscottl * Register this media as a disk 719195534Sscottl */ 720195534Sscottl mtx_unlock(periph->sim->mtx); 721198897Smav adagetparams(periph, cgd); 722195534Sscottl softc->disk = disk_alloc(); 723195534Sscottl softc->disk->d_open = adaopen; 724195534Sscottl softc->disk->d_close = adaclose; 725195534Sscottl softc->disk->d_strategy = adastrategy; 726195534Sscottl softc->disk->d_dump = adadump; 727195534Sscottl softc->disk->d_name = "ada"; 728195534Sscottl softc->disk->d_drv1 = periph; 729195534Sscottl maxio = cpi.maxio; /* Honor max I/O size of SIM */ 730195534Sscottl if (maxio == 0) 731195534Sscottl maxio = DFLTPHYS; /* traditional default */ 732195534Sscottl else if (maxio > MAXPHYS) 733195534Sscottl maxio = MAXPHYS; /* for safety */ 734201139Smav if (softc->flags & ADA_FLAG_CAN_48BIT) 735198897Smav maxio = min(maxio, 65536 * softc->params.secsize); 736195534Sscottl else /* 28bit ATA command limit */ 737198897Smav maxio = min(maxio, 256 * softc->params.secsize); 738195534Sscottl softc->disk->d_maxsize = maxio; 739195534Sscottl softc->disk->d_unit = periph->unit_number; 740195534Sscottl softc->disk->d_flags = 0; 741195534Sscottl if (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) 742195534Sscottl softc->disk->d_flags |= DISKFLAG_CANFLUSHCACHE; 743201139Smav if ((softc->flags & ADA_FLAG_CAN_TRIM) || 744201139Smav ((softc->flags & ADA_FLAG_CAN_CFA) && 745201139Smav !(softc->flags & ADA_FLAG_CAN_48BIT))) 746201139Smav softc->disk->d_flags |= DISKFLAG_CANDELETE; 747197896Spjd strlcpy(softc->disk->d_ident, cgd->serial_num, 748197896Spjd MIN(sizeof(softc->disk->d_ident), cgd->serial_num_len + 1)); 749210471Smav softc->disk->d_hba_vendor = cpi.hba_vendor; 750210471Smav softc->disk->d_hba_device = cpi.hba_device; 751210471Smav softc->disk->d_hba_subvendor = cpi.hba_subvendor; 752210471Smav softc->disk->d_hba_subdevice = cpi.hba_subdevice; 753195534Sscottl 754195534Sscottl softc->disk->d_sectorsize = softc->params.secsize; 755198897Smav softc->disk->d_mediasize = (off_t)softc->params.sectors * 756198897Smav softc->params.secsize; 757200969Smav if (ata_physical_sector_size(&cgd->ident_data) != 758200969Smav softc->params.secsize) { 759200969Smav softc->disk->d_stripesize = 760200969Smav ata_physical_sector_size(&cgd->ident_data); 761200969Smav softc->disk->d_stripeoffset = (softc->disk->d_stripesize - 762200969Smav ata_logical_sector_offset(&cgd->ident_data)) % 763200969Smav softc->disk->d_stripesize; 764200969Smav } 765195534Sscottl softc->disk->d_fwsectors = softc->params.secs_per_track; 766195534Sscottl softc->disk->d_fwheads = softc->params.heads; 767208349Smarius ata_disk_firmware_geom_adjust(softc->disk); 768195534Sscottl 769195534Sscottl disk_create(softc->disk, DISK_VERSION); 770195534Sscottl mtx_lock(periph->sim->mtx); 771195534Sscottl 772195534Sscottl dp = &softc->params; 773195534Sscottl snprintf(announce_buf, sizeof(announce_buf), 774195534Sscottl "%juMB (%ju %u byte sectors: %dH %dS/T %dC)", 775195534Sscottl (uintmax_t)(((uintmax_t)dp->secsize * 776195534Sscottl dp->sectors) / (1024*1024)), 777195534Sscottl (uintmax_t)dp->sectors, 778195534Sscottl dp->secsize, dp->heads, 779195534Sscottl dp->secs_per_track, dp->cylinders); 780195534Sscottl xpt_announce_periph(periph, announce_buf); 781195534Sscottl /* 782195534Sscottl * Add async callbacks for bus reset and 783195534Sscottl * bus device reset calls. I don't bother 784195534Sscottl * checking if this fails as, in most cases, 785195534Sscottl * the system will function just fine without 786195534Sscottl * them and the only alternative would be to 787195534Sscottl * not attach the device on failure. 788195534Sscottl */ 789198708Smav xpt_register_async(AC_LOST_DEVICE, 790195534Sscottl adaasync, periph, periph->path); 791195534Sscottl 792195534Sscottl /* 793195534Sscottl * Schedule a periodic event to occasionally send an 794195534Sscottl * ordered tag to a device. 795195534Sscottl */ 796195534Sscottl callout_init_mtx(&softc->sendordered_c, periph->sim->mtx, 0); 797195534Sscottl callout_reset(&softc->sendordered_c, 798195534Sscottl (ADA_DEFAULT_TIMEOUT * hz) / ADA_ORDEREDTAG_INTERVAL, 799195534Sscottl adasendorderedtag, softc); 800195534Sscottl 801195534Sscottl return(CAM_REQ_CMP); 802195534Sscottl} 803195534Sscottl 804195534Sscottlstatic void 805195534Sscottladastart(struct cam_periph *periph, union ccb *start_ccb) 806195534Sscottl{ 807198328Smav struct ada_softc *softc = (struct ada_softc *)periph->softc; 808198328Smav struct ccb_ataio *ataio = &start_ccb->ataio; 809195534Sscottl 810195534Sscottl switch (softc->state) { 811195534Sscottl case ADA_STATE_NORMAL: 812195534Sscottl { 813195534Sscottl struct bio *bp; 814201139Smav u_int8_t tag_code; 815195534Sscottl 816201139Smav /* Execute immediate CCB if waiting. */ 817195534Sscottl if (periph->immediate_priority <= periph->pinfo.priority) { 818195534Sscottl CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE, 819195534Sscottl ("queuing for immediate ccb\n")); 820195534Sscottl start_ccb->ccb_h.ccb_state = ADA_CCB_WAITING; 821195534Sscottl SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, 822195534Sscottl periph_links.sle); 823195534Sscottl periph->immediate_priority = CAM_PRIORITY_NONE; 824195534Sscottl wakeup(&periph->ccb_list); 825201139Smav /* Have more work to do, so ensure we stay scheduled */ 826201139Smav adaschedule(periph); 827201139Smav break; 828201139Smav } 829201139Smav /* Run TRIM if not running yet. */ 830201139Smav if (!softc->trim_running && 831201139Smav (bp = bioq_first(&softc->trim_queue)) != 0) { 832201139Smav struct trim_request *req = &softc->trim_req; 833201139Smav struct bio *bp1; 834201139Smav int bps = 0, ranges = 0; 835201139Smav 836201139Smav softc->trim_running = 1; 837201139Smav bzero(req, sizeof(*req)); 838201139Smav bp1 = bp; 839201139Smav do { 840201139Smav uint64_t lba = bp1->bio_pblkno; 841201139Smav int count = bp1->bio_bcount / 842201139Smav softc->params.secsize; 843201139Smav 844201139Smav bioq_remove(&softc->trim_queue, bp1); 845201139Smav while (count > 0) { 846201139Smav int c = min(count, 0xffff); 847201139Smav int off = ranges * 8; 848201139Smav 849201139Smav req->data[off + 0] = lba & 0xff; 850201139Smav req->data[off + 1] = (lba >> 8) & 0xff; 851201139Smav req->data[off + 2] = (lba >> 16) & 0xff; 852201139Smav req->data[off + 3] = (lba >> 24) & 0xff; 853201139Smav req->data[off + 4] = (lba >> 32) & 0xff; 854201139Smav req->data[off + 5] = (lba >> 40) & 0xff; 855201139Smav req->data[off + 6] = c & 0xff; 856201139Smav req->data[off + 7] = (c >> 8) & 0xff; 857201139Smav lba += c; 858201139Smav count -= c; 859201139Smav ranges++; 860201139Smav } 861201139Smav req->bps[bps++] = bp1; 862201139Smav bp1 = bioq_first(&softc->trim_queue); 863201139Smav if (bp1 == NULL || 864201139Smav bp1->bio_bcount / softc->params.secsize > 865201139Smav (softc->trim_max_ranges - ranges) * 0xffff) 866201139Smav break; 867201139Smav } while (1); 868201139Smav cam_fill_ataio(ataio, 869201139Smav ada_retry_count, 870201139Smav adadone, 871201139Smav CAM_DIR_OUT, 872201139Smav 0, 873201139Smav req->data, 874201139Smav ((ranges + 63) / 64) * 512, 875201139Smav ada_default_timeout * 1000); 876201139Smav ata_48bit_cmd(ataio, ATA_DATA_SET_MANAGEMENT, 877201139Smav ATA_DSM_TRIM, 0, (ranges + 63) / 64); 878201139Smav start_ccb->ccb_h.ccb_state = ADA_CCB_TRIM; 879201139Smav goto out; 880201139Smav } 881201139Smav /* Run regular command. */ 882201139Smav bp = bioq_first(&softc->bio_queue); 883201139Smav if (bp == NULL) { 884195534Sscottl xpt_release_ccb(start_ccb); 885201139Smav break; 886201139Smav } 887201139Smav bioq_remove(&softc->bio_queue, bp); 888201139Smav 889212160Sgibbs if ((bp->bio_flags & BIO_ORDERED) != 0 890212160Sgibbs || (softc->flags & ADA_FLAG_NEED_OTAG) != 0) { 891201139Smav softc->flags &= ~ADA_FLAG_NEED_OTAG; 892201139Smav softc->ordered_tag_count++; 893201139Smav tag_code = 0; 894195534Sscottl } else { 895201139Smav tag_code = 1; 896201139Smav } 897201139Smav switch (bp->bio_cmd) { 898201139Smav case BIO_READ: 899201139Smav case BIO_WRITE: 900201139Smav { 901201139Smav uint64_t lba = bp->bio_pblkno; 902201139Smav uint16_t count = bp->bio_bcount / softc->params.secsize; 903195534Sscottl 904201139Smav cam_fill_ataio(ataio, 905201139Smav ada_retry_count, 906201139Smav adadone, 907201139Smav bp->bio_cmd == BIO_READ ? 908201139Smav CAM_DIR_IN : CAM_DIR_OUT, 909201139Smav tag_code, 910201139Smav bp->bio_data, 911201139Smav bp->bio_bcount, 912201139Smav ada_default_timeout*1000); 913195534Sscottl 914201139Smav if ((softc->flags & ADA_FLAG_CAN_NCQ) && tag_code) { 915201139Smav if (bp->bio_cmd == BIO_READ) { 916201139Smav ata_ncq_cmd(ataio, ATA_READ_FPDMA_QUEUED, 917201139Smav lba, count); 918201139Smav } else { 919201139Smav ata_ncq_cmd(ataio, ATA_WRITE_FPDMA_QUEUED, 920201139Smav lba, count); 921201139Smav } 922201139Smav } else if ((softc->flags & ADA_FLAG_CAN_48BIT) && 923201139Smav (lba + count >= ATA_MAX_28BIT_LBA || 924201139Smav count > 256)) { 925201139Smav if (softc->flags & ADA_FLAG_CAN_DMA) { 926195534Sscottl if (bp->bio_cmd == BIO_READ) { 927201139Smav ata_48bit_cmd(ataio, ATA_READ_DMA48, 928201139Smav 0, lba, count); 929195534Sscottl } else { 930201139Smav ata_48bit_cmd(ataio, ATA_WRITE_DMA48, 931201139Smav 0, lba, count); 932195534Sscottl } 933201139Smav } else { 934201139Smav if (bp->bio_cmd == BIO_READ) { 935201139Smav ata_48bit_cmd(ataio, ATA_READ_MUL48, 936201139Smav 0, lba, count); 937195534Sscottl } else { 938201139Smav ata_48bit_cmd(ataio, ATA_WRITE_MUL48, 939201139Smav 0, lba, count); 940195534Sscottl } 941201139Smav } 942201139Smav } else { 943201139Smav if (count == 256) 944201139Smav count = 0; 945201139Smav if (softc->flags & ADA_FLAG_CAN_DMA) { 946201139Smav if (bp->bio_cmd == BIO_READ) { 947201139Smav ata_28bit_cmd(ataio, ATA_READ_DMA, 948201139Smav 0, lba, count); 949201139Smav } else { 950201139Smav ata_28bit_cmd(ataio, ATA_WRITE_DMA, 951201139Smav 0, lba, count); 952201139Smav } 953195534Sscottl } else { 954201139Smav if (bp->bio_cmd == BIO_READ) { 955201139Smav ata_28bit_cmd(ataio, ATA_READ_MUL, 956201139Smav 0, lba, count); 957195534Sscottl } else { 958201139Smav ata_28bit_cmd(ataio, ATA_WRITE_MUL, 959201139Smav 0, lba, count); 960195534Sscottl } 961195534Sscottl } 962195534Sscottl } 963201139Smav break; 964201139Smav } 965201139Smav case BIO_DELETE: 966201139Smav { 967201139Smav uint64_t lba = bp->bio_pblkno; 968201139Smav uint16_t count = bp->bio_bcount / softc->params.secsize; 969195534Sscottl 970201139Smav cam_fill_ataio(ataio, 971201139Smav ada_retry_count, 972201139Smav adadone, 973201139Smav CAM_DIR_NONE, 974201139Smav 0, 975201139Smav NULL, 976201139Smav 0, 977201139Smav ada_default_timeout*1000); 978201139Smav 979201139Smav if (count >= 256) 980201139Smav count = 0; 981201139Smav ata_28bit_cmd(ataio, ATA_CFA_ERASE, 0, lba, count); 982201139Smav break; 983195534Sscottl } 984201139Smav case BIO_FLUSH: 985201139Smav cam_fill_ataio(ataio, 986201139Smav 1, 987201139Smav adadone, 988201139Smav CAM_DIR_NONE, 989201139Smav 0, 990201139Smav NULL, 991201139Smav 0, 992201139Smav ada_default_timeout*1000); 993201139Smav 994201139Smav if (softc->flags & ADA_FLAG_CAN_48BIT) 995201139Smav ata_48bit_cmd(ataio, ATA_FLUSHCACHE48, 0, 0, 0); 996201139Smav else 997201139Smav ata_28bit_cmd(ataio, ATA_FLUSHCACHE, 0, 0, 0); 998201139Smav break; 999195534Sscottl } 1000201139Smav start_ccb->ccb_h.ccb_state = ADA_CCB_BUFFER_IO; 1001201139Smavout: 1002201139Smav start_ccb->ccb_h.ccb_bp = bp; 1003201139Smav softc->outstanding_cmds++; 1004201139Smav xpt_action(start_ccb); 1005201139Smav 1006201139Smav /* May have more work to do, so ensure we stay scheduled */ 1007201139Smav adaschedule(periph); 1008195534Sscottl break; 1009195534Sscottl } 1010195534Sscottl } 1011195534Sscottl} 1012195534Sscottl 1013195534Sscottlstatic void 1014195534Sscottladadone(struct cam_periph *periph, union ccb *done_ccb) 1015195534Sscottl{ 1016195534Sscottl struct ada_softc *softc; 1017195534Sscottl struct ccb_ataio *ataio; 1018195534Sscottl 1019195534Sscottl softc = (struct ada_softc *)periph->softc; 1020195534Sscottl ataio = &done_ccb->ataio; 1021195534Sscottl switch (ataio->ccb_h.ccb_state & ADA_CCB_TYPE_MASK) { 1022195534Sscottl case ADA_CCB_BUFFER_IO: 1023201139Smav case ADA_CCB_TRIM: 1024195534Sscottl { 1025195534Sscottl struct bio *bp; 1026195534Sscottl 1027195534Sscottl bp = (struct bio *)done_ccb->ccb_h.ccb_bp; 1028195534Sscottl if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 1029195534Sscottl int error; 1030195534Sscottl 1031198328Smav error = adaerror(done_ccb, 0, 0); 1032195534Sscottl if (error == ERESTART) { 1033198328Smav /* A retry was scheduled, so just return. */ 1034195534Sscottl return; 1035195534Sscottl } 1036195534Sscottl if (error != 0) { 1037195534Sscottl if (error == ENXIO) { 1038195534Sscottl /* 1039195534Sscottl * Catastrophic error. Mark our pack as 1040195534Sscottl * invalid. 1041195534Sscottl */ 1042195534Sscottl /* 1043195534Sscottl * XXX See if this is really a media 1044195534Sscottl * XXX change first? 1045195534Sscottl */ 1046195534Sscottl xpt_print(periph->path, 1047195534Sscottl "Invalidating pack\n"); 1048195534Sscottl softc->flags |= ADA_FLAG_PACK_INVALID; 1049195534Sscottl } 1050195534Sscottl bp->bio_error = error; 1051195534Sscottl bp->bio_resid = bp->bio_bcount; 1052195534Sscottl bp->bio_flags |= BIO_ERROR; 1053195534Sscottl } else { 1054195534Sscottl bp->bio_resid = ataio->resid; 1055195534Sscottl bp->bio_error = 0; 1056195534Sscottl if (bp->bio_resid != 0) 1057195534Sscottl bp->bio_flags |= BIO_ERROR; 1058195534Sscottl } 1059195534Sscottl if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 1060195534Sscottl cam_release_devq(done_ccb->ccb_h.path, 1061195534Sscottl /*relsim_flags*/0, 1062195534Sscottl /*reduction*/0, 1063195534Sscottl /*timeout*/0, 1064195534Sscottl /*getcount_only*/0); 1065195534Sscottl } else { 1066195534Sscottl if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 1067195534Sscottl panic("REQ_CMP with QFRZN"); 1068195534Sscottl bp->bio_resid = ataio->resid; 1069195534Sscottl if (ataio->resid > 0) 1070195534Sscottl bp->bio_flags |= BIO_ERROR; 1071195534Sscottl } 1072195534Sscottl softc->outstanding_cmds--; 1073195534Sscottl if (softc->outstanding_cmds == 0) 1074195534Sscottl softc->flags |= ADA_FLAG_WENT_IDLE; 1075201139Smav if ((ataio->ccb_h.ccb_state & ADA_CCB_TYPE_MASK) == 1076201139Smav ADA_CCB_TRIM) { 1077201139Smav struct trim_request *req = 1078201139Smav (struct trim_request *)ataio->data_ptr; 1079201139Smav int i; 1080195534Sscottl 1081201139Smav for (i = 1; i < softc->trim_max_ranges && 1082201139Smav req->bps[i]; i++) { 1083201139Smav struct bio *bp1 = req->bps[i]; 1084201139Smav 1085201139Smav bp1->bio_resid = bp->bio_resid; 1086201139Smav bp1->bio_error = bp->bio_error; 1087201139Smav if (bp->bio_flags & BIO_ERROR) 1088201139Smav bp1->bio_flags |= BIO_ERROR; 1089201139Smav biodone(bp1); 1090201139Smav } 1091201139Smav softc->trim_running = 0; 1092201139Smav biodone(bp); 1093201139Smav adaschedule(periph); 1094201139Smav } else 1095201139Smav biodone(bp); 1096195534Sscottl break; 1097195534Sscottl } 1098195534Sscottl case ADA_CCB_WAITING: 1099195534Sscottl { 1100195534Sscottl /* Caller will release the CCB */ 1101195534Sscottl wakeup(&done_ccb->ccb_h.cbfcnp); 1102195534Sscottl return; 1103195534Sscottl } 1104195534Sscottl case ADA_CCB_DUMP: 1105195534Sscottl /* No-op. We're polling */ 1106195534Sscottl return; 1107195534Sscottl default: 1108195534Sscottl break; 1109195534Sscottl } 1110195534Sscottl xpt_release_ccb(done_ccb); 1111195534Sscottl} 1112195534Sscottl 1113195534Sscottlstatic int 1114195534Sscottladaerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) 1115195534Sscottl{ 1116195534Sscottl struct ada_softc *softc; 1117195534Sscottl struct cam_periph *periph; 1118195534Sscottl 1119195534Sscottl periph = xpt_path_periph(ccb->ccb_h.path); 1120195534Sscottl softc = (struct ada_softc *)periph->softc; 1121195534Sscottl 1122203385Smav return(cam_periph_error(ccb, cam_flags, sense_flags, NULL)); 1123195534Sscottl} 1124195534Sscottl 1125195534Sscottlstatic void 1126198897Smavadagetparams(struct cam_periph *periph, struct ccb_getdev *cgd) 1127195534Sscottl{ 1128195534Sscottl struct ada_softc *softc = (struct ada_softc *)periph->softc; 1129195534Sscottl struct disk_params *dp = &softc->params; 1130195534Sscottl u_int64_t lbasize48; 1131195534Sscottl u_int32_t lbasize; 1132195534Sscottl 1133198897Smav dp->secsize = ata_logical_sector_size(&cgd->ident_data); 1134195534Sscottl if ((cgd->ident_data.atavalid & ATA_FLAG_54_58) && 1135195534Sscottl cgd->ident_data.current_heads && cgd->ident_data.current_sectors) { 1136195534Sscottl dp->heads = cgd->ident_data.current_heads; 1137195534Sscottl dp->secs_per_track = cgd->ident_data.current_sectors; 1138195534Sscottl dp->cylinders = cgd->ident_data.cylinders; 1139195534Sscottl dp->sectors = (u_int32_t)cgd->ident_data.current_size_1 | 1140195534Sscottl ((u_int32_t)cgd->ident_data.current_size_2 << 16); 1141195534Sscottl } else { 1142195534Sscottl dp->heads = cgd->ident_data.heads; 1143195534Sscottl dp->secs_per_track = cgd->ident_data.sectors; 1144195534Sscottl dp->cylinders = cgd->ident_data.cylinders; 1145195534Sscottl dp->sectors = cgd->ident_data.cylinders * dp->heads * dp->secs_per_track; 1146195534Sscottl } 1147195534Sscottl lbasize = (u_int32_t)cgd->ident_data.lba_size_1 | 1148195534Sscottl ((u_int32_t)cgd->ident_data.lba_size_2 << 16); 1149195534Sscottl 1150195534Sscottl /* use the 28bit LBA size if valid or bigger than the CHS mapping */ 1151195534Sscottl if (cgd->ident_data.cylinders == 16383 || dp->sectors < lbasize) 1152195534Sscottl dp->sectors = lbasize; 1153195534Sscottl 1154195534Sscottl /* use the 48bit LBA size if valid */ 1155195534Sscottl lbasize48 = ((u_int64_t)cgd->ident_data.lba_size48_1) | 1156195534Sscottl ((u_int64_t)cgd->ident_data.lba_size48_2 << 16) | 1157195534Sscottl ((u_int64_t)cgd->ident_data.lba_size48_3 << 32) | 1158195534Sscottl ((u_int64_t)cgd->ident_data.lba_size48_4 << 48); 1159195534Sscottl if ((cgd->ident_data.support.command2 & ATA_SUPPORT_ADDRESS48) && 1160195534Sscottl lbasize48 > ATA_MAX_28BIT_LBA) 1161195534Sscottl dp->sectors = lbasize48; 1162195534Sscottl} 1163195534Sscottl 1164195534Sscottlstatic void 1165195534Sscottladasendorderedtag(void *arg) 1166195534Sscottl{ 1167195534Sscottl struct ada_softc *softc = arg; 1168195534Sscottl 1169195534Sscottl if (ada_send_ordered) { 1170195534Sscottl if ((softc->ordered_tag_count == 0) 1171195534Sscottl && ((softc->flags & ADA_FLAG_WENT_IDLE) == 0)) { 1172195534Sscottl softc->flags |= ADA_FLAG_NEED_OTAG; 1173195534Sscottl } 1174195534Sscottl if (softc->outstanding_cmds > 0) 1175195534Sscottl softc->flags &= ~ADA_FLAG_WENT_IDLE; 1176195534Sscottl 1177195534Sscottl softc->ordered_tag_count = 0; 1178195534Sscottl } 1179195534Sscottl /* Queue us up again */ 1180195534Sscottl callout_reset(&softc->sendordered_c, 1181195534Sscottl (ADA_DEFAULT_TIMEOUT * hz) / ADA_ORDEREDTAG_INTERVAL, 1182195534Sscottl adasendorderedtag, softc); 1183195534Sscottl} 1184195534Sscottl 1185195534Sscottl/* 1186195534Sscottl * Step through all ADA peripheral drivers, and if the device is still open, 1187195534Sscottl * sync the disk cache to physical media. 1188195534Sscottl */ 1189195534Sscottlstatic void 1190195534Sscottladashutdown(void * arg, int howto) 1191195534Sscottl{ 1192195534Sscottl struct cam_periph *periph; 1193195534Sscottl struct ada_softc *softc; 1194195534Sscottl 1195195534Sscottl TAILQ_FOREACH(periph, &adadriver.units, unit_links) { 1196195534Sscottl union ccb ccb; 1197195534Sscottl 1198200180Smav /* If we paniced with lock held - not recurse here. */ 1199200180Smav if (cam_periph_owned(periph)) 1200200180Smav continue; 1201195534Sscottl cam_periph_lock(periph); 1202195534Sscottl softc = (struct ada_softc *)periph->softc; 1203195534Sscottl /* 1204195534Sscottl * We only sync the cache if the drive is still open, and 1205195534Sscottl * if the drive is capable of it.. 1206195534Sscottl */ 1207195534Sscottl if (((softc->flags & ADA_FLAG_OPEN) == 0) || 1208195534Sscottl (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) == 0) { 1209195534Sscottl cam_periph_unlock(periph); 1210195534Sscottl continue; 1211195534Sscottl } 1212195534Sscottl 1213198382Smav xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 1214195534Sscottl 1215195534Sscottl ccb.ccb_h.ccb_state = ADA_CCB_DUMP; 1216195534Sscottl cam_fill_ataio(&ccb.ataio, 1217195534Sscottl 1, 1218195534Sscottl adadone, 1219195534Sscottl CAM_DIR_NONE, 1220195534Sscottl 0, 1221195534Sscottl NULL, 1222195534Sscottl 0, 1223195534Sscottl ada_default_timeout*1000); 1224195534Sscottl 1225195534Sscottl if (softc->flags & ADA_FLAG_CAN_48BIT) 1226195534Sscottl ata_48bit_cmd(&ccb.ataio, ATA_FLUSHCACHE48, 0, 0, 0); 1227195534Sscottl else 1228196659Smav ata_28bit_cmd(&ccb.ataio, ATA_FLUSHCACHE, 0, 0, 0); 1229195534Sscottl xpt_polled_action(&ccb); 1230195534Sscottl 1231195534Sscottl if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) 1232195534Sscottl xpt_print(periph->path, "Synchronize cache failed\n"); 1233195534Sscottl 1234195534Sscottl if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0) 1235195534Sscottl cam_release_devq(ccb.ccb_h.path, 1236195534Sscottl /*relsim_flags*/0, 1237195534Sscottl /*reduction*/0, 1238195534Sscottl /*timeout*/0, 1239195534Sscottl /*getcount_only*/0); 1240195534Sscottl cam_periph_unlock(periph); 1241195534Sscottl } 1242214279Sbrucec 1243214279Sbrucec if (ada_spindown_shutdown == 0 || 1244214279Sbrucec (howto & (RB_HALT | RB_POWEROFF)) == 0) 1245214279Sbrucec return; 1246214279Sbrucec 1247214279Sbrucec TAILQ_FOREACH(periph, &adadriver.units, unit_links) { 1248214279Sbrucec union ccb ccb; 1249214279Sbrucec 1250214279Sbrucec /* If we paniced with lock held - not recurse here. */ 1251214279Sbrucec if (cam_periph_owned(periph)) 1252214279Sbrucec continue; 1253214279Sbrucec cam_periph_lock(periph); 1254214279Sbrucec softc = (struct ada_softc *)periph->softc; 1255214279Sbrucec /* 1256214279Sbrucec * We only spin-down the drive if it is capable of it.. 1257214279Sbrucec */ 1258214279Sbrucec if ((softc->flags & ADA_FLAG_CAN_POWERMGT) == 0) { 1259214279Sbrucec cam_periph_unlock(periph); 1260214279Sbrucec continue; 1261214279Sbrucec } 1262214279Sbrucec 1263214279Sbrucec if (bootverbose) 1264214279Sbrucec xpt_print(periph->path, "spin-down\n"); 1265214279Sbrucec 1266214279Sbrucec xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 1267214279Sbrucec 1268214279Sbrucec ccb.ccb_h.ccb_state = ADA_CCB_DUMP; 1269214279Sbrucec cam_fill_ataio(&ccb.ataio, 1270214279Sbrucec 1, 1271214279Sbrucec adadone, 1272214279Sbrucec CAM_DIR_NONE, 1273214279Sbrucec 0, 1274214279Sbrucec NULL, 1275214279Sbrucec 0, 1276214279Sbrucec ada_default_timeout*1000); 1277214279Sbrucec 1278214279Sbrucec ata_28bit_cmd(&ccb.ataio, ATA_STANDBY_IMMEDIATE, 0, 0, 0); 1279214279Sbrucec xpt_polled_action(&ccb); 1280214279Sbrucec 1281214279Sbrucec if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) 1282214279Sbrucec xpt_print(periph->path, "Spin-down disk failed\n"); 1283214279Sbrucec 1284214279Sbrucec if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0) 1285214279Sbrucec cam_release_devq(ccb.ccb_h.path, 1286214279Sbrucec /*relsim_flags*/0, 1287214279Sbrucec /*reduction*/0, 1288214279Sbrucec /*timeout*/0, 1289214279Sbrucec /*getcount_only*/0); 1290214279Sbrucec cam_periph_unlock(periph); 1291214279Sbrucec } 1292195534Sscottl} 1293195534Sscottl 1294195534Sscottl#endif /* _KERNEL */ 1295