ata_da.c revision 208349
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 208349 2010-05-20 12:46:19Z marius $"); 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> 45195534Sscottl#include <geom/geom_disk.h> 46195534Sscottl#endif /* _KERNEL */ 47195534Sscottl 48195534Sscottl#ifndef _KERNEL 49195534Sscottl#include <stdio.h> 50195534Sscottl#include <string.h> 51195534Sscottl#endif /* _KERNEL */ 52195534Sscottl 53195534Sscottl#include <cam/cam.h> 54195534Sscottl#include <cam/cam_ccb.h> 55195534Sscottl#include <cam/cam_periph.h> 56195534Sscottl#include <cam/cam_xpt_periph.h> 57195534Sscottl#include <cam/cam_sim.h> 58195534Sscottl 59195534Sscottl#include <cam/ata/ata_all.h> 60195534Sscottl 61208349Smarius#include <machine/md_var.h> /* geometry translation */ 62208349Smarius 63195534Sscottl#ifdef _KERNEL 64195534Sscottl 65195534Sscottl#define ATA_MAX_28BIT_LBA 268435455UL 66195534Sscottl 67195534Sscottltypedef enum { 68198708Smav ADA_STATE_NORMAL 69195534Sscottl} ada_state; 70195534Sscottl 71195534Sscottltypedef enum { 72195534Sscottl ADA_FLAG_PACK_INVALID = 0x001, 73195534Sscottl ADA_FLAG_CAN_48BIT = 0x002, 74195534Sscottl ADA_FLAG_CAN_FLUSHCACHE = 0x004, 75198328Smav ADA_FLAG_CAN_NCQ = 0x008, 76198328Smav ADA_FLAG_CAN_DMA = 0x010, 77195534Sscottl ADA_FLAG_NEED_OTAG = 0x020, 78195534Sscottl ADA_FLAG_WENT_IDLE = 0x040, 79201139Smav ADA_FLAG_CAN_TRIM = 0x080, 80195534Sscottl ADA_FLAG_OPEN = 0x100, 81201139Smav ADA_FLAG_SCTX_INIT = 0x200, 82201139Smav ADA_FLAG_CAN_CFA = 0x400 83195534Sscottl} ada_flags; 84195534Sscottl 85195534Sscottltypedef enum { 86198328Smav ADA_Q_NONE = 0x00 87195534Sscottl} ada_quirks; 88195534Sscottl 89195534Sscottltypedef enum { 90195534Sscottl ADA_CCB_BUFFER_IO = 0x03, 91195534Sscottl ADA_CCB_WAITING = 0x04, 92195534Sscottl ADA_CCB_DUMP = 0x05, 93201139Smav ADA_CCB_TRIM = 0x06, 94195534Sscottl ADA_CCB_TYPE_MASK = 0x0F, 95195534Sscottl} ada_ccb_state; 96195534Sscottl 97195534Sscottl/* Offsets into our private area for storing information */ 98195534Sscottl#define ccb_state ppriv_field0 99195534Sscottl#define ccb_bp ppriv_ptr1 100195534Sscottl 101195534Sscottlstruct disk_params { 102195534Sscottl u_int8_t heads; 103198897Smav u_int8_t secs_per_track; 104195534Sscottl u_int32_t cylinders; 105198897Smav u_int32_t secsize; /* Number of bytes/logical sector */ 106198897Smav u_int64_t sectors; /* Total number sectors */ 107195534Sscottl}; 108195534Sscottl 109201139Smav#define TRIM_MAX_BLOCKS 4 110201139Smav#define TRIM_MAX_RANGES TRIM_MAX_BLOCKS * 64 111201139Smavstruct trim_request { 112201139Smav uint8_t data[TRIM_MAX_RANGES * 8]; 113201139Smav struct bio *bps[TRIM_MAX_RANGES]; 114201139Smav}; 115201139Smav 116195534Sscottlstruct ada_softc { 117195534Sscottl struct bio_queue_head bio_queue; 118201139Smav struct bio_queue_head trim_queue; 119195534Sscottl ada_state state; 120195534Sscottl ada_flags flags; 121195534Sscottl ada_quirks quirks; 122195534Sscottl int ordered_tag_count; 123195534Sscottl int outstanding_cmds; 124201139Smav int trim_max_ranges; 125201139Smav int trim_running; 126195534Sscottl struct disk_params params; 127195534Sscottl struct disk *disk; 128195534Sscottl struct task sysctl_task; 129195534Sscottl struct sysctl_ctx_list sysctl_ctx; 130195534Sscottl struct sysctl_oid *sysctl_tree; 131195534Sscottl struct callout sendordered_c; 132201139Smav struct trim_request trim_req; 133195534Sscottl}; 134195534Sscottl 135195534Sscottlstruct ada_quirk_entry { 136195534Sscottl struct scsi_inquiry_pattern inq_pat; 137195534Sscottl ada_quirks quirks; 138195534Sscottl}; 139195534Sscottl 140199178Smavstatic struct ada_quirk_entry ada_quirk_table[] = 141199178Smav{ 142199178Smav { 143199178Smav /* Default */ 144199178Smav { 145199178Smav T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED, 146199178Smav /*vendor*/"*", /*product*/"*", /*revision*/"*" 147199178Smav }, 148199178Smav /*quirks*/0 149199178Smav }, 150199178Smav}; 151195534Sscottl 152195534Sscottlstatic disk_strategy_t adastrategy; 153195534Sscottlstatic dumper_t adadump; 154195534Sscottlstatic periph_init_t adainit; 155195534Sscottlstatic void adaasync(void *callback_arg, u_int32_t code, 156195534Sscottl struct cam_path *path, void *arg); 157195534Sscottlstatic void adasysctlinit(void *context, int pending); 158195534Sscottlstatic periph_ctor_t adaregister; 159195534Sscottlstatic periph_dtor_t adacleanup; 160195534Sscottlstatic periph_start_t adastart; 161195534Sscottlstatic periph_oninv_t adaoninvalidate; 162195534Sscottlstatic void adadone(struct cam_periph *periph, 163195534Sscottl union ccb *done_ccb); 164195534Sscottlstatic int adaerror(union ccb *ccb, u_int32_t cam_flags, 165195534Sscottl u_int32_t sense_flags); 166198897Smavstatic void adagetparams(struct cam_periph *periph, 167195534Sscottl struct ccb_getdev *cgd); 168195534Sscottlstatic timeout_t adasendorderedtag; 169195534Sscottlstatic void adashutdown(void *arg, int howto); 170195534Sscottl 171195534Sscottl#ifndef ADA_DEFAULT_TIMEOUT 172195534Sscottl#define ADA_DEFAULT_TIMEOUT 30 /* Timeout in seconds */ 173195534Sscottl#endif 174195534Sscottl 175195534Sscottl#ifndef ADA_DEFAULT_RETRY 176195534Sscottl#define ADA_DEFAULT_RETRY 4 177195534Sscottl#endif 178195534Sscottl 179195534Sscottl#ifndef ADA_DEFAULT_SEND_ORDERED 180195534Sscottl#define ADA_DEFAULT_SEND_ORDERED 1 181195534Sscottl#endif 182195534Sscottl 183208349Smarius/* 184208349Smarius * Most platforms map firmware geometry to actual, but some don't. If 185208349Smarius * not overridden, default to nothing. 186208349Smarius */ 187208349Smarius#ifndef ata_disk_firmware_geom_adjust 188208349Smarius#define ata_disk_firmware_geom_adjust(disk) 189208349Smarius#endif 190195534Sscottl 191195534Sscottlstatic int ada_retry_count = ADA_DEFAULT_RETRY; 192195534Sscottlstatic int ada_default_timeout = ADA_DEFAULT_TIMEOUT; 193195534Sscottlstatic int ada_send_ordered = ADA_DEFAULT_SEND_ORDERED; 194195534Sscottl 195195534SscottlSYSCTL_NODE(_kern_cam, OID_AUTO, ada, CTLFLAG_RD, 0, 196195534Sscottl "CAM Direct Access Disk driver"); 197195534SscottlSYSCTL_INT(_kern_cam_ada, OID_AUTO, retry_count, CTLFLAG_RW, 198195534Sscottl &ada_retry_count, 0, "Normal I/O retry count"); 199195534SscottlTUNABLE_INT("kern.cam.ada.retry_count", &ada_retry_count); 200195534SscottlSYSCTL_INT(_kern_cam_ada, OID_AUTO, default_timeout, CTLFLAG_RW, 201195534Sscottl &ada_default_timeout, 0, "Normal I/O timeout (in seconds)"); 202195534SscottlTUNABLE_INT("kern.cam.ada.default_timeout", &ada_default_timeout); 203195534SscottlSYSCTL_INT(_kern_cam_ada, OID_AUTO, ada_send_ordered, CTLFLAG_RW, 204195534Sscottl &ada_send_ordered, 0, "Send Ordered Tags"); 205195534SscottlTUNABLE_INT("kern.cam.ada.ada_send_ordered", &ada_send_ordered); 206195534Sscottl 207195534Sscottl/* 208195534Sscottl * ADA_ORDEREDTAG_INTERVAL determines how often, relative 209195534Sscottl * to the default timeout, we check to see whether an ordered 210195534Sscottl * tagged transaction is appropriate to prevent simple tag 211195534Sscottl * starvation. Since we'd like to ensure that there is at least 212195534Sscottl * 1/2 of the timeout length left for a starved transaction to 213195534Sscottl * complete after we've sent an ordered tag, we must poll at least 214195534Sscottl * four times in every timeout period. This takes care of the worst 215195534Sscottl * case where a starved transaction starts during an interval that 216195534Sscottl * meets the requirement "don't send an ordered tag" test so it takes 217195534Sscottl * us two intervals to determine that a tag must be sent. 218195534Sscottl */ 219195534Sscottl#ifndef ADA_ORDEREDTAG_INTERVAL 220195534Sscottl#define ADA_ORDEREDTAG_INTERVAL 4 221195534Sscottl#endif 222195534Sscottl 223195534Sscottlstatic struct periph_driver adadriver = 224195534Sscottl{ 225195534Sscottl adainit, "ada", 226195534Sscottl TAILQ_HEAD_INITIALIZER(adadriver.units), /* generation */ 0 227195534Sscottl}; 228195534Sscottl 229195534SscottlPERIPHDRIVER_DECLARE(ada, adadriver); 230195534Sscottl 231195534SscottlMALLOC_DEFINE(M_ATADA, "ata_da", "ata_da buffers"); 232195534Sscottl 233195534Sscottlstatic int 234195534Sscottladaopen(struct disk *dp) 235195534Sscottl{ 236195534Sscottl struct cam_periph *periph; 237195534Sscottl struct ada_softc *softc; 238195534Sscottl int unit; 239195534Sscottl int error; 240195534Sscottl 241195534Sscottl periph = (struct cam_periph *)dp->d_drv1; 242195534Sscottl if (periph == NULL) { 243195534Sscottl return (ENXIO); 244195534Sscottl } 245195534Sscottl 246195534Sscottl if (cam_periph_acquire(periph) != CAM_REQ_CMP) { 247195534Sscottl return(ENXIO); 248195534Sscottl } 249195534Sscottl 250195534Sscottl cam_periph_lock(periph); 251195534Sscottl if ((error = cam_periph_hold(periph, PRIBIO|PCATCH)) != 0) { 252195534Sscottl cam_periph_unlock(periph); 253195534Sscottl cam_periph_release(periph); 254195534Sscottl return (error); 255195534Sscottl } 256195534Sscottl 257195534Sscottl unit = periph->unit_number; 258195534Sscottl softc = (struct ada_softc *)periph->softc; 259195534Sscottl softc->flags |= ADA_FLAG_OPEN; 260195534Sscottl 261195534Sscottl CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, 262195534Sscottl ("adaopen: disk=%s%d (unit %d)\n", dp->d_name, dp->d_unit, 263195534Sscottl unit)); 264195534Sscottl 265195534Sscottl if ((softc->flags & ADA_FLAG_PACK_INVALID) != 0) { 266195534Sscottl /* Invalidate our pack information. */ 267195534Sscottl softc->flags &= ~ADA_FLAG_PACK_INVALID; 268195534Sscottl } 269195534Sscottl 270195534Sscottl cam_periph_unhold(periph); 271195534Sscottl cam_periph_unlock(periph); 272195534Sscottl return (0); 273195534Sscottl} 274195534Sscottl 275195534Sscottlstatic int 276195534Sscottladaclose(struct disk *dp) 277195534Sscottl{ 278195534Sscottl struct cam_periph *periph; 279195534Sscottl struct ada_softc *softc; 280195534Sscottl union ccb *ccb; 281195534Sscottl int error; 282195534Sscottl 283195534Sscottl periph = (struct cam_periph *)dp->d_drv1; 284195534Sscottl if (periph == NULL) 285195534Sscottl return (ENXIO); 286195534Sscottl 287195534Sscottl cam_periph_lock(periph); 288195534Sscottl if ((error = cam_periph_hold(periph, PRIBIO)) != 0) { 289195534Sscottl cam_periph_unlock(periph); 290195534Sscottl cam_periph_release(periph); 291195534Sscottl return (error); 292195534Sscottl } 293195534Sscottl 294195534Sscottl softc = (struct ada_softc *)periph->softc; 295195534Sscottl /* We only sync the cache if the drive is capable of it. */ 296195534Sscottl if (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) { 297195534Sscottl 298198382Smav ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 299195534Sscottl cam_fill_ataio(&ccb->ataio, 300195534Sscottl 1, 301195534Sscottl adadone, 302195534Sscottl CAM_DIR_NONE, 303195534Sscottl 0, 304195534Sscottl NULL, 305195534Sscottl 0, 306195534Sscottl ada_default_timeout*1000); 307195534Sscottl 308195534Sscottl if (softc->flags & ADA_FLAG_CAN_48BIT) 309195534Sscottl ata_48bit_cmd(&ccb->ataio, ATA_FLUSHCACHE48, 0, 0, 0); 310195534Sscottl else 311196659Smav ata_28bit_cmd(&ccb->ataio, ATA_FLUSHCACHE, 0, 0, 0); 312195748Smav cam_periph_runccb(ccb, /*error_routine*/NULL, /*cam_flags*/0, 313198328Smav /*sense_flags*/0, softc->disk->d_devstat); 314195534Sscottl 315195534Sscottl if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) 316195534Sscottl xpt_print(periph->path, "Synchronize cache failed\n"); 317195534Sscottl 318195534Sscottl if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 319195534Sscottl cam_release_devq(ccb->ccb_h.path, 320195534Sscottl /*relsim_flags*/0, 321195534Sscottl /*reduction*/0, 322195534Sscottl /*timeout*/0, 323195534Sscottl /*getcount_only*/0); 324195534Sscottl xpt_release_ccb(ccb); 325195534Sscottl } 326195534Sscottl 327195534Sscottl softc->flags &= ~ADA_FLAG_OPEN; 328195534Sscottl cam_periph_unhold(periph); 329195534Sscottl cam_periph_unlock(periph); 330195534Sscottl cam_periph_release(periph); 331195534Sscottl return (0); 332195534Sscottl} 333195534Sscottl 334201139Smavstatic void 335201139Smavadaschedule(struct cam_periph *periph) 336201139Smav{ 337201139Smav struct ada_softc *softc = (struct ada_softc *)periph->softc; 338201139Smav 339201139Smav if (bioq_first(&softc->bio_queue) || 340201139Smav (!softc->trim_running && bioq_first(&softc->trim_queue))) { 341201139Smav /* Have more work to do, so ensure we stay scheduled */ 342201139Smav xpt_schedule(periph, CAM_PRIORITY_NORMAL); 343201139Smav } 344201139Smav} 345201139Smav 346195534Sscottl/* 347195534Sscottl * Actually translate the requested transfer into one the physical driver 348195534Sscottl * can understand. The transfer is described by a buf and will include 349195534Sscottl * only one physical transfer. 350195534Sscottl */ 351195534Sscottlstatic void 352195534Sscottladastrategy(struct bio *bp) 353195534Sscottl{ 354195534Sscottl struct cam_periph *periph; 355195534Sscottl struct ada_softc *softc; 356195534Sscottl 357195534Sscottl periph = (struct cam_periph *)bp->bio_disk->d_drv1; 358195534Sscottl if (periph == NULL) { 359195534Sscottl biofinish(bp, NULL, ENXIO); 360195534Sscottl return; 361195534Sscottl } 362195534Sscottl softc = (struct ada_softc *)periph->softc; 363195534Sscottl 364195534Sscottl cam_periph_lock(periph); 365195534Sscottl 366195534Sscottl /* 367195534Sscottl * If the device has been made invalid, error out 368195534Sscottl */ 369195534Sscottl if ((softc->flags & ADA_FLAG_PACK_INVALID)) { 370195534Sscottl cam_periph_unlock(periph); 371195534Sscottl biofinish(bp, NULL, ENXIO); 372195534Sscottl return; 373195534Sscottl } 374195534Sscottl 375195534Sscottl /* 376195534Sscottl * Place it in the queue of disk activities for this disk 377195534Sscottl */ 378201139Smav if (bp->bio_cmd == BIO_DELETE && 379201139Smav (softc->flags & ADA_FLAG_CAN_TRIM)) 380201139Smav bioq_disksort(&softc->trim_queue, bp); 381201139Smav else 382201139Smav bioq_disksort(&softc->bio_queue, bp); 383195534Sscottl 384195534Sscottl /* 385195534Sscottl * Schedule ourselves for performing the work. 386195534Sscottl */ 387201139Smav adaschedule(periph); 388195534Sscottl cam_periph_unlock(periph); 389195534Sscottl 390195534Sscottl return; 391195534Sscottl} 392195534Sscottl 393195534Sscottlstatic int 394195534Sscottladadump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t length) 395195534Sscottl{ 396195534Sscottl struct cam_periph *periph; 397195534Sscottl struct ada_softc *softc; 398195534Sscottl u_int secsize; 399195534Sscottl union ccb ccb; 400195534Sscottl struct disk *dp; 401195534Sscottl uint64_t lba; 402195534Sscottl uint16_t count; 403195534Sscottl 404195534Sscottl dp = arg; 405195534Sscottl periph = dp->d_drv1; 406195534Sscottl if (periph == NULL) 407195534Sscottl return (ENXIO); 408195534Sscottl softc = (struct ada_softc *)periph->softc; 409195534Sscottl cam_periph_lock(periph); 410195534Sscottl secsize = softc->params.secsize; 411195534Sscottl lba = offset / secsize; 412195534Sscottl count = length / secsize; 413195534Sscottl 414195534Sscottl if ((softc->flags & ADA_FLAG_PACK_INVALID) != 0) { 415195534Sscottl cam_periph_unlock(periph); 416195534Sscottl return (ENXIO); 417195534Sscottl } 418195534Sscottl 419195534Sscottl if (length > 0) { 420198382Smav xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 421195534Sscottl ccb.ccb_h.ccb_state = ADA_CCB_DUMP; 422195534Sscottl cam_fill_ataio(&ccb.ataio, 423195534Sscottl 0, 424195534Sscottl adadone, 425195534Sscottl CAM_DIR_OUT, 426195534Sscottl 0, 427195534Sscottl (u_int8_t *) virtual, 428195534Sscottl length, 429195534Sscottl ada_default_timeout*1000); 430195534Sscottl if ((softc->flags & ADA_FLAG_CAN_48BIT) && 431195534Sscottl (lba + count >= ATA_MAX_28BIT_LBA || 432195534Sscottl count >= 256)) { 433195534Sscottl ata_48bit_cmd(&ccb.ataio, ATA_WRITE_DMA48, 434195534Sscottl 0, lba, count); 435195534Sscottl } else { 436196659Smav ata_28bit_cmd(&ccb.ataio, ATA_WRITE_DMA, 437195534Sscottl 0, lba, count); 438195534Sscottl } 439195534Sscottl xpt_polled_action(&ccb); 440195534Sscottl 441195534Sscottl if ((ccb.ataio.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 442195534Sscottl printf("Aborting dump due to I/O error.\n"); 443195534Sscottl cam_periph_unlock(periph); 444195534Sscottl return(EIO); 445195534Sscottl } 446195534Sscottl cam_periph_unlock(periph); 447195534Sscottl return(0); 448195534Sscottl } 449195534Sscottl 450195534Sscottl if (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) { 451198382Smav xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 452195534Sscottl 453195534Sscottl ccb.ccb_h.ccb_state = ADA_CCB_DUMP; 454195534Sscottl cam_fill_ataio(&ccb.ataio, 455195534Sscottl 1, 456195534Sscottl adadone, 457195534Sscottl CAM_DIR_NONE, 458195534Sscottl 0, 459195534Sscottl NULL, 460195534Sscottl 0, 461195534Sscottl ada_default_timeout*1000); 462195534Sscottl 463195534Sscottl if (softc->flags & ADA_FLAG_CAN_48BIT) 464195534Sscottl ata_48bit_cmd(&ccb.ataio, ATA_FLUSHCACHE48, 0, 0, 0); 465195534Sscottl else 466196659Smav ata_28bit_cmd(&ccb.ataio, ATA_FLUSHCACHE, 0, 0, 0); 467195534Sscottl xpt_polled_action(&ccb); 468195534Sscottl 469195534Sscottl if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) 470195534Sscottl xpt_print(periph->path, "Synchronize cache failed\n"); 471195534Sscottl 472195534Sscottl if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0) 473195534Sscottl cam_release_devq(ccb.ccb_h.path, 474195534Sscottl /*relsim_flags*/0, 475195534Sscottl /*reduction*/0, 476195534Sscottl /*timeout*/0, 477195534Sscottl /*getcount_only*/0); 478195534Sscottl } 479195534Sscottl cam_periph_unlock(periph); 480195534Sscottl return (0); 481195534Sscottl} 482195534Sscottl 483195534Sscottlstatic void 484195534Sscottladainit(void) 485195534Sscottl{ 486195534Sscottl cam_status status; 487195534Sscottl 488195534Sscottl /* 489195534Sscottl * Install a global async callback. This callback will 490195534Sscottl * receive async callbacks like "new device found". 491195534Sscottl */ 492195534Sscottl status = xpt_register_async(AC_FOUND_DEVICE, adaasync, NULL, NULL); 493195534Sscottl 494195534Sscottl if (status != CAM_REQ_CMP) { 495195534Sscottl printf("ada: Failed to attach master async callback " 496195534Sscottl "due to status 0x%x!\n", status); 497195534Sscottl } else if (ada_send_ordered) { 498195534Sscottl 499195534Sscottl /* Register our shutdown event handler */ 500195534Sscottl if ((EVENTHANDLER_REGISTER(shutdown_post_sync, adashutdown, 501195534Sscottl NULL, SHUTDOWN_PRI_DEFAULT)) == NULL) 502195534Sscottl printf("adainit: shutdown event registration failed!\n"); 503195534Sscottl } 504195534Sscottl} 505195534Sscottl 506195534Sscottlstatic void 507195534Sscottladaoninvalidate(struct cam_periph *periph) 508195534Sscottl{ 509195534Sscottl struct ada_softc *softc; 510195534Sscottl 511195534Sscottl softc = (struct ada_softc *)periph->softc; 512195534Sscottl 513195534Sscottl /* 514195534Sscottl * De-register any async callbacks. 515195534Sscottl */ 516195534Sscottl xpt_register_async(0, adaasync, periph, periph->path); 517195534Sscottl 518195534Sscottl softc->flags |= ADA_FLAG_PACK_INVALID; 519195534Sscottl 520195534Sscottl /* 521195534Sscottl * Return all queued I/O with ENXIO. 522195534Sscottl * XXX Handle any transactions queued to the card 523195534Sscottl * with XPT_ABORT_CCB. 524195534Sscottl */ 525195534Sscottl bioq_flush(&softc->bio_queue, NULL, ENXIO); 526201139Smav bioq_flush(&softc->trim_queue, NULL, ENXIO); 527195534Sscottl 528195534Sscottl disk_gone(softc->disk); 529195534Sscottl xpt_print(periph->path, "lost device\n"); 530195534Sscottl} 531195534Sscottl 532195534Sscottlstatic void 533195534Sscottladacleanup(struct cam_periph *periph) 534195534Sscottl{ 535195534Sscottl struct ada_softc *softc; 536195534Sscottl 537195534Sscottl softc = (struct ada_softc *)periph->softc; 538195534Sscottl 539195534Sscottl xpt_print(periph->path, "removing device entry\n"); 540195534Sscottl cam_periph_unlock(periph); 541195534Sscottl 542195534Sscottl /* 543195534Sscottl * If we can't free the sysctl tree, oh well... 544195534Sscottl */ 545195534Sscottl if ((softc->flags & ADA_FLAG_SCTX_INIT) != 0 546195534Sscottl && sysctl_ctx_free(&softc->sysctl_ctx) != 0) { 547195534Sscottl xpt_print(periph->path, "can't remove sysctl context\n"); 548195534Sscottl } 549195534Sscottl 550195534Sscottl disk_destroy(softc->disk); 551195534Sscottl callout_drain(&softc->sendordered_c); 552195534Sscottl free(softc, M_DEVBUF); 553195534Sscottl cam_periph_lock(periph); 554195534Sscottl} 555195534Sscottl 556195534Sscottlstatic void 557195534Sscottladaasync(void *callback_arg, u_int32_t code, 558195534Sscottl struct cam_path *path, void *arg) 559195534Sscottl{ 560195534Sscottl struct cam_periph *periph; 561195534Sscottl 562195534Sscottl periph = (struct cam_periph *)callback_arg; 563195534Sscottl switch (code) { 564195534Sscottl case AC_FOUND_DEVICE: 565195534Sscottl { 566195534Sscottl struct ccb_getdev *cgd; 567195534Sscottl cam_status status; 568195534Sscottl 569195534Sscottl cgd = (struct ccb_getdev *)arg; 570195534Sscottl if (cgd == NULL) 571195534Sscottl break; 572195534Sscottl 573195534Sscottl if (cgd->protocol != PROTO_ATA) 574195534Sscottl break; 575195534Sscottl 576195534Sscottl /* 577195534Sscottl * Allocate a peripheral instance for 578195534Sscottl * this device and start the probe 579195534Sscottl * process. 580195534Sscottl */ 581195534Sscottl status = cam_periph_alloc(adaregister, adaoninvalidate, 582195534Sscottl adacleanup, adastart, 583195534Sscottl "ada", CAM_PERIPH_BIO, 584195534Sscottl cgd->ccb_h.path, adaasync, 585195534Sscottl AC_FOUND_DEVICE, cgd); 586195534Sscottl 587195534Sscottl if (status != CAM_REQ_CMP 588195534Sscottl && status != CAM_REQ_INPROG) 589195534Sscottl printf("adaasync: Unable to attach to new device " 590195534Sscottl "due to status 0x%x\n", status); 591195534Sscottl break; 592195534Sscottl } 593195534Sscottl default: 594195534Sscottl cam_periph_async(periph, code, path, arg); 595195534Sscottl break; 596195534Sscottl } 597195534Sscottl} 598195534Sscottl 599195534Sscottlstatic void 600195534Sscottladasysctlinit(void *context, int pending) 601195534Sscottl{ 602195534Sscottl struct cam_periph *periph; 603195534Sscottl struct ada_softc *softc; 604195534Sscottl char tmpstr[80], tmpstr2[80]; 605195534Sscottl 606195534Sscottl periph = (struct cam_periph *)context; 607195534Sscottl if (cam_periph_acquire(periph) != CAM_REQ_CMP) 608195534Sscottl return; 609195534Sscottl 610195534Sscottl softc = (struct ada_softc *)periph->softc; 611195534Sscottl snprintf(tmpstr, sizeof(tmpstr), "CAM ADA unit %d", periph->unit_number); 612195534Sscottl snprintf(tmpstr2, sizeof(tmpstr2), "%d", periph->unit_number); 613195534Sscottl 614195534Sscottl sysctl_ctx_init(&softc->sysctl_ctx); 615195534Sscottl softc->flags |= ADA_FLAG_SCTX_INIT; 616195534Sscottl softc->sysctl_tree = SYSCTL_ADD_NODE(&softc->sysctl_ctx, 617195534Sscottl SYSCTL_STATIC_CHILDREN(_kern_cam_ada), OID_AUTO, tmpstr2, 618195534Sscottl CTLFLAG_RD, 0, tmpstr); 619195534Sscottl if (softc->sysctl_tree == NULL) { 620195534Sscottl printf("adasysctlinit: unable to allocate sysctl tree\n"); 621195534Sscottl cam_periph_release(periph); 622195534Sscottl return; 623195534Sscottl } 624195534Sscottl 625195534Sscottl cam_periph_release(periph); 626195534Sscottl} 627195534Sscottl 628195534Sscottlstatic cam_status 629195534Sscottladaregister(struct cam_periph *periph, void *arg) 630195534Sscottl{ 631195534Sscottl struct ada_softc *softc; 632195534Sscottl struct ccb_pathinq cpi; 633195534Sscottl struct ccb_getdev *cgd; 634195534Sscottl char announce_buf[80]; 635195534Sscottl struct disk_params *dp; 636195534Sscottl caddr_t match; 637195534Sscottl u_int maxio; 638195534Sscottl 639195534Sscottl cgd = (struct ccb_getdev *)arg; 640195534Sscottl if (periph == NULL) { 641195534Sscottl printf("adaregister: periph was NULL!!\n"); 642195534Sscottl return(CAM_REQ_CMP_ERR); 643195534Sscottl } 644195534Sscottl 645195534Sscottl if (cgd == NULL) { 646195534Sscottl printf("adaregister: no getdev CCB, can't register device\n"); 647195534Sscottl return(CAM_REQ_CMP_ERR); 648195534Sscottl } 649195534Sscottl 650195534Sscottl softc = (struct ada_softc *)malloc(sizeof(*softc), M_DEVBUF, 651195534Sscottl M_NOWAIT|M_ZERO); 652195534Sscottl 653195534Sscottl if (softc == NULL) { 654195534Sscottl printf("adaregister: Unable to probe new device. " 655198328Smav "Unable to allocate softc\n"); 656195534Sscottl return(CAM_REQ_CMP_ERR); 657195534Sscottl } 658195534Sscottl 659195534Sscottl bioq_init(&softc->bio_queue); 660201139Smav bioq_init(&softc->trim_queue); 661195534Sscottl 662198328Smav if (cgd->ident_data.capabilities1 & ATA_SUPPORT_DMA) 663198328Smav softc->flags |= ADA_FLAG_CAN_DMA; 664195534Sscottl if (cgd->ident_data.support.command2 & ATA_SUPPORT_ADDRESS48) 665195534Sscottl softc->flags |= ADA_FLAG_CAN_48BIT; 666195534Sscottl if (cgd->ident_data.support.command2 & ATA_SUPPORT_FLUSHCACHE) 667195534Sscottl softc->flags |= ADA_FLAG_CAN_FLUSHCACHE; 668195534Sscottl if (cgd->ident_data.satacapabilities & ATA_SUPPORT_NCQ && 669199178Smav cgd->inq_flags & SID_CmdQue) 670195534Sscottl softc->flags |= ADA_FLAG_CAN_NCQ; 671201139Smav if (cgd->ident_data.support_dsm & ATA_SUPPORT_DSM_TRIM) { 672201139Smav softc->flags |= ADA_FLAG_CAN_TRIM; 673201139Smav softc->trim_max_ranges = TRIM_MAX_RANGES; 674201139Smav if (cgd->ident_data.max_dsm_blocks != 0) { 675201139Smav softc->trim_max_ranges = 676201139Smav min(cgd->ident_data.max_dsm_blocks * 64, 677201139Smav softc->trim_max_ranges); 678201139Smav } 679201139Smav } 680201139Smav if (cgd->ident_data.support.command2 & ATA_SUPPORT_CFA) 681201139Smav softc->flags |= ADA_FLAG_CAN_CFA; 682198708Smav softc->state = ADA_STATE_NORMAL; 683195534Sscottl 684195534Sscottl periph->softc = softc; 685195534Sscottl 686195534Sscottl /* 687195534Sscottl * See if this device has any quirks. 688195534Sscottl */ 689199178Smav match = cam_quirkmatch((caddr_t)&cgd->ident_data, 690199178Smav (caddr_t)ada_quirk_table, 691199178Smav sizeof(ada_quirk_table)/sizeof(*ada_quirk_table), 692199178Smav sizeof(*ada_quirk_table), ata_identify_match); 693195534Sscottl if (match != NULL) 694195534Sscottl softc->quirks = ((struct ada_quirk_entry *)match)->quirks; 695195534Sscottl else 696195534Sscottl softc->quirks = ADA_Q_NONE; 697195534Sscottl 698195534Sscottl bzero(&cpi, sizeof(cpi)); 699203108Smav xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NONE); 700195534Sscottl cpi.ccb_h.func_code = XPT_PATH_INQ; 701195534Sscottl xpt_action((union ccb *)&cpi); 702195534Sscottl 703195534Sscottl TASK_INIT(&softc->sysctl_task, 0, adasysctlinit, periph); 704195534Sscottl 705195534Sscottl /* 706195534Sscottl * Register this media as a disk 707195534Sscottl */ 708195534Sscottl mtx_unlock(periph->sim->mtx); 709198897Smav adagetparams(periph, cgd); 710195534Sscottl softc->disk = disk_alloc(); 711195534Sscottl softc->disk->d_open = adaopen; 712195534Sscottl softc->disk->d_close = adaclose; 713195534Sscottl softc->disk->d_strategy = adastrategy; 714195534Sscottl softc->disk->d_dump = adadump; 715195534Sscottl softc->disk->d_name = "ada"; 716195534Sscottl softc->disk->d_drv1 = periph; 717195534Sscottl maxio = cpi.maxio; /* Honor max I/O size of SIM */ 718195534Sscottl if (maxio == 0) 719195534Sscottl maxio = DFLTPHYS; /* traditional default */ 720195534Sscottl else if (maxio > MAXPHYS) 721195534Sscottl maxio = MAXPHYS; /* for safety */ 722201139Smav if (softc->flags & ADA_FLAG_CAN_48BIT) 723198897Smav maxio = min(maxio, 65536 * softc->params.secsize); 724195534Sscottl else /* 28bit ATA command limit */ 725198897Smav maxio = min(maxio, 256 * softc->params.secsize); 726195534Sscottl softc->disk->d_maxsize = maxio; 727195534Sscottl softc->disk->d_unit = periph->unit_number; 728195534Sscottl softc->disk->d_flags = 0; 729195534Sscottl if (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) 730195534Sscottl softc->disk->d_flags |= DISKFLAG_CANFLUSHCACHE; 731201139Smav if ((softc->flags & ADA_FLAG_CAN_TRIM) || 732201139Smav ((softc->flags & ADA_FLAG_CAN_CFA) && 733201139Smav !(softc->flags & ADA_FLAG_CAN_48BIT))) 734201139Smav softc->disk->d_flags |= DISKFLAG_CANDELETE; 735197896Spjd strlcpy(softc->disk->d_ident, cgd->serial_num, 736197896Spjd MIN(sizeof(softc->disk->d_ident), cgd->serial_num_len + 1)); 737195534Sscottl 738195534Sscottl softc->disk->d_sectorsize = softc->params.secsize; 739198897Smav softc->disk->d_mediasize = (off_t)softc->params.sectors * 740198897Smav softc->params.secsize; 741200969Smav if (ata_physical_sector_size(&cgd->ident_data) != 742200969Smav softc->params.secsize) { 743200969Smav softc->disk->d_stripesize = 744200969Smav ata_physical_sector_size(&cgd->ident_data); 745200969Smav softc->disk->d_stripeoffset = (softc->disk->d_stripesize - 746200969Smav ata_logical_sector_offset(&cgd->ident_data)) % 747200969Smav softc->disk->d_stripesize; 748200969Smav } 749195534Sscottl softc->disk->d_fwsectors = softc->params.secs_per_track; 750195534Sscottl softc->disk->d_fwheads = softc->params.heads; 751208349Smarius ata_disk_firmware_geom_adjust(softc->disk); 752195534Sscottl 753195534Sscottl disk_create(softc->disk, DISK_VERSION); 754195534Sscottl mtx_lock(periph->sim->mtx); 755195534Sscottl 756195534Sscottl dp = &softc->params; 757195534Sscottl snprintf(announce_buf, sizeof(announce_buf), 758195534Sscottl "%juMB (%ju %u byte sectors: %dH %dS/T %dC)", 759195534Sscottl (uintmax_t)(((uintmax_t)dp->secsize * 760195534Sscottl dp->sectors) / (1024*1024)), 761195534Sscottl (uintmax_t)dp->sectors, 762195534Sscottl dp->secsize, dp->heads, 763195534Sscottl dp->secs_per_track, dp->cylinders); 764195534Sscottl xpt_announce_periph(periph, announce_buf); 765195534Sscottl /* 766195534Sscottl * Add async callbacks for bus reset and 767195534Sscottl * bus device reset calls. I don't bother 768195534Sscottl * checking if this fails as, in most cases, 769195534Sscottl * the system will function just fine without 770195534Sscottl * them and the only alternative would be to 771195534Sscottl * not attach the device on failure. 772195534Sscottl */ 773198708Smav xpt_register_async(AC_LOST_DEVICE, 774195534Sscottl adaasync, periph, periph->path); 775195534Sscottl 776195534Sscottl /* 777195534Sscottl * Schedule a periodic event to occasionally send an 778195534Sscottl * ordered tag to a device. 779195534Sscottl */ 780195534Sscottl callout_init_mtx(&softc->sendordered_c, periph->sim->mtx, 0); 781195534Sscottl callout_reset(&softc->sendordered_c, 782195534Sscottl (ADA_DEFAULT_TIMEOUT * hz) / ADA_ORDEREDTAG_INTERVAL, 783195534Sscottl adasendorderedtag, softc); 784195534Sscottl 785195534Sscottl return(CAM_REQ_CMP); 786195534Sscottl} 787195534Sscottl 788195534Sscottlstatic void 789195534Sscottladastart(struct cam_periph *periph, union ccb *start_ccb) 790195534Sscottl{ 791198328Smav struct ada_softc *softc = (struct ada_softc *)periph->softc; 792198328Smav struct ccb_ataio *ataio = &start_ccb->ataio; 793195534Sscottl 794195534Sscottl switch (softc->state) { 795195534Sscottl case ADA_STATE_NORMAL: 796195534Sscottl { 797195534Sscottl struct bio *bp; 798201139Smav u_int8_t tag_code; 799195534Sscottl 800201139Smav /* Execute immediate CCB if waiting. */ 801195534Sscottl if (periph->immediate_priority <= periph->pinfo.priority) { 802195534Sscottl CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE, 803195534Sscottl ("queuing for immediate ccb\n")); 804195534Sscottl start_ccb->ccb_h.ccb_state = ADA_CCB_WAITING; 805195534Sscottl SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, 806195534Sscottl periph_links.sle); 807195534Sscottl periph->immediate_priority = CAM_PRIORITY_NONE; 808195534Sscottl wakeup(&periph->ccb_list); 809201139Smav /* Have more work to do, so ensure we stay scheduled */ 810201139Smav adaschedule(periph); 811201139Smav break; 812201139Smav } 813201139Smav /* Run TRIM if not running yet. */ 814201139Smav if (!softc->trim_running && 815201139Smav (bp = bioq_first(&softc->trim_queue)) != 0) { 816201139Smav struct trim_request *req = &softc->trim_req; 817201139Smav struct bio *bp1; 818201139Smav int bps = 0, ranges = 0; 819201139Smav 820201139Smav softc->trim_running = 1; 821201139Smav bzero(req, sizeof(*req)); 822201139Smav bp1 = bp; 823201139Smav do { 824201139Smav uint64_t lba = bp1->bio_pblkno; 825201139Smav int count = bp1->bio_bcount / 826201139Smav softc->params.secsize; 827201139Smav 828201139Smav bioq_remove(&softc->trim_queue, bp1); 829201139Smav while (count > 0) { 830201139Smav int c = min(count, 0xffff); 831201139Smav int off = ranges * 8; 832201139Smav 833201139Smav req->data[off + 0] = lba & 0xff; 834201139Smav req->data[off + 1] = (lba >> 8) & 0xff; 835201139Smav req->data[off + 2] = (lba >> 16) & 0xff; 836201139Smav req->data[off + 3] = (lba >> 24) & 0xff; 837201139Smav req->data[off + 4] = (lba >> 32) & 0xff; 838201139Smav req->data[off + 5] = (lba >> 40) & 0xff; 839201139Smav req->data[off + 6] = c & 0xff; 840201139Smav req->data[off + 7] = (c >> 8) & 0xff; 841201139Smav lba += c; 842201139Smav count -= c; 843201139Smav ranges++; 844201139Smav } 845201139Smav req->bps[bps++] = bp1; 846201139Smav bp1 = bioq_first(&softc->trim_queue); 847201139Smav if (bp1 == NULL || 848201139Smav bp1->bio_bcount / softc->params.secsize > 849201139Smav (softc->trim_max_ranges - ranges) * 0xffff) 850201139Smav break; 851201139Smav } while (1); 852201139Smav cam_fill_ataio(ataio, 853201139Smav ada_retry_count, 854201139Smav adadone, 855201139Smav CAM_DIR_OUT, 856201139Smav 0, 857201139Smav req->data, 858201139Smav ((ranges + 63) / 64) * 512, 859201139Smav ada_default_timeout * 1000); 860201139Smav ata_48bit_cmd(ataio, ATA_DATA_SET_MANAGEMENT, 861201139Smav ATA_DSM_TRIM, 0, (ranges + 63) / 64); 862201139Smav start_ccb->ccb_h.ccb_state = ADA_CCB_TRIM; 863201139Smav goto out; 864201139Smav } 865201139Smav /* Run regular command. */ 866201139Smav bp = bioq_first(&softc->bio_queue); 867201139Smav if (bp == NULL) { 868195534Sscottl xpt_release_ccb(start_ccb); 869201139Smav break; 870201139Smav } 871201139Smav bioq_remove(&softc->bio_queue, bp); 872201139Smav 873201139Smav if ((softc->flags & ADA_FLAG_NEED_OTAG) != 0) { 874201139Smav softc->flags &= ~ADA_FLAG_NEED_OTAG; 875201139Smav softc->ordered_tag_count++; 876201139Smav tag_code = 0; 877195534Sscottl } else { 878201139Smav tag_code = 1; 879201139Smav } 880201139Smav switch (bp->bio_cmd) { 881201139Smav case BIO_READ: 882201139Smav case BIO_WRITE: 883201139Smav { 884201139Smav uint64_t lba = bp->bio_pblkno; 885201139Smav uint16_t count = bp->bio_bcount / softc->params.secsize; 886195534Sscottl 887201139Smav cam_fill_ataio(ataio, 888201139Smav ada_retry_count, 889201139Smav adadone, 890201139Smav bp->bio_cmd == BIO_READ ? 891201139Smav CAM_DIR_IN : CAM_DIR_OUT, 892201139Smav tag_code, 893201139Smav bp->bio_data, 894201139Smav bp->bio_bcount, 895201139Smav ada_default_timeout*1000); 896195534Sscottl 897201139Smav if ((softc->flags & ADA_FLAG_CAN_NCQ) && tag_code) { 898201139Smav if (bp->bio_cmd == BIO_READ) { 899201139Smav ata_ncq_cmd(ataio, ATA_READ_FPDMA_QUEUED, 900201139Smav lba, count); 901201139Smav } else { 902201139Smav ata_ncq_cmd(ataio, ATA_WRITE_FPDMA_QUEUED, 903201139Smav lba, count); 904201139Smav } 905201139Smav } else if ((softc->flags & ADA_FLAG_CAN_48BIT) && 906201139Smav (lba + count >= ATA_MAX_28BIT_LBA || 907201139Smav count > 256)) { 908201139Smav if (softc->flags & ADA_FLAG_CAN_DMA) { 909195534Sscottl if (bp->bio_cmd == BIO_READ) { 910201139Smav ata_48bit_cmd(ataio, ATA_READ_DMA48, 911201139Smav 0, lba, count); 912195534Sscottl } else { 913201139Smav ata_48bit_cmd(ataio, ATA_WRITE_DMA48, 914201139Smav 0, lba, count); 915195534Sscottl } 916201139Smav } else { 917201139Smav if (bp->bio_cmd == BIO_READ) { 918201139Smav ata_48bit_cmd(ataio, ATA_READ_MUL48, 919201139Smav 0, lba, count); 920195534Sscottl } else { 921201139Smav ata_48bit_cmd(ataio, ATA_WRITE_MUL48, 922201139Smav 0, lba, count); 923195534Sscottl } 924201139Smav } 925201139Smav } else { 926201139Smav if (count == 256) 927201139Smav count = 0; 928201139Smav if (softc->flags & ADA_FLAG_CAN_DMA) { 929201139Smav if (bp->bio_cmd == BIO_READ) { 930201139Smav ata_28bit_cmd(ataio, ATA_READ_DMA, 931201139Smav 0, lba, count); 932201139Smav } else { 933201139Smav ata_28bit_cmd(ataio, ATA_WRITE_DMA, 934201139Smav 0, lba, count); 935201139Smav } 936195534Sscottl } else { 937201139Smav if (bp->bio_cmd == BIO_READ) { 938201139Smav ata_28bit_cmd(ataio, ATA_READ_MUL, 939201139Smav 0, lba, count); 940195534Sscottl } else { 941201139Smav ata_28bit_cmd(ataio, ATA_WRITE_MUL, 942201139Smav 0, lba, count); 943195534Sscottl } 944195534Sscottl } 945195534Sscottl } 946201139Smav break; 947201139Smav } 948201139Smav case BIO_DELETE: 949201139Smav { 950201139Smav uint64_t lba = bp->bio_pblkno; 951201139Smav uint16_t count = bp->bio_bcount / softc->params.secsize; 952195534Sscottl 953201139Smav cam_fill_ataio(ataio, 954201139Smav ada_retry_count, 955201139Smav adadone, 956201139Smav CAM_DIR_NONE, 957201139Smav 0, 958201139Smav NULL, 959201139Smav 0, 960201139Smav ada_default_timeout*1000); 961201139Smav 962201139Smav if (count >= 256) 963201139Smav count = 0; 964201139Smav ata_28bit_cmd(ataio, ATA_CFA_ERASE, 0, lba, count); 965201139Smav break; 966195534Sscottl } 967201139Smav case BIO_FLUSH: 968201139Smav cam_fill_ataio(ataio, 969201139Smav 1, 970201139Smav adadone, 971201139Smav CAM_DIR_NONE, 972201139Smav 0, 973201139Smav NULL, 974201139Smav 0, 975201139Smav ada_default_timeout*1000); 976201139Smav 977201139Smav if (softc->flags & ADA_FLAG_CAN_48BIT) 978201139Smav ata_48bit_cmd(ataio, ATA_FLUSHCACHE48, 0, 0, 0); 979201139Smav else 980201139Smav ata_28bit_cmd(ataio, ATA_FLUSHCACHE, 0, 0, 0); 981201139Smav break; 982195534Sscottl } 983201139Smav start_ccb->ccb_h.ccb_state = ADA_CCB_BUFFER_IO; 984201139Smavout: 985201139Smav start_ccb->ccb_h.ccb_bp = bp; 986201139Smav softc->outstanding_cmds++; 987201139Smav xpt_action(start_ccb); 988201139Smav 989201139Smav /* May have more work to do, so ensure we stay scheduled */ 990201139Smav adaschedule(periph); 991195534Sscottl break; 992195534Sscottl } 993195534Sscottl } 994195534Sscottl} 995195534Sscottl 996195534Sscottlstatic void 997195534Sscottladadone(struct cam_periph *periph, union ccb *done_ccb) 998195534Sscottl{ 999195534Sscottl struct ada_softc *softc; 1000195534Sscottl struct ccb_ataio *ataio; 1001195534Sscottl 1002195534Sscottl softc = (struct ada_softc *)periph->softc; 1003195534Sscottl ataio = &done_ccb->ataio; 1004195534Sscottl switch (ataio->ccb_h.ccb_state & ADA_CCB_TYPE_MASK) { 1005195534Sscottl case ADA_CCB_BUFFER_IO: 1006201139Smav case ADA_CCB_TRIM: 1007195534Sscottl { 1008195534Sscottl struct bio *bp; 1009195534Sscottl 1010195534Sscottl bp = (struct bio *)done_ccb->ccb_h.ccb_bp; 1011195534Sscottl if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 1012195534Sscottl int error; 1013195534Sscottl 1014198328Smav error = adaerror(done_ccb, 0, 0); 1015195534Sscottl if (error == ERESTART) { 1016198328Smav /* A retry was scheduled, so just return. */ 1017195534Sscottl return; 1018195534Sscottl } 1019195534Sscottl if (error != 0) { 1020195534Sscottl if (error == ENXIO) { 1021195534Sscottl /* 1022195534Sscottl * Catastrophic error. Mark our pack as 1023195534Sscottl * invalid. 1024195534Sscottl */ 1025195534Sscottl /* 1026195534Sscottl * XXX See if this is really a media 1027195534Sscottl * XXX change first? 1028195534Sscottl */ 1029195534Sscottl xpt_print(periph->path, 1030195534Sscottl "Invalidating pack\n"); 1031195534Sscottl softc->flags |= ADA_FLAG_PACK_INVALID; 1032195534Sscottl } 1033195534Sscottl bp->bio_error = error; 1034195534Sscottl bp->bio_resid = bp->bio_bcount; 1035195534Sscottl bp->bio_flags |= BIO_ERROR; 1036195534Sscottl } else { 1037195534Sscottl bp->bio_resid = ataio->resid; 1038195534Sscottl bp->bio_error = 0; 1039195534Sscottl if (bp->bio_resid != 0) 1040195534Sscottl bp->bio_flags |= BIO_ERROR; 1041195534Sscottl } 1042195534Sscottl if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 1043195534Sscottl cam_release_devq(done_ccb->ccb_h.path, 1044195534Sscottl /*relsim_flags*/0, 1045195534Sscottl /*reduction*/0, 1046195534Sscottl /*timeout*/0, 1047195534Sscottl /*getcount_only*/0); 1048195534Sscottl } else { 1049195534Sscottl if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 1050195534Sscottl panic("REQ_CMP with QFRZN"); 1051195534Sscottl bp->bio_resid = ataio->resid; 1052195534Sscottl if (ataio->resid > 0) 1053195534Sscottl bp->bio_flags |= BIO_ERROR; 1054195534Sscottl } 1055195534Sscottl softc->outstanding_cmds--; 1056195534Sscottl if (softc->outstanding_cmds == 0) 1057195534Sscottl softc->flags |= ADA_FLAG_WENT_IDLE; 1058201139Smav if ((ataio->ccb_h.ccb_state & ADA_CCB_TYPE_MASK) == 1059201139Smav ADA_CCB_TRIM) { 1060201139Smav struct trim_request *req = 1061201139Smav (struct trim_request *)ataio->data_ptr; 1062201139Smav int i; 1063195534Sscottl 1064201139Smav for (i = 1; i < softc->trim_max_ranges && 1065201139Smav req->bps[i]; i++) { 1066201139Smav struct bio *bp1 = req->bps[i]; 1067201139Smav 1068201139Smav bp1->bio_resid = bp->bio_resid; 1069201139Smav bp1->bio_error = bp->bio_error; 1070201139Smav if (bp->bio_flags & BIO_ERROR) 1071201139Smav bp1->bio_flags |= BIO_ERROR; 1072201139Smav biodone(bp1); 1073201139Smav } 1074201139Smav softc->trim_running = 0; 1075201139Smav biodone(bp); 1076201139Smav adaschedule(periph); 1077201139Smav } else 1078201139Smav biodone(bp); 1079195534Sscottl break; 1080195534Sscottl } 1081195534Sscottl case ADA_CCB_WAITING: 1082195534Sscottl { 1083195534Sscottl /* Caller will release the CCB */ 1084195534Sscottl wakeup(&done_ccb->ccb_h.cbfcnp); 1085195534Sscottl return; 1086195534Sscottl } 1087195534Sscottl case ADA_CCB_DUMP: 1088195534Sscottl /* No-op. We're polling */ 1089195534Sscottl return; 1090195534Sscottl default: 1091195534Sscottl break; 1092195534Sscottl } 1093195534Sscottl xpt_release_ccb(done_ccb); 1094195534Sscottl} 1095195534Sscottl 1096195534Sscottlstatic int 1097195534Sscottladaerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) 1098195534Sscottl{ 1099195534Sscottl struct ada_softc *softc; 1100195534Sscottl struct cam_periph *periph; 1101195534Sscottl 1102195534Sscottl periph = xpt_path_periph(ccb->ccb_h.path); 1103195534Sscottl softc = (struct ada_softc *)periph->softc; 1104195534Sscottl 1105203385Smav return(cam_periph_error(ccb, cam_flags, sense_flags, NULL)); 1106195534Sscottl} 1107195534Sscottl 1108195534Sscottlstatic void 1109198897Smavadagetparams(struct cam_periph *periph, struct ccb_getdev *cgd) 1110195534Sscottl{ 1111195534Sscottl struct ada_softc *softc = (struct ada_softc *)periph->softc; 1112195534Sscottl struct disk_params *dp = &softc->params; 1113195534Sscottl u_int64_t lbasize48; 1114195534Sscottl u_int32_t lbasize; 1115195534Sscottl 1116198897Smav dp->secsize = ata_logical_sector_size(&cgd->ident_data); 1117195534Sscottl if ((cgd->ident_data.atavalid & ATA_FLAG_54_58) && 1118195534Sscottl cgd->ident_data.current_heads && cgd->ident_data.current_sectors) { 1119195534Sscottl dp->heads = cgd->ident_data.current_heads; 1120195534Sscottl dp->secs_per_track = cgd->ident_data.current_sectors; 1121195534Sscottl dp->cylinders = cgd->ident_data.cylinders; 1122195534Sscottl dp->sectors = (u_int32_t)cgd->ident_data.current_size_1 | 1123195534Sscottl ((u_int32_t)cgd->ident_data.current_size_2 << 16); 1124195534Sscottl } else { 1125195534Sscottl dp->heads = cgd->ident_data.heads; 1126195534Sscottl dp->secs_per_track = cgd->ident_data.sectors; 1127195534Sscottl dp->cylinders = cgd->ident_data.cylinders; 1128195534Sscottl dp->sectors = cgd->ident_data.cylinders * dp->heads * dp->secs_per_track; 1129195534Sscottl } 1130195534Sscottl lbasize = (u_int32_t)cgd->ident_data.lba_size_1 | 1131195534Sscottl ((u_int32_t)cgd->ident_data.lba_size_2 << 16); 1132195534Sscottl 1133195534Sscottl /* use the 28bit LBA size if valid or bigger than the CHS mapping */ 1134195534Sscottl if (cgd->ident_data.cylinders == 16383 || dp->sectors < lbasize) 1135195534Sscottl dp->sectors = lbasize; 1136195534Sscottl 1137195534Sscottl /* use the 48bit LBA size if valid */ 1138195534Sscottl lbasize48 = ((u_int64_t)cgd->ident_data.lba_size48_1) | 1139195534Sscottl ((u_int64_t)cgd->ident_data.lba_size48_2 << 16) | 1140195534Sscottl ((u_int64_t)cgd->ident_data.lba_size48_3 << 32) | 1141195534Sscottl ((u_int64_t)cgd->ident_data.lba_size48_4 << 48); 1142195534Sscottl if ((cgd->ident_data.support.command2 & ATA_SUPPORT_ADDRESS48) && 1143195534Sscottl lbasize48 > ATA_MAX_28BIT_LBA) 1144195534Sscottl dp->sectors = lbasize48; 1145195534Sscottl} 1146195534Sscottl 1147195534Sscottlstatic void 1148195534Sscottladasendorderedtag(void *arg) 1149195534Sscottl{ 1150195534Sscottl struct ada_softc *softc = arg; 1151195534Sscottl 1152195534Sscottl if (ada_send_ordered) { 1153195534Sscottl if ((softc->ordered_tag_count == 0) 1154195534Sscottl && ((softc->flags & ADA_FLAG_WENT_IDLE) == 0)) { 1155195534Sscottl softc->flags |= ADA_FLAG_NEED_OTAG; 1156195534Sscottl } 1157195534Sscottl if (softc->outstanding_cmds > 0) 1158195534Sscottl softc->flags &= ~ADA_FLAG_WENT_IDLE; 1159195534Sscottl 1160195534Sscottl softc->ordered_tag_count = 0; 1161195534Sscottl } 1162195534Sscottl /* Queue us up again */ 1163195534Sscottl callout_reset(&softc->sendordered_c, 1164195534Sscottl (ADA_DEFAULT_TIMEOUT * hz) / ADA_ORDEREDTAG_INTERVAL, 1165195534Sscottl adasendorderedtag, softc); 1166195534Sscottl} 1167195534Sscottl 1168195534Sscottl/* 1169195534Sscottl * Step through all ADA peripheral drivers, and if the device is still open, 1170195534Sscottl * sync the disk cache to physical media. 1171195534Sscottl */ 1172195534Sscottlstatic void 1173195534Sscottladashutdown(void * arg, int howto) 1174195534Sscottl{ 1175195534Sscottl struct cam_periph *periph; 1176195534Sscottl struct ada_softc *softc; 1177195534Sscottl 1178195534Sscottl TAILQ_FOREACH(periph, &adadriver.units, unit_links) { 1179195534Sscottl union ccb ccb; 1180195534Sscottl 1181200180Smav /* If we paniced with lock held - not recurse here. */ 1182200180Smav if (cam_periph_owned(periph)) 1183200180Smav continue; 1184195534Sscottl cam_periph_lock(periph); 1185195534Sscottl softc = (struct ada_softc *)periph->softc; 1186195534Sscottl /* 1187195534Sscottl * We only sync the cache if the drive is still open, and 1188195534Sscottl * if the drive is capable of it.. 1189195534Sscottl */ 1190195534Sscottl if (((softc->flags & ADA_FLAG_OPEN) == 0) || 1191195534Sscottl (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) == 0) { 1192195534Sscottl cam_periph_unlock(periph); 1193195534Sscottl continue; 1194195534Sscottl } 1195195534Sscottl 1196198382Smav xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 1197195534Sscottl 1198195534Sscottl ccb.ccb_h.ccb_state = ADA_CCB_DUMP; 1199195534Sscottl cam_fill_ataio(&ccb.ataio, 1200195534Sscottl 1, 1201195534Sscottl adadone, 1202195534Sscottl CAM_DIR_NONE, 1203195534Sscottl 0, 1204195534Sscottl NULL, 1205195534Sscottl 0, 1206195534Sscottl ada_default_timeout*1000); 1207195534Sscottl 1208195534Sscottl if (softc->flags & ADA_FLAG_CAN_48BIT) 1209195534Sscottl ata_48bit_cmd(&ccb.ataio, ATA_FLUSHCACHE48, 0, 0, 0); 1210195534Sscottl else 1211196659Smav ata_28bit_cmd(&ccb.ataio, ATA_FLUSHCACHE, 0, 0, 0); 1212195534Sscottl xpt_polled_action(&ccb); 1213195534Sscottl 1214195534Sscottl if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) 1215195534Sscottl xpt_print(periph->path, "Synchronize cache failed\n"); 1216195534Sscottl 1217195534Sscottl if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0) 1218195534Sscottl cam_release_devq(ccb.ccb_h.path, 1219195534Sscottl /*relsim_flags*/0, 1220195534Sscottl /*reduction*/0, 1221195534Sscottl /*timeout*/0, 1222195534Sscottl /*getcount_only*/0); 1223195534Sscottl cam_periph_unlock(periph); 1224195534Sscottl } 1225195534Sscottl} 1226195534Sscottl 1227195534Sscottl#endif /* _KERNEL */ 1228