ata_da.c revision 256216
178828Sobrien/*- 278828Sobrien * Copyright (c) 2009 Alexander Motin <mav@FreeBSD.org> 3218822Sdim * All rights reserved. 433965Sjdp * 533965Sjdp * Redistribution and use in source and binary forms, with or without 6218822Sdim * modification, are permitted provided that the following conditions 733965Sjdp * are met: 8218822Sdim * 1. Redistributions of source code must retain the above copyright 9218822Sdim * notice, this list of conditions and the following disclaimer, 10218822Sdim * without modification, immediately at the beginning of the file. 11218822Sdim * 2. Redistributions in binary form must reproduce the above copyright 1233965Sjdp * notice, this list of conditions and the following disclaimer in the 13218822Sdim * documentation and/or other materials provided with the distribution. 14218822Sdim * 15218822Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16218822Sdim * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1733965Sjdp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18218822Sdim * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19218822Sdim * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20218822Sdim * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2133965Sjdp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2233965Sjdp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2333965Sjdp * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2433965Sjdp * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2533965Sjdp */ 2633965Sjdp 2733965Sjdp#include <sys/cdefs.h> 2833965Sjdp__FBSDID("$FreeBSD: stable/9/sys/cam/ata/ata_da.c 256216 2013-10-09 18:58:28Z mav $"); 29218822Sdim 3033965Sjdp#include "opt_ada.h" 3133965Sjdp#include "opt_ata.h" 32130561Sobrien 3333965Sjdp#include <sys/param.h> 3433965Sjdp 3533965Sjdp#ifdef _KERNEL 3677298Sobrien#include <sys/systm.h> 3733965Sjdp#include <sys/kernel.h> 3833965Sjdp#include <sys/bio.h> 3933965Sjdp#include <sys/sysctl.h> 4033965Sjdp#include <sys/taskqueue.h> 4160484Sobrien#include <sys/lock.h> 4233965Sjdp#include <sys/mutex.h> 4333965Sjdp#include <sys/conf.h> 4433965Sjdp#include <sys/devicestat.h> 4533965Sjdp#include <sys/eventhandler.h> 4633965Sjdp#include <sys/malloc.h> 4733965Sjdp#include <sys/cons.h> 4833965Sjdp#include <sys/proc.h> 49218822Sdim#include <sys/reboot.h> 5033965Sjdp#include <geom/geom_disk.h> 51130561Sobrien#endif /* _KERNEL */ 52130561Sobrien 5333965Sjdp#ifndef _KERNEL 54130561Sobrien#include <stdio.h> 55130561Sobrien#include <string.h> 56130561Sobrien#endif /* _KERNEL */ 5760484Sobrien 5833965Sjdp#include <cam/cam.h> 5933965Sjdp#include <cam/cam_ccb.h> 6033965Sjdp#include <cam/cam_periph.h> 6133965Sjdp#include <cam/cam_xpt_periph.h> 6233965Sjdp#include <cam/cam_sim.h> 6333965Sjdp 6433965Sjdp#include <cam/ata/ata_all.h> 6533965Sjdp 6633965Sjdp#include <machine/md_var.h> /* geometry translation */ 67104834Sobrien 68104834Sobrien#ifdef _KERNEL 69104834Sobrien 70104834Sobrien#define ATA_MAX_28BIT_LBA 268435455UL 71104834Sobrien 72104834Sobrientypedef enum { 7333965Sjdp ADA_STATE_RAHEAD, 7460484Sobrien ADA_STATE_WCACHE, 7560484Sobrien ADA_STATE_NORMAL 7689857Sobrien} ada_state; 7760484Sobrien 7833965Sjdptypedef enum { 7933965Sjdp ADA_FLAG_CAN_48BIT = 0x0002, 8033965Sjdp ADA_FLAG_CAN_FLUSHCACHE = 0x0004, 8133965Sjdp ADA_FLAG_CAN_NCQ = 0x0008, 82130561Sobrien ADA_FLAG_CAN_DMA = 0x0010, 83130561Sobrien ADA_FLAG_NEED_OTAG = 0x0020, 8433965Sjdp ADA_FLAG_WENT_IDLE = 0x0040, 8533965Sjdp ADA_FLAG_CAN_TRIM = 0x0080, 8633965Sjdp ADA_FLAG_OPEN = 0x0100, 8733965Sjdp ADA_FLAG_SCTX_INIT = 0x0200, 8833965Sjdp ADA_FLAG_CAN_CFA = 0x0400, 8933965Sjdp ADA_FLAG_CAN_POWERMGT = 0x0800, 9033965Sjdp ADA_FLAG_CAN_DMA48 = 0x1000, 9133965Sjdp ADA_FLAG_DIRTY = 0x2000 9233965Sjdp} ada_flags; 9333965Sjdp 9433965Sjdptypedef enum { 95218822Sdim ADA_Q_NONE = 0x00, 96104834Sobrien ADA_Q_4K = 0x01, 9760484Sobrien} ada_quirks; 9889857Sobrien 9933965Sjdp#define ADA_Q_BIT_STRING \ 10060484Sobrien "\020" \ 10160484Sobrien "\0014K" 10260484Sobrien 103130561Sobrientypedef enum { 10433965Sjdp ADA_CCB_RAHEAD = 0x01, 10533965Sjdp ADA_CCB_WCACHE = 0x02, 10633965Sjdp ADA_CCB_BUFFER_IO = 0x03, 10733965Sjdp ADA_CCB_WAITING = 0x04, 10833965Sjdp ADA_CCB_DUMP = 0x05, 10933965Sjdp ADA_CCB_TRIM = 0x06, 11033965Sjdp ADA_CCB_TYPE_MASK = 0x0F, 111130561Sobrien} ada_ccb_state; 11233965Sjdp 11333965Sjdp/* Offsets into our private area for storing information */ 11433965Sjdp#define ccb_state ppriv_field0 11533965Sjdp#define ccb_bp ppriv_ptr1 11633965Sjdp 11733965Sjdpstruct disk_params { 11833965Sjdp u_int8_t heads; 11933965Sjdp u_int8_t secs_per_track; 12033965Sjdp u_int32_t cylinders; 12133965Sjdp u_int32_t secsize; /* Number of bytes/logical sector */ 12233965Sjdp u_int64_t sectors; /* Total number sectors */ 12333965Sjdp}; 12433965Sjdp 12533965Sjdp#define TRIM_MAX_BLOCKS 8 126130561Sobrien#define TRIM_MAX_RANGES (TRIM_MAX_BLOCKS * ATA_DSM_BLK_RANGES) 12733965Sjdp#define TRIM_MAX_BIOS (TRIM_MAX_RANGES * 4) 12838889Sjdpstruct trim_request { 129218822Sdim uint8_t data[TRIM_MAX_RANGES * ATA_DSM_RANGE_SIZE]; 130218822Sdim struct bio *bps[TRIM_MAX_BIOS]; 13133965Sjdp}; 13233965Sjdp 13389857Sobrienstruct ada_softc { 134218822Sdim struct bio_queue_head bio_queue; 13533965Sjdp struct bio_queue_head trim_queue; 136218822Sdim ada_state state; 13733965Sjdp ada_flags flags; 138218822Sdim ada_quirks quirks; 13933965Sjdp int sort_io_queue; 140218822Sdim int ordered_tag_count; 14133965Sjdp int outstanding_cmds; 14233965Sjdp int trim_max_ranges; 14333965Sjdp int trim_running; 144218822Sdim int read_ahead; 145218822Sdim int write_cache; 14633965Sjdp#ifdef ADA_TEST_FAILURE 14760484Sobrien int force_read_error; 14833965Sjdp int force_write_error; 14933965Sjdp int periodic_read_error; 15033965Sjdp int periodic_read_count; 15138889Sjdp#endif 152218822Sdim struct disk_params params; 15360484Sobrien struct disk *disk; 154218822Sdim struct task sysctl_task; 15533965Sjdp struct sysctl_ctx_list sysctl_ctx; 15633965Sjdp struct sysctl_oid *sysctl_tree; 15733965Sjdp struct callout sendordered_c; 158218822Sdim struct trim_request trim_req; 15933965Sjdp}; 16033965Sjdp 16133965Sjdpstruct ada_quirk_entry { 162130561Sobrien struct scsi_inquiry_pattern inq_pat; 16333965Sjdp ada_quirks quirks; 16433965Sjdp}; 16533965Sjdp 166218822Sdimstatic struct ada_quirk_entry ada_quirk_table[] = 16733965Sjdp{ 16833965Sjdp { 16933965Sjdp /* Hitachi Advanced Format (4k) drives */ 17033965Sjdp { T_DIRECT, SIP_MEDIA_FIXED, "*", "Hitachi H??????????E3*", "*" }, 17133965Sjdp /*quirks*/ADA_Q_4K 17233965Sjdp }, 17333965Sjdp { 17433965Sjdp /* Samsung Advanced Format (4k) drives */ 17533965Sjdp { T_DIRECT, SIP_MEDIA_FIXED, "*", "SAMSUNG HD155UI*", "*" }, 17633965Sjdp /*quirks*/ADA_Q_4K 17733965Sjdp }, 17833965Sjdp { 17933965Sjdp /* Samsung Advanced Format (4k) drives */ 18033965Sjdp { T_DIRECT, SIP_MEDIA_FIXED, "*", "SAMSUNG HD204UI*", "*" }, 181104834Sobrien /*quirks*/ADA_Q_4K 18233965Sjdp }, 183130561Sobrien { 18433965Sjdp /* Seagate Barracuda Green Advanced Format (4k) drives */ 18533965Sjdp { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST????DL*", "*" }, 18633965Sjdp /*quirks*/ADA_Q_4K 18760484Sobrien }, 18833965Sjdp { 18933965Sjdp /* Seagate Barracuda Advanced Format (4k) drives */ 19033965Sjdp { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST???DM*", "*" }, 19133965Sjdp /*quirks*/ADA_Q_4K 19233965Sjdp }, 19333965Sjdp { 19433965Sjdp /* Seagate Barracuda Advanced Format (4k) drives */ 19533965Sjdp { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST????DM*", "*" }, 19633965Sjdp /*quirks*/ADA_Q_4K 19733965Sjdp }, 19833965Sjdp { 19933965Sjdp /* Seagate Momentus Advanced Format (4k) drives */ 20033965Sjdp { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9500423AS*", "*" }, 20133965Sjdp /*quirks*/ADA_Q_4K 20233965Sjdp }, 203130561Sobrien { 20433965Sjdp /* Seagate Momentus Advanced Format (4k) drives */ 20533965Sjdp { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9500424AS*", "*" }, 20660484Sobrien /*quirks*/ADA_Q_4K 20733965Sjdp }, 20833965Sjdp { 20933965Sjdp /* Seagate Momentus Advanced Format (4k) drives */ 21033965Sjdp { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9640423AS*", "*" }, 21133965Sjdp /*quirks*/ADA_Q_4K 212130561Sobrien }, 21333965Sjdp { 21433965Sjdp /* Seagate Momentus Advanced Format (4k) drives */ 21533965Sjdp { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9640424AS*", "*" }, 21633965Sjdp /*quirks*/ADA_Q_4K 217130561Sobrien }, 21833965Sjdp { 21933965Sjdp /* Seagate Momentus Advanced Format (4k) drives */ 22033965Sjdp { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9750420AS*", "*" }, 22133965Sjdp /*quirks*/ADA_Q_4K 22233965Sjdp }, 22333965Sjdp { 22433965Sjdp /* Seagate Momentus Advanced Format (4k) drives */ 22533965Sjdp { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9750422AS*", "*" }, 22633965Sjdp /*quirks*/ADA_Q_4K 22733965Sjdp }, 22833965Sjdp { 22933965Sjdp /* Seagate Momentus Advanced Format (4k) drives */ 23033965Sjdp { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST9750423AS*", "*" }, 23133965Sjdp /*quirks*/ADA_Q_4K 23233965Sjdp }, 23333965Sjdp { 23433965Sjdp /* Seagate Momentus Thin Advanced Format (4k) drives */ 23533965Sjdp { T_DIRECT, SIP_MEDIA_FIXED, "*", "ST???LT*", "*" }, 23633965Sjdp /*quirks*/ADA_Q_4K 237130561Sobrien }, 238130561Sobrien { 23933965Sjdp /* WDC Caviar Green Advanced Format (4k) drives */ 24033965Sjdp { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD????RS*", "*" }, 24133965Sjdp /*quirks*/ADA_Q_4K 242104834Sobrien }, 24333965Sjdp { 24433965Sjdp /* WDC Caviar Green Advanced Format (4k) drives */ 245104834Sobrien { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD????RX*", "*" }, 246104834Sobrien /*quirks*/ADA_Q_4K 24733965Sjdp }, 24833965Sjdp { 24933965Sjdp /* WDC Caviar Green Advanced Format (4k) drives */ 25089857Sobrien { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD??????RS*", "*" }, 25189857Sobrien /*quirks*/ADA_Q_4K 25289857Sobrien }, 25333965Sjdp { 254130561Sobrien /* WDC Caviar Green Advanced Format (4k) drives */ 25533965Sjdp { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD??????RX*", "*" }, 25633965Sjdp /*quirks*/ADA_Q_4K 25733965Sjdp }, 25833965Sjdp { 25933965Sjdp /* WDC Scorpio Black Advanced Format (4k) drives */ 26033965Sjdp { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD???PKT*", "*" }, 26133965Sjdp /*quirks*/ADA_Q_4K 26233965Sjdp }, 26333965Sjdp { 26433965Sjdp /* WDC Scorpio Black Advanced Format (4k) drives */ 26533965Sjdp { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD?????PKT*", "*" }, 26633965Sjdp /*quirks*/ADA_Q_4K 26733965Sjdp }, 26833965Sjdp { 26933965Sjdp /* WDC Scorpio Blue Advanced Format (4k) drives */ 27033965Sjdp { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD???PVT*", "*" }, 27133965Sjdp /*quirks*/ADA_Q_4K 27233965Sjdp }, 27333965Sjdp { 27433965Sjdp /* WDC Scorpio Blue Advanced Format (4k) drives */ 27533965Sjdp { T_DIRECT, SIP_MEDIA_FIXED, "*", "WDC WD?????PVT*", "*" }, 27633965Sjdp /*quirks*/ADA_Q_4K 27733965Sjdp }, 27833965Sjdp /* SSDs */ 27933965Sjdp { 28033965Sjdp /* 28133965Sjdp * Corsair Force 2 SSDs 28233965Sjdp * 4k optimised & trim only works in 4k requests + 4k aligned 283218822Sdim */ 28433965Sjdp { T_DIRECT, SIP_MEDIA_FIXED, "*", "Corsair CSSD-F*", "*" }, 285218822Sdim /*quirks*/ADA_Q_4K 286218822Sdim }, 287218822Sdim { 288218822Sdim /* 289218822Sdim * Corsair Force 3 SSDs 29033965Sjdp * 4k optimised & trim only works in 4k requests + 4k aligned 29133965Sjdp */ 292218822Sdim { T_DIRECT, SIP_MEDIA_FIXED, "*", "Corsair Force 3*", "*" }, 29360484Sobrien /*quirks*/ADA_Q_4K 294218822Sdim }, 29533965Sjdp { 29633965Sjdp /* 29733965Sjdp * Corsair Force GT SSDs 29833965Sjdp * 4k optimised & trim only works in 4k requests + 4k aligned 299218822Sdim */ 300218822Sdim { T_DIRECT, SIP_MEDIA_FIXED, "*", "Corsair Force GT*", "*" }, 301218822Sdim /*quirks*/ADA_Q_4K 30233965Sjdp }, 30333965Sjdp { 30433965Sjdp /* 305218822Sdim * Crucial M4 SSDs 30633965Sjdp * 4k optimised & trim only works in 4k requests + 4k aligned 30733965Sjdp */ 30833965Sjdp { T_DIRECT, SIP_MEDIA_FIXED, "*", "M4-CT???M4SSD2*", "*" }, 30933965Sjdp /*quirks*/ADA_Q_4K 31033965Sjdp }, 31133965Sjdp { 31233965Sjdp /* 31333965Sjdp * Crucial RealSSD C300 SSDs 31433965Sjdp * 4k optimised 31533965Sjdp */ 31633965Sjdp { T_DIRECT, SIP_MEDIA_FIXED, "*", "C300-CTFDDAC???MAG*", 31733965Sjdp "*" }, /*quirks*/ADA_Q_4K 31833965Sjdp }, 31933965Sjdp { 32033965Sjdp /* 32133965Sjdp * Intel 320 Series SSDs 32233965Sjdp * 4k optimised & trim only works in 4k requests + 4k aligned 32333965Sjdp */ 324130561Sobrien { T_DIRECT, SIP_MEDIA_FIXED, "*", "INTEL SSDSA2CW*", "*" }, 32533965Sjdp /*quirks*/ADA_Q_4K 32633965Sjdp }, 32733965Sjdp { 32833965Sjdp /* 32933965Sjdp * Intel 330 Series SSDs 33033965Sjdp * 4k optimised & trim only works in 4k requests + 4k aligned 33133965Sjdp */ 33233965Sjdp { T_DIRECT, SIP_MEDIA_FIXED, "*", "INTEL SSDSC2CT*", "*" }, 333130561Sobrien /*quirks*/ADA_Q_4K 33433965Sjdp }, 335130561Sobrien { 33689857Sobrien /* 337130561Sobrien * Intel 510 Series SSDs 33833965Sjdp * 4k optimised & trim only works in 4k requests + 4k aligned 33933965Sjdp */ 34033965Sjdp { T_DIRECT, SIP_MEDIA_FIXED, "*", "INTEL SSDSC2MH*", "*" }, 34133965Sjdp /*quirks*/ADA_Q_4K 34233965Sjdp }, 34333965Sjdp { 34433965Sjdp /* 345130561Sobrien * Intel 520 Series SSDs 34689857Sobrien * 4k optimised & trim only works in 4k requests + 4k aligned 34789857Sobrien */ 34889857Sobrien { T_DIRECT, SIP_MEDIA_FIXED, "*", "INTEL SSDSC2BW*", "*" }, 34933965Sjdp /*quirks*/ADA_Q_4K 35033965Sjdp }, 35133965Sjdp { 35233965Sjdp /* 35360484Sobrien * Kingston E100 Series SSDs 35433965Sjdp * 4k optimised & trim only works in 4k requests + 4k aligned 35533965Sjdp */ 35633965Sjdp { T_DIRECT, SIP_MEDIA_FIXED, "*", "KINGSTON SE100S3*", "*" }, 35733965Sjdp /*quirks*/ADA_Q_4K 35833965Sjdp }, 35933965Sjdp { 36033965Sjdp /* 36133965Sjdp * Kingston HyperX 3k SSDs 36233965Sjdp * 4k optimised & trim only works in 4k requests + 4k aligned 36333965Sjdp */ 36433965Sjdp { T_DIRECT, SIP_MEDIA_FIXED, "*", "KINGSTON SH103S3*", "*" }, 36533965Sjdp /*quirks*/ADA_Q_4K 36633965Sjdp }, 36733965Sjdp { 36833965Sjdp /* 36933965Sjdp * OCZ Agility 3 SSDs 37033965Sjdp * 4k optimised & trim only works in 4k requests + 4k aligned 37133965Sjdp */ 37233965Sjdp { T_DIRECT, SIP_MEDIA_FIXED, "*", "OCZ-AGILITY3*", "*" }, 37333965Sjdp /*quirks*/ADA_Q_4K 37433965Sjdp }, 375218822Sdim { 376218822Sdim /* 377218822Sdim * OCZ Deneva R Series SSDs 378218822Sdim * 4k optimised & trim only works in 4k requests + 4k aligned 379218822Sdim */ 380218822Sdim { T_DIRECT, SIP_MEDIA_FIXED, "*", "DENRSTE251M45*", "*" }, 381218822Sdim /*quirks*/ADA_Q_4K 382218822Sdim }, 383218822Sdim { 384218822Sdim /* 385218822Sdim * OCZ Vertex 2 SSDs (inc pro series) 386218822Sdim * 4k optimised & trim only works in 4k requests + 4k aligned 38733965Sjdp */ 38833965Sjdp { T_DIRECT, SIP_MEDIA_FIXED, "*", "OCZ?VERTEX2*", "*" }, 38933965Sjdp /*quirks*/ADA_Q_4K 39033965Sjdp }, 39133965Sjdp { 39233965Sjdp /* 39333965Sjdp * OCZ Vertex 3 SSDs 39433965Sjdp * 4k optimised & trim only works in 4k requests + 4k aligned 39533965Sjdp */ 39633965Sjdp { T_DIRECT, SIP_MEDIA_FIXED, "*", "OCZ-VERTEX3*", "*" }, 39733965Sjdp /*quirks*/ADA_Q_4K 39833965Sjdp }, 39933965Sjdp { 40033965Sjdp /* 401130561Sobrien * OCZ Vertex 4 SSDs 40233965Sjdp * 4k optimised & trim only works in 4k requests + 4k aligned 403130561Sobrien */ 404130561Sobrien { T_DIRECT, SIP_MEDIA_FIXED, "*", "OCZ-VERTEX4*", "*" }, 405130561Sobrien /*quirks*/ADA_Q_4K 40633965Sjdp }, 40733965Sjdp { 40833965Sjdp /* 40933965Sjdp * Samsung 830 Series SSDs 41060484Sobrien * 4k optimised 41133965Sjdp */ 41260484Sobrien { T_DIRECT, SIP_MEDIA_FIXED, "*", "SAMSUNG SSD 830 Series*", "*" }, 41360484Sobrien /*quirks*/ADA_Q_4K 41460484Sobrien }, 41533965Sjdp { 41660484Sobrien /* 41760484Sobrien * SuperTalent TeraDrive CT SSDs 41860484Sobrien * 4k optimised & trim only works in 4k requests + 4k aligned 41933965Sjdp */ 42060484Sobrien { T_DIRECT, SIP_MEDIA_FIXED, "*", "FTM??CT25H*", "*" }, 42160484Sobrien /*quirks*/ADA_Q_4K 42260484Sobrien }, 42333965Sjdp { 42433965Sjdp /* 42560484Sobrien * XceedIOPS SATA SSDs 42660484Sobrien * 4k optimised 42733965Sjdp */ 42860484Sobrien { T_DIRECT, SIP_MEDIA_FIXED, "*", "SG9XCS2D*", "*" }, 429218822Sdim /*quirks*/ADA_Q_4K 43060484Sobrien }, 43133965Sjdp { 43260484Sobrien /* Default */ 43333965Sjdp { 43460484Sobrien T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED, 435218822Sdim /*vendor*/"*", /*product*/"*", /*revision*/"*" 43660484Sobrien }, 43733965Sjdp /*quirks*/0 438218822Sdim }, 43933965Sjdp}; 44060484Sobrien 441218822Sdimstatic disk_strategy_t adastrategy; 44260484Sobrienstatic dumper_t adadump; 44333965Sjdpstatic periph_init_t adainit; 444218822Sdimstatic void adaasync(void *callback_arg, u_int32_t code, 44533965Sjdp struct cam_path *path, void *arg); 446218822Sdimstatic void adasysctlinit(void *context, int pending); 447218822Sdimstatic periph_ctor_t adaregister; 448218822Sdimstatic periph_dtor_t adacleanup; 449218822Sdimstatic periph_start_t adastart; 450218822Sdimstatic periph_oninv_t adaoninvalidate; 451218822Sdimstatic void adadone(struct cam_periph *periph, 452218822Sdim union ccb *done_ccb); 453218822Sdimstatic int adaerror(union ccb *ccb, u_int32_t cam_flags, 454218822Sdim u_int32_t sense_flags); 455218822Sdimstatic void adagetparams(struct cam_periph *periph, 456218822Sdim struct ccb_getdev *cgd); 457218822Sdimstatic timeout_t adasendorderedtag; 458218822Sdimstatic void adashutdown(void *arg, int howto); 459218822Sdimstatic void adasuspend(void *arg); 460218822Sdimstatic void adaresume(void *arg); 461218822Sdim 462218822Sdim#ifndef ADA_DEFAULT_LEGACY_ALIASES 463218822Sdim#ifdef ATA_CAM 464218822Sdim#define ADA_DEFAULT_LEGACY_ALIASES 1 465218822Sdim#else 466218822Sdim#define ADA_DEFAULT_LEGACY_ALIASES 0 467218822Sdim#endif 468218822Sdim#endif 469218822Sdim 470218822Sdim#ifndef ADA_DEFAULT_TIMEOUT 471218822Sdim#define ADA_DEFAULT_TIMEOUT 30 /* Timeout in seconds */ 472218822Sdim#endif 473218822Sdim 474218822Sdim#ifndef ADA_DEFAULT_RETRY 475218822Sdim#define ADA_DEFAULT_RETRY 4 47660484Sobrien#endif 477218822Sdim 47860484Sobrien#ifndef ADA_DEFAULT_SEND_ORDERED 47933965Sjdp#define ADA_DEFAULT_SEND_ORDERED 1 48060484Sobrien#endif 48160484Sobrien 48260484Sobrien#ifndef ADA_DEFAULT_SPINDOWN_SHUTDOWN 48360484Sobrien#define ADA_DEFAULT_SPINDOWN_SHUTDOWN 1 48460484Sobrien#endif 48560484Sobrien 48660484Sobrien#ifndef ADA_DEFAULT_SPINDOWN_SUSPEND 48760484Sobrien#define ADA_DEFAULT_SPINDOWN_SUSPEND 1 48860484Sobrien#endif 489130561Sobrien 49060484Sobrien#ifndef ADA_DEFAULT_READ_AHEAD 49160484Sobrien#define ADA_DEFAULT_READ_AHEAD 1 49260484Sobrien#endif 49360484Sobrien 49460484Sobrien#ifndef ADA_DEFAULT_WRITE_CACHE 49560484Sobrien#define ADA_DEFAULT_WRITE_CACHE 1 49660484Sobrien#endif 49760484Sobrien 49860484Sobrien#define ADA_RA (softc->read_ahead >= 0 ? \ 49960484Sobrien softc->read_ahead : ada_read_ahead) 50060484Sobrien#define ADA_WC (softc->write_cache >= 0 ? \ 50160484Sobrien softc->write_cache : ada_write_cache) 50260484Sobrien#define ADA_SIO (softc->sort_io_queue >= 0 ? \ 50389857Sobrien softc->sort_io_queue : cam_sort_io_queues) 50460484Sobrien 50589857Sobrien/* 50689857Sobrien * Most platforms map firmware geometry to actual, but some don't. If 50789857Sobrien * not overridden, default to nothing. 50889857Sobrien */ 50989857Sobrien#ifndef ata_disk_firmware_geom_adjust 51060484Sobrien#define ata_disk_firmware_geom_adjust(disk) 51189857Sobrien#endif 51289857Sobrien 51360484Sobrienstatic int ada_legacy_aliases = ADA_DEFAULT_LEGACY_ALIASES; 51489857Sobrienstatic int ada_retry_count = ADA_DEFAULT_RETRY; 51589857Sobrienstatic int ada_default_timeout = ADA_DEFAULT_TIMEOUT; 51689857Sobrienstatic int ada_send_ordered = ADA_DEFAULT_SEND_ORDERED; 51789857Sobrienstatic int ada_spindown_shutdown = ADA_DEFAULT_SPINDOWN_SHUTDOWN; 51889857Sobrienstatic int ada_spindown_suspend = ADA_DEFAULT_SPINDOWN_SUSPEND; 51960484Sobrienstatic int ada_read_ahead = ADA_DEFAULT_READ_AHEAD; 52060484Sobrienstatic int ada_write_cache = ADA_DEFAULT_WRITE_CACHE; 52160484Sobrien 52260484Sobrienstatic SYSCTL_NODE(_kern_cam, OID_AUTO, ada, CTLFLAG_RD, 0, 52360484Sobrien "CAM Direct Access Disk driver"); 52460484SobrienSYSCTL_INT(_kern_cam_ada, OID_AUTO, legacy_aliases, CTLFLAG_RW, 52589857Sobrien &ada_legacy_aliases, 0, "Create legacy-like device aliases"); 52689857SobrienTUNABLE_INT("kern.cam.ada.legacy_aliases", &ada_legacy_aliases); 52789857SobrienSYSCTL_INT(_kern_cam_ada, OID_AUTO, retry_count, CTLFLAG_RW, 528218822Sdim &ada_retry_count, 0, "Normal I/O retry count"); 52989857SobrienTUNABLE_INT("kern.cam.ada.retry_count", &ada_retry_count); 53060484SobrienSYSCTL_INT(_kern_cam_ada, OID_AUTO, default_timeout, CTLFLAG_RW, 53189857Sobrien &ada_default_timeout, 0, "Normal I/O timeout (in seconds)"); 53260484SobrienTUNABLE_INT("kern.cam.ada.default_timeout", &ada_default_timeout); 53389857SobrienSYSCTL_INT(_kern_cam_ada, OID_AUTO, send_ordered, CTLFLAG_RW, 53460484Sobrien &ada_send_ordered, 0, "Send Ordered Tags"); 53589857SobrienTUNABLE_INT("kern.cam.ada.send_ordered", &ada_send_ordered); 53660484SobrienSYSCTL_INT(_kern_cam_ada, OID_AUTO, spindown_shutdown, CTLFLAG_RW, 53789857Sobrien &ada_spindown_shutdown, 0, "Spin down upon shutdown"); 53860484SobrienTUNABLE_INT("kern.cam.ada.spindown_shutdown", &ada_spindown_shutdown); 53933965SjdpSYSCTL_INT(_kern_cam_ada, OID_AUTO, spindown_suspend, CTLFLAG_RW, 54033965Sjdp &ada_spindown_suspend, 0, "Spin down upon suspend"); 54160484SobrienTUNABLE_INT("kern.cam.ada.spindown_suspend", &ada_spindown_suspend); 54260484SobrienSYSCTL_INT(_kern_cam_ada, OID_AUTO, read_ahead, CTLFLAG_RW, 54360484Sobrien &ada_read_ahead, 0, "Enable disk read-ahead"); 544130561SobrienTUNABLE_INT("kern.cam.ada.read_ahead", &ada_read_ahead); 54560484SobrienSYSCTL_INT(_kern_cam_ada, OID_AUTO, write_cache, CTLFLAG_RW, 546130561Sobrien &ada_write_cache, 0, "Enable disk write cache"); 54760484SobrienTUNABLE_INT("kern.cam.ada.write_cache", &ada_write_cache); 54860484Sobrien 54933965Sjdp/* 55033965Sjdp * ADA_ORDEREDTAG_INTERVAL determines how often, relative 55133965Sjdp * to the default timeout, we check to see whether an ordered 55233965Sjdp * tagged transaction is appropriate to prevent simple tag 553130561Sobrien * starvation. Since we'd like to ensure that there is at least 55433965Sjdp * 1/2 of the timeout length left for a starved transaction to 55533965Sjdp * complete after we've sent an ordered tag, we must poll at least 55633965Sjdp * four times in every timeout period. This takes care of the worst 55733965Sjdp * case where a starved transaction starts during an interval that 558130561Sobrien * meets the requirement "don't send an ordered tag" test so it takes 559130561Sobrien * us two intervals to determine that a tag must be sent. 56033965Sjdp */ 561218822Sdim#ifndef ADA_ORDEREDTAG_INTERVAL 56260484Sobrien#define ADA_ORDEREDTAG_INTERVAL 4 563130561Sobrien#endif 56460484Sobrien 56560484Sobrienstatic struct periph_driver adadriver = 56633965Sjdp{ 56733965Sjdp adainit, "ada", 56833965Sjdp TAILQ_HEAD_INITIALIZER(adadriver.units), /* generation */ 0 569104834Sobrien}; 57033965Sjdp 571130561SobrienPERIPHDRIVER_DECLARE(ada, adadriver); 572104834Sobrien 57333965Sjdpstatic MALLOC_DEFINE(M_ATADA, "ata_da", "ata_da buffers"); 574104834Sobrien 57533965Sjdpstatic int 576218822Sdimadaopen(struct disk *dp) 577218822Sdim{ 578218822Sdim struct cam_periph *periph; 57933965Sjdp struct ada_softc *softc; 58033965Sjdp int error; 58133965Sjdp 58233965Sjdp periph = (struct cam_periph *)dp->d_drv1; 58333965Sjdp if (cam_periph_acquire(periph) != CAM_REQ_CMP) { 58433965Sjdp return(ENXIO); 585130561Sobrien } 58633965Sjdp 58733965Sjdp cam_periph_lock(periph); 58833965Sjdp if ((error = cam_periph_hold(periph, PRIBIO|PCATCH)) != 0) { 58933965Sjdp cam_periph_unlock(periph); 59033965Sjdp cam_periph_release(periph); 59133965Sjdp return (error); 59233965Sjdp } 59333965Sjdp 59438889Sjdp CAM_DEBUG(periph->path, CAM_DEBUG_TRACE | CAM_DEBUG_PERIPH, 59538889Sjdp ("adaopen\n")); 59633965Sjdp 59733965Sjdp softc = (struct ada_softc *)periph->softc; 59833965Sjdp softc->flags |= ADA_FLAG_OPEN; 59933965Sjdp 60033965Sjdp cam_periph_unhold(periph); 60133965Sjdp cam_periph_unlock(periph); 60233965Sjdp return (0); 60333965Sjdp} 604104834Sobrien 605104834Sobrienstatic int 60633965Sjdpadaclose(struct disk *dp) 607218822Sdim{ 60833965Sjdp struct cam_periph *periph; 60933965Sjdp struct ada_softc *softc; 61033965Sjdp union ccb *ccb; 611104834Sobrien int error; 612104834Sobrien 613104834Sobrien periph = (struct cam_periph *)dp->d_drv1; 614104834Sobrien cam_periph_lock(periph); 615104834Sobrien if (cam_periph_hold(periph, PRIBIO) != 0) { 61633965Sjdp cam_periph_unlock(periph); 61733965Sjdp cam_periph_release(periph); 61833965Sjdp return (0); 61933965Sjdp } 62033965Sjdp 62133965Sjdp softc = (struct ada_softc *)periph->softc; 62233965Sjdp 62333965Sjdp CAM_DEBUG(periph->path, CAM_DEBUG_TRACE | CAM_DEBUG_PERIPH, 62433965Sjdp ("adaclose\n")); 62533965Sjdp 62633965Sjdp /* We only sync the cache if the drive is capable of it. */ 62733965Sjdp if ((softc->flags & ADA_FLAG_DIRTY) != 0 && 62833965Sjdp (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) != 0 && 62933965Sjdp (periph->flags & CAM_PERIPH_INVALID) == 0) { 63033965Sjdp 63133965Sjdp ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 63233965Sjdp cam_fill_ataio(&ccb->ataio, 63333965Sjdp 1, 63433965Sjdp adadone, 63533965Sjdp CAM_DIR_NONE, 63633965Sjdp 0, 63733965Sjdp NULL, 63833965Sjdp 0, 63933965Sjdp ada_default_timeout*1000); 64033965Sjdp 64133965Sjdp if (softc->flags & ADA_FLAG_CAN_48BIT) 64233965Sjdp ata_48bit_cmd(&ccb->ataio, ATA_FLUSHCACHE48, 0, 0, 0); 64333965Sjdp else 64433965Sjdp ata_28bit_cmd(&ccb->ataio, ATA_FLUSHCACHE, 0, 0, 0); 64533965Sjdp error = cam_periph_runccb(ccb, adaerror, /*cam_flags*/0, 64633965Sjdp /*sense_flags*/0, softc->disk->d_devstat); 64733965Sjdp 64833965Sjdp if (error != 0) 64933965Sjdp xpt_print(periph->path, "Synchronize cache failed\n"); 65033965Sjdp else 65133965Sjdp softc->flags &= ~ADA_FLAG_DIRTY; 65233965Sjdp xpt_release_ccb(ccb); 65333965Sjdp } 65433965Sjdp 65533965Sjdp softc->flags &= ~ADA_FLAG_OPEN; 656218822Sdim cam_periph_unhold(periph); 65733965Sjdp cam_periph_unlock(periph); 658218822Sdim cam_periph_release(periph); 659218822Sdim return (0); 660218822Sdim} 661218822Sdim 66233965Sjdpstatic void 66333965Sjdpadaschedule(struct cam_periph *periph) 66433965Sjdp{ 66533965Sjdp struct ada_softc *softc = (struct ada_softc *)periph->softc; 66633965Sjdp uint32_t prio; 66733965Sjdp 66833965Sjdp if (softc->state != ADA_STATE_NORMAL) 66933965Sjdp return; 67033965Sjdp 67133965Sjdp /* Check if cam_periph_getccb() was called. */ 67233965Sjdp prio = periph->immediate_priority; 67333965Sjdp 67433965Sjdp /* Check if we have more work to do. */ 67533965Sjdp if (bioq_first(&softc->bio_queue) || 67633965Sjdp (!softc->trim_running && bioq_first(&softc->trim_queue))) { 67733965Sjdp prio = CAM_PRIORITY_NORMAL; 67833965Sjdp } 67933965Sjdp 680107492Sobrien /* Schedule CCB if any of above is true. */ 681130561Sobrien if (prio != CAM_PRIORITY_NONE) 68233965Sjdp xpt_schedule(periph, prio); 68333965Sjdp} 684107492Sobrien 68577298Sobrien/* 68677298Sobrien * Actually translate the requested transfer into one the physical driver 68777298Sobrien * can understand. The transfer is described by a buf and will include 68833965Sjdp * only one physical transfer. 689218822Sdim */ 690218822Sdimstatic void 691218822Sdimadastrategy(struct bio *bp) 692218822Sdim{ 69338889Sjdp struct cam_periph *periph; 69438889Sjdp struct ada_softc *softc; 69538889Sjdp 69633965Sjdp periph = (struct cam_periph *)bp->bio_disk->d_drv1; 697218822Sdim softc = (struct ada_softc *)periph->softc; 698218822Sdim 69933965Sjdp cam_periph_lock(periph); 70060484Sobrien 70133965Sjdp CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("adastrategy(%p)\n", bp)); 70233965Sjdp 70360484Sobrien /* 70460484Sobrien * If the device has been made invalid, error out 70560484Sobrien */ 70633965Sjdp if ((periph->flags & CAM_PERIPH_INVALID) != 0) { 70733965Sjdp cam_periph_unlock(periph); 70860484Sobrien biofinish(bp, NULL, ENXIO); 70960484Sobrien return; 71060484Sobrien } 71160484Sobrien 71260484Sobrien /* 71360484Sobrien * Place it in the queue of disk activities for this disk 71460484Sobrien */ 71560484Sobrien if (bp->bio_cmd == BIO_DELETE && 71660484Sobrien (softc->flags & ADA_FLAG_CAN_TRIM)) { 71760484Sobrien if (ADA_SIO) 71860484Sobrien bioq_disksort(&softc->trim_queue, bp); 71960484Sobrien else 72033965Sjdp bioq_insert_tail(&softc->trim_queue, bp); 72133965Sjdp } else { 72233965Sjdp if (ADA_SIO) 72333965Sjdp bioq_disksort(&softc->bio_queue, bp); 72433965Sjdp else 72533965Sjdp bioq_insert_tail(&softc->bio_queue, bp); 72633965Sjdp } 72733965Sjdp 72833965Sjdp /* 72933965Sjdp * Schedule ourselves for performing the work. 73033965Sjdp */ 73133965Sjdp adaschedule(periph); 73233965Sjdp cam_periph_unlock(periph); 73333965Sjdp 73433965Sjdp return; 73533965Sjdp} 73633965Sjdp 73733965Sjdpstatic int 73833965Sjdpadadump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t length) 73933965Sjdp{ 74033965Sjdp struct cam_periph *periph; 74133965Sjdp struct ada_softc *softc; 74233965Sjdp u_int secsize; 74333965Sjdp union ccb ccb; 74433965Sjdp struct disk *dp; 74533965Sjdp uint64_t lba; 74633965Sjdp uint16_t count; 74733965Sjdp int error = 0; 74833965Sjdp 749130561Sobrien dp = arg; 75033965Sjdp periph = dp->d_drv1; 751130561Sobrien softc = (struct ada_softc *)periph->softc; 75233965Sjdp cam_periph_lock(periph); 753130561Sobrien secsize = softc->params.secsize; 75433965Sjdp lba = offset / secsize; 75533965Sjdp count = length / secsize; 75633965Sjdp 75733965Sjdp if ((periph->flags & CAM_PERIPH_INVALID) != 0) { 75833965Sjdp cam_periph_unlock(periph); 75933965Sjdp return (ENXIO); 76033965Sjdp } 76133965Sjdp 76233965Sjdp if (length > 0) { 76333965Sjdp xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 76433965Sjdp ccb.ccb_h.ccb_state = ADA_CCB_DUMP; 76533965Sjdp cam_fill_ataio(&ccb.ataio, 76633965Sjdp 0, 76733965Sjdp adadone, 76833965Sjdp CAM_DIR_OUT, 76933965Sjdp 0, 77033965Sjdp (u_int8_t *) virtual, 77133965Sjdp length, 77233965Sjdp ada_default_timeout*1000); 77333965Sjdp if ((softc->flags & ADA_FLAG_CAN_48BIT) && 77433965Sjdp (lba + count >= ATA_MAX_28BIT_LBA || 77533965Sjdp count >= 256)) { 77633965Sjdp ata_48bit_cmd(&ccb.ataio, ATA_WRITE_DMA48, 77733965Sjdp 0, lba, count); 77833965Sjdp } else { 779218822Sdim ata_28bit_cmd(&ccb.ataio, ATA_WRITE_DMA, 78033965Sjdp 0, lba, count); 781218822Sdim } 78233965Sjdp xpt_polled_action(&ccb); 78333965Sjdp 78433965Sjdp error = cam_periph_error(&ccb, 78533965Sjdp 0, SF_NO_RECOVERY | SF_NO_RETRY, NULL); 786218822Sdim if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0) 78733965Sjdp cam_release_devq(ccb.ccb_h.path, /*relsim_flags*/0, 78833965Sjdp /*reduction*/0, /*timeout*/0, /*getcount_only*/0); 78933965Sjdp if (error != 0) 790218822Sdim printf("Aborting dump due to I/O error.\n"); 79133965Sjdp 792218822Sdim cam_periph_unlock(periph); 79333965Sjdp return (error); 79433965Sjdp } 79533965Sjdp 796218822Sdim if (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) { 79733965Sjdp xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 79833965Sjdp 799218822Sdim ccb.ccb_h.ccb_state = ADA_CCB_DUMP; 80033965Sjdp cam_fill_ataio(&ccb.ataio, 801218822Sdim 0, 80233965Sjdp adadone, 803218822Sdim CAM_DIR_NONE, 80433965Sjdp 0, 805218822Sdim NULL, 80633965Sjdp 0, 807218822Sdim ada_default_timeout*1000); 80833965Sjdp 809218822Sdim if (softc->flags & ADA_FLAG_CAN_48BIT) 81033965Sjdp ata_48bit_cmd(&ccb.ataio, ATA_FLUSHCACHE48, 0, 0, 0); 811218822Sdim else 81233965Sjdp ata_28bit_cmd(&ccb.ataio, ATA_FLUSHCACHE, 0, 0, 0); 813218822Sdim xpt_polled_action(&ccb); 81433965Sjdp 815218822Sdim error = cam_periph_error(&ccb, 81633965Sjdp 0, SF_NO_RECOVERY | SF_NO_RETRY, NULL); 817218822Sdim if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0) 81833965Sjdp cam_release_devq(ccb.ccb_h.path, /*relsim_flags*/0, 819218822Sdim /*reduction*/0, /*timeout*/0, /*getcount_only*/0); 82033965Sjdp if (error != 0) 821218822Sdim xpt_print(periph->path, "Synchronize cache failed\n"); 82233965Sjdp } 823218822Sdim cam_periph_unlock(periph); 82433965Sjdp return (error); 825218822Sdim} 82633965Sjdp 827218822Sdimstatic void 82833965Sjdpadainit(void) 829218822Sdim{ 83033965Sjdp cam_status status; 831218822Sdim 83233965Sjdp /* 833218822Sdim * Install a global async callback. This callback will 83433965Sjdp * receive async callbacks like "new device found". 835218822Sdim */ 83633965Sjdp status = xpt_register_async(AC_FOUND_DEVICE, adaasync, NULL, NULL); 837218822Sdim 83833965Sjdp if (status != CAM_REQ_CMP) { 839104834Sobrien printf("ada: Failed to attach master async callback " 84033965Sjdp "due to status 0x%x!\n", status); 841218822Sdim } else if (ada_send_ordered) { 84233965Sjdp 843218822Sdim /* Register our event handlers */ 844218822Sdim if ((EVENTHANDLER_REGISTER(power_suspend, adasuspend, 84533965Sjdp NULL, EVENTHANDLER_PRI_LAST)) == NULL) 846218822Sdim printf("adainit: power event registration failed!\n"); 84733965Sjdp if ((EVENTHANDLER_REGISTER(power_resume, adaresume, 848218822Sdim NULL, EVENTHANDLER_PRI_LAST)) == NULL) 84933965Sjdp printf("adainit: power event registration failed!\n"); 850218822Sdim if ((EVENTHANDLER_REGISTER(shutdown_post_sync, adashutdown, 851218822Sdim NULL, SHUTDOWN_PRI_DEFAULT)) == NULL) 852218822Sdim printf("adainit: shutdown event registration failed!\n"); 85333965Sjdp } 854218822Sdim} 85533965Sjdp 856218822Sdim/* 857130561Sobrien * Callback from GEOM, called when it has finished cleaning up its 858218822Sdim * resources. 859104834Sobrien */ 860104834Sobrienstatic void 861218822Sdimadadiskgonecb(struct disk *dp) 862218822Sdim{ 863104834Sobrien struct cam_periph *periph; 864218822Sdim 865218822Sdim periph = (struct cam_periph *)dp->d_drv1; 866218822Sdim 867218822Sdim cam_periph_release(periph); 868218822Sdim} 869218822Sdim 870218822Sdimstatic void 871218822Sdimadaoninvalidate(struct cam_periph *periph) 872218822Sdim{ 873218822Sdim struct ada_softc *softc; 87433965Sjdp 875218822Sdim softc = (struct ada_softc *)periph->softc; 87633965Sjdp 877218822Sdim /* 87860484Sobrien * De-register any async callbacks. 87960484Sobrien */ 88060484Sobrien xpt_register_async(0, adaasync, periph, periph->path); 88160484Sobrien 88260484Sobrien /* 88360484Sobrien * Return all queued I/O with ENXIO. 884218822Sdim * XXX Handle any transactions queued to the card 885218822Sdim * with XPT_ABORT_CCB. 886218822Sdim */ 887218822Sdim bioq_flush(&softc->bio_queue, NULL, ENXIO); 88833965Sjdp bioq_flush(&softc->trim_queue, NULL, ENXIO); 88933965Sjdp 89033965Sjdp disk_gone(softc->disk); 89160484Sobrien xpt_print(periph->path, "lost device\n"); 89260484Sobrien} 893104834Sobrien 89460484Sobrienstatic void 89560484Sobrienadacleanup(struct cam_periph *periph) 89633965Sjdp{ 89733965Sjdp struct ada_softc *softc; 89833965Sjdp 89933965Sjdp softc = (struct ada_softc *)periph->softc; 90033965Sjdp 901218822Sdim xpt_print(periph->path, "removing device entry\n"); 902218822Sdim cam_periph_unlock(periph); 903218822Sdim 904218822Sdim /* 905218822Sdim * If we can't free the sysctl tree, oh well... 906130561Sobrien */ 907130561Sobrien if ((softc->flags & ADA_FLAG_SCTX_INIT) != 0 908130561Sobrien && sysctl_ctx_free(&softc->sysctl_ctx) != 0) { 909130561Sobrien xpt_print(periph->path, "can't remove sysctl context\n"); 910130561Sobrien } 911218822Sdim 912218822Sdim disk_destroy(softc->disk); 913218822Sdim callout_drain(&softc->sendordered_c); 914218822Sdim free(softc, M_DEVBUF); 915218822Sdim cam_periph_lock(periph); 916218822Sdim} 917218822Sdim 91833965Sjdpstatic void 919130561Sobrienadaasync(void *callback_arg, u_int32_t code, 920130561Sobrien struct cam_path *path, void *arg) 921218822Sdim{ 922130561Sobrien struct ccb_getdev cgd; 923218822Sdim struct cam_periph *periph; 92433965Sjdp struct ada_softc *softc; 92533965Sjdp 92633965Sjdp periph = (struct cam_periph *)callback_arg; 92733965Sjdp switch (code) { 928218822Sdim case AC_FOUND_DEVICE: 92933965Sjdp { 930130561Sobrien struct ccb_getdev *cgd; 93133965Sjdp cam_status status; 93260484Sobrien 93333965Sjdp cgd = (struct ccb_getdev *)arg; 93433965Sjdp if (cgd == NULL) 935218822Sdim break; 93633965Sjdp 93733965Sjdp if (cgd->protocol != PROTO_ATA) 938107492Sobrien break; 93933965Sjdp 94033965Sjdp /* 941130561Sobrien * Allocate a peripheral instance for 94233965Sjdp * this device and start the probe 943130561Sobrien * process. 94433965Sjdp */ 945130561Sobrien status = cam_periph_alloc(adaregister, adaoninvalidate, 94633965Sjdp adacleanup, adastart, 94733965Sjdp "ada", CAM_PERIPH_BIO, 94833965Sjdp cgd->ccb_h.path, adaasync, 94933965Sjdp AC_FOUND_DEVICE, cgd); 95060484Sobrien 95133965Sjdp if (status != CAM_REQ_CMP 95233965Sjdp && status != CAM_REQ_INPROG) 953104834Sobrien printf("adaasync: Unable to attach to new device " 954130561Sobrien "due to status 0x%x\n", status); 95533965Sjdp break; 95633965Sjdp } 95733965Sjdp case AC_GETDEV_CHANGED: 95833965Sjdp { 95933965Sjdp softc = (struct ada_softc *)periph->softc; 96033965Sjdp xpt_setup_ccb(&cgd.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 96133965Sjdp cgd.ccb_h.func_code = XPT_GDEV_TYPE; 96233965Sjdp xpt_action((union ccb *)&cgd); 96333965Sjdp 96433965Sjdp if ((cgd.ident_data.capabilities1 & ATA_SUPPORT_DMA) && 96533965Sjdp (cgd.inq_flags & SID_DMA)) 96633965Sjdp softc->flags |= ADA_FLAG_CAN_DMA; 96733965Sjdp else 96833965Sjdp softc->flags &= ~ADA_FLAG_CAN_DMA; 96933965Sjdp if (cgd.ident_data.support.command2 & ATA_SUPPORT_ADDRESS48) { 97033965Sjdp softc->flags |= ADA_FLAG_CAN_48BIT; 97133965Sjdp if (cgd.inq_flags & SID_DMA48) 972218822Sdim softc->flags |= ADA_FLAG_CAN_DMA48; 973218822Sdim else 974218822Sdim softc->flags &= ~ADA_FLAG_CAN_DMA48; 975218822Sdim } else 97633965Sjdp softc->flags &= ~(ADA_FLAG_CAN_48BIT | 97733965Sjdp ADA_FLAG_CAN_DMA48); 97833965Sjdp if ((cgd.ident_data.satacapabilities & ATA_SUPPORT_NCQ) && 97933965Sjdp (cgd.inq_flags & SID_DMA) && (cgd.inq_flags & SID_CmdQue)) 98033965Sjdp softc->flags |= ADA_FLAG_CAN_NCQ; 98138889Sjdp else 98233965Sjdp softc->flags &= ~ADA_FLAG_CAN_NCQ; 98333965Sjdp if ((cgd.ident_data.support_dsm & ATA_SUPPORT_DSM_TRIM) && 98433965Sjdp (cgd.inq_flags & SID_DMA)) 98533965Sjdp softc->flags |= ADA_FLAG_CAN_TRIM; 98633965Sjdp else 98733965Sjdp softc->flags &= ~ADA_FLAG_CAN_TRIM; 98833965Sjdp 98933965Sjdp cam_periph_async(periph, code, path, arg); 99033965Sjdp break; 99133965Sjdp } 99233965Sjdp case AC_ADVINFO_CHANGED: 99333965Sjdp { 99433965Sjdp uintptr_t buftype; 99533965Sjdp 99633965Sjdp buftype = (uintptr_t)arg; 99733965Sjdp if (buftype == CDAI_TYPE_PHYS_PATH) { 99833965Sjdp struct ada_softc *softc; 99933965Sjdp 100033965Sjdp softc = periph->softc; 100133965Sjdp disk_attr_changed(softc->disk, "GEOM::physpath", 100233965Sjdp M_NOWAIT); 100333965Sjdp } 100433965Sjdp break; 100533965Sjdp } 100633965Sjdp case AC_SENT_BDR: 100733965Sjdp case AC_BUS_RESET: 100833965Sjdp { 100933965Sjdp softc = (struct ada_softc *)periph->softc; 101033965Sjdp cam_periph_async(periph, code, path, arg); 1011130561Sobrien if (softc->state != ADA_STATE_NORMAL) 101233965Sjdp break; 101333965Sjdp xpt_setup_ccb(&cgd.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 101433965Sjdp cgd.ccb_h.func_code = XPT_GDEV_TYPE; 101533965Sjdp xpt_action((union ccb *)&cgd); 101633965Sjdp if (ADA_RA >= 0 && 101733965Sjdp cgd.ident_data.support.command1 & ATA_SUPPORT_LOOKAHEAD) 101833965Sjdp softc->state = ADA_STATE_RAHEAD; 101933965Sjdp else if (ADA_WC >= 0 && 102033965Sjdp cgd.ident_data.support.command1 & ATA_SUPPORT_WRITECACHE) 102133965Sjdp softc->state = ADA_STATE_WCACHE; 102233965Sjdp else 102333965Sjdp break; 102433965Sjdp cam_periph_acquire(periph); 102533965Sjdp xpt_schedule(periph, CAM_PRIORITY_DEV); 1026130561Sobrien } 102733965Sjdp default: 102833965Sjdp cam_periph_async(periph, code, path, arg); 102933965Sjdp break; 103033965Sjdp } 103133965Sjdp} 103233965Sjdp 103333965Sjdpstatic void 103433965Sjdpadasysctlinit(void *context, int pending) 103533965Sjdp{ 103633965Sjdp struct cam_periph *periph; 103733965Sjdp struct ada_softc *softc; 103833965Sjdp char tmpstr[80], tmpstr2[80]; 103933965Sjdp 104033965Sjdp periph = (struct cam_periph *)context; 104133965Sjdp 104233965Sjdp /* periph was held for us when this task was enqueued */ 104333965Sjdp if ((periph->flags & CAM_PERIPH_INVALID) != 0) { 104433965Sjdp cam_periph_release(periph); 104533965Sjdp return; 104633965Sjdp } 104733965Sjdp 104833965Sjdp softc = (struct ada_softc *)periph->softc; 104933965Sjdp snprintf(tmpstr, sizeof(tmpstr), "CAM ADA unit %d", periph->unit_number); 105033965Sjdp snprintf(tmpstr2, sizeof(tmpstr2), "%d", periph->unit_number); 105133965Sjdp 105233965Sjdp sysctl_ctx_init(&softc->sysctl_ctx); 105333965Sjdp softc->flags |= ADA_FLAG_SCTX_INIT; 105433965Sjdp softc->sysctl_tree = SYSCTL_ADD_NODE(&softc->sysctl_ctx, 105533965Sjdp SYSCTL_STATIC_CHILDREN(_kern_cam_ada), OID_AUTO, tmpstr2, 105633965Sjdp CTLFLAG_RD, 0, tmpstr); 105733965Sjdp if (softc->sysctl_tree == NULL) { 105833965Sjdp printf("adasysctlinit: unable to allocate sysctl tree\n"); 105933965Sjdp cam_periph_release(periph); 106033965Sjdp return; 106133965Sjdp } 106233965Sjdp 106333965Sjdp SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 106433965Sjdp OID_AUTO, "read_ahead", CTLFLAG_RW | CTLFLAG_MPSAFE, 106533965Sjdp &softc->read_ahead, 0, "Enable disk read ahead."); 106633965Sjdp SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 106733965Sjdp OID_AUTO, "write_cache", CTLFLAG_RW | CTLFLAG_MPSAFE, 106833965Sjdp &softc->write_cache, 0, "Enable disk write cache."); 106933965Sjdp SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 107033965Sjdp OID_AUTO, "sort_io_queue", CTLFLAG_RW | CTLFLAG_MPSAFE, 107133965Sjdp &softc->sort_io_queue, 0, 107233965Sjdp "Sort IO queue to try and optimise disk access patterns"); 107333965Sjdp#ifdef ADA_TEST_FAILURE 107433965Sjdp /* 107533965Sjdp * Add a 'door bell' sysctl which allows one to set it from userland 107633965Sjdp * and cause something bad to happen. For the moment, we only allow 107733965Sjdp * whacking the next read or write. 107833965Sjdp */ 107933965Sjdp SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 108033965Sjdp OID_AUTO, "force_read_error", CTLFLAG_RW | CTLFLAG_MPSAFE, 108133965Sjdp &softc->force_read_error, 0, 108233965Sjdp "Force a read error for the next N reads."); 1083130561Sobrien SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 108433965Sjdp OID_AUTO, "force_write_error", CTLFLAG_RW | CTLFLAG_MPSAFE, 108533965Sjdp &softc->force_write_error, 0, 108633965Sjdp "Force a write error for the next N writes."); 108733965Sjdp SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), 108833965Sjdp OID_AUTO, "periodic_read_error", CTLFLAG_RW | CTLFLAG_MPSAFE, 108933965Sjdp &softc->periodic_read_error, 0, 109033965Sjdp "Force a read error every N reads (don't set too low)."); 109133965Sjdp#endif 109233965Sjdp cam_periph_release(periph); 109333965Sjdp} 109433965Sjdp 1095130561Sobrienstatic int 1096130561Sobrienadagetattr(struct bio *bp) 1097130561Sobrien{ 1098130561Sobrien int ret; 1099130561Sobrien struct cam_periph *periph; 1100130561Sobrien 1101130561Sobrien periph = (struct cam_periph *)bp->bio_disk->d_drv1; 1102130561Sobrien cam_periph_lock(periph); 1103130561Sobrien ret = xpt_getattr(bp->bio_data, bp->bio_length, bp->bio_attribute, 1104130561Sobrien periph->path); 1105130561Sobrien cam_periph_unlock(periph); 1106130561Sobrien if (ret == 0) 1107130561Sobrien bp->bio_completed = bp->bio_length; 1108130561Sobrien return ret; 110933965Sjdp} 111033965Sjdp 111133965Sjdpstatic cam_status 111233965Sjdpadaregister(struct cam_periph *periph, void *arg) 111333965Sjdp{ 111433965Sjdp struct ada_softc *softc; 111533965Sjdp struct ccb_pathinq cpi; 111633965Sjdp struct ccb_getdev *cgd; 111733965Sjdp char announce_buf[80], buf1[32]; 111833965Sjdp struct disk_params *dp; 111933965Sjdp caddr_t match; 112033965Sjdp u_int maxio; 112133965Sjdp int legacy_id, quirks; 1122130561Sobrien 112333965Sjdp cgd = (struct ccb_getdev *)arg; 1124130561Sobrien if (cgd == NULL) { 112533965Sjdp printf("adaregister: no getdev CCB, can't register device\n"); 112633965Sjdp return(CAM_REQ_CMP_ERR); 112733965Sjdp } 112860484Sobrien 112933965Sjdp softc = (struct ada_softc *)malloc(sizeof(*softc), M_DEVBUF, 113033965Sjdp M_NOWAIT|M_ZERO); 113133965Sjdp 113233965Sjdp if (softc == NULL) { 113333965Sjdp printf("adaregister: Unable to probe new device. " 113433965Sjdp "Unable to allocate softc\n"); 113533965Sjdp return(CAM_REQ_CMP_ERR); 113633965Sjdp } 113733965Sjdp 113833965Sjdp bioq_init(&softc->bio_queue); 113933965Sjdp bioq_init(&softc->trim_queue); 114033965Sjdp 114133965Sjdp if ((cgd->ident_data.capabilities1 & ATA_SUPPORT_DMA) && 114233965Sjdp (cgd->inq_flags & SID_DMA)) 114333965Sjdp softc->flags |= ADA_FLAG_CAN_DMA; 114433965Sjdp if (cgd->ident_data.support.command2 & ATA_SUPPORT_ADDRESS48) { 114533965Sjdp softc->flags |= ADA_FLAG_CAN_48BIT; 114633965Sjdp if (cgd->inq_flags & SID_DMA48) 114733965Sjdp softc->flags |= ADA_FLAG_CAN_DMA48; 1148218822Sdim } 1149218822Sdim if (cgd->ident_data.support.command2 & ATA_SUPPORT_FLUSHCACHE) 1150218822Sdim softc->flags |= ADA_FLAG_CAN_FLUSHCACHE; 1151218822Sdim if (cgd->ident_data.support.command1 & ATA_SUPPORT_POWERMGT) 1152218822Sdim softc->flags |= ADA_FLAG_CAN_POWERMGT; 1153218822Sdim if ((cgd->ident_data.satacapabilities & ATA_SUPPORT_NCQ) && 1154218822Sdim (cgd->inq_flags & SID_DMA) && (cgd->inq_flags & SID_CmdQue)) 1155218822Sdim softc->flags |= ADA_FLAG_CAN_NCQ; 1156218822Sdim if ((cgd->ident_data.support_dsm & ATA_SUPPORT_DSM_TRIM) && 1157218822Sdim (cgd->inq_flags & SID_DMA)) { 1158218822Sdim softc->flags |= ADA_FLAG_CAN_TRIM; 1159218822Sdim softc->trim_max_ranges = TRIM_MAX_RANGES; 1160218822Sdim if (cgd->ident_data.max_dsm_blocks != 0) { 1161218822Sdim softc->trim_max_ranges = 1162218822Sdim min(cgd->ident_data.max_dsm_blocks * 1163218822Sdim ATA_DSM_BLK_RANGES, softc->trim_max_ranges); 1164218822Sdim } 1165218822Sdim } 1166218822Sdim if (cgd->ident_data.support.command2 & ATA_SUPPORT_CFA) 1167218822Sdim softc->flags |= ADA_FLAG_CAN_CFA; 1168218822Sdim 1169218822Sdim periph->softc = softc; 1170218822Sdim 1171218822Sdim /* 1172218822Sdim * See if this device has any quirks. 1173218822Sdim */ 1174218822Sdim match = cam_quirkmatch((caddr_t)&cgd->ident_data, 1175218822Sdim (caddr_t)ada_quirk_table, 117633965Sjdp sizeof(ada_quirk_table)/sizeof(*ada_quirk_table), 117733965Sjdp sizeof(*ada_quirk_table), ata_identify_match); 117833965Sjdp if (match != NULL) 117933965Sjdp softc->quirks = ((struct ada_quirk_entry *)match)->quirks; 118033965Sjdp else 118160484Sobrien softc->quirks = ADA_Q_NONE; 118233965Sjdp 118333965Sjdp bzero(&cpi, sizeof(cpi)); 118433965Sjdp xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NONE); 118533965Sjdp cpi.ccb_h.func_code = XPT_PATH_INQ; 118633965Sjdp xpt_action((union ccb *)&cpi); 118733965Sjdp 118833965Sjdp TASK_INIT(&softc->sysctl_task, 0, adasysctlinit, periph); 118933965Sjdp 119033965Sjdp /* 119133965Sjdp * Register this media as a disk 119233965Sjdp */ 119333965Sjdp (void)cam_periph_hold(periph, PRIBIO); 119433965Sjdp cam_periph_unlock(periph); 119533965Sjdp snprintf(announce_buf, sizeof(announce_buf), 119638889Sjdp "kern.cam.ada.%d.quirks", periph->unit_number); 119733965Sjdp quirks = softc->quirks; 119833965Sjdp TUNABLE_INT_FETCH(announce_buf, &quirks); 119933965Sjdp softc->quirks = quirks; 120033965Sjdp softc->read_ahead = -1; 120133965Sjdp snprintf(announce_buf, sizeof(announce_buf), 120233965Sjdp "kern.cam.ada.%d.read_ahead", periph->unit_number); 120333965Sjdp TUNABLE_INT_FETCH(announce_buf, &softc->read_ahead); 120433965Sjdp softc->write_cache = -1; 120533965Sjdp snprintf(announce_buf, sizeof(announce_buf), 120633965Sjdp "kern.cam.ada.%d.write_cache", periph->unit_number); 120733965Sjdp TUNABLE_INT_FETCH(announce_buf, &softc->write_cache); 120889857Sobrien /* Disable queue sorting for non-rotational media by default. */ 120933965Sjdp if (cgd->ident_data.media_rotation_rate == 1) 121089857Sobrien softc->sort_io_queue = 0; 121189857Sobrien else 121289857Sobrien softc->sort_io_queue = -1; 121389857Sobrien adagetparams(periph, cgd); 121433965Sjdp softc->disk = disk_alloc(); 121533965Sjdp softc->disk->d_devstat = devstat_new_entry(periph->periph_name, 121633965Sjdp periph->unit_number, softc->params.secsize, 121733965Sjdp DEVSTAT_ALL_SUPPORTED, 121833965Sjdp DEVSTAT_TYPE_DIRECT | 121933965Sjdp XPORT_DEVSTAT_TYPE(cpi.transport), 122033965Sjdp DEVSTAT_PRIORITY_DISK); 122133965Sjdp softc->disk->d_open = adaopen; 122233965Sjdp softc->disk->d_close = adaclose; 122333965Sjdp softc->disk->d_strategy = adastrategy; 122433965Sjdp softc->disk->d_getattr = adagetattr; 122533965Sjdp softc->disk->d_dump = adadump; 122633965Sjdp softc->disk->d_gone = adadiskgonecb; 122733965Sjdp softc->disk->d_name = "ada"; 122833965Sjdp softc->disk->d_drv1 = periph; 122933965Sjdp maxio = cpi.maxio; /* Honor max I/O size of SIM */ 123033965Sjdp if (maxio == 0) 123133965Sjdp maxio = DFLTPHYS; /* traditional default */ 123233965Sjdp else if (maxio > MAXPHYS) 123333965Sjdp maxio = MAXPHYS; /* for safety */ 123433965Sjdp if (softc->flags & ADA_FLAG_CAN_48BIT) 123533965Sjdp maxio = min(maxio, 65536 * softc->params.secsize); 123633965Sjdp else /* 28bit ATA command limit */ 123733965Sjdp maxio = min(maxio, 256 * softc->params.secsize); 123833965Sjdp softc->disk->d_maxsize = maxio; 123933965Sjdp softc->disk->d_unit = periph->unit_number; 124033965Sjdp softc->disk->d_flags = 0; 124133965Sjdp if (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) 124233965Sjdp softc->disk->d_flags |= DISKFLAG_CANFLUSHCACHE; 124333965Sjdp if (softc->flags & ADA_FLAG_CAN_TRIM) { 124433965Sjdp softc->disk->d_flags |= DISKFLAG_CANDELETE; 124533965Sjdp softc->disk->d_delmaxsize = softc->params.secsize * 124633965Sjdp ATA_DSM_RANGE_MAX * 124733965Sjdp softc->trim_max_ranges; 124833965Sjdp } else if ((softc->flags & ADA_FLAG_CAN_CFA) && 124933965Sjdp !(softc->flags & ADA_FLAG_CAN_48BIT)) { 125033965Sjdp softc->disk->d_flags |= DISKFLAG_CANDELETE; 125133965Sjdp softc->disk->d_delmaxsize = 256 * softc->params.secsize; 125233965Sjdp } else 125333965Sjdp softc->disk->d_delmaxsize = maxio; 125433965Sjdp if ((cpi.hba_misc & PIM_UNMAPPED) != 0) 125533965Sjdp softc->disk->d_flags |= DISKFLAG_UNMAPPED_BIO; 125633965Sjdp strlcpy(softc->disk->d_descr, cgd->ident_data.model, 125733965Sjdp MIN(sizeof(softc->disk->d_descr), sizeof(cgd->ident_data.model))); 125833965Sjdp strlcpy(softc->disk->d_ident, cgd->ident_data.serial, 1259218822Sdim MIN(sizeof(softc->disk->d_ident), sizeof(cgd->ident_data.serial))); 126033965Sjdp softc->disk->d_hba_vendor = cpi.hba_vendor; 1261218822Sdim softc->disk->d_hba_device = cpi.hba_device; 1262218822Sdim softc->disk->d_hba_subvendor = cpi.hba_subvendor; 1263218822Sdim softc->disk->d_hba_subdevice = cpi.hba_subdevice; 1264218822Sdim 126533965Sjdp softc->disk->d_sectorsize = softc->params.secsize; 126633965Sjdp softc->disk->d_mediasize = (off_t)softc->params.sectors * 1267218822Sdim softc->params.secsize; 126833965Sjdp if (ata_physical_sector_size(&cgd->ident_data) != 1269218822Sdim softc->params.secsize) { 1270218822Sdim softc->disk->d_stripesize = 1271218822Sdim ata_physical_sector_size(&cgd->ident_data); 1272218822Sdim softc->disk->d_stripeoffset = (softc->disk->d_stripesize - 1273130561Sobrien ata_logical_sector_offset(&cgd->ident_data)) % 1274130561Sobrien softc->disk->d_stripesize; 1275130561Sobrien } else if (softc->quirks & ADA_Q_4K) { 1276130561Sobrien softc->disk->d_stripesize = 4096; 1277130561Sobrien softc->disk->d_stripeoffset = 0; 1278130561Sobrien } 1279130561Sobrien softc->disk->d_fwsectors = softc->params.secs_per_track; 1280218822Sdim softc->disk->d_fwheads = softc->params.heads; 1281218822Sdim ata_disk_firmware_geom_adjust(softc->disk); 1282218822Sdim 1283130561Sobrien if (ada_legacy_aliases) { 1284130561Sobrien#ifdef ATA_STATIC_ID 1285130561Sobrien legacy_id = xpt_path_legacy_ata_id(periph->path); 128660484Sobrien#else 128760484Sobrien legacy_id = softc->disk->d_unit; 128860484Sobrien#endif 128960484Sobrien if (legacy_id >= 0) { 129060484Sobrien snprintf(announce_buf, sizeof(announce_buf), 1291130561Sobrien "kern.devalias.%s%d", 129260484Sobrien softc->disk->d_name, softc->disk->d_unit); 129377298Sobrien snprintf(buf1, sizeof(buf1), 129460484Sobrien "ad%d", legacy_id); 129560484Sobrien setenv(announce_buf, buf1); 1296218822Sdim } 1297218822Sdim } else 1298218822Sdim legacy_id = -1; 1299218822Sdim /* 1300218822Sdim * Acquire a reference to the periph before we register with GEOM. 1301218822Sdim * We'll release this reference once GEOM calls us back (via 1302218822Sdim * adadiskgonecb()) telling us that our provider has been freed. 1303218822Sdim */ 1304218822Sdim if (cam_periph_acquire(periph) != CAM_REQ_CMP) { 1305218822Sdim xpt_print(periph->path, "%s: lost periph during " 1306218822Sdim "registration!\n", __func__); 1307218822Sdim cam_periph_lock(periph); 1308218822Sdim return (CAM_REQ_CMP_ERR); 1309218822Sdim } 1310218822Sdim disk_create(softc->disk, DISK_VERSION); 1311218822Sdim cam_periph_lock(periph); 1312218822Sdim cam_periph_unhold(periph); 1313218822Sdim 1314218822Sdim dp = &softc->params; 1315218822Sdim snprintf(announce_buf, sizeof(announce_buf), 1316218822Sdim "%juMB (%ju %u byte sectors: %dH %dS/T %dC)", 1317218822Sdim (uintmax_t)(((uintmax_t)dp->secsize * 1318218822Sdim dp->sectors) / (1024*1024)), 1319218822Sdim (uintmax_t)dp->sectors, 132033965Sjdp dp->secsize, dp->heads, 132133965Sjdp dp->secs_per_track, dp->cylinders); 1322130561Sobrien xpt_announce_periph(periph, announce_buf); 1323130561Sobrien xpt_announce_quirks(periph, softc->quirks, ADA_Q_BIT_STRING); 1324130561Sobrien if (legacy_id >= 0) 1325130561Sobrien printf("%s%d: Previously was known as ad%d\n", 1326130561Sobrien periph->periph_name, periph->unit_number, legacy_id); 132733965Sjdp 132833965Sjdp /* 1329130561Sobrien * Create our sysctl variables, now that we know 133033965Sjdp * we have successfully attached. 1331130561Sobrien */ 133233965Sjdp cam_periph_acquire(periph); 133360484Sobrien taskqueue_enqueue(taskqueue_thread, &softc->sysctl_task); 133433965Sjdp 133533965Sjdp /* 133633965Sjdp * Add async callbacks for bus reset and 133733965Sjdp * bus device reset calls. I don't bother 133833965Sjdp * checking if this fails as, in most cases, 133933965Sjdp * the system will function just fine without 1340 * them and the only alternative would be to 1341 * not attach the device on failure. 1342 */ 1343 xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE | 1344 AC_GETDEV_CHANGED | AC_ADVINFO_CHANGED, 1345 adaasync, periph, periph->path); 1346 1347 /* 1348 * Schedule a periodic event to occasionally send an 1349 * ordered tag to a device. 1350 */ 1351 callout_init_mtx(&softc->sendordered_c, periph->sim->mtx, 0); 1352 callout_reset(&softc->sendordered_c, 1353 (ada_default_timeout * hz) / ADA_ORDEREDTAG_INTERVAL, 1354 adasendorderedtag, softc); 1355 1356 if (ADA_RA >= 0 && 1357 cgd->ident_data.support.command1 & ATA_SUPPORT_LOOKAHEAD) { 1358 softc->state = ADA_STATE_RAHEAD; 1359 cam_periph_acquire(periph); 1360 xpt_schedule(periph, CAM_PRIORITY_DEV); 1361 } else if (ADA_WC >= 0 && 1362 cgd->ident_data.support.command1 & ATA_SUPPORT_WRITECACHE) { 1363 softc->state = ADA_STATE_WCACHE; 1364 cam_periph_acquire(periph); 1365 xpt_schedule(periph, CAM_PRIORITY_DEV); 1366 } else 1367 softc->state = ADA_STATE_NORMAL; 1368 1369 return(CAM_REQ_CMP); 1370} 1371 1372static void 1373adastart(struct cam_periph *periph, union ccb *start_ccb) 1374{ 1375 struct ada_softc *softc = (struct ada_softc *)periph->softc; 1376 struct ccb_ataio *ataio = &start_ccb->ataio; 1377 1378 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("adastart\n")); 1379 1380 switch (softc->state) { 1381 case ADA_STATE_NORMAL: 1382 { 1383 struct bio *bp; 1384 u_int8_t tag_code; 1385 1386 /* Execute immediate CCB if waiting. */ 1387 if (periph->immediate_priority <= periph->pinfo.priority) { 1388 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 1389 ("queuing for immediate ccb\n")); 1390 start_ccb->ccb_h.ccb_state = ADA_CCB_WAITING; 1391 SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, 1392 periph_links.sle); 1393 periph->immediate_priority = CAM_PRIORITY_NONE; 1394 wakeup(&periph->ccb_list); 1395 /* Have more work to do, so ensure we stay scheduled */ 1396 adaschedule(periph); 1397 break; 1398 } 1399 /* Run TRIM if not running yet. */ 1400 if (!softc->trim_running && 1401 (bp = bioq_first(&softc->trim_queue)) != 0) { 1402 struct trim_request *req = &softc->trim_req; 1403 struct bio *bp1; 1404 uint64_t lastlba = (uint64_t)-1; 1405 int bps = 0, c, lastcount = 0, off, ranges = 0; 1406 1407 softc->trim_running = 1; 1408 bzero(req, sizeof(*req)); 1409 bp1 = bp; 1410 do { 1411 uint64_t lba = bp1->bio_pblkno; 1412 int count = bp1->bio_bcount / 1413 softc->params.secsize; 1414 1415 bioq_remove(&softc->trim_queue, bp1); 1416 1417 /* Try to extend the previous range. */ 1418 if (lba == lastlba) { 1419 c = min(count, ATA_DSM_RANGE_MAX - lastcount); 1420 lastcount += c; 1421 off = (ranges - 1) * ATA_DSM_RANGE_SIZE; 1422 req->data[off + 6] = lastcount & 0xff; 1423 req->data[off + 7] = 1424 (lastcount >> 8) & 0xff; 1425 count -= c; 1426 lba += c; 1427 } 1428 1429 while (count > 0) { 1430 c = min(count, ATA_DSM_RANGE_MAX); 1431 off = ranges * ATA_DSM_RANGE_SIZE; 1432 req->data[off + 0] = lba & 0xff; 1433 req->data[off + 1] = (lba >> 8) & 0xff; 1434 req->data[off + 2] = (lba >> 16) & 0xff; 1435 req->data[off + 3] = (lba >> 24) & 0xff; 1436 req->data[off + 4] = (lba >> 32) & 0xff; 1437 req->data[off + 5] = (lba >> 40) & 0xff; 1438 req->data[off + 6] = c & 0xff; 1439 req->data[off + 7] = (c >> 8) & 0xff; 1440 lba += c; 1441 count -= c; 1442 lastcount = c; 1443 ranges++; 1444 /* 1445 * Its the caller's responsibility to ensure the 1446 * request will fit so we don't need to check for 1447 * overrun here 1448 */ 1449 } 1450 lastlba = lba; 1451 req->bps[bps++] = bp1; 1452 bp1 = bioq_first(&softc->trim_queue); 1453 if (bps >= TRIM_MAX_BIOS || 1454 bp1 == NULL || 1455 bp1->bio_bcount / softc->params.secsize > 1456 (softc->trim_max_ranges - ranges) * 1457 ATA_DSM_RANGE_MAX) 1458 break; 1459 } while (1); 1460 cam_fill_ataio(ataio, 1461 ada_retry_count, 1462 adadone, 1463 CAM_DIR_OUT, 1464 0, 1465 req->data, 1466 ((ranges + ATA_DSM_BLK_RANGES - 1) / 1467 ATA_DSM_BLK_RANGES) * ATA_DSM_BLK_SIZE, 1468 ada_default_timeout * 1000); 1469 ata_48bit_cmd(ataio, ATA_DATA_SET_MANAGEMENT, 1470 ATA_DSM_TRIM, 0, (ranges + ATA_DSM_BLK_RANGES - 1471 1) / ATA_DSM_BLK_RANGES); 1472 start_ccb->ccb_h.ccb_state = ADA_CCB_TRIM; 1473 goto out; 1474 } 1475 /* Run regular command. */ 1476 bp = bioq_first(&softc->bio_queue); 1477 if (bp == NULL) { 1478 xpt_release_ccb(start_ccb); 1479 break; 1480 } 1481 bioq_remove(&softc->bio_queue, bp); 1482 1483 if ((bp->bio_flags & BIO_ORDERED) != 0 1484 || (softc->flags & ADA_FLAG_NEED_OTAG) != 0) { 1485 softc->flags &= ~ADA_FLAG_NEED_OTAG; 1486 softc->ordered_tag_count++; 1487 tag_code = 0; 1488 } else { 1489 tag_code = 1; 1490 } 1491 switch (bp->bio_cmd) { 1492 case BIO_WRITE: 1493 softc->flags |= ADA_FLAG_DIRTY; 1494 /* FALLTHROUGH */ 1495 case BIO_READ: 1496 { 1497 uint64_t lba = bp->bio_pblkno; 1498 uint16_t count = bp->bio_bcount / softc->params.secsize; 1499#ifdef ADA_TEST_FAILURE 1500 int fail = 0; 1501 1502 /* 1503 * Support the failure ioctls. If the command is a 1504 * read, and there are pending forced read errors, or 1505 * if a write and pending write errors, then fail this 1506 * operation with EIO. This is useful for testing 1507 * purposes. Also, support having every Nth read fail. 1508 * 1509 * This is a rather blunt tool. 1510 */ 1511 if (bp->bio_cmd == BIO_READ) { 1512 if (softc->force_read_error) { 1513 softc->force_read_error--; 1514 fail = 1; 1515 } 1516 if (softc->periodic_read_error > 0) { 1517 if (++softc->periodic_read_count >= 1518 softc->periodic_read_error) { 1519 softc->periodic_read_count = 0; 1520 fail = 1; 1521 } 1522 } 1523 } else { 1524 if (softc->force_write_error) { 1525 softc->force_write_error--; 1526 fail = 1; 1527 } 1528 } 1529 if (fail) { 1530 bp->bio_error = EIO; 1531 bp->bio_flags |= BIO_ERROR; 1532 biodone(bp); 1533 xpt_release_ccb(start_ccb); 1534 adaschedule(periph); 1535 return; 1536 } 1537#endif 1538 KASSERT((bp->bio_flags & BIO_UNMAPPED) == 0 || 1539 round_page(bp->bio_bcount + bp->bio_ma_offset) / 1540 PAGE_SIZE == bp->bio_ma_n, 1541 ("Short bio %p", bp)); 1542 cam_fill_ataio(ataio, 1543 ada_retry_count, 1544 adadone, 1545 (bp->bio_cmd == BIO_READ ? CAM_DIR_IN : 1546 CAM_DIR_OUT) | ((bp->bio_flags & BIO_UNMAPPED) 1547 != 0 ? CAM_DATA_BIO : 0), 1548 tag_code, 1549 ((bp->bio_flags & BIO_UNMAPPED) != 0) ? (void *)bp : 1550 bp->bio_data, 1551 bp->bio_bcount, 1552 ada_default_timeout*1000); 1553 1554 if ((softc->flags & ADA_FLAG_CAN_NCQ) && tag_code) { 1555 if (bp->bio_cmd == BIO_READ) { 1556 ata_ncq_cmd(ataio, ATA_READ_FPDMA_QUEUED, 1557 lba, count); 1558 } else { 1559 ata_ncq_cmd(ataio, ATA_WRITE_FPDMA_QUEUED, 1560 lba, count); 1561 } 1562 } else if ((softc->flags & ADA_FLAG_CAN_48BIT) && 1563 (lba + count >= ATA_MAX_28BIT_LBA || 1564 count > 256)) { 1565 if (softc->flags & ADA_FLAG_CAN_DMA48) { 1566 if (bp->bio_cmd == BIO_READ) { 1567 ata_48bit_cmd(ataio, ATA_READ_DMA48, 1568 0, lba, count); 1569 } else { 1570 ata_48bit_cmd(ataio, ATA_WRITE_DMA48, 1571 0, lba, count); 1572 } 1573 } else { 1574 if (bp->bio_cmd == BIO_READ) { 1575 ata_48bit_cmd(ataio, ATA_READ_MUL48, 1576 0, lba, count); 1577 } else { 1578 ata_48bit_cmd(ataio, ATA_WRITE_MUL48, 1579 0, lba, count); 1580 } 1581 } 1582 } else { 1583 if (count == 256) 1584 count = 0; 1585 if (softc->flags & ADA_FLAG_CAN_DMA) { 1586 if (bp->bio_cmd == BIO_READ) { 1587 ata_28bit_cmd(ataio, ATA_READ_DMA, 1588 0, lba, count); 1589 } else { 1590 ata_28bit_cmd(ataio, ATA_WRITE_DMA, 1591 0, lba, count); 1592 } 1593 } else { 1594 if (bp->bio_cmd == BIO_READ) { 1595 ata_28bit_cmd(ataio, ATA_READ_MUL, 1596 0, lba, count); 1597 } else { 1598 ata_28bit_cmd(ataio, ATA_WRITE_MUL, 1599 0, lba, count); 1600 } 1601 } 1602 } 1603 break; 1604 } 1605 case BIO_DELETE: 1606 { 1607 uint64_t lba = bp->bio_pblkno; 1608 uint16_t count = bp->bio_bcount / softc->params.secsize; 1609 1610 cam_fill_ataio(ataio, 1611 ada_retry_count, 1612 adadone, 1613 CAM_DIR_NONE, 1614 0, 1615 NULL, 1616 0, 1617 ada_default_timeout*1000); 1618 1619 if (count >= 256) 1620 count = 0; 1621 ata_28bit_cmd(ataio, ATA_CFA_ERASE, 0, lba, count); 1622 break; 1623 } 1624 case BIO_FLUSH: 1625 cam_fill_ataio(ataio, 1626 1, 1627 adadone, 1628 CAM_DIR_NONE, 1629 0, 1630 NULL, 1631 0, 1632 ada_default_timeout*1000); 1633 1634 if (softc->flags & ADA_FLAG_CAN_48BIT) 1635 ata_48bit_cmd(ataio, ATA_FLUSHCACHE48, 0, 0, 0); 1636 else 1637 ata_28bit_cmd(ataio, ATA_FLUSHCACHE, 0, 0, 0); 1638 break; 1639 } 1640 start_ccb->ccb_h.ccb_state = ADA_CCB_BUFFER_IO; 1641out: 1642 start_ccb->ccb_h.ccb_bp = bp; 1643 softc->outstanding_cmds++; 1644 xpt_action(start_ccb); 1645 1646 /* May have more work to do, so ensure we stay scheduled */ 1647 adaschedule(periph); 1648 break; 1649 } 1650 case ADA_STATE_RAHEAD: 1651 case ADA_STATE_WCACHE: 1652 { 1653 if ((periph->flags & CAM_PERIPH_INVALID) != 0) { 1654 softc->state = ADA_STATE_NORMAL; 1655 xpt_release_ccb(start_ccb); 1656 adaschedule(periph); 1657 cam_periph_release_locked(periph); 1658 return; 1659 } 1660 1661 cam_fill_ataio(ataio, 1662 1, 1663 adadone, 1664 CAM_DIR_NONE, 1665 0, 1666 NULL, 1667 0, 1668 ada_default_timeout*1000); 1669 1670 if (softc->state == ADA_STATE_RAHEAD) { 1671 ata_28bit_cmd(ataio, ATA_SETFEATURES, ADA_RA ? 1672 ATA_SF_ENAB_RCACHE : ATA_SF_DIS_RCACHE, 0, 0); 1673 start_ccb->ccb_h.ccb_state = ADA_CCB_RAHEAD; 1674 } else { 1675 ata_28bit_cmd(ataio, ATA_SETFEATURES, ADA_WC ? 1676 ATA_SF_ENAB_WCACHE : ATA_SF_DIS_WCACHE, 0, 0); 1677 start_ccb->ccb_h.ccb_state = ADA_CCB_WCACHE; 1678 } 1679 start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE; 1680 xpt_action(start_ccb); 1681 break; 1682 } 1683 } 1684} 1685 1686static void 1687adadone(struct cam_periph *periph, union ccb *done_ccb) 1688{ 1689 struct ada_softc *softc; 1690 struct ccb_ataio *ataio; 1691 struct ccb_getdev *cgd; 1692 struct cam_path *path; 1693 int state; 1694 1695 softc = (struct ada_softc *)periph->softc; 1696 ataio = &done_ccb->ataio; 1697 path = done_ccb->ccb_h.path; 1698 1699 CAM_DEBUG(path, CAM_DEBUG_TRACE, ("adadone\n")); 1700 1701 state = ataio->ccb_h.ccb_state & ADA_CCB_TYPE_MASK; 1702 switch (state) { 1703 case ADA_CCB_BUFFER_IO: 1704 case ADA_CCB_TRIM: 1705 { 1706 struct bio *bp; 1707 int error; 1708 1709 if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 1710 error = adaerror(done_ccb, 0, 0); 1711 if (error == ERESTART) { 1712 /* A retry was scheduled, so just return. */ 1713 return; 1714 } 1715 if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 1716 cam_release_devq(path, 1717 /*relsim_flags*/0, 1718 /*reduction*/0, 1719 /*timeout*/0, 1720 /*getcount_only*/0); 1721 } else { 1722 if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 1723 panic("REQ_CMP with QFRZN"); 1724 error = 0; 1725 } 1726 bp = (struct bio *)done_ccb->ccb_h.ccb_bp; 1727 bp->bio_error = error; 1728 if (error != 0) { 1729 bp->bio_resid = bp->bio_bcount; 1730 bp->bio_flags |= BIO_ERROR; 1731 } else { 1732 if (state == ADA_CCB_TRIM) 1733 bp->bio_resid = 0; 1734 else 1735 bp->bio_resid = ataio->resid; 1736 if (bp->bio_resid > 0) 1737 bp->bio_flags |= BIO_ERROR; 1738 } 1739 softc->outstanding_cmds--; 1740 if (softc->outstanding_cmds == 0) 1741 softc->flags |= ADA_FLAG_WENT_IDLE; 1742 if (state == ADA_CCB_TRIM) { 1743 struct trim_request *req = 1744 (struct trim_request *)ataio->data_ptr; 1745 int i; 1746 1747 for (i = 1; i < TRIM_MAX_BIOS && req->bps[i]; i++) { 1748 struct bio *bp1 = req->bps[i]; 1749 1750 bp1->bio_error = bp->bio_error; 1751 if (bp->bio_flags & BIO_ERROR) { 1752 bp1->bio_flags |= BIO_ERROR; 1753 bp1->bio_resid = bp1->bio_bcount; 1754 } else 1755 bp1->bio_resid = 0; 1756 biodone(bp1); 1757 } 1758 softc->trim_running = 0; 1759 biodone(bp); 1760 adaschedule(periph); 1761 } else 1762 biodone(bp); 1763 break; 1764 } 1765 case ADA_CCB_RAHEAD: 1766 { 1767 if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 1768 if (adaerror(done_ccb, 0, 0) == ERESTART) { 1769out: 1770 /* Drop freeze taken due to CAM_DEV_QFREEZE */ 1771 cam_release_devq(path, 0, 0, 0, FALSE); 1772 return; 1773 } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 1774 cam_release_devq(path, 1775 /*relsim_flags*/0, 1776 /*reduction*/0, 1777 /*timeout*/0, 1778 /*getcount_only*/0); 1779 } 1780 } 1781 1782 /* 1783 * Since our peripheral may be invalidated by an error 1784 * above or an external event, we must release our CCB 1785 * before releasing the reference on the peripheral. 1786 * The peripheral will only go away once the last reference 1787 * is removed, and we need it around for the CCB release 1788 * operation. 1789 */ 1790 cgd = (struct ccb_getdev *)done_ccb; 1791 xpt_setup_ccb(&cgd->ccb_h, path, CAM_PRIORITY_NORMAL); 1792 cgd->ccb_h.func_code = XPT_GDEV_TYPE; 1793 xpt_action((union ccb *)cgd); 1794 if (ADA_WC >= 0 && 1795 cgd->ident_data.support.command1 & ATA_SUPPORT_WRITECACHE) { 1796 softc->state = ADA_STATE_WCACHE; 1797 xpt_release_ccb(done_ccb); 1798 xpt_schedule(periph, CAM_PRIORITY_DEV); 1799 goto out; 1800 } 1801 softc->state = ADA_STATE_NORMAL; 1802 xpt_release_ccb(done_ccb); 1803 /* Drop freeze taken due to CAM_DEV_QFREEZE */ 1804 cam_release_devq(path, 0, 0, 0, FALSE); 1805 adaschedule(periph); 1806 cam_periph_release_locked(periph); 1807 return; 1808 } 1809 case ADA_CCB_WCACHE: 1810 { 1811 if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 1812 if (adaerror(done_ccb, 0, 0) == ERESTART) { 1813 goto out; 1814 } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 1815 cam_release_devq(path, 1816 /*relsim_flags*/0, 1817 /*reduction*/0, 1818 /*timeout*/0, 1819 /*getcount_only*/0); 1820 } 1821 } 1822 1823 softc->state = ADA_STATE_NORMAL; 1824 /* 1825 * Since our peripheral may be invalidated by an error 1826 * above or an external event, we must release our CCB 1827 * before releasing the reference on the peripheral. 1828 * The peripheral will only go away once the last reference 1829 * is removed, and we need it around for the CCB release 1830 * operation. 1831 */ 1832 xpt_release_ccb(done_ccb); 1833 /* Drop freeze taken due to CAM_DEV_QFREEZE */ 1834 cam_release_devq(path, 0, 0, 0, FALSE); 1835 adaschedule(periph); 1836 cam_periph_release_locked(periph); 1837 return; 1838 } 1839 case ADA_CCB_WAITING: 1840 { 1841 /* Caller will release the CCB */ 1842 wakeup(&done_ccb->ccb_h.cbfcnp); 1843 return; 1844 } 1845 case ADA_CCB_DUMP: 1846 /* No-op. We're polling */ 1847 return; 1848 default: 1849 break; 1850 } 1851 xpt_release_ccb(done_ccb); 1852} 1853 1854static int 1855adaerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) 1856{ 1857 1858 return(cam_periph_error(ccb, cam_flags, sense_flags, NULL)); 1859} 1860 1861static void 1862adagetparams(struct cam_periph *periph, struct ccb_getdev *cgd) 1863{ 1864 struct ada_softc *softc = (struct ada_softc *)periph->softc; 1865 struct disk_params *dp = &softc->params; 1866 u_int64_t lbasize48; 1867 u_int32_t lbasize; 1868 1869 dp->secsize = ata_logical_sector_size(&cgd->ident_data); 1870 if ((cgd->ident_data.atavalid & ATA_FLAG_54_58) && 1871 cgd->ident_data.current_heads && cgd->ident_data.current_sectors) { 1872 dp->heads = cgd->ident_data.current_heads; 1873 dp->secs_per_track = cgd->ident_data.current_sectors; 1874 dp->cylinders = cgd->ident_data.cylinders; 1875 dp->sectors = (u_int32_t)cgd->ident_data.current_size_1 | 1876 ((u_int32_t)cgd->ident_data.current_size_2 << 16); 1877 } else { 1878 dp->heads = cgd->ident_data.heads; 1879 dp->secs_per_track = cgd->ident_data.sectors; 1880 dp->cylinders = cgd->ident_data.cylinders; 1881 dp->sectors = cgd->ident_data.cylinders * dp->heads * dp->secs_per_track; 1882 } 1883 lbasize = (u_int32_t)cgd->ident_data.lba_size_1 | 1884 ((u_int32_t)cgd->ident_data.lba_size_2 << 16); 1885 1886 /* use the 28bit LBA size if valid or bigger than the CHS mapping */ 1887 if (cgd->ident_data.cylinders == 16383 || dp->sectors < lbasize) 1888 dp->sectors = lbasize; 1889 1890 /* use the 48bit LBA size if valid */ 1891 lbasize48 = ((u_int64_t)cgd->ident_data.lba_size48_1) | 1892 ((u_int64_t)cgd->ident_data.lba_size48_2 << 16) | 1893 ((u_int64_t)cgd->ident_data.lba_size48_3 << 32) | 1894 ((u_int64_t)cgd->ident_data.lba_size48_4 << 48); 1895 if ((cgd->ident_data.support.command2 & ATA_SUPPORT_ADDRESS48) && 1896 lbasize48 > ATA_MAX_28BIT_LBA) 1897 dp->sectors = lbasize48; 1898} 1899 1900static void 1901adasendorderedtag(void *arg) 1902{ 1903 struct ada_softc *softc = arg; 1904 1905 if (ada_send_ordered) { 1906 if ((softc->ordered_tag_count == 0) 1907 && ((softc->flags & ADA_FLAG_WENT_IDLE) == 0)) { 1908 softc->flags |= ADA_FLAG_NEED_OTAG; 1909 } 1910 if (softc->outstanding_cmds > 0) 1911 softc->flags &= ~ADA_FLAG_WENT_IDLE; 1912 1913 softc->ordered_tag_count = 0; 1914 } 1915 /* Queue us up again */ 1916 callout_reset(&softc->sendordered_c, 1917 (ada_default_timeout * hz) / ADA_ORDEREDTAG_INTERVAL, 1918 adasendorderedtag, softc); 1919} 1920 1921/* 1922 * Step through all ADA peripheral drivers, and if the device is still open, 1923 * sync the disk cache to physical media. 1924 */ 1925static void 1926adaflush(void) 1927{ 1928 struct cam_periph *periph; 1929 struct ada_softc *softc; 1930 union ccb *ccb; 1931 int error; 1932 1933 CAM_PERIPH_FOREACH(periph, &adadriver) { 1934 softc = (struct ada_softc *)periph->softc; 1935 if (SCHEDULER_STOPPED()) { 1936 /* If we paniced with the lock held, do not recurse. */ 1937 if (!cam_periph_owned(periph) && 1938 (softc->flags & ADA_FLAG_OPEN)) { 1939 adadump(softc->disk, NULL, 0, 0, 0); 1940 } 1941 continue; 1942 } 1943 cam_periph_lock(periph); 1944 /* 1945 * We only sync the cache if the drive is still open, and 1946 * if the drive is capable of it.. 1947 */ 1948 if (((softc->flags & ADA_FLAG_OPEN) == 0) || 1949 (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) == 0) { 1950 cam_periph_unlock(periph); 1951 continue; 1952 } 1953 1954 ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 1955 cam_fill_ataio(&ccb->ataio, 1956 0, 1957 adadone, 1958 CAM_DIR_NONE, 1959 0, 1960 NULL, 1961 0, 1962 ada_default_timeout*1000); 1963 if (softc->flags & ADA_FLAG_CAN_48BIT) 1964 ata_48bit_cmd(&ccb->ataio, ATA_FLUSHCACHE48, 0, 0, 0); 1965 else 1966 ata_28bit_cmd(&ccb->ataio, ATA_FLUSHCACHE, 0, 0, 0); 1967 1968 error = cam_periph_runccb(ccb, adaerror, /*cam_flags*/0, 1969 /*sense_flags*/ SF_NO_RECOVERY | SF_NO_RETRY, 1970 softc->disk->d_devstat); 1971 if (error != 0) 1972 xpt_print(periph->path, "Synchronize cache failed\n"); 1973 xpt_release_ccb(ccb); 1974 cam_periph_unlock(periph); 1975 } 1976} 1977 1978static void 1979adaspindown(uint8_t cmd, int flags) 1980{ 1981 struct cam_periph *periph; 1982 struct ada_softc *softc; 1983 union ccb *ccb; 1984 int error; 1985 1986 CAM_PERIPH_FOREACH(periph, &adadriver) { 1987 /* If we paniced with lock held - not recurse here. */ 1988 if (cam_periph_owned(periph)) 1989 continue; 1990 cam_periph_lock(periph); 1991 softc = (struct ada_softc *)periph->softc; 1992 /* 1993 * We only spin-down the drive if it is capable of it.. 1994 */ 1995 if ((softc->flags & ADA_FLAG_CAN_POWERMGT) == 0) { 1996 cam_periph_unlock(periph); 1997 continue; 1998 } 1999 2000 if (bootverbose) 2001 xpt_print(periph->path, "spin-down\n"); 2002 2003 ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 2004 cam_fill_ataio(&ccb->ataio, 2005 0, 2006 adadone, 2007 CAM_DIR_NONE | flags, 2008 0, 2009 NULL, 2010 0, 2011 ada_default_timeout*1000); 2012 ata_28bit_cmd(&ccb->ataio, cmd, 0, 0, 0); 2013 2014 error = cam_periph_runccb(ccb, adaerror, /*cam_flags*/0, 2015 /*sense_flags*/ SF_NO_RECOVERY | SF_NO_RETRY, 2016 softc->disk->d_devstat); 2017 if (error != 0) 2018 xpt_print(periph->path, "Spin-down disk failed\n"); 2019 xpt_release_ccb(ccb); 2020 cam_periph_unlock(periph); 2021 } 2022} 2023 2024static void 2025adashutdown(void *arg, int howto) 2026{ 2027 2028 adaflush(); 2029 if (ada_spindown_shutdown != 0 && 2030 (howto & (RB_HALT | RB_POWEROFF)) != 0) 2031 adaspindown(ATA_STANDBY_IMMEDIATE, 0); 2032} 2033 2034static void 2035adasuspend(void *arg) 2036{ 2037 2038 adaflush(); 2039 if (ada_spindown_suspend != 0) 2040 adaspindown(ATA_SLEEP, CAM_DEV_QFREEZE); 2041} 2042 2043static void 2044adaresume(void *arg) 2045{ 2046 struct cam_periph *periph; 2047 struct ada_softc *softc; 2048 2049 if (ada_spindown_suspend == 0) 2050 return; 2051 2052 CAM_PERIPH_FOREACH(periph, &adadriver) { 2053 cam_periph_lock(periph); 2054 softc = (struct ada_softc *)periph->softc; 2055 /* 2056 * We only spin-down the drive if it is capable of it.. 2057 */ 2058 if ((softc->flags & ADA_FLAG_CAN_POWERMGT) == 0) { 2059 cam_periph_unlock(periph); 2060 continue; 2061 } 2062 2063 if (bootverbose) 2064 xpt_print(periph->path, "resume\n"); 2065 2066 /* 2067 * Drop freeze taken due to CAM_DEV_QFREEZE flag set on 2068 * sleep request. 2069 */ 2070 cam_release_devq(periph->path, 2071 /*relsim_flags*/0, 2072 /*openings*/0, 2073 /*timeout*/0, 2074 /*getcount_only*/0); 2075 2076 cam_periph_unlock(periph); 2077 } 2078} 2079 2080#endif /* _KERNEL */ 2081