1258223a3SMatthew Dillon /* 2258223a3SMatthew Dillon * Copyright (c) 2009 The DragonFly Project. All rights reserved. 3258223a3SMatthew Dillon * 4258223a3SMatthew Dillon * This code is derived from software contributed to The DragonFly Project 5258223a3SMatthew Dillon * by Matthew Dillon <dillon@backplane.com> 6258223a3SMatthew Dillon * 7258223a3SMatthew Dillon * Redistribution and use in source and binary forms, with or without 8258223a3SMatthew Dillon * modification, are permitted provided that the following conditions 9258223a3SMatthew Dillon * are met: 10258223a3SMatthew Dillon * 11258223a3SMatthew Dillon * 1. Redistributions of source code must retain the above copyright 12258223a3SMatthew Dillon * notice, this list of conditions and the following disclaimer. 13258223a3SMatthew Dillon * 2. Redistributions in binary form must reproduce the above copyright 14258223a3SMatthew Dillon * notice, this list of conditions and the following disclaimer in 15258223a3SMatthew Dillon * the documentation and/or other materials provided with the 16258223a3SMatthew Dillon * distribution. 17258223a3SMatthew Dillon * 3. Neither the name of The DragonFly Project nor the names of its 18258223a3SMatthew Dillon * contributors may be used to endorse or promote products derived 19258223a3SMatthew Dillon * from this software without specific, prior written permission. 20258223a3SMatthew Dillon * 21258223a3SMatthew Dillon * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22258223a3SMatthew Dillon * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23258223a3SMatthew Dillon * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24258223a3SMatthew Dillon * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25258223a3SMatthew Dillon * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26258223a3SMatthew Dillon * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27258223a3SMatthew Dillon * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28258223a3SMatthew Dillon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29258223a3SMatthew Dillon * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30258223a3SMatthew Dillon * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31258223a3SMatthew Dillon * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32258223a3SMatthew Dillon * SUCH DAMAGE. 33258223a3SMatthew Dillon * 34258223a3SMatthew Dillon * 35258223a3SMatthew Dillon * Copyright (c) 2007 David Gwynne <dlg@openbsd.org> 36258223a3SMatthew Dillon * 37258223a3SMatthew Dillon * Permission to use, copy, modify, and distribute this software for any 38258223a3SMatthew Dillon * purpose with or without fee is hereby granted, provided that the above 39258223a3SMatthew Dillon * copyright notice and this permission notice appear in all copies. 40258223a3SMatthew Dillon * 41258223a3SMatthew Dillon * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 42258223a3SMatthew Dillon * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 43258223a3SMatthew Dillon * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 44258223a3SMatthew Dillon * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 45258223a3SMatthew Dillon * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 46258223a3SMatthew Dillon * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 47258223a3SMatthew Dillon * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 48258223a3SMatthew Dillon * 49258223a3SMatthew Dillon * $OpenBSD: atascsi.c,v 1.64 2009/02/16 21:19:06 miod Exp $ 50258223a3SMatthew Dillon * $DragonFly$ 51258223a3SMatthew Dillon */ 52258223a3SMatthew Dillon /* 53258223a3SMatthew Dillon * Implement each SATA port as its own SCSI bus on CAM. This way we can 54258223a3SMatthew Dillon * implement future port multiplier features as individual devices on the 55258223a3SMatthew Dillon * bus. 56258223a3SMatthew Dillon * 57258223a3SMatthew Dillon * Much of the cdb<->xa conversion code was taken from OpenBSD, the rest 58258223a3SMatthew Dillon * was written natively for DragonFly. 59258223a3SMatthew Dillon */ 60258223a3SMatthew Dillon 61258223a3SMatthew Dillon #include "ahci.h" 62258223a3SMatthew Dillon 63b4189e5eSMatthew Dillon const char *ScsiTypeArray[32] = { 64b4189e5eSMatthew Dillon "DIRECT", 65b4189e5eSMatthew Dillon "SEQUENTIAL", 66b4189e5eSMatthew Dillon "PRINTER", 67b4189e5eSMatthew Dillon "PROCESSOR", 68b4189e5eSMatthew Dillon "WORM", 69b4189e5eSMatthew Dillon "CDROM", 70b4189e5eSMatthew Dillon "SCANNER", 71b4189e5eSMatthew Dillon "OPTICAL", 72b4189e5eSMatthew Dillon "CHANGER", 73b4189e5eSMatthew Dillon "COMM", 74b4189e5eSMatthew Dillon "ASC0", 75b4189e5eSMatthew Dillon "ASC1", 76b4189e5eSMatthew Dillon "STORARRAY", 77b4189e5eSMatthew Dillon "ENCLOSURE", 78b4189e5eSMatthew Dillon "RBC", 79b4189e5eSMatthew Dillon "OCRW", 80b4189e5eSMatthew Dillon "0x10", 81b4189e5eSMatthew Dillon "OSD", 82b4189e5eSMatthew Dillon "ADC", 83b4189e5eSMatthew Dillon "0x13", 84b4189e5eSMatthew Dillon "0x14", 85b4189e5eSMatthew Dillon "0x15", 86b4189e5eSMatthew Dillon "0x16", 87b4189e5eSMatthew Dillon "0x17", 88b4189e5eSMatthew Dillon "0x18", 89b4189e5eSMatthew Dillon "0x19", 90b4189e5eSMatthew Dillon "0x1A", 91b4189e5eSMatthew Dillon "0x1B", 92b4189e5eSMatthew Dillon "0x1C", 93b4189e5eSMatthew Dillon "0x1D", 94b4189e5eSMatthew Dillon "0x1E", 95b4189e5eSMatthew Dillon "NODEVICE" 96b4189e5eSMatthew Dillon }; 97b4189e5eSMatthew Dillon 98258223a3SMatthew Dillon static void ahci_xpt_action(struct cam_sim *sim, union ccb *ccb); 99258223a3SMatthew Dillon static void ahci_xpt_poll(struct cam_sim *sim); 100258223a3SMatthew Dillon static void ahci_xpt_scsi_disk_io(struct cam_sim *sim, union ccb *ccb); 101258223a3SMatthew Dillon static void ahci_xpt_scsi_atapi_io(struct cam_sim *sim, union ccb *ccb); 102258223a3SMatthew Dillon 103258223a3SMatthew Dillon static void ahci_ata_complete_disk_rw(struct ata_xfer *xa); 104258223a3SMatthew Dillon static void ahci_ata_complete_disk_synchronize_cache(struct ata_xfer *xa); 105b4189e5eSMatthew Dillon static void ahci_atapi_complete_cmd(struct ata_xfer *xa); 106b4189e5eSMatthew Dillon static void ahci_ata_dummy_sense(struct scsi_sense_data *sense_data); 1077d4fcf34SMatthew Dillon static void ahci_ata_atapi_sense(struct ata_fis_d2h *rfis, 1087d4fcf34SMatthew Dillon struct scsi_sense_data *sense_data); 109258223a3SMatthew Dillon 110258223a3SMatthew Dillon static int ahci_cam_probe(struct ahci_port *ap); 111b4189e5eSMatthew Dillon static int ahci_cam_probe_disk(struct ahci_port *ap); 112b4189e5eSMatthew Dillon static int ahci_cam_probe_atapi(struct ahci_port *ap); 113b4189e5eSMatthew Dillon static void ahci_ata_dummy_done(struct ata_xfer *xa); 114258223a3SMatthew Dillon static void ata_fix_identify(struct ata_identify *id); 115258223a3SMatthew Dillon static void ahci_cam_rescan(struct ahci_port *ap); 116258223a3SMatthew Dillon 117258223a3SMatthew Dillon int 118258223a3SMatthew Dillon ahci_cam_attach(struct ahci_port *ap) 119258223a3SMatthew Dillon { 120258223a3SMatthew Dillon struct cam_devq *devq; 121258223a3SMatthew Dillon struct cam_sim *sim; 122258223a3SMatthew Dillon int error; 123258223a3SMatthew Dillon int unit; 124258223a3SMatthew Dillon 125*cec85a37SMatthew Dillon /* 126*cec85a37SMatthew Dillon * We want at least one ccb to be available for error processing 127*cec85a37SMatthew Dillon * so don't let CAM use more then ncmds - 1. 128*cec85a37SMatthew Dillon */ 129258223a3SMatthew Dillon unit = device_get_unit(ap->ap_sc->sc_dev); 130*cec85a37SMatthew Dillon if (ap->ap_sc->sc_ncmds > 1) 131*cec85a37SMatthew Dillon devq = cam_simq_alloc(ap->ap_sc->sc_ncmds - 1); 132*cec85a37SMatthew Dillon else 133258223a3SMatthew Dillon devq = cam_simq_alloc(ap->ap_sc->sc_ncmds); 134258223a3SMatthew Dillon if (devq == NULL) { 135258223a3SMatthew Dillon return (ENOMEM); 136258223a3SMatthew Dillon } 137258223a3SMatthew Dillon sim = cam_sim_alloc(ahci_xpt_action, ahci_xpt_poll, "ahci", 138258223a3SMatthew Dillon (void *)ap, unit, &sim_mplock, 1, 1, devq); 139258223a3SMatthew Dillon cam_simq_release(devq); 140258223a3SMatthew Dillon if (sim == NULL) { 141258223a3SMatthew Dillon return (ENOMEM); 142258223a3SMatthew Dillon } 143258223a3SMatthew Dillon ap->ap_sim = sim; 144258223a3SMatthew Dillon error = xpt_bus_register(ap->ap_sim, ap->ap_num); 145258223a3SMatthew Dillon if (error != CAM_SUCCESS) { 146258223a3SMatthew Dillon ahci_cam_detach(ap); 147258223a3SMatthew Dillon return (EINVAL); 148258223a3SMatthew Dillon } 149258223a3SMatthew Dillon ap->ap_flags |= AP_F_BUS_REGISTERED; 150258223a3SMatthew Dillon error = xpt_create_path(&ap->ap_path, NULL, cam_sim_path(sim), 151258223a3SMatthew Dillon CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 152258223a3SMatthew Dillon if (error != CAM_REQ_CMP) { 153258223a3SMatthew Dillon ahci_cam_detach(ap); 154258223a3SMatthew Dillon return (ENOMEM); 155258223a3SMatthew Dillon } 156258223a3SMatthew Dillon 157258223a3SMatthew Dillon error = ahci_cam_probe(ap); 158258223a3SMatthew Dillon if (error) { 159258223a3SMatthew Dillon ahci_cam_detach(ap); 160258223a3SMatthew Dillon return (EIO); 161258223a3SMatthew Dillon } 162258223a3SMatthew Dillon ap->ap_flags |= AP_F_CAM_ATTACHED; 163258223a3SMatthew Dillon 164258223a3SMatthew Dillon ahci_cam_rescan(ap); 165258223a3SMatthew Dillon 166258223a3SMatthew Dillon return(0); 167258223a3SMatthew Dillon } 168258223a3SMatthew Dillon 169258223a3SMatthew Dillon void 170fd8bd957SMatthew Dillon ahci_cam_changed(struct ahci_port *ap, int found) 171258223a3SMatthew Dillon { 172fd8bd957SMatthew Dillon struct cam_path *tmppath; 173fd8bd957SMatthew Dillon 174258223a3SMatthew Dillon if (ap->ap_sim == NULL) 175258223a3SMatthew Dillon return; 176fd8bd957SMatthew Dillon if (xpt_create_path(&tmppath, NULL, cam_sim_path(ap->ap_sim), 177fd8bd957SMatthew Dillon 0, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 178fd8bd957SMatthew Dillon return; 179fd8bd957SMatthew Dillon } 180fd8bd957SMatthew Dillon if (found) { 181258223a3SMatthew Dillon ahci_cam_probe(ap); 182fd8bd957SMatthew Dillon /* 183fd8bd957SMatthew Dillon * XXX calling AC_FOUND_DEVICE with inquiry data is 184fd8bd957SMatthew Dillon * basically a NOP. For now just tell CAM to 185fd8bd957SMatthew Dillon * rescan the bus. 186fd8bd957SMatthew Dillon */ 187fd8bd957SMatthew Dillon xpt_async(AC_FOUND_DEVICE, tmppath, NULL); 188258223a3SMatthew Dillon ahci_cam_rescan(ap); 189fd8bd957SMatthew Dillon } else { 190fd8bd957SMatthew Dillon xpt_async(AC_LOST_DEVICE, tmppath, NULL); 191fd8bd957SMatthew Dillon } 192fd8bd957SMatthew Dillon xpt_free_path(tmppath); 193258223a3SMatthew Dillon } 194258223a3SMatthew Dillon 195258223a3SMatthew Dillon void 196258223a3SMatthew Dillon ahci_cam_detach(struct ahci_port *ap) 197258223a3SMatthew Dillon { 198258223a3SMatthew Dillon int error; 199258223a3SMatthew Dillon 200258223a3SMatthew Dillon if ((ap->ap_flags & AP_F_CAM_ATTACHED) == 0) 201258223a3SMatthew Dillon return; 202258223a3SMatthew Dillon get_mplock(); 203258223a3SMatthew Dillon if (ap->ap_sim) { 204258223a3SMatthew Dillon xpt_freeze_simq(ap->ap_sim, 1); 205258223a3SMatthew Dillon } 206258223a3SMatthew Dillon if (ap->ap_path) { 207258223a3SMatthew Dillon xpt_free_path(ap->ap_path); 208258223a3SMatthew Dillon ap->ap_path = NULL; 209258223a3SMatthew Dillon } 210258223a3SMatthew Dillon if (ap->ap_flags & AP_F_BUS_REGISTERED) { 211258223a3SMatthew Dillon error = xpt_bus_deregister(cam_sim_path(ap->ap_sim)); 212258223a3SMatthew Dillon KKASSERT(error == CAM_REQ_CMP); 213258223a3SMatthew Dillon ap->ap_flags &= ~AP_F_BUS_REGISTERED; 214258223a3SMatthew Dillon } 215258223a3SMatthew Dillon if (ap->ap_sim) { 216258223a3SMatthew Dillon cam_sim_free(ap->ap_sim); 217258223a3SMatthew Dillon ap->ap_sim = NULL; 218258223a3SMatthew Dillon } 219258223a3SMatthew Dillon rel_mplock(); 220258223a3SMatthew Dillon ap->ap_flags &= ~AP_F_CAM_ATTACHED; 221258223a3SMatthew Dillon } 222258223a3SMatthew Dillon 223258223a3SMatthew Dillon /* 224258223a3SMatthew Dillon * Once the AHCI port has been attched we need to probe for a device or 225258223a3SMatthew Dillon * devices on the port and setup various options. 226258223a3SMatthew Dillon */ 227258223a3SMatthew Dillon static int 228258223a3SMatthew Dillon ahci_cam_probe(struct ahci_port *ap) 229258223a3SMatthew Dillon { 230258223a3SMatthew Dillon struct ata_xfer *xa; 231258223a3SMatthew Dillon u_int64_t capacity; 232258223a3SMatthew Dillon u_int64_t capacity_bytes; 233258223a3SMatthew Dillon int model_len; 234258223a3SMatthew Dillon int status; 235fd8bd957SMatthew Dillon int error; 236258223a3SMatthew Dillon int devncqdepth; 237258223a3SMatthew Dillon int i; 238669fbbf7SMatthew Dillon const char *wcstr; 239669fbbf7SMatthew Dillon const char *rastr; 240fd8bd957SMatthew Dillon const char *scstr; 241fd8bd957SMatthew Dillon const char *type; 242fd8bd957SMatthew Dillon 243fd8bd957SMatthew Dillon if (ap->ap_ata.ap_type == ATA_PORT_T_NONE) 244fd8bd957SMatthew Dillon return (EIO); 245258223a3SMatthew Dillon 246258223a3SMatthew Dillon /* 247258223a3SMatthew Dillon * Issue identify, saving the result 248258223a3SMatthew Dillon */ 249258223a3SMatthew Dillon xa = ahci_ata_get_xfer(ap); 250258223a3SMatthew Dillon xa->complete = ahci_ata_dummy_done; 251258223a3SMatthew Dillon xa->data = &ap->ap_ata.ap_identify; 252258223a3SMatthew Dillon xa->datalen = sizeof(ap->ap_ata.ap_identify); 253258223a3SMatthew Dillon xa->fis->flags = ATA_H2D_FLAGS_CMD; 254fd8bd957SMatthew Dillon if (ap->ap_ata.ap_type == ATA_PORT_T_ATAPI) { 255fd8bd957SMatthew Dillon xa->fis->command = ATA_C_ATAPI_IDENTIFY; 256fd8bd957SMatthew Dillon type = "ATAPI"; 257fd8bd957SMatthew Dillon } else { 258258223a3SMatthew Dillon xa->fis->command = ATA_C_IDENTIFY; 259fd8bd957SMatthew Dillon type = "DISK"; 260fd8bd957SMatthew Dillon } 261258223a3SMatthew Dillon xa->fis->features = 0; 262258223a3SMatthew Dillon xa->fis->device = 0; 263258223a3SMatthew Dillon xa->flags = ATA_F_READ | ATA_F_PIO | ATA_F_POLL; 264258223a3SMatthew Dillon xa->timeout = hz; 265258223a3SMatthew Dillon 266258223a3SMatthew Dillon status = ahci_ata_cmd(xa); 267258223a3SMatthew Dillon if (status != ATA_COMPLETE) { 268fd8bd957SMatthew Dillon kprintf("%s: Detected %s device but unable to IDENTIFY\n", 269fd8bd957SMatthew Dillon PORTNAME(ap), type); 270258223a3SMatthew Dillon ahci_ata_put_xfer(xa); 271258223a3SMatthew Dillon return(EIO); 272258223a3SMatthew Dillon } 273258223a3SMatthew Dillon if (xa->state != ATA_S_COMPLETE) { 274fd8bd957SMatthew Dillon kprintf("%s: Detected %s device but unable to IDENTIFY " 275258223a3SMatthew Dillon " xa->state=%d\n", 276fd8bd957SMatthew Dillon PORTNAME(ap), type, xa->state); 277258223a3SMatthew Dillon ahci_ata_put_xfer(xa); 278258223a3SMatthew Dillon return(EIO); 279258223a3SMatthew Dillon } 280258223a3SMatthew Dillon ahci_ata_put_xfer(xa); 281258223a3SMatthew Dillon 282258223a3SMatthew Dillon ata_fix_identify(&ap->ap_ata.ap_identify); 283258223a3SMatthew Dillon 284258223a3SMatthew Dillon /* 285258223a3SMatthew Dillon * Read capacity using SATA probe info. 286258223a3SMatthew Dillon */ 287258223a3SMatthew Dillon if (le16toh(ap->ap_ata.ap_identify.cmdset83) & 0x0400) { 288258223a3SMatthew Dillon /* LBA48 feature set supported */ 289258223a3SMatthew Dillon capacity = 0; 290258223a3SMatthew Dillon for (i = 3; i >= 0; --i) { 291258223a3SMatthew Dillon capacity <<= 16; 292258223a3SMatthew Dillon capacity += 293258223a3SMatthew Dillon le16toh(ap->ap_ata.ap_identify.addrsecxt[i]); 294258223a3SMatthew Dillon } 295258223a3SMatthew Dillon } else { 296258223a3SMatthew Dillon capacity = le16toh(ap->ap_ata.ap_identify.addrsec[1]); 297258223a3SMatthew Dillon capacity <<= 16; 298258223a3SMatthew Dillon capacity += le16toh(ap->ap_ata.ap_identify.addrsec[0]); 299258223a3SMatthew Dillon } 300258223a3SMatthew Dillon ap->ap_ata.ap_capacity = capacity; 301258223a3SMatthew Dillon ap->ap_ata.ap_features |= ATA_PORT_F_PROBED; 302258223a3SMatthew Dillon 303258223a3SMatthew Dillon capacity_bytes = capacity * 512; 304258223a3SMatthew Dillon 305258223a3SMatthew Dillon /* 306258223a3SMatthew Dillon * Negotiate NCQ, throw away any ata_xfer's beyond the negotiated 307258223a3SMatthew Dillon * number of slots and limit the number of CAM ccb's to one less 308258223a3SMatthew Dillon * so we always have a slot available for recovery. 309258223a3SMatthew Dillon * 310258223a3SMatthew Dillon * NCQ is not used if ap_ncqdepth is 1 or the host controller does 311258223a3SMatthew Dillon * not support it, and in that case the driver can handle extra 312258223a3SMatthew Dillon * ccb's. 313*cec85a37SMatthew Dillon * 314*cec85a37SMatthew Dillon * Remember at least one extra CCB needs to be reserved for the 315*cec85a37SMatthew Dillon * error ccb. 316258223a3SMatthew Dillon */ 317258223a3SMatthew Dillon if ((ap->ap_sc->sc_cap & AHCI_REG_CAP_SNCQ) && 318258223a3SMatthew Dillon (le16toh(ap->ap_ata.ap_identify.satacap) & (1 << 8))) { 319258223a3SMatthew Dillon ap->ap_ata.ap_ncqdepth = (le16toh(ap->ap_ata.ap_identify.qdepth) & 0x1F) + 1; 320258223a3SMatthew Dillon devncqdepth = ap->ap_ata.ap_ncqdepth; 321258223a3SMatthew Dillon if (ap->ap_ata.ap_ncqdepth > ap->ap_sc->sc_ncmds) 322258223a3SMatthew Dillon ap->ap_ata.ap_ncqdepth = ap->ap_sc->sc_ncmds; 323*cec85a37SMatthew Dillon if (ap->ap_ata.ap_ncqdepth > 1) { 324258223a3SMatthew Dillon for (i = 0; i < ap->ap_sc->sc_ncmds; ++i) { 325258223a3SMatthew Dillon xa = ahci_ata_get_xfer(ap); 326258223a3SMatthew Dillon if (xa->tag < ap->ap_ata.ap_ncqdepth) { 327258223a3SMatthew Dillon xa->state = ATA_S_COMPLETE; 328258223a3SMatthew Dillon ahci_ata_put_xfer(xa); 329258223a3SMatthew Dillon } 330258223a3SMatthew Dillon } 331*cec85a37SMatthew Dillon if (ap->ap_ata.ap_ncqdepth >= ap->ap_sc->sc_ncmds) { 332258223a3SMatthew Dillon cam_devq_resize(ap->ap_sim->devq, 333258223a3SMatthew Dillon ap->ap_ata.ap_ncqdepth - 1); 334258223a3SMatthew Dillon } 335*cec85a37SMatthew Dillon } 336258223a3SMatthew Dillon } else { 337258223a3SMatthew Dillon devncqdepth = 0; 338258223a3SMatthew Dillon } 339258223a3SMatthew Dillon 340fd8bd957SMatthew Dillon /* 341fd8bd957SMatthew Dillon * Make the model string a bit more presentable 342fd8bd957SMatthew Dillon */ 343258223a3SMatthew Dillon for (model_len = 40; model_len; --model_len) { 344258223a3SMatthew Dillon if (ap->ap_ata.ap_identify.model[model_len-1] == ' ') 345258223a3SMatthew Dillon continue; 346258223a3SMatthew Dillon if (ap->ap_ata.ap_identify.model[model_len-1] == 0) 347258223a3SMatthew Dillon continue; 348258223a3SMatthew Dillon break; 349258223a3SMatthew Dillon } 350669fbbf7SMatthew Dillon 351fd8bd957SMatthew Dillon /* 352fd8bd957SMatthew Dillon * Generate informatiive strings. 353fd8bd957SMatthew Dillon * 354fd8bd957SMatthew Dillon * NOTE: We do not automatically set write caching, lookahead, 355fd8bd957SMatthew Dillon * or the security state for ATAPI devices. 356fd8bd957SMatthew Dillon */ 357669fbbf7SMatthew Dillon if (ap->ap_ata.ap_identify.cmdset82 & ATA_IDENTIFY_WRITECACHE) { 358669fbbf7SMatthew Dillon if (ap->ap_ata.ap_identify.features85 & ATA_IDENTIFY_WRITECACHE) 359669fbbf7SMatthew Dillon wcstr = "enabled"; 360fd8bd957SMatthew Dillon else if (ap->ap_ata.ap_type == ATA_PORT_T_ATAPI) 361fd8bd957SMatthew Dillon wcstr = "disabled"; 362669fbbf7SMatthew Dillon else 363669fbbf7SMatthew Dillon wcstr = "enabling"; 364669fbbf7SMatthew Dillon } else { 365669fbbf7SMatthew Dillon wcstr = "notsupp"; 366669fbbf7SMatthew Dillon } 367669fbbf7SMatthew Dillon 368669fbbf7SMatthew Dillon if (ap->ap_ata.ap_identify.cmdset82 & ATA_IDENTIFY_LOOKAHEAD) { 369669fbbf7SMatthew Dillon if (ap->ap_ata.ap_identify.features85 & ATA_IDENTIFY_LOOKAHEAD) 370669fbbf7SMatthew Dillon rastr = "enabled"; 371fd8bd957SMatthew Dillon else if (ap->ap_ata.ap_type == ATA_PORT_T_ATAPI) 372fd8bd957SMatthew Dillon rastr = "disabled"; 373669fbbf7SMatthew Dillon else 374669fbbf7SMatthew Dillon rastr = "enabling"; 375669fbbf7SMatthew Dillon } else { 376669fbbf7SMatthew Dillon rastr = "notsupp"; 377669fbbf7SMatthew Dillon } 378669fbbf7SMatthew Dillon 379fd8bd957SMatthew Dillon if (ap->ap_ata.ap_identify.cmdset82 & ATA_IDENTIFY_SECURITY) { 380fd8bd957SMatthew Dillon if (ap->ap_ata.ap_identify.securestatus & ATA_SECURE_FROZEN) 381fd8bd957SMatthew Dillon scstr = "frozen"; 382fd8bd957SMatthew Dillon else if (ap->ap_ata.ap_type == ATA_PORT_T_ATAPI) 383fd8bd957SMatthew Dillon scstr = "unfrozen"; 384fd8bd957SMatthew Dillon else 385fd8bd957SMatthew Dillon scstr = "freezing"; 386fd8bd957SMatthew Dillon } else { 387fd8bd957SMatthew Dillon scstr = "notsupp"; 388fd8bd957SMatthew Dillon } 389fd8bd957SMatthew Dillon 390fd8bd957SMatthew Dillon kprintf("%s: Found %s \"%*.*s %8.8s\" serial=\"%20.20s\"\n" 391258223a3SMatthew Dillon "%s: tags=%d/%d satacaps=%04x satafeat=%04x " 392258223a3SMatthew Dillon "capacity=%lld.%02dMB\n" 393fd8bd957SMatthew Dillon "%s: f85=%04x f86=%04x f87=%04x WC=%s RA=%s SEC=%s\n", 394258223a3SMatthew Dillon PORTNAME(ap), 395fd8bd957SMatthew Dillon type, 396258223a3SMatthew Dillon model_len, model_len, 397258223a3SMatthew Dillon ap->ap_ata.ap_identify.model, 398258223a3SMatthew Dillon ap->ap_ata.ap_identify.firmware, 399258223a3SMatthew Dillon ap->ap_ata.ap_identify.serial, 400258223a3SMatthew Dillon 401258223a3SMatthew Dillon PORTNAME(ap), 402258223a3SMatthew Dillon devncqdepth, ap->ap_sc->sc_ncmds, 403258223a3SMatthew Dillon ap->ap_ata.ap_identify.satacap, 404258223a3SMatthew Dillon ap->ap_ata.ap_identify.satafsup, 405258223a3SMatthew Dillon (long long)capacity_bytes / (1024 * 1024), 406258223a3SMatthew Dillon (int)(capacity_bytes % (1024 * 1024)) * 100 / (1024 * 1024), 407258223a3SMatthew Dillon 408258223a3SMatthew Dillon PORTNAME(ap), 409258223a3SMatthew Dillon ap->ap_ata.ap_identify.features85, 410258223a3SMatthew Dillon ap->ap_ata.ap_identify.features86, 411669fbbf7SMatthew Dillon ap->ap_ata.ap_identify.features87, 412669fbbf7SMatthew Dillon wcstr, 413fd8bd957SMatthew Dillon rastr, 414fd8bd957SMatthew Dillon scstr 415258223a3SMatthew Dillon ); 416258223a3SMatthew Dillon 417258223a3SMatthew Dillon /* 418fd8bd957SMatthew Dillon * Additional type-specific probing 419fd8bd957SMatthew Dillon */ 420fd8bd957SMatthew Dillon switch(ap->ap_ata.ap_type) { 421fd8bd957SMatthew Dillon case ATA_PORT_T_DISK: 422fd8bd957SMatthew Dillon error = ahci_cam_probe_disk(ap); 423fd8bd957SMatthew Dillon break; 424fd8bd957SMatthew Dillon default: 425fd8bd957SMatthew Dillon error = ahci_cam_probe_atapi(ap); 426fd8bd957SMatthew Dillon break; 427fd8bd957SMatthew Dillon } 428fd8bd957SMatthew Dillon return (0); 429fd8bd957SMatthew Dillon } 430fd8bd957SMatthew Dillon 431fd8bd957SMatthew Dillon /* 432fd8bd957SMatthew Dillon * DISK-specific probe after initial ident 433fd8bd957SMatthew Dillon */ 434fd8bd957SMatthew Dillon static int 435fd8bd957SMatthew Dillon ahci_cam_probe_disk(struct ahci_port *ap) 436fd8bd957SMatthew Dillon { 437fd8bd957SMatthew Dillon struct ata_xfer *xa; 438fd8bd957SMatthew Dillon int status; 439fd8bd957SMatthew Dillon 440fd8bd957SMatthew Dillon /* 441258223a3SMatthew Dillon * Enable write cache if supported 442fd8bd957SMatthew Dillon * 443fd8bd957SMatthew Dillon * NOTE: "WD My Book" external disk devices have a very poor 444fd8bd957SMatthew Dillon * daughter board between the the ESATA and the HD. Sending 445fd8bd957SMatthew Dillon * any ATA_C_SET_FEATURES commands will break the hardware port 446fd8bd957SMatthew Dillon * with a fatal protocol error. However, this device also 447fd8bd957SMatthew Dillon * indicates that WRITECACHE is already on and READAHEAD is 448fd8bd957SMatthew Dillon * not supported so we avoid the issue. 449258223a3SMatthew Dillon */ 450669fbbf7SMatthew Dillon if ((ap->ap_ata.ap_identify.cmdset82 & ATA_IDENTIFY_WRITECACHE) && 451669fbbf7SMatthew Dillon (ap->ap_ata.ap_identify.features85 & ATA_IDENTIFY_WRITECACHE) == 0) { 452258223a3SMatthew Dillon xa = ahci_ata_get_xfer(ap); 453258223a3SMatthew Dillon xa->complete = ahci_ata_dummy_done; 454258223a3SMatthew Dillon xa->fis->command = ATA_C_SET_FEATURES; 455669fbbf7SMatthew Dillon /*xa->fis->features = ATA_SF_WRITECACHE_EN;*/ 456669fbbf7SMatthew Dillon xa->fis->features = ATA_SF_LOOKAHEAD_EN; 457258223a3SMatthew Dillon xa->fis->flags = ATA_H2D_FLAGS_CMD; 458669fbbf7SMatthew Dillon xa->fis->device = 0; 459258223a3SMatthew Dillon xa->flags = ATA_F_READ | ATA_F_PIO | ATA_F_POLL; 460258223a3SMatthew Dillon xa->timeout = hz; 461669fbbf7SMatthew Dillon xa->datalen = 0; 462258223a3SMatthew Dillon status = ahci_ata_cmd(xa); 463258223a3SMatthew Dillon if (status == ATA_COMPLETE) 464258223a3SMatthew Dillon ap->ap_ata.ap_features |= ATA_PORT_F_WCACHE; 465258223a3SMatthew Dillon ahci_ata_put_xfer(xa); 466258223a3SMatthew Dillon } 467258223a3SMatthew Dillon 468258223a3SMatthew Dillon /* 469258223a3SMatthew Dillon * Enable readahead if supported 470258223a3SMatthew Dillon */ 471669fbbf7SMatthew Dillon if ((ap->ap_ata.ap_identify.cmdset82 & ATA_IDENTIFY_LOOKAHEAD) && 472669fbbf7SMatthew Dillon (ap->ap_ata.ap_identify.features85 & ATA_IDENTIFY_LOOKAHEAD) == 0) { 473258223a3SMatthew Dillon xa = ahci_ata_get_xfer(ap); 474258223a3SMatthew Dillon xa->complete = ahci_ata_dummy_done; 475258223a3SMatthew Dillon xa->fis->command = ATA_C_SET_FEATURES; 476258223a3SMatthew Dillon xa->fis->features = ATA_SF_LOOKAHEAD_EN; 477258223a3SMatthew Dillon xa->fis->flags = ATA_H2D_FLAGS_CMD; 478669fbbf7SMatthew Dillon xa->fis->device = 0; 479258223a3SMatthew Dillon xa->flags = ATA_F_READ | ATA_F_PIO | ATA_F_POLL; 480258223a3SMatthew Dillon xa->timeout = hz; 481669fbbf7SMatthew Dillon xa->datalen = 0; 482258223a3SMatthew Dillon status = ahci_ata_cmd(xa); 483258223a3SMatthew Dillon if (status == ATA_COMPLETE) 484258223a3SMatthew Dillon ap->ap_ata.ap_features |= ATA_PORT_F_RAHEAD; 485258223a3SMatthew Dillon ahci_ata_put_xfer(xa); 486258223a3SMatthew Dillon } 487258223a3SMatthew Dillon 488258223a3SMatthew Dillon /* 489258223a3SMatthew Dillon * FREEZE LOCK the device so malicious users can't lock it on us. 490258223a3SMatthew Dillon * As there is no harm in issuing this to devices that don't 491258223a3SMatthew Dillon * support the security feature set we just send it, and don't bother 492258223a3SMatthew Dillon * checking if the device sends a command abort to tell us it doesn't 493258223a3SMatthew Dillon * support it 494258223a3SMatthew Dillon */ 495fd8bd957SMatthew Dillon if ((ap->ap_ata.ap_identify.cmdset82 & ATA_IDENTIFY_SECURITY) && 496fd8bd957SMatthew Dillon (ap->ap_ata.ap_identify.securestatus & ATA_SECURE_FROZEN) == 0) { 497258223a3SMatthew Dillon xa = ahci_ata_get_xfer(ap); 498258223a3SMatthew Dillon xa->complete = ahci_ata_dummy_done; 499258223a3SMatthew Dillon xa->fis->command = ATA_C_SEC_FREEZE_LOCK; 500258223a3SMatthew Dillon xa->fis->flags = ATA_H2D_FLAGS_CMD; 501258223a3SMatthew Dillon xa->flags = ATA_F_READ | ATA_F_PIO | ATA_F_POLL; 502258223a3SMatthew Dillon xa->timeout = hz; 503669fbbf7SMatthew Dillon xa->datalen = 0; 504258223a3SMatthew Dillon status = ahci_ata_cmd(xa); 505258223a3SMatthew Dillon if (status == ATA_COMPLETE) 506258223a3SMatthew Dillon ap->ap_ata.ap_features |= ATA_PORT_F_FRZLCK; 507258223a3SMatthew Dillon ahci_ata_put_xfer(xa); 508669fbbf7SMatthew Dillon } 509258223a3SMatthew Dillon 510b4189e5eSMatthew Dillon return (0); 511b4189e5eSMatthew Dillon } 512b4189e5eSMatthew Dillon 513fd8bd957SMatthew Dillon /* 514fd8bd957SMatthew Dillon * ATAPI-specific probe after initial ident 515fd8bd957SMatthew Dillon */ 516b4189e5eSMatthew Dillon static int 517b4189e5eSMatthew Dillon ahci_cam_probe_atapi(struct ahci_port *ap) 518b4189e5eSMatthew Dillon { 519fd8bd957SMatthew Dillon return(0); 520fd8bd957SMatthew Dillon } 521fd8bd957SMatthew Dillon 522fd8bd957SMatthew Dillon #if 0 523fd8bd957SMatthew Dillon /* 524fd8bd957SMatthew Dillon * Keep this old code around for a little bit, it is another way 525fd8bd957SMatthew Dillon * to probe an ATAPI device by using a ATAPI (SCSI) INQUIRY 526fd8bd957SMatthew Dillon */ 527b4189e5eSMatthew Dillon struct ata_xfer *xa; 528b4189e5eSMatthew Dillon int status; 529b4189e5eSMatthew Dillon int devncqdepth; 530b4189e5eSMatthew Dillon struct scsi_inquiry_data *inq_data; 531b4189e5eSMatthew Dillon struct scsi_inquiry *inq_cmd; 532b4189e5eSMatthew Dillon 533b4189e5eSMatthew Dillon inq_data = kmalloc(sizeof(*inq_data), M_TEMP, M_WAITOK | M_ZERO); 534b4189e5eSMatthew Dillon 535258223a3SMatthew Dillon /* 536b4189e5eSMatthew Dillon * Issue identify, saving the result 537258223a3SMatthew Dillon */ 538b4189e5eSMatthew Dillon xa = ahci_ata_get_xfer(ap); 539b4189e5eSMatthew Dillon xa->complete = ahci_ata_dummy_done; 540b4189e5eSMatthew Dillon xa->data = inq_data; 541b4189e5eSMatthew Dillon xa->datalen = sizeof(*inq_data); 542b4189e5eSMatthew Dillon xa->flags = ATA_F_READ | ATA_F_PACKET | ATA_F_PIO | ATA_F_POLL; 543b4189e5eSMatthew Dillon xa->timeout = hz; 544b4189e5eSMatthew Dillon 545b4189e5eSMatthew Dillon xa->fis->flags = ATA_H2D_FLAGS_CMD; 546b4189e5eSMatthew Dillon xa->fis->command = ATA_C_PACKET; 547b4189e5eSMatthew Dillon xa->fis->device = 0; 548b4189e5eSMatthew Dillon xa->fis->sector_count = xa->tag << 3; 549b4189e5eSMatthew Dillon xa->fis->features = ATA_H2D_FEATURES_DMA | 550b4189e5eSMatthew Dillon ((xa->flags & ATA_F_WRITE) ? 551b4189e5eSMatthew Dillon ATA_H2D_FEATURES_DIR_WRITE : ATA_H2D_FEATURES_DIR_READ); 552b4189e5eSMatthew Dillon xa->fis->lba_mid = 0x00; 553b4189e5eSMatthew Dillon xa->fis->lba_high = 0x20; 554b4189e5eSMatthew Dillon 555b4189e5eSMatthew Dillon inq_cmd = (void *)xa->packetcmd; 556b4189e5eSMatthew Dillon inq_cmd->opcode = INQUIRY; 557b4189e5eSMatthew Dillon inq_cmd->length = SHORT_INQUIRY_LENGTH; 558b4189e5eSMatthew Dillon 559b4189e5eSMatthew Dillon status = ahci_ata_cmd(xa); 560b4189e5eSMatthew Dillon if (status != ATA_COMPLETE) { 561b4189e5eSMatthew Dillon kprintf("%s: Detected ATAPI device but unable to INQUIRY\n", 562b4189e5eSMatthew Dillon PORTNAME(ap)); 563b4189e5eSMatthew Dillon ahci_ata_put_xfer(xa); 564b4189e5eSMatthew Dillon kfree(inq_data, M_TEMP); 565b4189e5eSMatthew Dillon return(EIO); 566b4189e5eSMatthew Dillon } 567b4189e5eSMatthew Dillon if (xa->state != ATA_S_COMPLETE) { 568b4189e5eSMatthew Dillon kprintf("%s: Detected ATAPI device but unable to INQUIRY " 569b4189e5eSMatthew Dillon " xa->state=%d\n", 570b4189e5eSMatthew Dillon PORTNAME(ap), xa->state); 571b4189e5eSMatthew Dillon ahci_ata_put_xfer(xa); 572b4189e5eSMatthew Dillon kfree(inq_data, M_TEMP); 573b4189e5eSMatthew Dillon return(EIO); 574b4189e5eSMatthew Dillon } 575b4189e5eSMatthew Dillon ahci_ata_put_xfer(xa); 576b4189e5eSMatthew Dillon 577b4189e5eSMatthew Dillon ap->ap_ata.ap_features |= ATA_PORT_F_PROBED; 578b4189e5eSMatthew Dillon 579b4189e5eSMatthew Dillon /* 580b4189e5eSMatthew Dillon * XXX Negotiate NCQ with ATAPI? How do we do this? 581b4189e5eSMatthew Dillon */ 582b4189e5eSMatthew Dillon 583b4189e5eSMatthew Dillon devncqdepth = 0; 584b4189e5eSMatthew Dillon 585b4189e5eSMatthew Dillon kprintf("%s: Found ATAPI %s \"%8.8s %16.16s\" rev=\"%4.4s\"\n" 586b4189e5eSMatthew Dillon "%s: tags=%d/%d\n", 587b4189e5eSMatthew Dillon PORTNAME(ap), 588b4189e5eSMatthew Dillon ScsiTypeArray[SID_TYPE(inq_data)], 589b4189e5eSMatthew Dillon inq_data->vendor, 590b4189e5eSMatthew Dillon inq_data->product, 591b4189e5eSMatthew Dillon inq_data->revision, 592b4189e5eSMatthew Dillon 593b4189e5eSMatthew Dillon PORTNAME(ap), 594b4189e5eSMatthew Dillon devncqdepth, ap->ap_sc->sc_ncmds 595b4189e5eSMatthew Dillon ); 596b4189e5eSMatthew Dillon kfree(inq_data, M_TEMP); 597b4189e5eSMatthew Dillon #endif 598258223a3SMatthew Dillon 599b4189e5eSMatthew Dillon /* 600b4189e5eSMatthew Dillon * Fix byte ordering so buffers can be accessed as 601b4189e5eSMatthew Dillon * strings. 602b4189e5eSMatthew Dillon */ 603258223a3SMatthew Dillon static void 604258223a3SMatthew Dillon ata_fix_identify(struct ata_identify *id) 605258223a3SMatthew Dillon { 606258223a3SMatthew Dillon u_int16_t *swap; 607258223a3SMatthew Dillon int i; 608258223a3SMatthew Dillon 609258223a3SMatthew Dillon swap = (u_int16_t *)id->serial; 610258223a3SMatthew Dillon for (i = 0; i < sizeof(id->serial) / sizeof(u_int16_t); i++) 611258223a3SMatthew Dillon swap[i] = bswap16(swap[i]); 612258223a3SMatthew Dillon 613258223a3SMatthew Dillon swap = (u_int16_t *)id->firmware; 614258223a3SMatthew Dillon for (i = 0; i < sizeof(id->firmware) / sizeof(u_int16_t); i++) 615258223a3SMatthew Dillon swap[i] = bswap16(swap[i]); 616258223a3SMatthew Dillon 617258223a3SMatthew Dillon swap = (u_int16_t *)id->model; 618258223a3SMatthew Dillon for (i = 0; i < sizeof(id->model) / sizeof(u_int16_t); i++) 619258223a3SMatthew Dillon swap[i] = bswap16(swap[i]); 620258223a3SMatthew Dillon } 621258223a3SMatthew Dillon 622258223a3SMatthew Dillon /* 623b4189e5eSMatthew Dillon * Dummy done callback for xa. 624b4189e5eSMatthew Dillon */ 625b4189e5eSMatthew Dillon static void 626b4189e5eSMatthew Dillon ahci_ata_dummy_done(struct ata_xfer *xa) 627b4189e5eSMatthew Dillon { 628b4189e5eSMatthew Dillon } 629b4189e5eSMatthew Dillon 630b4189e5eSMatthew Dillon /* 631fd8bd957SMatthew Dillon * Initiate a bus scan. 632fd8bd957SMatthew Dillon * 633fd8bd957SMatthew Dillon * An asynchronous bus scan is used to avoid reentrancy issues 634258223a3SMatthew Dillon */ 635258223a3SMatthew Dillon static void 636258223a3SMatthew Dillon ahci_cam_rescan_callback(struct cam_periph *periph, union ccb *ccb) 637258223a3SMatthew Dillon { 638258223a3SMatthew Dillon kfree(ccb, M_TEMP); 639258223a3SMatthew Dillon } 640258223a3SMatthew Dillon 641258223a3SMatthew Dillon static void 642258223a3SMatthew Dillon ahci_cam_rescan(struct ahci_port *ap) 643258223a3SMatthew Dillon { 644258223a3SMatthew Dillon struct cam_path *path; 645258223a3SMatthew Dillon union ccb *ccb; 646258223a3SMatthew Dillon int status; 647258223a3SMatthew Dillon 648258223a3SMatthew Dillon ccb = kmalloc(sizeof(*ccb), M_TEMP, M_WAITOK | M_ZERO); 649258223a3SMatthew Dillon status = xpt_create_path(&path, xpt_periph, cam_sim_path(ap->ap_sim), 650258223a3SMatthew Dillon CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 651258223a3SMatthew Dillon if (status != CAM_REQ_CMP) 652258223a3SMatthew Dillon return; 653258223a3SMatthew Dillon 654258223a3SMatthew Dillon xpt_setup_ccb(&ccb->ccb_h, path, 5); /* 5 = low priority */ 655fd8bd957SMatthew Dillon ccb->ccb_h.func_code = XPT_SCAN_BUS | XPT_FC_QUEUED; 656258223a3SMatthew Dillon ccb->ccb_h.cbfcnp = ahci_cam_rescan_callback; 657258223a3SMatthew Dillon ccb->crcn.flags = CAM_FLAG_NONE; 658258223a3SMatthew Dillon xpt_action(ccb); 659258223a3SMatthew Dillon 660258223a3SMatthew Dillon /* scan is now underway */ 661258223a3SMatthew Dillon } 662258223a3SMatthew Dillon 663258223a3SMatthew Dillon /* 664258223a3SMatthew Dillon * Action function - dispatch command 665258223a3SMatthew Dillon */ 666258223a3SMatthew Dillon static 667258223a3SMatthew Dillon void 668258223a3SMatthew Dillon ahci_xpt_action(struct cam_sim *sim, union ccb *ccb) 669258223a3SMatthew Dillon { 670258223a3SMatthew Dillon struct ahci_port *ap; 671258223a3SMatthew Dillon struct ccb_hdr *ccbh; 672258223a3SMatthew Dillon int unit; 673258223a3SMatthew Dillon 674258223a3SMatthew Dillon /* XXX lock */ 675258223a3SMatthew Dillon ap = cam_sim_softc(sim); 676258223a3SMatthew Dillon KKASSERT(ap != NULL); 677258223a3SMatthew Dillon ccbh = &ccb->ccb_h; 678258223a3SMatthew Dillon unit = cam_sim_unit(sim); 679258223a3SMatthew Dillon 680258223a3SMatthew Dillon /* 681258223a3SMatthew Dillon * Non-zero target and lun ids will be used for future 682258223a3SMatthew Dillon * port multiplication(?). A target wildcard indicates only 683258223a3SMatthew Dillon * the general bus is being probed. 684258223a3SMatthew Dillon * 685258223a3SMatthew Dillon * XXX What do we do with a LUN wildcard? 686258223a3SMatthew Dillon */ 687258223a3SMatthew Dillon if (ccbh->target_id != CAM_TARGET_WILDCARD) { 688258223a3SMatthew Dillon if (ap->ap_ata.ap_type == ATA_PORT_T_NONE) { 689258223a3SMatthew Dillon ccbh->status = CAM_REQ_INVALID; 690258223a3SMatthew Dillon xpt_done(ccb); 691258223a3SMatthew Dillon return; 692258223a3SMatthew Dillon } 693258223a3SMatthew Dillon if (ccbh->target_id) { 694258223a3SMatthew Dillon ccbh->status = CAM_DEV_NOT_THERE; 695258223a3SMatthew Dillon xpt_done(ccb); 696258223a3SMatthew Dillon return; 697258223a3SMatthew Dillon } 698258223a3SMatthew Dillon if (ccbh->target_lun != CAM_LUN_WILDCARD && ccbh->target_lun) { 699258223a3SMatthew Dillon ccbh->status = CAM_DEV_NOT_THERE; 700258223a3SMatthew Dillon xpt_done(ccb); 701258223a3SMatthew Dillon return; 702258223a3SMatthew Dillon } 703258223a3SMatthew Dillon } 704258223a3SMatthew Dillon 705258223a3SMatthew Dillon /* 706258223a3SMatthew Dillon * Switch on the meta XPT command 707258223a3SMatthew Dillon */ 708258223a3SMatthew Dillon switch(ccbh->func_code) { 709258223a3SMatthew Dillon case XPT_PATH_INQ: 710258223a3SMatthew Dillon ccb->cpi.version_num = 1; 711258223a3SMatthew Dillon ccb->cpi.hba_inquiry = 0; 712258223a3SMatthew Dillon ccb->cpi.target_sprt = 0; 713258223a3SMatthew Dillon ccb->cpi.hba_misc = 0; 714258223a3SMatthew Dillon ccb->cpi.hba_eng_cnt = 0; 715258223a3SMatthew Dillon bzero(ccb->cpi.vuhba_flags, sizeof(ccb->cpi.vuhba_flags)); 716258223a3SMatthew Dillon ccb->cpi.max_target = 7; 717258223a3SMatthew Dillon ccb->cpi.max_lun = 0; 718258223a3SMatthew Dillon ccb->cpi.async_flags = 0; 719258223a3SMatthew Dillon ccb->cpi.hpath_id = 0; 720258223a3SMatthew Dillon ccb->cpi.initiator_id = 7; 721258223a3SMatthew Dillon ccb->cpi.unit_number = cam_sim_unit(sim); 722258223a3SMatthew Dillon ccb->cpi.bus_id = cam_sim_bus(sim); 723258223a3SMatthew Dillon ccb->cpi.base_transfer_speed = 150000; 724258223a3SMatthew Dillon ccb->cpi.transport = XPORT_AHCI; 725258223a3SMatthew Dillon ccb->cpi.transport_version = 1; 726258223a3SMatthew Dillon ccb->cpi.protocol = PROTO_SCSI; 727258223a3SMatthew Dillon ccb->cpi.protocol_version = SCSI_REV_2; 728258223a3SMatthew Dillon 729258223a3SMatthew Dillon /* 730258223a3SMatthew Dillon * Non-zero target and lun ids will be used for future 731258223a3SMatthew Dillon * port multiplication(?). A target wildcard indicates only 732258223a3SMatthew Dillon * the general bus is being probed. 733258223a3SMatthew Dillon * 734258223a3SMatthew Dillon * XXX What do we do with a LUN wildcard? 735258223a3SMatthew Dillon */ 736258223a3SMatthew Dillon if (ccbh->target_id != CAM_TARGET_WILDCARD) { 737258223a3SMatthew Dillon switch(ahci_pread(ap, AHCI_PREG_SSTS) & 738258223a3SMatthew Dillon AHCI_PREG_SSTS_SPD) { 739258223a3SMatthew Dillon case AHCI_PREG_SSTS_SPD_GEN1: 740258223a3SMatthew Dillon ccb->cpi.base_transfer_speed = 150000; 741258223a3SMatthew Dillon break; 742258223a3SMatthew Dillon case AHCI_PREG_SSTS_SPD_GEN2: 743258223a3SMatthew Dillon ccb->cpi.base_transfer_speed = 300000; 744258223a3SMatthew Dillon break; 745258223a3SMatthew Dillon default: 746258223a3SMatthew Dillon /* unknown */ 747258223a3SMatthew Dillon ccb->cpi.base_transfer_speed = 1000; 748258223a3SMatthew Dillon break; 749258223a3SMatthew Dillon } 750258223a3SMatthew Dillon /* XXX check attached, set base xfer speed */ 751258223a3SMatthew Dillon } 752258223a3SMatthew Dillon ccbh->status = CAM_REQ_CMP; 753258223a3SMatthew Dillon xpt_done(ccb); 754258223a3SMatthew Dillon break; 755258223a3SMatthew Dillon case XPT_RESET_DEV: 756fd8bd957SMatthew Dillon lwkt_serialize_enter(&ap->ap_sc->sc_serializer); 757fd8bd957SMatthew Dillon ahci_port_softreset(ap); 758fd8bd957SMatthew Dillon lwkt_serialize_exit(&ap->ap_sc->sc_serializer); 759fd8bd957SMatthew Dillon 760fd8bd957SMatthew Dillon ccbh->status = CAM_REQ_CMP; 761258223a3SMatthew Dillon xpt_done(ccb); 762258223a3SMatthew Dillon break; 763258223a3SMatthew Dillon case XPT_RESET_BUS: 764fd8bd957SMatthew Dillon lwkt_serialize_enter(&ap->ap_sc->sc_serializer); 765fd8bd957SMatthew Dillon ahci_port_portreset(ap); 766fd8bd957SMatthew Dillon ahci_port_softreset(ap); 767fd8bd957SMatthew Dillon lwkt_serialize_exit(&ap->ap_sc->sc_serializer); 768fd8bd957SMatthew Dillon 769fd8bd957SMatthew Dillon xpt_async(AC_BUS_RESET, ap->ap_path, NULL); 770fd8bd957SMatthew Dillon 771fd8bd957SMatthew Dillon ccbh->status = CAM_REQ_CMP; 772258223a3SMatthew Dillon xpt_done(ccb); 773258223a3SMatthew Dillon break; 774258223a3SMatthew Dillon case XPT_SET_TRAN_SETTINGS: 775258223a3SMatthew Dillon ccbh->status = CAM_FUNC_NOTAVAIL; 776258223a3SMatthew Dillon xpt_done(ccb); 777258223a3SMatthew Dillon break; 778258223a3SMatthew Dillon case XPT_GET_TRAN_SETTINGS: 779258223a3SMatthew Dillon ccb->cts.protocol = PROTO_SCSI; 780258223a3SMatthew Dillon ccb->cts.protocol_version = SCSI_REV_2; 781258223a3SMatthew Dillon ccb->cts.transport = XPORT_AHCI; 782258223a3SMatthew Dillon ccb->cts.transport_version = XPORT_VERSION_UNSPECIFIED; 783258223a3SMatthew Dillon ccb->cts.proto_specific.valid = 0; 784258223a3SMatthew Dillon ccb->cts.xport_specific.valid = 0; 785258223a3SMatthew Dillon ccbh->status = CAM_REQ_CMP; 786258223a3SMatthew Dillon xpt_done(ccb); 787258223a3SMatthew Dillon break; 788258223a3SMatthew Dillon case XPT_CALC_GEOMETRY: 789258223a3SMatthew Dillon cam_calc_geometry(&ccb->ccg, 1); 790258223a3SMatthew Dillon xpt_done(ccb); 791258223a3SMatthew Dillon break; 792258223a3SMatthew Dillon case XPT_SCSI_IO: 793258223a3SMatthew Dillon switch(ap->ap_ata.ap_type) { 794258223a3SMatthew Dillon case ATA_PORT_T_DISK: 795258223a3SMatthew Dillon ahci_xpt_scsi_disk_io(sim, ccb); 796258223a3SMatthew Dillon break; 797258223a3SMatthew Dillon case ATA_PORT_T_ATAPI: 798258223a3SMatthew Dillon ahci_xpt_scsi_atapi_io(sim, ccb); 799258223a3SMatthew Dillon break; 800258223a3SMatthew Dillon default: 801258223a3SMatthew Dillon ccbh->status = CAM_REQ_INVALID; 802258223a3SMatthew Dillon xpt_done(ccb); 803258223a3SMatthew Dillon break; 804258223a3SMatthew Dillon } 805258223a3SMatthew Dillon break; 806258223a3SMatthew Dillon default: 807258223a3SMatthew Dillon kprintf("xpt_unknown\n"); 808258223a3SMatthew Dillon ccbh->status = CAM_REQ_INVALID; 809258223a3SMatthew Dillon xpt_done(ccb); 810258223a3SMatthew Dillon break; 811258223a3SMatthew Dillon } 812258223a3SMatthew Dillon } 813258223a3SMatthew Dillon 814258223a3SMatthew Dillon /* 815258223a3SMatthew Dillon * Poll function (unused?) 816258223a3SMatthew Dillon */ 817258223a3SMatthew Dillon static 818258223a3SMatthew Dillon void 819258223a3SMatthew Dillon ahci_xpt_poll(struct cam_sim *sim) 820258223a3SMatthew Dillon { 821258223a3SMatthew Dillon /*struct ahci_port *ap = cam_sim_softc(sim);*/ 822258223a3SMatthew Dillon 823258223a3SMatthew Dillon kprintf("ahci_xpt_poll\n"); 824258223a3SMatthew Dillon /* XXX lock */ 825258223a3SMatthew Dillon } 826258223a3SMatthew Dillon 827258223a3SMatthew Dillon /* 828b4189e5eSMatthew Dillon * Convert the SCSI command in ccb to an ata_xfer command in xa 829b4189e5eSMatthew Dillon * for ATA_PORT_T_DISK operations. Set the completion function 830b4189e5eSMatthew Dillon * to convert the response back, then dispatch to the OpenBSD AHCI 831b4189e5eSMatthew Dillon * layer. 832258223a3SMatthew Dillon * 833b4189e5eSMatthew Dillon * AHCI DISK commands only support a limited command set, and we 834b4189e5eSMatthew Dillon * fake additional commands to make it play nice with the CAM subsystem. 835258223a3SMatthew Dillon */ 836258223a3SMatthew Dillon static 837258223a3SMatthew Dillon void 838258223a3SMatthew Dillon ahci_xpt_scsi_disk_io(struct cam_sim *sim, union ccb *ccb) 839258223a3SMatthew Dillon { 840258223a3SMatthew Dillon struct ahci_port *ap; 841258223a3SMatthew Dillon struct ccb_hdr *ccbh; 842258223a3SMatthew Dillon struct ccb_scsiio *csio; 843258223a3SMatthew Dillon struct ata_xfer *xa; 844258223a3SMatthew Dillon struct ata_fis_h2d *fis; 845258223a3SMatthew Dillon scsi_cdb_t cdb; 846258223a3SMatthew Dillon union scsi_data *rdata; 847258223a3SMatthew Dillon int rdata_len; 848258223a3SMatthew Dillon u_int64_t capacity; 849258223a3SMatthew Dillon u_int64_t lba; 850258223a3SMatthew Dillon u_int32_t count; 851258223a3SMatthew Dillon 852258223a3SMatthew Dillon ap = cam_sim_softc(sim); 853258223a3SMatthew Dillon ccbh = &ccb->csio.ccb_h; 854258223a3SMatthew Dillon csio = &ccb->csio; 855258223a3SMatthew Dillon xa = ahci_ata_get_xfer(ap); 856258223a3SMatthew Dillon rdata = (void *)csio->data_ptr; 857258223a3SMatthew Dillon rdata_len = csio->dxfer_len; 858258223a3SMatthew Dillon 859258223a3SMatthew Dillon /* 860258223a3SMatthew Dillon * Build the FIS or process the csio to completion. 861258223a3SMatthew Dillon */ 862258223a3SMatthew Dillon cdb = (void *)((ccbh->flags & CAM_CDB_POINTER) ? 863258223a3SMatthew Dillon csio->cdb_io.cdb_ptr : csio->cdb_io.cdb_bytes); 864258223a3SMatthew Dillon 865258223a3SMatthew Dillon switch(cdb->generic.opcode) { 866258223a3SMatthew Dillon case REQUEST_SENSE: 867258223a3SMatthew Dillon /* 868258223a3SMatthew Dillon * Auto-sense everything, so explicit sense requests 869258223a3SMatthew Dillon * return no-sense. 870258223a3SMatthew Dillon */ 871258223a3SMatthew Dillon ccbh->status = CAM_SCSI_STATUS_ERROR; 872258223a3SMatthew Dillon break; 873258223a3SMatthew Dillon case INQUIRY: 874258223a3SMatthew Dillon /* 875258223a3SMatthew Dillon * Inquiry supported features 876258223a3SMatthew Dillon * 877258223a3SMatthew Dillon * [opcode, byte2, page_code, length, control] 878258223a3SMatthew Dillon */ 879258223a3SMatthew Dillon if (cdb->inquiry.byte2 & SI_EVPD) { 880258223a3SMatthew Dillon switch(cdb->inquiry.page_code) { 881258223a3SMatthew Dillon case SVPD_SUPPORTED_PAGE_LIST: 882258223a3SMatthew Dillon /* XXX atascsi_disk_vpd_supported */ 883258223a3SMatthew Dillon case SVPD_UNIT_SERIAL_NUMBER: 884258223a3SMatthew Dillon /* XXX atascsi_disk_vpd_serial */ 885258223a3SMatthew Dillon case SVPD_UNIT_DEVID: 886258223a3SMatthew Dillon /* XXX atascsi_disk_vpd_ident */ 887258223a3SMatthew Dillon default: 888258223a3SMatthew Dillon ccbh->status = CAM_FUNC_NOTAVAIL; 889258223a3SMatthew Dillon break; 890258223a3SMatthew Dillon } 891258223a3SMatthew Dillon } else { 892258223a3SMatthew Dillon bzero(rdata, rdata_len); 893258223a3SMatthew Dillon if (rdata_len < SHORT_INQUIRY_LENGTH) { 894258223a3SMatthew Dillon ccbh->status = CAM_CCB_LEN_ERR; 895258223a3SMatthew Dillon break; 896258223a3SMatthew Dillon } 897258223a3SMatthew Dillon if (rdata_len > sizeof(rdata->inquiry_data)) 898258223a3SMatthew Dillon rdata_len = sizeof(rdata->inquiry_data); 899258223a3SMatthew Dillon rdata->inquiry_data.device = T_DIRECT; 900258223a3SMatthew Dillon rdata->inquiry_data.version = SCSI_REV_SPC2; 901258223a3SMatthew Dillon rdata->inquiry_data.response_format = 2; 902258223a3SMatthew Dillon rdata->inquiry_data.additional_length = 32; 903258223a3SMatthew Dillon bcopy("SATA ", rdata->inquiry_data.vendor, 8); 904258223a3SMatthew Dillon bcopy(ap->ap_ata.ap_identify.model, 905258223a3SMatthew Dillon rdata->inquiry_data.product, 906258223a3SMatthew Dillon sizeof(rdata->inquiry_data.product)); 907258223a3SMatthew Dillon bcopy(ap->ap_ata.ap_identify.firmware, 908258223a3SMatthew Dillon rdata->inquiry_data.revision, 909258223a3SMatthew Dillon sizeof(rdata->inquiry_data.revision)); 910258223a3SMatthew Dillon ccbh->status = CAM_REQ_CMP; 911258223a3SMatthew Dillon } 912258223a3SMatthew Dillon break; 913258223a3SMatthew Dillon case READ_CAPACITY_16: 914258223a3SMatthew Dillon if (cdb->read_capacity_16.service_action != SRC16_SERVICE_ACTION) { 915258223a3SMatthew Dillon ccbh->status = CAM_REQ_INVALID; 916258223a3SMatthew Dillon break; 917258223a3SMatthew Dillon } 918258223a3SMatthew Dillon if (rdata_len < sizeof(rdata->read_capacity_data_16)) { 919258223a3SMatthew Dillon ccbh->status = CAM_CCB_LEN_ERR; 920258223a3SMatthew Dillon break; 921258223a3SMatthew Dillon } 922258223a3SMatthew Dillon /* fall through */ 923258223a3SMatthew Dillon case READ_CAPACITY: 924258223a3SMatthew Dillon if (rdata_len < sizeof(rdata->read_capacity_data)) { 925258223a3SMatthew Dillon ccbh->status = CAM_CCB_LEN_ERR; 926258223a3SMatthew Dillon break; 927258223a3SMatthew Dillon } 928258223a3SMatthew Dillon 929258223a3SMatthew Dillon capacity = ap->ap_ata.ap_capacity; 930258223a3SMatthew Dillon 931258223a3SMatthew Dillon bzero(rdata, rdata_len); 932258223a3SMatthew Dillon if (cdb->generic.opcode == READ_CAPACITY) { 933258223a3SMatthew Dillon rdata_len = sizeof(rdata->read_capacity_data); 934258223a3SMatthew Dillon if (capacity > 0xFFFFFFFFU) 935258223a3SMatthew Dillon capacity = 0xFFFFFFFFU; 936258223a3SMatthew Dillon bzero(&rdata->read_capacity_data, rdata_len); 937258223a3SMatthew Dillon scsi_ulto4b((u_int32_t)capacity - 1, 938258223a3SMatthew Dillon rdata->read_capacity_data.addr); 939258223a3SMatthew Dillon scsi_ulto4b(512, rdata->read_capacity_data.length); 940258223a3SMatthew Dillon } else { 941258223a3SMatthew Dillon rdata_len = sizeof(rdata->read_capacity_data_16); 942258223a3SMatthew Dillon bzero(&rdata->read_capacity_data_16, rdata_len); 943258223a3SMatthew Dillon scsi_u64to8b(capacity - 1, 944258223a3SMatthew Dillon rdata->read_capacity_data_16.addr); 945258223a3SMatthew Dillon scsi_ulto4b(512, rdata->read_capacity_data_16.length); 946258223a3SMatthew Dillon } 947258223a3SMatthew Dillon ccbh->status = CAM_REQ_CMP; 948258223a3SMatthew Dillon break; 949258223a3SMatthew Dillon case SYNCHRONIZE_CACHE: 950258223a3SMatthew Dillon /* 951258223a3SMatthew Dillon * Synchronize cache. Specification says this can take 952258223a3SMatthew Dillon * greater then 30 seconds so give it at least 45. 953258223a3SMatthew Dillon */ 954258223a3SMatthew Dillon fis = xa->fis; 955258223a3SMatthew Dillon xa->datalen = 0; 956258223a3SMatthew Dillon xa->flags = ATA_F_READ; 957258223a3SMatthew Dillon xa->complete = ahci_ata_complete_disk_synchronize_cache; 958258223a3SMatthew Dillon if (xa->timeout < 45 * hz) 959258223a3SMatthew Dillon xa->timeout = 45 * hz; 960258223a3SMatthew Dillon fis->flags = ATA_H2D_FLAGS_CMD; 961258223a3SMatthew Dillon fis->command = ATA_C_FLUSH_CACHE; 962258223a3SMatthew Dillon fis->device = 0; 963258223a3SMatthew Dillon break; 964258223a3SMatthew Dillon case TEST_UNIT_READY: 965258223a3SMatthew Dillon case START_STOP_UNIT: 966258223a3SMatthew Dillon case PREVENT_ALLOW: 967258223a3SMatthew Dillon /* 968258223a3SMatthew Dillon * Just silently return success 969258223a3SMatthew Dillon */ 970258223a3SMatthew Dillon ccbh->status = CAM_REQ_CMP; 971258223a3SMatthew Dillon rdata_len = 0; 972258223a3SMatthew Dillon break; 973258223a3SMatthew Dillon case ATA_PASS_12: 974258223a3SMatthew Dillon case ATA_PASS_16: 975258223a3SMatthew Dillon /* 976258223a3SMatthew Dillon * XXX implement pass-through 977258223a3SMatthew Dillon */ 978258223a3SMatthew Dillon ccbh->status = CAM_FUNC_NOTAVAIL; 979258223a3SMatthew Dillon break; 980258223a3SMatthew Dillon default: 981258223a3SMatthew Dillon switch(cdb->generic.opcode) { 982258223a3SMatthew Dillon case READ_6: 983258223a3SMatthew Dillon lba = scsi_3btoul(cdb->rw_6.addr) & 0x1FFFFF; 984258223a3SMatthew Dillon count = cdb->rw_6.length ? cdb->rw_6.length : 0x100; 985258223a3SMatthew Dillon xa->flags = ATA_F_READ; 986258223a3SMatthew Dillon break; 987258223a3SMatthew Dillon case READ_10: 988258223a3SMatthew Dillon lba = scsi_4btoul(cdb->rw_10.addr); 989258223a3SMatthew Dillon count = scsi_2btoul(cdb->rw_10.length); 990258223a3SMatthew Dillon xa->flags = ATA_F_READ; 991258223a3SMatthew Dillon break; 992258223a3SMatthew Dillon case READ_12: 993258223a3SMatthew Dillon lba = scsi_4btoul(cdb->rw_12.addr); 994258223a3SMatthew Dillon count = scsi_4btoul(cdb->rw_12.length); 995258223a3SMatthew Dillon xa->flags = ATA_F_READ; 996258223a3SMatthew Dillon break; 997258223a3SMatthew Dillon case READ_16: 998258223a3SMatthew Dillon lba = scsi_8btou64(cdb->rw_16.addr); 999258223a3SMatthew Dillon count = scsi_4btoul(cdb->rw_16.length); 1000258223a3SMatthew Dillon xa->flags = ATA_F_READ; 1001258223a3SMatthew Dillon break; 1002258223a3SMatthew Dillon case WRITE_6: 1003258223a3SMatthew Dillon lba = scsi_3btoul(cdb->rw_6.addr) & 0x1FFFFF; 1004258223a3SMatthew Dillon count = cdb->rw_6.length ? cdb->rw_6.length : 0x100; 1005258223a3SMatthew Dillon xa->flags = ATA_F_WRITE; 1006258223a3SMatthew Dillon break; 1007258223a3SMatthew Dillon case WRITE_10: 1008258223a3SMatthew Dillon lba = scsi_4btoul(cdb->rw_10.addr); 1009258223a3SMatthew Dillon count = scsi_2btoul(cdb->rw_10.length); 1010258223a3SMatthew Dillon xa->flags = ATA_F_WRITE; 1011258223a3SMatthew Dillon break; 1012258223a3SMatthew Dillon case WRITE_12: 1013258223a3SMatthew Dillon lba = scsi_4btoul(cdb->rw_12.addr); 1014258223a3SMatthew Dillon count = scsi_4btoul(cdb->rw_12.length); 1015258223a3SMatthew Dillon xa->flags = ATA_F_WRITE; 1016258223a3SMatthew Dillon break; 1017258223a3SMatthew Dillon case WRITE_16: 1018258223a3SMatthew Dillon lba = scsi_8btou64(cdb->rw_16.addr); 1019258223a3SMatthew Dillon count = scsi_4btoul(cdb->rw_16.length); 1020258223a3SMatthew Dillon xa->flags = ATA_F_WRITE; 1021258223a3SMatthew Dillon break; 1022258223a3SMatthew Dillon default: 1023258223a3SMatthew Dillon ccbh->status = CAM_REQ_INVALID; 1024258223a3SMatthew Dillon break; 1025258223a3SMatthew Dillon } 1026258223a3SMatthew Dillon if (ccbh->status != CAM_REQ_INPROG) 1027258223a3SMatthew Dillon break; 1028258223a3SMatthew Dillon 1029258223a3SMatthew Dillon fis = xa->fis; 1030258223a3SMatthew Dillon fis->flags = ATA_H2D_FLAGS_CMD; 1031258223a3SMatthew Dillon fis->lba_low = (u_int8_t)lba; 1032258223a3SMatthew Dillon fis->lba_mid = (u_int8_t)(lba >> 8); 1033258223a3SMatthew Dillon fis->lba_high = (u_int8_t)(lba >> 16); 1034258223a3SMatthew Dillon fis->device = ATA_H2D_DEVICE_LBA; 1035258223a3SMatthew Dillon 1036258223a3SMatthew Dillon if (ap->ap_ata.ap_ncqdepth > 1 && 1037258223a3SMatthew Dillon (ap->ap_sc->sc_cap & AHCI_REG_CAP_SNCQ) && 1038258223a3SMatthew Dillon (ccbh->flags & CAM_POLLED) == 0) { 1039258223a3SMatthew Dillon /* 1040258223a3SMatthew Dillon * Use NCQ - always uses 48 bit addressing 1041258223a3SMatthew Dillon */ 1042258223a3SMatthew Dillon xa->flags |= ATA_F_NCQ; 1043258223a3SMatthew Dillon fis->command = (xa->flags & ATA_F_WRITE) ? 1044258223a3SMatthew Dillon ATA_C_WRITE_FPDMA : ATA_C_READ_FPDMA; 1045258223a3SMatthew Dillon fis->lba_low_exp = (u_int8_t)(lba >> 24); 1046258223a3SMatthew Dillon fis->lba_mid_exp = (u_int8_t)(lba >> 32); 1047258223a3SMatthew Dillon fis->lba_high_exp = (u_int8_t)(lba >> 40); 1048258223a3SMatthew Dillon fis->sector_count = xa->tag << 3; 1049258223a3SMatthew Dillon fis->features = (u_int8_t)count; 1050258223a3SMatthew Dillon fis->features_exp = (u_int8_t)(count >> 8); 1051258223a3SMatthew Dillon } else if (count > 0x100 || lba > 0xFFFFFFFFU) { 1052258223a3SMatthew Dillon /* 1053258223a3SMatthew Dillon * Use LBA48 1054258223a3SMatthew Dillon */ 1055258223a3SMatthew Dillon fis->command = (xa->flags & ATA_F_WRITE) ? 1056258223a3SMatthew Dillon ATA_C_WRITEDMA_EXT : ATA_C_READDMA_EXT; 1057258223a3SMatthew Dillon fis->lba_low_exp = (u_int8_t)(lba >> 24); 1058258223a3SMatthew Dillon fis->lba_mid_exp = (u_int8_t)(lba >> 32); 1059258223a3SMatthew Dillon fis->lba_high_exp = (u_int8_t)(lba >> 40); 1060258223a3SMatthew Dillon fis->sector_count = (u_int8_t)count; 1061258223a3SMatthew Dillon fis->sector_count_exp = (u_int8_t)(count >> 8); 1062258223a3SMatthew Dillon } else { 1063258223a3SMatthew Dillon /* 1064258223a3SMatthew Dillon * Use LBA 1065258223a3SMatthew Dillon * 1066258223a3SMatthew Dillon * NOTE: 256 sectors is supported, stored as 0. 1067258223a3SMatthew Dillon */ 1068258223a3SMatthew Dillon fis->command = (xa->flags & ATA_F_WRITE) ? 1069258223a3SMatthew Dillon ATA_C_WRITEDMA : ATA_C_READDMA; 1070258223a3SMatthew Dillon fis->device |= (u_int8_t)(lba >> 24) & 0x0F; 1071258223a3SMatthew Dillon fis->sector_count = (u_int8_t)count; 1072258223a3SMatthew Dillon } 1073258223a3SMatthew Dillon 1074258223a3SMatthew Dillon xa->data = csio->data_ptr; 1075258223a3SMatthew Dillon xa->datalen = csio->dxfer_len; 1076258223a3SMatthew Dillon xa->complete = ahci_ata_complete_disk_rw; 1077258223a3SMatthew Dillon xa->timeout = ccbh->timeout * hz / 1000; 1078258223a3SMatthew Dillon if (ccbh->flags & CAM_POLLED) 1079258223a3SMatthew Dillon xa->flags |= ATA_F_POLL; 1080258223a3SMatthew Dillon break; 1081258223a3SMatthew Dillon } 1082258223a3SMatthew Dillon 1083258223a3SMatthew Dillon /* 1084258223a3SMatthew Dillon * If the request is still in progress the xa and FIS have 1085258223a3SMatthew Dillon * been set up and must be dispatched. Otherwise the request 1086258223a3SMatthew Dillon * is complete. 1087258223a3SMatthew Dillon */ 1088258223a3SMatthew Dillon if (ccbh->status == CAM_REQ_INPROG) { 1089258223a3SMatthew Dillon KKASSERT(xa->complete != NULL); 1090258223a3SMatthew Dillon xa->atascsi_private = ccb; 1091258223a3SMatthew Dillon ccb->ccb_h.sim_priv.entries[0].ptr = ap; 1092258223a3SMatthew Dillon lwkt_serialize_enter(&ap->ap_sc->sc_serializer); 1093258223a3SMatthew Dillon ahci_ata_cmd(xa); 1094258223a3SMatthew Dillon lwkt_serialize_exit(&ap->ap_sc->sc_serializer); 1095258223a3SMatthew Dillon } else { 1096258223a3SMatthew Dillon ahci_ata_put_xfer(xa); 1097258223a3SMatthew Dillon xpt_done(ccb); 1098258223a3SMatthew Dillon } 1099258223a3SMatthew Dillon } 1100258223a3SMatthew Dillon 1101b4189e5eSMatthew Dillon /* 1102b4189e5eSMatthew Dillon * Convert the SCSI command in ccb to an ata_xfer command in xa 1103b4189e5eSMatthew Dillon * for ATA_PORT_T_ATAPI operations. Set the completion function 1104b4189e5eSMatthew Dillon * to convert the response back, then dispatch to the OpenBSD AHCI 1105b4189e5eSMatthew Dillon * layer. 1106b4189e5eSMatthew Dillon */ 1107258223a3SMatthew Dillon static 1108258223a3SMatthew Dillon void 1109258223a3SMatthew Dillon ahci_xpt_scsi_atapi_io(struct cam_sim *sim, union ccb *ccb) 1110258223a3SMatthew Dillon { 1111258223a3SMatthew Dillon struct ahci_port *ap; 1112258223a3SMatthew Dillon struct ccb_hdr *ccbh; 1113258223a3SMatthew Dillon struct ccb_scsiio *csio; 1114258223a3SMatthew Dillon struct ata_xfer *xa; 1115258223a3SMatthew Dillon struct ata_fis_h2d *fis; 1116b4189e5eSMatthew Dillon scsi_cdb_t cdbs; 1117b4189e5eSMatthew Dillon scsi_cdb_t cdbd; 1118b4189e5eSMatthew Dillon int flags; 1119258223a3SMatthew Dillon 1120258223a3SMatthew Dillon ap = cam_sim_softc(sim); 1121258223a3SMatthew Dillon ccbh = &ccb->csio.ccb_h; 1122258223a3SMatthew Dillon csio = &ccb->csio; 1123b4189e5eSMatthew Dillon 1124b4189e5eSMatthew Dillon switch (ccbh->flags & CAM_DIR_MASK) { 1125b4189e5eSMatthew Dillon case CAM_DIR_IN: 1126b4189e5eSMatthew Dillon flags = ATA_F_PACKET | ATA_F_READ; 1127b4189e5eSMatthew Dillon break; 1128b4189e5eSMatthew Dillon case CAM_DIR_OUT: 1129b4189e5eSMatthew Dillon flags = ATA_F_PACKET | ATA_F_WRITE; 1130b4189e5eSMatthew Dillon break; 1131b4189e5eSMatthew Dillon case CAM_DIR_NONE: 1132b4189e5eSMatthew Dillon flags = ATA_F_PACKET; 1133b4189e5eSMatthew Dillon break; 1134b4189e5eSMatthew Dillon default: 1135b4189e5eSMatthew Dillon ccbh->status = CAM_REQ_INVALID; 1136b4189e5eSMatthew Dillon xpt_done(ccb); 1137b4189e5eSMatthew Dillon return; 1138b4189e5eSMatthew Dillon /* NOT REACHED */ 1139b4189e5eSMatthew Dillon } 1140b4189e5eSMatthew Dillon 1141b4189e5eSMatthew Dillon /* 1142b4189e5eSMatthew Dillon * The command has to fit in the packet command buffer. 1143b4189e5eSMatthew Dillon */ 1144b4189e5eSMatthew Dillon if (csio->cdb_len < 6 || csio->cdb_len > 16) { 1145b4189e5eSMatthew Dillon ccbh->status = CAM_CCB_LEN_ERR; 1146b4189e5eSMatthew Dillon xpt_done(ccb); 1147b4189e5eSMatthew Dillon return; 1148b4189e5eSMatthew Dillon } 1149b4189e5eSMatthew Dillon 1150b4189e5eSMatthew Dillon /* 1151b4189e5eSMatthew Dillon * Initialize the XA and FIS. 1152b4189e5eSMatthew Dillon */ 1153258223a3SMatthew Dillon xa = ahci_ata_get_xfer(ap); 1154258223a3SMatthew Dillon fis = xa->fis; 1155258223a3SMatthew Dillon 1156b4189e5eSMatthew Dillon xa->flags = flags; 1157b4189e5eSMatthew Dillon xa->data = csio->data_ptr; 1158b4189e5eSMatthew Dillon xa->datalen = csio->dxfer_len; 1159b4189e5eSMatthew Dillon xa->timeout = ccbh->timeout * hz / 1000; 1160b4189e5eSMatthew Dillon if (ccbh->flags & CAM_POLLED) 1161b4189e5eSMatthew Dillon xa->flags |= ATA_F_POLL; 1162258223a3SMatthew Dillon 1163b4189e5eSMatthew Dillon fis->flags = ATA_H2D_FLAGS_CMD; 1164b4189e5eSMatthew Dillon fis->command = ATA_C_PACKET; 1165b4189e5eSMatthew Dillon fis->device = 0; 1166b4189e5eSMatthew Dillon fis->sector_count = xa->tag << 3; 1167b4189e5eSMatthew Dillon fis->features = ATA_H2D_FEATURES_DMA | 1168b4189e5eSMatthew Dillon ((xa->flags & ATA_F_WRITE) ? 1169b4189e5eSMatthew Dillon ATA_H2D_FEATURES_DIR_WRITE : ATA_H2D_FEATURES_DIR_READ); 1170b4189e5eSMatthew Dillon fis->lba_mid = 0x00; 1171b4189e5eSMatthew Dillon fis->lba_high = 0x20; 1172b4189e5eSMatthew Dillon 1173258223a3SMatthew Dillon /* 1174b4189e5eSMatthew Dillon * Copy the cdb to the packetcmd buffer in the FIS using a 1175b4189e5eSMatthew Dillon * convenient pointer in the xa. 1176258223a3SMatthew Dillon */ 1177b4189e5eSMatthew Dillon cdbs = (void *)((ccbh->flags & CAM_CDB_POINTER) ? 1178b4189e5eSMatthew Dillon csio->cdb_io.cdb_ptr : csio->cdb_io.cdb_bytes); 1179b4189e5eSMatthew Dillon bcopy(cdbs, xa->packetcmd, csio->cdb_len); 1180b4189e5eSMatthew Dillon 1181669fbbf7SMatthew Dillon #if 0 1182b4189e5eSMatthew Dillon kprintf("opcode %d cdb_len %d dxfer_len %d\n", 1183b4189e5eSMatthew Dillon cdbs->generic.opcode, 1184b4189e5eSMatthew Dillon csio->cdb_len, csio->dxfer_len); 1185669fbbf7SMatthew Dillon #endif 1186b4189e5eSMatthew Dillon 1187b4189e5eSMatthew Dillon /* 1188b4189e5eSMatthew Dillon * Some ATAPI commands do not actually follow the SCSI standard. 1189b4189e5eSMatthew Dillon */ 1190b4189e5eSMatthew Dillon cdbd = (void *)xa->packetcmd; 1191b4189e5eSMatthew Dillon 1192b4189e5eSMatthew Dillon switch(cdbd->generic.opcode) { 1193258223a3SMatthew Dillon case INQUIRY: 1194b4189e5eSMatthew Dillon /* 1195b4189e5eSMatthew Dillon * Some ATAPI devices can't handle SI_EVPD being set 1196b4189e5eSMatthew Dillon * for a basic inquiry (page_code == 0). 1197b4189e5eSMatthew Dillon * 1198b4189e5eSMatthew Dillon * Some ATAPI devices can't handle long inquiry lengths, 1199b4189e5eSMatthew Dillon * don't ask me why. Truncate the inquiry length. 1200b4189e5eSMatthew Dillon */ 1201b4189e5eSMatthew Dillon if ((cdbd->inquiry.byte2 & SI_EVPD) && 1202b4189e5eSMatthew Dillon cdbd->inquiry.page_code == 0) { 1203b4189e5eSMatthew Dillon cdbd->inquiry.byte2 &= ~SI_EVPD; 1204b4189e5eSMatthew Dillon } 1205b4189e5eSMatthew Dillon if (cdbd->inquiry.page_code == 0 && 1206b4189e5eSMatthew Dillon cdbd->inquiry.length > SHORT_INQUIRY_LENGTH) { 1207b4189e5eSMatthew Dillon cdbd->inquiry.length = SHORT_INQUIRY_LENGTH; 1208b4189e5eSMatthew Dillon } 1209b4189e5eSMatthew Dillon break; 1210258223a3SMatthew Dillon case READ_6: 1211258223a3SMatthew Dillon case WRITE_6: 1212b4189e5eSMatthew Dillon /* 1213b4189e5eSMatthew Dillon * Convert *_6 to *_10 commands. Most ATAPI devices 1214b4189e5eSMatthew Dillon * cannot handle the SCSI READ_6 and WRITE_6 commands. 1215b4189e5eSMatthew Dillon */ 1216b4189e5eSMatthew Dillon cdbd->rw_10.opcode |= 0x20; 1217b4189e5eSMatthew Dillon cdbd->rw_10.byte2 = 0; 1218b4189e5eSMatthew Dillon cdbd->rw_10.addr[0] = cdbs->rw_6.addr[0] & 0x1F; 1219b4189e5eSMatthew Dillon cdbd->rw_10.addr[1] = cdbs->rw_6.addr[1]; 1220b4189e5eSMatthew Dillon cdbd->rw_10.addr[2] = cdbs->rw_6.addr[2]; 1221b4189e5eSMatthew Dillon cdbd->rw_10.addr[3] = 0; 1222b4189e5eSMatthew Dillon cdbd->rw_10.reserved = 0; 1223b4189e5eSMatthew Dillon cdbd->rw_10.length[0] = 0; 1224b4189e5eSMatthew Dillon cdbd->rw_10.length[1] = cdbs->rw_6.length; 1225b4189e5eSMatthew Dillon cdbd->rw_10.control = cdbs->rw_6.control; 1226b4189e5eSMatthew Dillon break; 1227258223a3SMatthew Dillon default: 1228258223a3SMatthew Dillon break; 1229258223a3SMatthew Dillon } 1230258223a3SMatthew Dillon 1231b4189e5eSMatthew Dillon /* 1232b4189e5eSMatthew Dillon * And dispatch 1233b4189e5eSMatthew Dillon */ 1234b4189e5eSMatthew Dillon xa->complete = ahci_atapi_complete_cmd; 1235258223a3SMatthew Dillon xa->atascsi_private = ccb; 1236258223a3SMatthew Dillon ccb->ccb_h.sim_priv.entries[0].ptr = ap; 1237258223a3SMatthew Dillon ahci_ata_cmd(xa); 1238258223a3SMatthew Dillon } 1239258223a3SMatthew Dillon 1240b4189e5eSMatthew Dillon /* 1241b4189e5eSMatthew Dillon * Completion function for ATA_PORT_T_DISK cache synchronization. 1242b4189e5eSMatthew Dillon */ 1243258223a3SMatthew Dillon static 1244258223a3SMatthew Dillon void 1245258223a3SMatthew Dillon ahci_ata_complete_disk_synchronize_cache(struct ata_xfer *xa) 1246258223a3SMatthew Dillon { 1247258223a3SMatthew Dillon union ccb *ccb = xa->atascsi_private; 1248258223a3SMatthew Dillon struct ccb_hdr *ccbh = &ccb->ccb_h; 1249258223a3SMatthew Dillon struct ahci_port *ap = ccb->ccb_h.sim_priv.entries[0].ptr; 1250258223a3SMatthew Dillon 1251258223a3SMatthew Dillon switch(xa->state) { 1252258223a3SMatthew Dillon case ATA_S_COMPLETE: 1253258223a3SMatthew Dillon ccbh->status = CAM_REQ_CMP; 1254b4189e5eSMatthew Dillon ccb->csio.scsi_status = SCSI_STATUS_OK; 1255258223a3SMatthew Dillon break; 1256258223a3SMatthew Dillon case ATA_S_ERROR: 1257258223a3SMatthew Dillon kprintf("%s: synchronize_cache: error\n", PORTNAME(ap)); 1258b4189e5eSMatthew Dillon ccbh->status = CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID; 1259b4189e5eSMatthew Dillon ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND; 1260b4189e5eSMatthew Dillon ahci_ata_dummy_sense(&ccb->csio.sense_data); 1261258223a3SMatthew Dillon break; 1262258223a3SMatthew Dillon case ATA_S_TIMEOUT: 1263258223a3SMatthew Dillon kprintf("%s: synchronize_cache: timeout\n", PORTNAME(ap)); 1264258223a3SMatthew Dillon ccbh->status = CAM_CMD_TIMEOUT; 1265258223a3SMatthew Dillon break; 1266258223a3SMatthew Dillon default: 1267258223a3SMatthew Dillon kprintf("%s: synchronize_cache: unknown state %d\n", 1268258223a3SMatthew Dillon PORTNAME(ap), xa->state); 1269258223a3SMatthew Dillon ccbh->status = CAM_REQ_CMP_ERR; 1270258223a3SMatthew Dillon break; 1271258223a3SMatthew Dillon } 1272258223a3SMatthew Dillon ahci_ata_put_xfer(xa); 1273258223a3SMatthew Dillon lwkt_serialize_exit(&ap->ap_sc->sc_serializer); 1274258223a3SMatthew Dillon xpt_done(ccb); 1275258223a3SMatthew Dillon lwkt_serialize_enter(&ap->ap_sc->sc_serializer); 1276258223a3SMatthew Dillon } 1277258223a3SMatthew Dillon 1278b4189e5eSMatthew Dillon /* 1279b4189e5eSMatthew Dillon * Completion function for ATA_PORT_T_DISK I/O 1280b4189e5eSMatthew Dillon */ 1281258223a3SMatthew Dillon static 1282258223a3SMatthew Dillon void 1283258223a3SMatthew Dillon ahci_ata_complete_disk_rw(struct ata_xfer *xa) 1284258223a3SMatthew Dillon { 1285258223a3SMatthew Dillon union ccb *ccb = xa->atascsi_private; 1286258223a3SMatthew Dillon struct ccb_hdr *ccbh = &ccb->ccb_h; 1287258223a3SMatthew Dillon struct ahci_port *ap = ccb->ccb_h.sim_priv.entries[0].ptr; 1288258223a3SMatthew Dillon 1289258223a3SMatthew Dillon switch(xa->state) { 1290258223a3SMatthew Dillon case ATA_S_COMPLETE: 1291258223a3SMatthew Dillon ccbh->status = CAM_REQ_CMP; 1292b4189e5eSMatthew Dillon ccb->csio.scsi_status = SCSI_STATUS_OK; 1293258223a3SMatthew Dillon break; 1294258223a3SMatthew Dillon case ATA_S_ERROR: 1295258223a3SMatthew Dillon kprintf("%s: disk_rw: error\n", PORTNAME(ap)); 1296b4189e5eSMatthew Dillon ccbh->status = CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID; 1297b4189e5eSMatthew Dillon ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND; 1298b4189e5eSMatthew Dillon ahci_ata_dummy_sense(&ccb->csio.sense_data); 1299258223a3SMatthew Dillon break; 1300258223a3SMatthew Dillon case ATA_S_TIMEOUT: 1301258223a3SMatthew Dillon kprintf("%s: disk_rw: timeout\n", PORTNAME(ap)); 1302258223a3SMatthew Dillon ccbh->status = CAM_CMD_TIMEOUT; 1303258223a3SMatthew Dillon break; 1304258223a3SMatthew Dillon default: 1305258223a3SMatthew Dillon kprintf("%s: disk_rw: unknown state %d\n", 1306258223a3SMatthew Dillon PORTNAME(ap), xa->state); 1307258223a3SMatthew Dillon ccbh->status = CAM_REQ_CMP_ERR; 1308258223a3SMatthew Dillon break; 1309258223a3SMatthew Dillon } 1310258223a3SMatthew Dillon ccb->csio.resid = xa->resid; 1311258223a3SMatthew Dillon ahci_ata_put_xfer(xa); 1312258223a3SMatthew Dillon lwkt_serialize_exit(&ap->ap_sc->sc_serializer); 1313258223a3SMatthew Dillon xpt_done(ccb); 1314258223a3SMatthew Dillon lwkt_serialize_enter(&ap->ap_sc->sc_serializer); 1315258223a3SMatthew Dillon } 1316b4189e5eSMatthew Dillon 13177d4fcf34SMatthew Dillon /* 13187d4fcf34SMatthew Dillon * Completion function for ATA_PORT_T_ATAPI I/O 13197d4fcf34SMatthew Dillon * 13207d4fcf34SMatthew Dillon * Sense data is returned in the rfis. 13217d4fcf34SMatthew Dillon */ 1322b4189e5eSMatthew Dillon static 1323b4189e5eSMatthew Dillon void 1324b4189e5eSMatthew Dillon ahci_atapi_complete_cmd(struct ata_xfer *xa) 1325b4189e5eSMatthew Dillon { 1326b4189e5eSMatthew Dillon union ccb *ccb = xa->atascsi_private; 1327b4189e5eSMatthew Dillon struct ccb_hdr *ccbh = &ccb->ccb_h; 1328b4189e5eSMatthew Dillon struct ahci_port *ap = ccb->ccb_h.sim_priv.entries[0].ptr; 1329b4189e5eSMatthew Dillon scsi_cdb_t cdb; 1330b4189e5eSMatthew Dillon 1331b4189e5eSMatthew Dillon cdb = (void *)((ccb->ccb_h.flags & CAM_CDB_POINTER) ? 1332b4189e5eSMatthew Dillon ccb->csio.cdb_io.cdb_ptr : ccb->csio.cdb_io.cdb_bytes); 1333b4189e5eSMatthew Dillon 1334b4189e5eSMatthew Dillon switch(xa->state) { 1335b4189e5eSMatthew Dillon case ATA_S_COMPLETE: 1336b4189e5eSMatthew Dillon ccbh->status = CAM_REQ_CMP; 1337b4189e5eSMatthew Dillon ccb->csio.scsi_status = SCSI_STATUS_OK; 1338b4189e5eSMatthew Dillon break; 1339b4189e5eSMatthew Dillon case ATA_S_ERROR: 1340b4189e5eSMatthew Dillon kprintf("%s: cmd %d: error\n", 1341b4189e5eSMatthew Dillon PORTNAME(ap), cdb->generic.opcode); 1342b4189e5eSMatthew Dillon ccbh->status = CAM_SCSI_STATUS_ERROR; 1343b4189e5eSMatthew Dillon ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND; 13447d4fcf34SMatthew Dillon ahci_ata_atapi_sense(&xa->rfis, &ccb->csio.sense_data); 1345b4189e5eSMatthew Dillon break; 1346b4189e5eSMatthew Dillon case ATA_S_TIMEOUT: 1347b4189e5eSMatthew Dillon kprintf("%s: cmd %d: timeout\n", 1348b4189e5eSMatthew Dillon PORTNAME(ap), cdb->generic.opcode); 1349b4189e5eSMatthew Dillon ccbh->status = CAM_CMD_TIMEOUT; 1350b4189e5eSMatthew Dillon break; 1351b4189e5eSMatthew Dillon default: 1352b4189e5eSMatthew Dillon kprintf("%s: cmd %d: unknown state %d\n", 1353b4189e5eSMatthew Dillon PORTNAME(ap), cdb->generic.opcode, xa->state); 1354b4189e5eSMatthew Dillon ccbh->status = CAM_REQ_CMP_ERR; 1355b4189e5eSMatthew Dillon break; 1356b4189e5eSMatthew Dillon } 1357b4189e5eSMatthew Dillon ccb->csio.resid = xa->resid; 1358b4189e5eSMatthew Dillon ahci_ata_put_xfer(xa); 1359b4189e5eSMatthew Dillon lwkt_serialize_exit(&ap->ap_sc->sc_serializer); 1360b4189e5eSMatthew Dillon xpt_done(ccb); 1361b4189e5eSMatthew Dillon lwkt_serialize_enter(&ap->ap_sc->sc_serializer); 1362b4189e5eSMatthew Dillon } 1363b4189e5eSMatthew Dillon 13647d4fcf34SMatthew Dillon /* 13657d4fcf34SMatthew Dillon * Construct dummy sense data for errors on DISKs 13667d4fcf34SMatthew Dillon */ 1367b4189e5eSMatthew Dillon static 1368b4189e5eSMatthew Dillon void 1369b4189e5eSMatthew Dillon ahci_ata_dummy_sense(struct scsi_sense_data *sense_data) 1370b4189e5eSMatthew Dillon { 1371b4189e5eSMatthew Dillon sense_data->error_code = SSD_ERRCODE_VALID | SSD_CURRENT_ERROR; 1372b4189e5eSMatthew Dillon sense_data->segment = 0; 1373b4189e5eSMatthew Dillon sense_data->flags = SSD_KEY_MEDIUM_ERROR; 1374b4189e5eSMatthew Dillon sense_data->info[0] = 0; 1375b4189e5eSMatthew Dillon sense_data->info[1] = 0; 1376b4189e5eSMatthew Dillon sense_data->info[2] = 0; 1377b4189e5eSMatthew Dillon sense_data->info[3] = 0; 1378b4189e5eSMatthew Dillon sense_data->extra_len = 0; 1379b4189e5eSMatthew Dillon } 13807d4fcf34SMatthew Dillon 13817d4fcf34SMatthew Dillon /* 13827d4fcf34SMatthew Dillon * Construct atapi sense data for errors on ATAPI 13837d4fcf34SMatthew Dillon * 13847d4fcf34SMatthew Dillon * The ATAPI sense data is stored in the passed rfis and must be converted 13857d4fcf34SMatthew Dillon * to SCSI sense data. 13867d4fcf34SMatthew Dillon */ 13877d4fcf34SMatthew Dillon static 13887d4fcf34SMatthew Dillon void 13897d4fcf34SMatthew Dillon ahci_ata_atapi_sense(struct ata_fis_d2h *rfis, 13907d4fcf34SMatthew Dillon struct scsi_sense_data *sense_data) 13917d4fcf34SMatthew Dillon { 13927d4fcf34SMatthew Dillon sense_data->error_code = SSD_ERRCODE_VALID | SSD_CURRENT_ERROR; 13937d4fcf34SMatthew Dillon sense_data->segment = 0; 13947d4fcf34SMatthew Dillon sense_data->flags = (rfis->error & 0xF0) >> 4; 13957d4fcf34SMatthew Dillon if (rfis->error & 0x04) 13967d4fcf34SMatthew Dillon sense_data->flags |= SSD_KEY_ILLEGAL_REQUEST; 13977d4fcf34SMatthew Dillon if (rfis->error & 0x02) 13987d4fcf34SMatthew Dillon sense_data->flags |= SSD_EOM; 13997d4fcf34SMatthew Dillon if (rfis->error & 0x01) 14007d4fcf34SMatthew Dillon sense_data->flags |= SSD_ILI; 14017d4fcf34SMatthew Dillon sense_data->info[0] = 0; 14027d4fcf34SMatthew Dillon sense_data->info[1] = 0; 14037d4fcf34SMatthew Dillon sense_data->info[2] = 0; 14047d4fcf34SMatthew Dillon sense_data->info[3] = 0; 14057d4fcf34SMatthew Dillon sense_data->extra_len = 0; 14067d4fcf34SMatthew Dillon } 1407