ata_da.c revision 197896
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 197896 2009-10-09 09:29:59Z pjd $"); 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 61195534Sscottl#ifdef _KERNEL 62195534Sscottl 63195534Sscottl#define ATA_MAX_28BIT_LBA 268435455UL 64195534Sscottl 65195534Sscottltypedef enum { 66195534Sscottl ADA_STATE_NORMAL 67195534Sscottl} ada_state; 68195534Sscottl 69195534Sscottltypedef enum { 70195534Sscottl ADA_FLAG_PACK_INVALID = 0x001, 71195534Sscottl ADA_FLAG_CAN_48BIT = 0x002, 72195534Sscottl ADA_FLAG_CAN_FLUSHCACHE = 0x004, 73195534Sscottl ADA_FLAG_CAN_NCQ = 0x008, 74195534Sscottl ADA_FLAG_TAGGED_QUEUING = 0x010, 75195534Sscottl ADA_FLAG_NEED_OTAG = 0x020, 76195534Sscottl ADA_FLAG_WENT_IDLE = 0x040, 77195534Sscottl ADA_FLAG_RETRY_UA = 0x080, 78195534Sscottl ADA_FLAG_OPEN = 0x100, 79195534Sscottl ADA_FLAG_SCTX_INIT = 0x200 80195534Sscottl} ada_flags; 81195534Sscottl 82195534Sscottltypedef enum { 83195534Sscottl ADA_Q_NONE = 0x00, 84195534Sscottl ADA_Q_NO_SYNC_CACHE = 0x01, 85195534Sscottl ADA_Q_NO_6_BYTE = 0x02, 86195534Sscottl ADA_Q_NO_PREVENT = 0x04 87195534Sscottl} ada_quirks; 88195534Sscottl 89195534Sscottltypedef enum { 90195534Sscottl ADA_CCB_PROBE = 0x01, 91195534Sscottl ADA_CCB_PROBE2 = 0x02, 92195534Sscottl ADA_CCB_BUFFER_IO = 0x03, 93195534Sscottl ADA_CCB_WAITING = 0x04, 94195534Sscottl ADA_CCB_DUMP = 0x05, 95195534Sscottl ADA_CCB_TYPE_MASK = 0x0F, 96195534Sscottl ADA_CCB_RETRY_UA = 0x10 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; 105195534Sscottl u_int32_t cylinders; 106195534Sscottl u_int8_t secs_per_track; 107195534Sscottl u_int32_t secsize; /* Number of bytes/sector */ 108195534Sscottl u_int64_t sectors; /* total number sectors */ 109195534Sscottl}; 110195534Sscottl 111195534Sscottlstruct ada_softc { 112195534Sscottl struct bio_queue_head bio_queue; 113195534Sscottl SLIST_ENTRY(ada_softc) links; 114195534Sscottl LIST_HEAD(, ccb_hdr) pending_ccbs; 115195534Sscottl ada_state state; 116195534Sscottl ada_flags flags; 117195534Sscottl ada_quirks quirks; 118195534Sscottl int ordered_tag_count; 119195534Sscottl int outstanding_cmds; 120195534Sscottl struct disk_params params; 121195534Sscottl struct disk *disk; 122195534Sscottl union ccb saved_ccb; 123195534Sscottl struct task sysctl_task; 124195534Sscottl struct sysctl_ctx_list sysctl_ctx; 125195534Sscottl struct sysctl_oid *sysctl_tree; 126195534Sscottl struct callout sendordered_c; 127195534Sscottl}; 128195534Sscottl 129195534Sscottlstruct ada_quirk_entry { 130195534Sscottl struct scsi_inquiry_pattern inq_pat; 131195534Sscottl ada_quirks quirks; 132195534Sscottl}; 133195534Sscottl 134195534Sscottl//static struct ada_quirk_entry ada_quirk_table[] = 135195534Sscottl//{ 136195534Sscottl//}; 137195534Sscottl 138195534Sscottlstatic disk_strategy_t adastrategy; 139195534Sscottlstatic dumper_t adadump; 140195534Sscottlstatic periph_init_t adainit; 141195534Sscottlstatic void adaasync(void *callback_arg, u_int32_t code, 142195534Sscottl struct cam_path *path, void *arg); 143195534Sscottlstatic void adasysctlinit(void *context, int pending); 144195534Sscottlstatic periph_ctor_t adaregister; 145195534Sscottlstatic periph_dtor_t adacleanup; 146195534Sscottlstatic periph_start_t adastart; 147195534Sscottlstatic periph_oninv_t adaoninvalidate; 148195534Sscottlstatic void adadone(struct cam_periph *periph, 149195534Sscottl union ccb *done_ccb); 150195534Sscottlstatic int adaerror(union ccb *ccb, u_int32_t cam_flags, 151195534Sscottl u_int32_t sense_flags); 152195534Sscottlstatic void adasetgeom(struct cam_periph *periph, 153195534Sscottl struct ccb_getdev *cgd); 154195534Sscottlstatic timeout_t adasendorderedtag; 155195534Sscottlstatic void adashutdown(void *arg, int howto); 156195534Sscottl 157195534Sscottl#ifndef ADA_DEFAULT_TIMEOUT 158195534Sscottl#define ADA_DEFAULT_TIMEOUT 30 /* Timeout in seconds */ 159195534Sscottl#endif 160195534Sscottl 161195534Sscottl#ifndef ADA_DEFAULT_RETRY 162195534Sscottl#define ADA_DEFAULT_RETRY 4 163195534Sscottl#endif 164195534Sscottl 165195534Sscottl#ifndef ADA_DEFAULT_SEND_ORDERED 166195534Sscottl#define ADA_DEFAULT_SEND_ORDERED 1 167195534Sscottl#endif 168195534Sscottl 169195534Sscottl 170195534Sscottlstatic int ada_retry_count = ADA_DEFAULT_RETRY; 171195534Sscottlstatic int ada_default_timeout = ADA_DEFAULT_TIMEOUT; 172195534Sscottlstatic int ada_send_ordered = ADA_DEFAULT_SEND_ORDERED; 173195534Sscottl 174195534SscottlSYSCTL_NODE(_kern_cam, OID_AUTO, ada, CTLFLAG_RD, 0, 175195534Sscottl "CAM Direct Access Disk driver"); 176195534SscottlSYSCTL_INT(_kern_cam_ada, OID_AUTO, retry_count, CTLFLAG_RW, 177195534Sscottl &ada_retry_count, 0, "Normal I/O retry count"); 178195534SscottlTUNABLE_INT("kern.cam.ada.retry_count", &ada_retry_count); 179195534SscottlSYSCTL_INT(_kern_cam_ada, OID_AUTO, default_timeout, CTLFLAG_RW, 180195534Sscottl &ada_default_timeout, 0, "Normal I/O timeout (in seconds)"); 181195534SscottlTUNABLE_INT("kern.cam.ada.default_timeout", &ada_default_timeout); 182195534SscottlSYSCTL_INT(_kern_cam_ada, OID_AUTO, ada_send_ordered, CTLFLAG_RW, 183195534Sscottl &ada_send_ordered, 0, "Send Ordered Tags"); 184195534SscottlTUNABLE_INT("kern.cam.ada.ada_send_ordered", &ada_send_ordered); 185195534Sscottl 186195534Sscottl/* 187195534Sscottl * ADA_ORDEREDTAG_INTERVAL determines how often, relative 188195534Sscottl * to the default timeout, we check to see whether an ordered 189195534Sscottl * tagged transaction is appropriate to prevent simple tag 190195534Sscottl * starvation. Since we'd like to ensure that there is at least 191195534Sscottl * 1/2 of the timeout length left for a starved transaction to 192195534Sscottl * complete after we've sent an ordered tag, we must poll at least 193195534Sscottl * four times in every timeout period. This takes care of the worst 194195534Sscottl * case where a starved transaction starts during an interval that 195195534Sscottl * meets the requirement "don't send an ordered tag" test so it takes 196195534Sscottl * us two intervals to determine that a tag must be sent. 197195534Sscottl */ 198195534Sscottl#ifndef ADA_ORDEREDTAG_INTERVAL 199195534Sscottl#define ADA_ORDEREDTAG_INTERVAL 4 200195534Sscottl#endif 201195534Sscottl 202195534Sscottlstatic struct periph_driver adadriver = 203195534Sscottl{ 204195534Sscottl adainit, "ada", 205195534Sscottl TAILQ_HEAD_INITIALIZER(adadriver.units), /* generation */ 0 206195534Sscottl}; 207195534Sscottl 208195534SscottlPERIPHDRIVER_DECLARE(ada, adadriver); 209195534Sscottl 210195534SscottlMALLOC_DEFINE(M_ATADA, "ata_da", "ata_da buffers"); 211195534Sscottl 212195534Sscottlstatic int 213195534Sscottladaopen(struct disk *dp) 214195534Sscottl{ 215195534Sscottl struct cam_periph *periph; 216195534Sscottl struct ada_softc *softc; 217195534Sscottl int unit; 218195534Sscottl int error; 219195534Sscottl 220195534Sscottl periph = (struct cam_periph *)dp->d_drv1; 221195534Sscottl if (periph == NULL) { 222195534Sscottl return (ENXIO); 223195534Sscottl } 224195534Sscottl 225195534Sscottl if (cam_periph_acquire(periph) != CAM_REQ_CMP) { 226195534Sscottl return(ENXIO); 227195534Sscottl } 228195534Sscottl 229195534Sscottl cam_periph_lock(periph); 230195534Sscottl if ((error = cam_periph_hold(periph, PRIBIO|PCATCH)) != 0) { 231195534Sscottl cam_periph_unlock(periph); 232195534Sscottl cam_periph_release(periph); 233195534Sscottl return (error); 234195534Sscottl } 235195534Sscottl 236195534Sscottl unit = periph->unit_number; 237195534Sscottl softc = (struct ada_softc *)periph->softc; 238195534Sscottl softc->flags |= ADA_FLAG_OPEN; 239195534Sscottl 240195534Sscottl CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, 241195534Sscottl ("adaopen: disk=%s%d (unit %d)\n", dp->d_name, dp->d_unit, 242195534Sscottl unit)); 243195534Sscottl 244195534Sscottl if ((softc->flags & ADA_FLAG_PACK_INVALID) != 0) { 245195534Sscottl /* Invalidate our pack information. */ 246195534Sscottl softc->flags &= ~ADA_FLAG_PACK_INVALID; 247195534Sscottl } 248195534Sscottl 249195534Sscottl cam_periph_unhold(periph); 250195534Sscottl cam_periph_unlock(periph); 251195534Sscottl return (0); 252195534Sscottl} 253195534Sscottl 254195534Sscottlstatic int 255195534Sscottladaclose(struct disk *dp) 256195534Sscottl{ 257195534Sscottl struct cam_periph *periph; 258195534Sscottl struct ada_softc *softc; 259195534Sscottl union ccb *ccb; 260195534Sscottl int error; 261195534Sscottl 262195534Sscottl periph = (struct cam_periph *)dp->d_drv1; 263195534Sscottl if (periph == NULL) 264195534Sscottl return (ENXIO); 265195534Sscottl 266195534Sscottl cam_periph_lock(periph); 267195534Sscottl if ((error = cam_periph_hold(periph, PRIBIO)) != 0) { 268195534Sscottl cam_periph_unlock(periph); 269195534Sscottl cam_periph_release(periph); 270195534Sscottl return (error); 271195534Sscottl } 272195534Sscottl 273195534Sscottl softc = (struct ada_softc *)periph->softc; 274195534Sscottl /* We only sync the cache if the drive is capable of it. */ 275195534Sscottl if (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) { 276195534Sscottl 277195534Sscottl ccb = cam_periph_getccb(periph, /*priority*/1); 278195534Sscottl cam_fill_ataio(&ccb->ataio, 279195534Sscottl 1, 280195534Sscottl adadone, 281195534Sscottl CAM_DIR_NONE, 282195534Sscottl 0, 283195534Sscottl NULL, 284195534Sscottl 0, 285195534Sscottl ada_default_timeout*1000); 286195534Sscottl 287195534Sscottl if (softc->flags & ADA_FLAG_CAN_48BIT) 288195534Sscottl ata_48bit_cmd(&ccb->ataio, ATA_FLUSHCACHE48, 0, 0, 0); 289195534Sscottl else 290196659Smav ata_28bit_cmd(&ccb->ataio, ATA_FLUSHCACHE, 0, 0, 0); 291195748Smav cam_periph_runccb(ccb, /*error_routine*/NULL, /*cam_flags*/0, 292195748Smav /*sense_flags*/SF_RETRY_UA, 293195748Smav softc->disk->d_devstat); 294195534Sscottl 295195534Sscottl if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) 296195534Sscottl xpt_print(periph->path, "Synchronize cache failed\n"); 297195534Sscottl 298195534Sscottl if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 299195534Sscottl cam_release_devq(ccb->ccb_h.path, 300195534Sscottl /*relsim_flags*/0, 301195534Sscottl /*reduction*/0, 302195534Sscottl /*timeout*/0, 303195534Sscottl /*getcount_only*/0); 304195534Sscottl xpt_release_ccb(ccb); 305195534Sscottl } 306195534Sscottl 307195534Sscottl softc->flags &= ~ADA_FLAG_OPEN; 308195534Sscottl cam_periph_unhold(periph); 309195534Sscottl cam_periph_unlock(periph); 310195534Sscottl cam_periph_release(periph); 311195534Sscottl return (0); 312195534Sscottl} 313195534Sscottl 314195534Sscottl/* 315195534Sscottl * Actually translate the requested transfer into one the physical driver 316195534Sscottl * can understand. The transfer is described by a buf and will include 317195534Sscottl * only one physical transfer. 318195534Sscottl */ 319195534Sscottlstatic void 320195534Sscottladastrategy(struct bio *bp) 321195534Sscottl{ 322195534Sscottl struct cam_periph *periph; 323195534Sscottl struct ada_softc *softc; 324195534Sscottl 325195534Sscottl periph = (struct cam_periph *)bp->bio_disk->d_drv1; 326195534Sscottl if (periph == NULL) { 327195534Sscottl biofinish(bp, NULL, ENXIO); 328195534Sscottl return; 329195534Sscottl } 330195534Sscottl softc = (struct ada_softc *)periph->softc; 331195534Sscottl 332195534Sscottl cam_periph_lock(periph); 333195534Sscottl 334195534Sscottl#if 0 335195534Sscottl /* 336195534Sscottl * check it's not too big a transfer for our adapter 337195534Sscottl */ 338195534Sscottl scsi_minphys(bp,&sd_switch); 339195534Sscottl#endif 340195534Sscottl 341195534Sscottl /* 342195534Sscottl * Mask interrupts so that the pack cannot be invalidated until 343195534Sscottl * after we are in the queue. Otherwise, we might not properly 344195534Sscottl * clean up one of the buffers. 345195534Sscottl */ 346195534Sscottl 347195534Sscottl /* 348195534Sscottl * If the device has been made invalid, error out 349195534Sscottl */ 350195534Sscottl if ((softc->flags & ADA_FLAG_PACK_INVALID)) { 351195534Sscottl cam_periph_unlock(periph); 352195534Sscottl biofinish(bp, NULL, ENXIO); 353195534Sscottl return; 354195534Sscottl } 355195534Sscottl 356195534Sscottl /* 357195534Sscottl * Place it in the queue of disk activities for this disk 358195534Sscottl */ 359195534Sscottl bioq_disksort(&softc->bio_queue, bp); 360195534Sscottl 361195534Sscottl /* 362195534Sscottl * Schedule ourselves for performing the work. 363195534Sscottl */ 364195534Sscottl xpt_schedule(periph, /* XXX priority */1); 365195534Sscottl cam_periph_unlock(periph); 366195534Sscottl 367195534Sscottl return; 368195534Sscottl} 369195534Sscottl 370195534Sscottlstatic int 371195534Sscottladadump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t length) 372195534Sscottl{ 373195534Sscottl struct cam_periph *periph; 374195534Sscottl struct ada_softc *softc; 375195534Sscottl u_int secsize; 376195534Sscottl union ccb ccb; 377195534Sscottl struct disk *dp; 378195534Sscottl uint64_t lba; 379195534Sscottl uint16_t count; 380195534Sscottl 381195534Sscottl dp = arg; 382195534Sscottl periph = dp->d_drv1; 383195534Sscottl if (periph == NULL) 384195534Sscottl return (ENXIO); 385195534Sscottl softc = (struct ada_softc *)periph->softc; 386195534Sscottl cam_periph_lock(periph); 387195534Sscottl secsize = softc->params.secsize; 388195534Sscottl lba = offset / secsize; 389195534Sscottl count = length / secsize; 390195534Sscottl 391195534Sscottl if ((softc->flags & ADA_FLAG_PACK_INVALID) != 0) { 392195534Sscottl cam_periph_unlock(periph); 393195534Sscottl return (ENXIO); 394195534Sscottl } 395195534Sscottl 396195534Sscottl if (length > 0) { 397195534Sscottl periph->flags |= CAM_PERIPH_POLLED; 398195534Sscottl xpt_setup_ccb(&ccb.ccb_h, periph->path, /*priority*/1); 399195534Sscottl ccb.ccb_h.ccb_state = ADA_CCB_DUMP; 400195534Sscottl cam_fill_ataio(&ccb.ataio, 401195534Sscottl 0, 402195534Sscottl adadone, 403195534Sscottl CAM_DIR_OUT, 404195534Sscottl 0, 405195534Sscottl (u_int8_t *) virtual, 406195534Sscottl length, 407195534Sscottl ada_default_timeout*1000); 408195534Sscottl if ((softc->flags & ADA_FLAG_CAN_48BIT) && 409195534Sscottl (lba + count >= ATA_MAX_28BIT_LBA || 410195534Sscottl count >= 256)) { 411195534Sscottl ata_48bit_cmd(&ccb.ataio, ATA_WRITE_DMA48, 412195534Sscottl 0, lba, count); 413195534Sscottl } else { 414196659Smav ata_28bit_cmd(&ccb.ataio, ATA_WRITE_DMA, 415195534Sscottl 0, lba, count); 416195534Sscottl } 417195534Sscottl xpt_polled_action(&ccb); 418195534Sscottl 419195534Sscottl if ((ccb.ataio.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 420195534Sscottl printf("Aborting dump due to I/O error.\n"); 421195534Sscottl cam_periph_unlock(periph); 422195534Sscottl return(EIO); 423195534Sscottl } 424195534Sscottl cam_periph_unlock(periph); 425195534Sscottl return(0); 426195534Sscottl } 427195534Sscottl 428195534Sscottl if (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) { 429195534Sscottl xpt_setup_ccb(&ccb.ccb_h, periph->path, /*priority*/1); 430195534Sscottl 431195534Sscottl ccb.ccb_h.ccb_state = ADA_CCB_DUMP; 432195534Sscottl cam_fill_ataio(&ccb.ataio, 433195534Sscottl 1, 434195534Sscottl adadone, 435195534Sscottl CAM_DIR_NONE, 436195534Sscottl 0, 437195534Sscottl NULL, 438195534Sscottl 0, 439195534Sscottl ada_default_timeout*1000); 440195534Sscottl 441195534Sscottl if (softc->flags & ADA_FLAG_CAN_48BIT) 442195534Sscottl ata_48bit_cmd(&ccb.ataio, ATA_FLUSHCACHE48, 0, 0, 0); 443195534Sscottl else 444196659Smav ata_28bit_cmd(&ccb.ataio, ATA_FLUSHCACHE, 0, 0, 0); 445195534Sscottl xpt_polled_action(&ccb); 446195534Sscottl 447195534Sscottl if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) 448195534Sscottl xpt_print(periph->path, "Synchronize cache failed\n"); 449195534Sscottl 450195534Sscottl if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0) 451195534Sscottl cam_release_devq(ccb.ccb_h.path, 452195534Sscottl /*relsim_flags*/0, 453195534Sscottl /*reduction*/0, 454195534Sscottl /*timeout*/0, 455195534Sscottl /*getcount_only*/0); 456195534Sscottl } 457195534Sscottl periph->flags &= ~CAM_PERIPH_POLLED; 458195534Sscottl cam_periph_unlock(periph); 459195534Sscottl return (0); 460195534Sscottl} 461195534Sscottl 462195534Sscottlstatic void 463195534Sscottladainit(void) 464195534Sscottl{ 465195534Sscottl cam_status status; 466195534Sscottl 467195534Sscottl /* 468195534Sscottl * Install a global async callback. This callback will 469195534Sscottl * receive async callbacks like "new device found". 470195534Sscottl */ 471195534Sscottl status = xpt_register_async(AC_FOUND_DEVICE, adaasync, NULL, NULL); 472195534Sscottl 473195534Sscottl if (status != CAM_REQ_CMP) { 474195534Sscottl printf("ada: Failed to attach master async callback " 475195534Sscottl "due to status 0x%x!\n", status); 476195534Sscottl } else if (ada_send_ordered) { 477195534Sscottl 478195534Sscottl /* Register our shutdown event handler */ 479195534Sscottl if ((EVENTHANDLER_REGISTER(shutdown_post_sync, adashutdown, 480195534Sscottl NULL, SHUTDOWN_PRI_DEFAULT)) == NULL) 481195534Sscottl printf("adainit: shutdown event registration failed!\n"); 482195534Sscottl } 483195534Sscottl} 484195534Sscottl 485195534Sscottlstatic void 486195534Sscottladaoninvalidate(struct cam_periph *periph) 487195534Sscottl{ 488195534Sscottl struct ada_softc *softc; 489195534Sscottl 490195534Sscottl softc = (struct ada_softc *)periph->softc; 491195534Sscottl 492195534Sscottl /* 493195534Sscottl * De-register any async callbacks. 494195534Sscottl */ 495195534Sscottl xpt_register_async(0, adaasync, periph, periph->path); 496195534Sscottl 497195534Sscottl softc->flags |= ADA_FLAG_PACK_INVALID; 498195534Sscottl 499195534Sscottl /* 500195534Sscottl * Return all queued I/O with ENXIO. 501195534Sscottl * XXX Handle any transactions queued to the card 502195534Sscottl * with XPT_ABORT_CCB. 503195534Sscottl */ 504195534Sscottl bioq_flush(&softc->bio_queue, NULL, ENXIO); 505195534Sscottl 506195534Sscottl disk_gone(softc->disk); 507195534Sscottl xpt_print(periph->path, "lost device\n"); 508195534Sscottl} 509195534Sscottl 510195534Sscottlstatic void 511195534Sscottladacleanup(struct cam_periph *periph) 512195534Sscottl{ 513195534Sscottl struct ada_softc *softc; 514195534Sscottl 515195534Sscottl softc = (struct ada_softc *)periph->softc; 516195534Sscottl 517195534Sscottl xpt_print(periph->path, "removing device entry\n"); 518195534Sscottl cam_periph_unlock(periph); 519195534Sscottl 520195534Sscottl /* 521195534Sscottl * If we can't free the sysctl tree, oh well... 522195534Sscottl */ 523195534Sscottl if ((softc->flags & ADA_FLAG_SCTX_INIT) != 0 524195534Sscottl && sysctl_ctx_free(&softc->sysctl_ctx) != 0) { 525195534Sscottl xpt_print(periph->path, "can't remove sysctl context\n"); 526195534Sscottl } 527195534Sscottl 528195534Sscottl disk_destroy(softc->disk); 529195534Sscottl callout_drain(&softc->sendordered_c); 530195534Sscottl free(softc, M_DEVBUF); 531195534Sscottl cam_periph_lock(periph); 532195534Sscottl} 533195534Sscottl 534195534Sscottlstatic void 535195534Sscottladaasync(void *callback_arg, u_int32_t code, 536195534Sscottl struct cam_path *path, void *arg) 537195534Sscottl{ 538195534Sscottl struct cam_periph *periph; 539195534Sscottl 540195534Sscottl periph = (struct cam_periph *)callback_arg; 541195534Sscottl switch (code) { 542195534Sscottl case AC_FOUND_DEVICE: 543195534Sscottl { 544195534Sscottl struct ccb_getdev *cgd; 545195534Sscottl cam_status status; 546195534Sscottl 547195534Sscottl cgd = (struct ccb_getdev *)arg; 548195534Sscottl if (cgd == NULL) 549195534Sscottl break; 550195534Sscottl 551195534Sscottl if (cgd->protocol != PROTO_ATA) 552195534Sscottl break; 553195534Sscottl 554195534Sscottl// if (SID_TYPE(&cgd->inq_data) != T_DIRECT 555195534Sscottl// && SID_TYPE(&cgd->inq_data) != T_RBC 556195534Sscottl// && SID_TYPE(&cgd->inq_data) != T_OPTICAL) 557195534Sscottl// break; 558195534Sscottl 559195534Sscottl /* 560195534Sscottl * Allocate a peripheral instance for 561195534Sscottl * this device and start the probe 562195534Sscottl * process. 563195534Sscottl */ 564195534Sscottl status = cam_periph_alloc(adaregister, adaoninvalidate, 565195534Sscottl adacleanup, adastart, 566195534Sscottl "ada", CAM_PERIPH_BIO, 567195534Sscottl cgd->ccb_h.path, adaasync, 568195534Sscottl AC_FOUND_DEVICE, cgd); 569195534Sscottl 570195534Sscottl if (status != CAM_REQ_CMP 571195534Sscottl && status != CAM_REQ_INPROG) 572195534Sscottl printf("adaasync: Unable to attach to new device " 573195534Sscottl "due to status 0x%x\n", status); 574195534Sscottl break; 575195534Sscottl } 576195534Sscottl case AC_SENT_BDR: 577195534Sscottl case AC_BUS_RESET: 578195534Sscottl { 579195534Sscottl struct ada_softc *softc; 580195534Sscottl struct ccb_hdr *ccbh; 581195534Sscottl 582195534Sscottl softc = (struct ada_softc *)periph->softc; 583195534Sscottl /* 584195534Sscottl * Don't fail on the expected unit attention 585195534Sscottl * that will occur. 586195534Sscottl */ 587195534Sscottl softc->flags |= ADA_FLAG_RETRY_UA; 588195534Sscottl LIST_FOREACH(ccbh, &softc->pending_ccbs, periph_links.le) 589195534Sscottl ccbh->ccb_state |= ADA_CCB_RETRY_UA; 590195534Sscottl /* FALLTHROUGH*/ 591195534Sscottl } 592195534Sscottl default: 593195534Sscottl cam_periph_async(periph, code, path, arg); 594195534Sscottl break; 595195534Sscottl } 596195534Sscottl} 597195534Sscottl 598195534Sscottlstatic void 599195534Sscottladasysctlinit(void *context, int pending) 600195534Sscottl{ 601195534Sscottl struct cam_periph *periph; 602195534Sscottl struct ada_softc *softc; 603195534Sscottl char tmpstr[80], tmpstr2[80]; 604195534Sscottl 605195534Sscottl periph = (struct cam_periph *)context; 606195534Sscottl if (cam_periph_acquire(periph) != CAM_REQ_CMP) 607195534Sscottl return; 608195534Sscottl 609195534Sscottl softc = (struct ada_softc *)periph->softc; 610195534Sscottl snprintf(tmpstr, sizeof(tmpstr), "CAM ADA unit %d", periph->unit_number); 611195534Sscottl snprintf(tmpstr2, sizeof(tmpstr2), "%d", periph->unit_number); 612195534Sscottl 613195534Sscottl sysctl_ctx_init(&softc->sysctl_ctx); 614195534Sscottl softc->flags |= ADA_FLAG_SCTX_INIT; 615195534Sscottl softc->sysctl_tree = SYSCTL_ADD_NODE(&softc->sysctl_ctx, 616195534Sscottl SYSCTL_STATIC_CHILDREN(_kern_cam_ada), OID_AUTO, tmpstr2, 617195534Sscottl CTLFLAG_RD, 0, tmpstr); 618195534Sscottl if (softc->sysctl_tree == NULL) { 619195534Sscottl printf("adasysctlinit: unable to allocate sysctl tree\n"); 620195534Sscottl cam_periph_release(periph); 621195534Sscottl return; 622195534Sscottl } 623195534Sscottl 624195534Sscottl cam_periph_release(periph); 625195534Sscottl} 626195534Sscottl 627195534Sscottlstatic cam_status 628195534Sscottladaregister(struct cam_periph *periph, void *arg) 629195534Sscottl{ 630195534Sscottl struct ada_softc *softc; 631195534Sscottl struct ccb_pathinq cpi; 632195534Sscottl struct ccb_getdev *cgd; 633195534Sscottl char announce_buf[80]; 634195534Sscottl struct disk_params *dp; 635195534Sscottl caddr_t match; 636195534Sscottl u_int maxio; 637195534Sscottl 638195534Sscottl cgd = (struct ccb_getdev *)arg; 639195534Sscottl if (periph == NULL) { 640195534Sscottl printf("adaregister: periph was NULL!!\n"); 641195534Sscottl return(CAM_REQ_CMP_ERR); 642195534Sscottl } 643195534Sscottl 644195534Sscottl if (cgd == NULL) { 645195534Sscottl printf("adaregister: no getdev CCB, can't register device\n"); 646195534Sscottl return(CAM_REQ_CMP_ERR); 647195534Sscottl } 648195534Sscottl 649195534Sscottl softc = (struct ada_softc *)malloc(sizeof(*softc), M_DEVBUF, 650195534Sscottl M_NOWAIT|M_ZERO); 651195534Sscottl 652195534Sscottl if (softc == NULL) { 653195534Sscottl printf("adaregister: Unable to probe new device. " 654195534Sscottl "Unable to allocate softc\n"); 655195534Sscottl return(CAM_REQ_CMP_ERR); 656195534Sscottl } 657195534Sscottl 658195534Sscottl LIST_INIT(&softc->pending_ccbs); 659195534Sscottl softc->state = ADA_STATE_NORMAL; 660195534Sscottl bioq_init(&softc->bio_queue); 661195534Sscottl 662195534Sscottl if (cgd->ident_data.support.command2 & ATA_SUPPORT_ADDRESS48) 663195534Sscottl softc->flags |= ADA_FLAG_CAN_48BIT; 664195534Sscottl if (cgd->ident_data.support.command2 & ATA_SUPPORT_FLUSHCACHE) 665195534Sscottl softc->flags |= ADA_FLAG_CAN_FLUSHCACHE; 666195534Sscottl if (cgd->ident_data.satacapabilities & ATA_SUPPORT_NCQ && 667195534Sscottl cgd->ident_data.queue >= 31) 668195534Sscottl softc->flags |= ADA_FLAG_CAN_NCQ; 669195534Sscottl// if ((cgd->inq_data.flags & SID_CmdQue) != 0) 670195534Sscottl// softc->flags |= ADA_FLAG_TAGGED_QUEUING; 671195534Sscottl 672195534Sscottl periph->softc = softc; 673195534Sscottl 674195534Sscottl /* 675195534Sscottl * See if this device has any quirks. 676195534Sscottl */ 677195534Sscottl// match = cam_quirkmatch((caddr_t)&cgd->inq_data, 678195534Sscottl// (caddr_t)ada_quirk_table, 679195534Sscottl// sizeof(ada_quirk_table)/sizeof(*ada_quirk_table), 680195534Sscottl// sizeof(*ada_quirk_table), scsi_inquiry_match); 681195534Sscottl match = NULL; 682195534Sscottl 683195534Sscottl if (match != NULL) 684195534Sscottl softc->quirks = ((struct ada_quirk_entry *)match)->quirks; 685195534Sscottl else 686195534Sscottl softc->quirks = ADA_Q_NONE; 687195534Sscottl 688195534Sscottl /* Check if the SIM does not want queued commands */ 689195534Sscottl bzero(&cpi, sizeof(cpi)); 690195534Sscottl xpt_setup_ccb(&cpi.ccb_h, periph->path, /*priority*/1); 691195534Sscottl cpi.ccb_h.func_code = XPT_PATH_INQ; 692195534Sscottl xpt_action((union ccb *)&cpi); 693195534Sscottl if (cpi.ccb_h.status != CAM_REQ_CMP || 694195534Sscottl (cpi.hba_inquiry & PI_TAG_ABLE) == 0) 695195534Sscottl softc->flags &= ~ADA_FLAG_CAN_NCQ; 696195534Sscottl 697195534Sscottl TASK_INIT(&softc->sysctl_task, 0, adasysctlinit, periph); 698195534Sscottl 699195534Sscottl /* 700195534Sscottl * Register this media as a disk 701195534Sscottl */ 702195534Sscottl mtx_unlock(periph->sim->mtx); 703195534Sscottl softc->disk = disk_alloc(); 704195534Sscottl softc->disk->d_open = adaopen; 705195534Sscottl softc->disk->d_close = adaclose; 706195534Sscottl softc->disk->d_strategy = adastrategy; 707195534Sscottl softc->disk->d_dump = adadump; 708195534Sscottl softc->disk->d_name = "ada"; 709195534Sscottl softc->disk->d_drv1 = periph; 710195534Sscottl maxio = cpi.maxio; /* Honor max I/O size of SIM */ 711195534Sscottl if (maxio == 0) 712195534Sscottl maxio = DFLTPHYS; /* traditional default */ 713195534Sscottl else if (maxio > MAXPHYS) 714195534Sscottl maxio = MAXPHYS; /* for safety */ 715195534Sscottl if (cgd->ident_data.support.command2 & ATA_SUPPORT_ADDRESS48) 716195534Sscottl maxio = min(maxio, 65535 * 512); 717195534Sscottl else /* 28bit ATA command limit */ 718195534Sscottl maxio = min(maxio, 255 * 512); 719195534Sscottl softc->disk->d_maxsize = maxio; 720195534Sscottl softc->disk->d_unit = periph->unit_number; 721195534Sscottl softc->disk->d_flags = 0; 722195534Sscottl if (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) 723195534Sscottl softc->disk->d_flags |= DISKFLAG_CANFLUSHCACHE; 724197896Spjd strlcpy(softc->disk->d_ident, cgd->serial_num, 725197896Spjd MIN(sizeof(softc->disk->d_ident), cgd->serial_num_len + 1)); 726195534Sscottl 727195534Sscottl adasetgeom(periph, cgd); 728195534Sscottl softc->disk->d_sectorsize = softc->params.secsize; 729195534Sscottl softc->disk->d_mediasize = softc->params.secsize * (off_t)softc->params.sectors; 730195534Sscottl /* XXX: these are not actually "firmware" values, so they may be wrong */ 731195534Sscottl softc->disk->d_fwsectors = softc->params.secs_per_track; 732195534Sscottl softc->disk->d_fwheads = softc->params.heads; 733195534Sscottl// softc->disk->d_devstat->block_size = softc->params.secsize; 734195534Sscottl// softc->disk->d_devstat->flags &= ~DEVSTAT_BS_UNAVAILABLE; 735195534Sscottl 736195534Sscottl disk_create(softc->disk, DISK_VERSION); 737195534Sscottl mtx_lock(periph->sim->mtx); 738195534Sscottl 739195534Sscottl dp = &softc->params; 740195534Sscottl snprintf(announce_buf, sizeof(announce_buf), 741195534Sscottl "%juMB (%ju %u byte sectors: %dH %dS/T %dC)", 742195534Sscottl (uintmax_t)(((uintmax_t)dp->secsize * 743195534Sscottl dp->sectors) / (1024*1024)), 744195534Sscottl (uintmax_t)dp->sectors, 745195534Sscottl dp->secsize, dp->heads, 746195534Sscottl dp->secs_per_track, dp->cylinders); 747195534Sscottl xpt_announce_periph(periph, announce_buf); 748195534Sscottl if (softc->flags & ADA_FLAG_CAN_NCQ) { 749195534Sscottl printf("%s%d: Native Command Queueing enabled\n", 750195534Sscottl periph->periph_name, periph->unit_number); 751195534Sscottl } 752195534Sscottl 753195534Sscottl /* 754195534Sscottl * Add async callbacks for bus reset and 755195534Sscottl * bus device reset calls. I don't bother 756195534Sscottl * checking if this fails as, in most cases, 757195534Sscottl * the system will function just fine without 758195534Sscottl * them and the only alternative would be to 759195534Sscottl * not attach the device on failure. 760195534Sscottl */ 761195534Sscottl xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE, 762195534Sscottl adaasync, periph, periph->path); 763195534Sscottl 764195534Sscottl /* 765195534Sscottl * Take an exclusive refcount on the periph while adastart is called 766195534Sscottl * to finish the probe. The reference will be dropped in adadone at 767195534Sscottl * the end of probe. 768195534Sscottl */ 769195534Sscottl// (void)cam_periph_hold(periph, PRIBIO); 770195534Sscottl// xpt_schedule(periph, /*priority*/5); 771195534Sscottl 772195534Sscottl /* 773195534Sscottl * Schedule a periodic event to occasionally send an 774195534Sscottl * ordered tag to a device. 775195534Sscottl */ 776195534Sscottl callout_init_mtx(&softc->sendordered_c, periph->sim->mtx, 0); 777195534Sscottl callout_reset(&softc->sendordered_c, 778195534Sscottl (ADA_DEFAULT_TIMEOUT * hz) / ADA_ORDEREDTAG_INTERVAL, 779195534Sscottl adasendorderedtag, softc); 780195534Sscottl 781195534Sscottl return(CAM_REQ_CMP); 782195534Sscottl} 783195534Sscottl 784195534Sscottlstatic void 785195534Sscottladastart(struct cam_periph *periph, union ccb *start_ccb) 786195534Sscottl{ 787195534Sscottl struct ada_softc *softc; 788195534Sscottl 789195534Sscottl softc = (struct ada_softc *)periph->softc; 790195534Sscottl 791195534Sscottl switch (softc->state) { 792195534Sscottl case ADA_STATE_NORMAL: 793195534Sscottl { 794195534Sscottl /* Pull a buffer from the queue and get going on it */ 795195534Sscottl struct bio *bp; 796195534Sscottl 797195534Sscottl /* 798195534Sscottl * See if there is a buf with work for us to do.. 799195534Sscottl */ 800195534Sscottl bp = bioq_first(&softc->bio_queue); 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); 809195534Sscottl } else if (bp == NULL) { 810195534Sscottl xpt_release_ccb(start_ccb); 811195534Sscottl } else { 812195534Sscottl struct ccb_ataio *ataio = &start_ccb->ataio; 813195534Sscottl u_int8_t tag_code; 814195534Sscottl 815195534Sscottl bioq_remove(&softc->bio_queue, bp); 816195534Sscottl 817195534Sscottl if ((softc->flags & ADA_FLAG_NEED_OTAG) != 0) { 818195534Sscottl softc->flags &= ~ADA_FLAG_NEED_OTAG; 819195534Sscottl softc->ordered_tag_count++; 820195534Sscottl tag_code = 0;//MSG_ORDERED_Q_TAG; 821195534Sscottl } else { 822195534Sscottl tag_code = 0;//MSG_SIMPLE_Q_TAG; 823195534Sscottl } 824195534Sscottl switch (bp->bio_cmd) { 825195534Sscottl case BIO_READ: 826195534Sscottl case BIO_WRITE: 827195534Sscottl { 828195534Sscottl uint64_t lba = bp->bio_pblkno; 829195534Sscottl uint16_t count = bp->bio_bcount / softc->params.secsize; 830195534Sscottl 831195534Sscottl cam_fill_ataio(ataio, 832195534Sscottl ada_retry_count, 833195534Sscottl adadone, 834195534Sscottl bp->bio_cmd == BIO_READ ? 835195534Sscottl CAM_DIR_IN : CAM_DIR_OUT, 836195534Sscottl tag_code, 837195534Sscottl bp->bio_data, 838195534Sscottl bp->bio_bcount, 839195534Sscottl ada_default_timeout*1000); 840195534Sscottl 841195534Sscottl if (softc->flags & ADA_FLAG_CAN_NCQ) { 842195534Sscottl if (bp->bio_cmd == BIO_READ) { 843195534Sscottl ata_ncq_cmd(ataio, ATA_READ_FPDMA_QUEUED, 844195534Sscottl lba, count); 845195534Sscottl } else { 846195534Sscottl ata_ncq_cmd(ataio, ATA_WRITE_FPDMA_QUEUED, 847195534Sscottl lba, count); 848195534Sscottl } 849195534Sscottl } else if ((softc->flags & ADA_FLAG_CAN_48BIT) && 850195534Sscottl (lba + count >= ATA_MAX_28BIT_LBA || 851195534Sscottl count >= 256)) { 852195534Sscottl if (bp->bio_cmd == BIO_READ) { 853195534Sscottl ata_48bit_cmd(ataio, ATA_READ_DMA48, 854195534Sscottl 0, lba, count); 855195534Sscottl } else { 856195534Sscottl ata_48bit_cmd(ataio, ATA_WRITE_DMA48, 857195534Sscottl 0, lba, count); 858195534Sscottl } 859195534Sscottl } else { 860195534Sscottl if (bp->bio_cmd == BIO_READ) { 861196659Smav ata_28bit_cmd(ataio, ATA_READ_DMA, 862195534Sscottl 0, lba, count); 863195534Sscottl } else { 864196659Smav ata_28bit_cmd(ataio, ATA_WRITE_DMA, 865195534Sscottl 0, lba, count); 866195534Sscottl } 867195534Sscottl } 868195534Sscottl } 869195534Sscottl break; 870195534Sscottl case BIO_FLUSH: 871195534Sscottl cam_fill_ataio(ataio, 872195534Sscottl 1, 873195534Sscottl adadone, 874195534Sscottl CAM_DIR_NONE, 875195534Sscottl tag_code, 876195534Sscottl NULL, 877195534Sscottl 0, 878195534Sscottl ada_default_timeout*1000); 879195534Sscottl 880195534Sscottl if (softc->flags & ADA_FLAG_CAN_48BIT) 881195534Sscottl ata_48bit_cmd(ataio, ATA_FLUSHCACHE48, 0, 0, 0); 882195534Sscottl else 883196659Smav ata_28bit_cmd(ataio, ATA_FLUSHCACHE, 0, 0, 0); 884195534Sscottl break; 885195534Sscottl } 886195534Sscottl start_ccb->ccb_h.ccb_state = ADA_CCB_BUFFER_IO; 887195534Sscottl 888195534Sscottl /* 889195534Sscottl * Block out any asyncronous callbacks 890195534Sscottl * while we touch the pending ccb list. 891195534Sscottl */ 892195534Sscottl LIST_INSERT_HEAD(&softc->pending_ccbs, 893195534Sscottl &start_ccb->ccb_h, periph_links.le); 894195534Sscottl softc->outstanding_cmds++; 895195534Sscottl 896195534Sscottl /* We expect a unit attention from this device */ 897195534Sscottl if ((softc->flags & ADA_FLAG_RETRY_UA) != 0) { 898195534Sscottl start_ccb->ccb_h.ccb_state |= ADA_CCB_RETRY_UA; 899195534Sscottl softc->flags &= ~ADA_FLAG_RETRY_UA; 900195534Sscottl } 901195534Sscottl 902195534Sscottl start_ccb->ccb_h.ccb_bp = bp; 903195534Sscottl bp = bioq_first(&softc->bio_queue); 904195534Sscottl 905195534Sscottl xpt_action(start_ccb); 906195534Sscottl } 907195534Sscottl 908195534Sscottl if (bp != NULL) { 909195534Sscottl /* Have more work to do, so ensure we stay scheduled */ 910195534Sscottl xpt_schedule(periph, /* XXX priority */1); 911195534Sscottl } 912195534Sscottl break; 913195534Sscottl } 914195534Sscottl } 915195534Sscottl} 916195534Sscottl 917195534Sscottlstatic void 918195534Sscottladadone(struct cam_periph *periph, union ccb *done_ccb) 919195534Sscottl{ 920195534Sscottl struct ada_softc *softc; 921195534Sscottl struct ccb_ataio *ataio; 922195534Sscottl 923195534Sscottl softc = (struct ada_softc *)periph->softc; 924195534Sscottl ataio = &done_ccb->ataio; 925195534Sscottl switch (ataio->ccb_h.ccb_state & ADA_CCB_TYPE_MASK) { 926195534Sscottl case ADA_CCB_BUFFER_IO: 927195534Sscottl { 928195534Sscottl struct bio *bp; 929195534Sscottl 930195534Sscottl bp = (struct bio *)done_ccb->ccb_h.ccb_bp; 931195534Sscottl if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 932195534Sscottl int error; 933195534Sscottl 934195534Sscottl error = adaerror(done_ccb, CAM_RETRY_SELTO, 0); 935195534Sscottl if (error == ERESTART) { 936195534Sscottl /* 937195534Sscottl * A retry was scheuled, so 938195534Sscottl * just return. 939195534Sscottl */ 940195534Sscottl return; 941195534Sscottl } 942195534Sscottl if (error != 0) { 943195534Sscottl 944195534Sscottl if (error == ENXIO) { 945195534Sscottl /* 946195534Sscottl * Catastrophic error. Mark our pack as 947195534Sscottl * invalid. 948195534Sscottl */ 949195534Sscottl /* 950195534Sscottl * XXX See if this is really a media 951195534Sscottl * XXX change first? 952195534Sscottl */ 953195534Sscottl xpt_print(periph->path, 954195534Sscottl "Invalidating pack\n"); 955195534Sscottl softc->flags |= ADA_FLAG_PACK_INVALID; 956195534Sscottl } 957195534Sscottl 958195534Sscottl /* 959195534Sscottl * return all queued I/O with EIO, so that 960195534Sscottl * the client can retry these I/Os in the 961195534Sscottl * proper order should it attempt to recover. 962195534Sscottl */ 963195534Sscottl bioq_flush(&softc->bio_queue, NULL, EIO); 964195534Sscottl bp->bio_error = error; 965195534Sscottl bp->bio_resid = bp->bio_bcount; 966195534Sscottl bp->bio_flags |= BIO_ERROR; 967195534Sscottl } else { 968195534Sscottl bp->bio_resid = ataio->resid; 969195534Sscottl bp->bio_error = 0; 970195534Sscottl if (bp->bio_resid != 0) 971195534Sscottl bp->bio_flags |= BIO_ERROR; 972195534Sscottl } 973195534Sscottl if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 974195534Sscottl cam_release_devq(done_ccb->ccb_h.path, 975195534Sscottl /*relsim_flags*/0, 976195534Sscottl /*reduction*/0, 977195534Sscottl /*timeout*/0, 978195534Sscottl /*getcount_only*/0); 979195534Sscottl } else { 980195534Sscottl if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 981195534Sscottl panic("REQ_CMP with QFRZN"); 982195534Sscottl bp->bio_resid = ataio->resid; 983195534Sscottl if (ataio->resid > 0) 984195534Sscottl bp->bio_flags |= BIO_ERROR; 985195534Sscottl } 986195534Sscottl 987195534Sscottl /* 988195534Sscottl * Block out any asyncronous callbacks 989195534Sscottl * while we touch the pending ccb list. 990195534Sscottl */ 991195534Sscottl LIST_REMOVE(&done_ccb->ccb_h, periph_links.le); 992195534Sscottl softc->outstanding_cmds--; 993195534Sscottl if (softc->outstanding_cmds == 0) 994195534Sscottl softc->flags |= ADA_FLAG_WENT_IDLE; 995195534Sscottl 996195534Sscottl biodone(bp); 997195534Sscottl break; 998195534Sscottl } 999195534Sscottl case ADA_CCB_WAITING: 1000195534Sscottl { 1001195534Sscottl /* Caller will release the CCB */ 1002195534Sscottl wakeup(&done_ccb->ccb_h.cbfcnp); 1003195534Sscottl return; 1004195534Sscottl } 1005195534Sscottl case ADA_CCB_DUMP: 1006195534Sscottl /* No-op. We're polling */ 1007195534Sscottl return; 1008195534Sscottl default: 1009195534Sscottl break; 1010195534Sscottl } 1011195534Sscottl xpt_release_ccb(done_ccb); 1012195534Sscottl} 1013195534Sscottl 1014195534Sscottlstatic int 1015195534Sscottladaerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) 1016195534Sscottl{ 1017195534Sscottl struct ada_softc *softc; 1018195534Sscottl struct cam_periph *periph; 1019195534Sscottl 1020195534Sscottl periph = xpt_path_periph(ccb->ccb_h.path); 1021195534Sscottl softc = (struct ada_softc *)periph->softc; 1022195534Sscottl 1023195534Sscottl return(cam_periph_error(ccb, cam_flags, sense_flags, 1024195534Sscottl &softc->saved_ccb)); 1025195534Sscottl} 1026195534Sscottl 1027195534Sscottlstatic void 1028195534Sscottladasetgeom(struct cam_periph *periph, struct ccb_getdev *cgd) 1029195534Sscottl{ 1030195534Sscottl struct ada_softc *softc = (struct ada_softc *)periph->softc; 1031195534Sscottl struct disk_params *dp = &softc->params; 1032195534Sscottl u_int64_t lbasize48; 1033195534Sscottl u_int32_t lbasize; 1034195534Sscottl 1035195534Sscottl dp->secsize = 512; 1036195534Sscottl if ((cgd->ident_data.atavalid & ATA_FLAG_54_58) && 1037195534Sscottl cgd->ident_data.current_heads && cgd->ident_data.current_sectors) { 1038195534Sscottl dp->heads = cgd->ident_data.current_heads; 1039195534Sscottl dp->secs_per_track = cgd->ident_data.current_sectors; 1040195534Sscottl dp->cylinders = cgd->ident_data.cylinders; 1041195534Sscottl dp->sectors = (u_int32_t)cgd->ident_data.current_size_1 | 1042195534Sscottl ((u_int32_t)cgd->ident_data.current_size_2 << 16); 1043195534Sscottl } else { 1044195534Sscottl dp->heads = cgd->ident_data.heads; 1045195534Sscottl dp->secs_per_track = cgd->ident_data.sectors; 1046195534Sscottl dp->cylinders = cgd->ident_data.cylinders; 1047195534Sscottl dp->sectors = cgd->ident_data.cylinders * dp->heads * dp->secs_per_track; 1048195534Sscottl } 1049195534Sscottl lbasize = (u_int32_t)cgd->ident_data.lba_size_1 | 1050195534Sscottl ((u_int32_t)cgd->ident_data.lba_size_2 << 16); 1051195534Sscottl 1052195534Sscottl /* does this device need oldstyle CHS addressing */ 1053195534Sscottl// if (!ad_version(cgd->ident_data.version_major) || !lbasize) 1054195534Sscottl// atadev->flags |= ATA_D_USE_CHS; 1055195534Sscottl 1056195534Sscottl /* use the 28bit LBA size if valid or bigger than the CHS mapping */ 1057195534Sscottl if (cgd->ident_data.cylinders == 16383 || dp->sectors < lbasize) 1058195534Sscottl dp->sectors = lbasize; 1059195534Sscottl 1060195534Sscottl /* use the 48bit LBA size if valid */ 1061195534Sscottl lbasize48 = ((u_int64_t)cgd->ident_data.lba_size48_1) | 1062195534Sscottl ((u_int64_t)cgd->ident_data.lba_size48_2 << 16) | 1063195534Sscottl ((u_int64_t)cgd->ident_data.lba_size48_3 << 32) | 1064195534Sscottl ((u_int64_t)cgd->ident_data.lba_size48_4 << 48); 1065195534Sscottl if ((cgd->ident_data.support.command2 & ATA_SUPPORT_ADDRESS48) && 1066195534Sscottl lbasize48 > ATA_MAX_28BIT_LBA) 1067195534Sscottl dp->sectors = lbasize48; 1068195534Sscottl} 1069195534Sscottl 1070195534Sscottlstatic void 1071195534Sscottladasendorderedtag(void *arg) 1072195534Sscottl{ 1073195534Sscottl struct ada_softc *softc = arg; 1074195534Sscottl 1075195534Sscottl if (ada_send_ordered) { 1076195534Sscottl if ((softc->ordered_tag_count == 0) 1077195534Sscottl && ((softc->flags & ADA_FLAG_WENT_IDLE) == 0)) { 1078195534Sscottl softc->flags |= ADA_FLAG_NEED_OTAG; 1079195534Sscottl } 1080195534Sscottl if (softc->outstanding_cmds > 0) 1081195534Sscottl softc->flags &= ~ADA_FLAG_WENT_IDLE; 1082195534Sscottl 1083195534Sscottl softc->ordered_tag_count = 0; 1084195534Sscottl } 1085195534Sscottl /* Queue us up again */ 1086195534Sscottl callout_reset(&softc->sendordered_c, 1087195534Sscottl (ADA_DEFAULT_TIMEOUT * hz) / ADA_ORDEREDTAG_INTERVAL, 1088195534Sscottl adasendorderedtag, softc); 1089195534Sscottl} 1090195534Sscottl 1091195534Sscottl/* 1092195534Sscottl * Step through all ADA peripheral drivers, and if the device is still open, 1093195534Sscottl * sync the disk cache to physical media. 1094195534Sscottl */ 1095195534Sscottlstatic void 1096195534Sscottladashutdown(void * arg, int howto) 1097195534Sscottl{ 1098195534Sscottl struct cam_periph *periph; 1099195534Sscottl struct ada_softc *softc; 1100195534Sscottl 1101195534Sscottl TAILQ_FOREACH(periph, &adadriver.units, unit_links) { 1102195534Sscottl union ccb ccb; 1103195534Sscottl 1104195534Sscottl cam_periph_lock(periph); 1105195534Sscottl softc = (struct ada_softc *)periph->softc; 1106195534Sscottl /* 1107195534Sscottl * We only sync the cache if the drive is still open, and 1108195534Sscottl * if the drive is capable of it.. 1109195534Sscottl */ 1110195534Sscottl if (((softc->flags & ADA_FLAG_OPEN) == 0) || 1111195534Sscottl (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) == 0) { 1112195534Sscottl cam_periph_unlock(periph); 1113195534Sscottl continue; 1114195534Sscottl } 1115195534Sscottl 1116195534Sscottl xpt_setup_ccb(&ccb.ccb_h, periph->path, /*priority*/1); 1117195534Sscottl 1118195534Sscottl ccb.ccb_h.ccb_state = ADA_CCB_DUMP; 1119195534Sscottl cam_fill_ataio(&ccb.ataio, 1120195534Sscottl 1, 1121195534Sscottl adadone, 1122195534Sscottl CAM_DIR_NONE, 1123195534Sscottl 0, 1124195534Sscottl NULL, 1125195534Sscottl 0, 1126195534Sscottl ada_default_timeout*1000); 1127195534Sscottl 1128195534Sscottl if (softc->flags & ADA_FLAG_CAN_48BIT) 1129195534Sscottl ata_48bit_cmd(&ccb.ataio, ATA_FLUSHCACHE48, 0, 0, 0); 1130195534Sscottl else 1131196659Smav ata_28bit_cmd(&ccb.ataio, ATA_FLUSHCACHE, 0, 0, 0); 1132195534Sscottl xpt_polled_action(&ccb); 1133195534Sscottl 1134195534Sscottl if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) 1135195534Sscottl xpt_print(periph->path, "Synchronize cache failed\n"); 1136195534Sscottl 1137195534Sscottl if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0) 1138195534Sscottl cam_release_devq(ccb.ccb_h.path, 1139195534Sscottl /*relsim_flags*/0, 1140195534Sscottl /*reduction*/0, 1141195534Sscottl /*timeout*/0, 1142195534Sscottl /*getcount_only*/0); 1143195534Sscottl cam_periph_unlock(periph); 1144195534Sscottl } 1145195534Sscottl} 1146195534Sscottl 1147195534Sscottl#endif /* _KERNEL */ 1148