ata_xpt.c revision 203385
1195534Sscottl/*- 2195534Sscottl * Copyright (c) 2009 Alexander Motin <mav@FreeBSD.org> 3195534Sscottl * All rights reserved. 4195534Sscottl * 5195534Sscottl * Redistribution and use in source and binary forms, with or without 6195534Sscottl * modification, are permitted provided that the following conditions 7195534Sscottl * are met: 8195534Sscottl * 1. Redistributions of source code must retain the above copyright 9195534Sscottl * notice, this list of conditions and the following disclaimer, 10195534Sscottl * without modification, immediately at the beginning of the file. 11195534Sscottl * 2. Redistributions in binary form must reproduce the above copyright 12195534Sscottl * notice, this list of conditions and the following disclaimer in the 13195534Sscottl * documentation and/or other materials provided with the distribution. 14195534Sscottl * 15195534Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16195534Sscottl * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17195534Sscottl * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18195534Sscottl * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19195534Sscottl * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20195534Sscottl * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21195534Sscottl * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22195534Sscottl * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23195534Sscottl * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24195534Sscottl * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25195534Sscottl */ 26195534Sscottl 27195534Sscottl#include <sys/cdefs.h> 28195534Sscottl__FBSDID("$FreeBSD: head/sys/cam/ata/ata_xpt.c 203385 2010-02-02 18:03:21Z mav $"); 29195534Sscottl 30195534Sscottl#include <sys/param.h> 31195534Sscottl#include <sys/bus.h> 32195534Sscottl#include <sys/endian.h> 33195534Sscottl#include <sys/systm.h> 34195534Sscottl#include <sys/types.h> 35195534Sscottl#include <sys/malloc.h> 36195534Sscottl#include <sys/kernel.h> 37195534Sscottl#include <sys/time.h> 38195534Sscottl#include <sys/conf.h> 39195534Sscottl#include <sys/fcntl.h> 40195534Sscottl#include <sys/interrupt.h> 41195534Sscottl#include <sys/sbuf.h> 42195534Sscottl 43195534Sscottl#include <sys/lock.h> 44195534Sscottl#include <sys/mutex.h> 45195534Sscottl#include <sys/sysctl.h> 46195534Sscottl 47195534Sscottl#ifdef PC98 48195534Sscottl#include <pc98/pc98/pc98_machdep.h> /* geometry translation */ 49195534Sscottl#endif 50195534Sscottl 51195534Sscottl#include <cam/cam.h> 52195534Sscottl#include <cam/cam_ccb.h> 53195534Sscottl#include <cam/cam_queue.h> 54195534Sscottl#include <cam/cam_periph.h> 55195534Sscottl#include <cam/cam_sim.h> 56195534Sscottl#include <cam/cam_xpt.h> 57195534Sscottl#include <cam/cam_xpt_sim.h> 58195534Sscottl#include <cam/cam_xpt_periph.h> 59195534Sscottl#include <cam/cam_xpt_internal.h> 60195534Sscottl#include <cam/cam_debug.h> 61195534Sscottl 62195534Sscottl#include <cam/scsi/scsi_all.h> 63195534Sscottl#include <cam/scsi/scsi_message.h> 64195534Sscottl#include <cam/ata/ata_all.h> 65195534Sscottl#include <machine/stdarg.h> /* for xpt_print below */ 66195534Sscottl#include "opt_cam.h" 67195534Sscottl 68199178Smavstruct ata_quirk_entry { 69195534Sscottl struct scsi_inquiry_pattern inq_pat; 70195534Sscottl u_int8_t quirks; 71199178Smav#define CAM_QUIRK_MAXTAGS 0x01 72195534Sscottl u_int maxtags; 73195534Sscottl}; 74195534Sscottl 75195534Sscottlstatic periph_init_t probe_periph_init; 76195534Sscottl 77195534Sscottlstatic struct periph_driver probe_driver = 78195534Sscottl{ 79195653Smav probe_periph_init, "aprobe", 80198708Smav TAILQ_HEAD_INITIALIZER(probe_driver.units), /* generation */ 0, 81198708Smav CAM_PERIPH_DRV_EARLY 82195534Sscottl}; 83195534Sscottl 84195653SmavPERIPHDRIVER_DECLARE(aprobe, probe_driver); 85195534Sscottl 86195534Sscottltypedef enum { 87195534Sscottl PROBE_RESET, 88195534Sscottl PROBE_IDENTIFY, 89195534Sscottl PROBE_SETMODE, 90198708Smav PROBE_SET_MULTI, 91195534Sscottl PROBE_INQUIRY, 92195534Sscottl PROBE_FULL_INQUIRY, 93195534Sscottl PROBE_PM_PID, 94195534Sscottl PROBE_PM_PRV, 95195534Sscottl PROBE_INVALID 96195534Sscottl} probe_action; 97195534Sscottl 98195534Sscottlstatic char *probe_action_text[] = { 99195534Sscottl "PROBE_RESET", 100195534Sscottl "PROBE_IDENTIFY", 101195534Sscottl "PROBE_SETMODE", 102198708Smav "PROBE_SET_MULTI", 103195534Sscottl "PROBE_INQUIRY", 104195534Sscottl "PROBE_FULL_INQUIRY", 105195534Sscottl "PROBE_PM_PID", 106195534Sscottl "PROBE_PM_PRV", 107195534Sscottl "PROBE_INVALID" 108195534Sscottl}; 109195534Sscottl 110195534Sscottl#define PROBE_SET_ACTION(softc, newaction) \ 111195534Sscottldo { \ 112195534Sscottl char **text; \ 113195534Sscottl text = probe_action_text; \ 114195534Sscottl CAM_DEBUG((softc)->periph->path, CAM_DEBUG_INFO, \ 115195534Sscottl ("Probe %s to %s\n", text[(softc)->action], \ 116195534Sscottl text[(newaction)])); \ 117195534Sscottl (softc)->action = (newaction); \ 118195534Sscottl} while(0) 119195534Sscottl 120195534Sscottltypedef enum { 121195534Sscottl PROBE_NO_ANNOUNCE = 0x04 122195534Sscottl} probe_flags; 123195534Sscottl 124195534Sscottltypedef struct { 125195534Sscottl TAILQ_HEAD(, ccb_hdr) request_ccbs; 126203385Smav struct ata_params ident_data; 127195534Sscottl probe_action action; 128195534Sscottl probe_flags flags; 129195534Sscottl uint32_t pm_pid; 130195534Sscottl uint32_t pm_prv; 131203108Smav int restart; 132195534Sscottl struct cam_periph *periph; 133195534Sscottl} probe_softc; 134195534Sscottl 135199178Smavstatic struct ata_quirk_entry ata_quirk_table[] = 136195534Sscottl{ 137195534Sscottl { 138195534Sscottl /* Default tagged queuing parameters for all devices */ 139195534Sscottl { 140195534Sscottl T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED, 141195534Sscottl /*vendor*/"*", /*product*/"*", /*revision*/"*" 142195534Sscottl }, 143199178Smav /*quirks*/0, /*maxtags*/0 144195534Sscottl }, 145195534Sscottl}; 146195534Sscottl 147199178Smavstatic const int ata_quirk_table_size = 148199178Smav sizeof(ata_quirk_table) / sizeof(*ata_quirk_table); 149195534Sscottl 150195534Sscottlstatic cam_status proberegister(struct cam_periph *periph, 151195534Sscottl void *arg); 152195534Sscottlstatic void probeschedule(struct cam_periph *probe_periph); 153195534Sscottlstatic void probestart(struct cam_periph *periph, union ccb *start_ccb); 154195534Sscottl//static void proberequestdefaultnegotiation(struct cam_periph *periph); 155195534Sscottl//static int proberequestbackoff(struct cam_periph *periph, 156195534Sscottl// struct cam_ed *device); 157195534Sscottlstatic void probedone(struct cam_periph *periph, union ccb *done_ccb); 158195534Sscottlstatic void probecleanup(struct cam_periph *periph); 159199178Smavstatic void ata_find_quirk(struct cam_ed *device); 160195534Sscottlstatic void ata_scan_bus(struct cam_periph *periph, union ccb *ccb); 161195534Sscottlstatic void ata_scan_lun(struct cam_periph *periph, 162195534Sscottl struct cam_path *path, cam_flags flags, 163195534Sscottl union ccb *ccb); 164195534Sscottlstatic void xptscandone(struct cam_periph *periph, union ccb *done_ccb); 165195534Sscottlstatic struct cam_ed * 166195534Sscottl ata_alloc_device(struct cam_eb *bus, struct cam_et *target, 167195534Sscottl lun_id_t lun_id); 168195534Sscottlstatic void ata_device_transport(struct cam_path *path); 169199178Smavstatic void ata_set_transfer_settings(struct ccb_trans_settings *cts, 170195534Sscottl struct cam_ed *device, 171195534Sscottl int async_update); 172195534Sscottlstatic void ata_dev_async(u_int32_t async_code, 173195534Sscottl struct cam_eb *bus, 174195534Sscottl struct cam_et *target, 175195534Sscottl struct cam_ed *device, 176195534Sscottl void *async_arg); 177195534Sscottlstatic void ata_action(union ccb *start_ccb); 178195534Sscottl 179195534Sscottlstatic struct xpt_xport ata_xport = { 180195534Sscottl .alloc_device = ata_alloc_device, 181195534Sscottl .action = ata_action, 182195534Sscottl .async = ata_dev_async, 183195534Sscottl}; 184195534Sscottl 185195534Sscottlstruct xpt_xport * 186195534Sscottlata_get_xport(void) 187195534Sscottl{ 188195534Sscottl return (&ata_xport); 189195534Sscottl} 190195534Sscottl 191195534Sscottlstatic void 192195534Sscottlprobe_periph_init() 193195534Sscottl{ 194195534Sscottl} 195195534Sscottl 196195534Sscottlstatic cam_status 197195534Sscottlproberegister(struct cam_periph *periph, void *arg) 198195534Sscottl{ 199195534Sscottl union ccb *request_ccb; /* CCB representing the probe request */ 200195534Sscottl cam_status status; 201195534Sscottl probe_softc *softc; 202195534Sscottl 203195534Sscottl request_ccb = (union ccb *)arg; 204195534Sscottl if (periph == NULL) { 205195534Sscottl printf("proberegister: periph was NULL!!\n"); 206195534Sscottl return(CAM_REQ_CMP_ERR); 207195534Sscottl } 208195534Sscottl 209195534Sscottl if (request_ccb == NULL) { 210195534Sscottl printf("proberegister: no probe CCB, " 211195534Sscottl "can't register device\n"); 212195534Sscottl return(CAM_REQ_CMP_ERR); 213195534Sscottl } 214195534Sscottl 215195534Sscottl softc = (probe_softc *)malloc(sizeof(*softc), M_CAMXPT, M_NOWAIT); 216195534Sscottl 217195534Sscottl if (softc == NULL) { 218195534Sscottl printf("proberegister: Unable to probe new device. " 219195534Sscottl "Unable to allocate softc\n"); 220195534Sscottl return(CAM_REQ_CMP_ERR); 221195534Sscottl } 222195534Sscottl TAILQ_INIT(&softc->request_ccbs); 223195534Sscottl TAILQ_INSERT_TAIL(&softc->request_ccbs, &request_ccb->ccb_h, 224195534Sscottl periph_links.tqe); 225195534Sscottl softc->flags = 0; 226195534Sscottl periph->softc = softc; 227195534Sscottl softc->periph = periph; 228195534Sscottl softc->action = PROBE_INVALID; 229195534Sscottl status = cam_periph_acquire(periph); 230195534Sscottl if (status != CAM_REQ_CMP) { 231195534Sscottl return (status); 232195534Sscottl } 233195534Sscottl /* 234203108Smav * Ensure nobody slip in until probe finish. 235195534Sscottl */ 236203108Smav cam_freeze_devq_arg(periph->path, 237203108Smav RELSIM_RELEASE_RUNLEVEL, CAM_RL_XPT + 1); 238195534Sscottl probeschedule(periph); 239195534Sscottl return(CAM_REQ_CMP); 240195534Sscottl} 241195534Sscottl 242195534Sscottlstatic void 243195534Sscottlprobeschedule(struct cam_periph *periph) 244195534Sscottl{ 245195534Sscottl union ccb *ccb; 246195534Sscottl probe_softc *softc; 247195534Sscottl 248195534Sscottl softc = (probe_softc *)periph->softc; 249195534Sscottl ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs); 250195534Sscottl 251198389Smav if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) || 252198389Smav periph->path->device->protocol == PROTO_SATAPM) 253195534Sscottl PROBE_SET_ACTION(softc, PROBE_RESET); 254195534Sscottl else 255195534Sscottl PROBE_SET_ACTION(softc, PROBE_IDENTIFY); 256195534Sscottl 257195534Sscottl if (ccb->crcn.flags & CAM_EXPECT_INQ_CHANGE) 258195534Sscottl softc->flags |= PROBE_NO_ANNOUNCE; 259195534Sscottl else 260195534Sscottl softc->flags &= ~PROBE_NO_ANNOUNCE; 261195534Sscottl 262203108Smav xpt_schedule(periph, CAM_PRIORITY_XPT); 263195534Sscottl} 264195534Sscottl 265195534Sscottlstatic void 266195534Sscottlprobestart(struct cam_periph *periph, union ccb *start_ccb) 267195534Sscottl{ 268199747Smav struct ccb_trans_settings cts; 269195534Sscottl struct ccb_ataio *ataio; 270195534Sscottl struct ccb_scsiio *csio; 271195534Sscottl probe_softc *softc; 272198708Smav struct cam_path *path; 273198708Smav struct ata_params *ident_buf; 274195534Sscottl 275195534Sscottl CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probestart\n")); 276195534Sscottl 277195534Sscottl softc = (probe_softc *)periph->softc; 278198708Smav path = start_ccb->ccb_h.path; 279195534Sscottl ataio = &start_ccb->ataio; 280195534Sscottl csio = &start_ccb->csio; 281198708Smav ident_buf = &periph->path->device->ident_data; 282195534Sscottl 283203108Smav if (softc->restart) { 284203108Smav softc->restart = 0; 285203108Smav if ((path->device->flags & CAM_DEV_UNCONFIGURED) || 286203108Smav path->device->protocol == PROTO_SATAPM) 287203108Smav softc->action = PROBE_RESET; 288203108Smav else 289203108Smav softc->action = PROBE_IDENTIFY; 290203108Smav } 291195534Sscottl switch (softc->action) { 292195534Sscottl case PROBE_RESET: 293195534Sscottl cam_fill_ataio(ataio, 294195534Sscottl 0, 295195534Sscottl probedone, 296195534Sscottl /*flags*/CAM_DIR_NONE, 297198389Smav 0, 298195534Sscottl /*data_ptr*/NULL, 299195534Sscottl /*dxfer_len*/0, 300203108Smav 15 * 1000); 301195534Sscottl ata_reset_cmd(ataio); 302195534Sscottl break; 303195534Sscottl case PROBE_IDENTIFY: 304195534Sscottl cam_fill_ataio(ataio, 305195534Sscottl 1, 306195534Sscottl probedone, 307195534Sscottl /*flags*/CAM_DIR_IN, 308198389Smav 0, 309203385Smav /*data_ptr*/(u_int8_t *)&softc->ident_data, 310203385Smav /*dxfer_len*/sizeof(softc->ident_data), 311195534Sscottl 30 * 1000); 312195534Sscottl if (periph->path->device->protocol == PROTO_ATA) 313196659Smav ata_28bit_cmd(ataio, ATA_ATA_IDENTIFY, 0, 0, 0); 314195534Sscottl else 315196659Smav ata_28bit_cmd(ataio, ATA_ATAPI_IDENTIFY, 0, 0, 0); 316195534Sscottl break; 317195534Sscottl case PROBE_SETMODE: 318199747Smav { 319199747Smav int mode, wantmode; 320199747Smav 321199747Smav mode = 0; 322199747Smav /* Fetch user modes from SIM. */ 323199747Smav bzero(&cts, sizeof(cts)); 324203108Smav xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE); 325199747Smav cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 326199747Smav cts.type = CTS_TYPE_USER_SETTINGS; 327199747Smav xpt_action((union ccb *)&cts); 328199747Smav if (path->device->transport == XPORT_ATA) { 329199747Smav if (cts.xport_specific.ata.valid & CTS_ATA_VALID_MODE) 330199747Smav mode = cts.xport_specific.ata.mode; 331199747Smav } else { 332199799Smav if (cts.xport_specific.sata.valid & CTS_SATA_VALID_MODE) 333199747Smav mode = cts.xport_specific.sata.mode; 334199747Smav } 335199747Smavnegotiate: 336199747Smav /* Honor device capabilities. */ 337199747Smav wantmode = mode = ata_max_mode(ident_buf, mode); 338199747Smav /* Report modes to SIM. */ 339199747Smav bzero(&cts, sizeof(cts)); 340203108Smav xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE); 341199747Smav cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 342199747Smav cts.type = CTS_TYPE_CURRENT_SETTINGS; 343199747Smav if (path->device->transport == XPORT_ATA) { 344199747Smav cts.xport_specific.ata.mode = mode; 345199747Smav cts.xport_specific.ata.valid = CTS_ATA_VALID_MODE; 346199747Smav } else { 347199747Smav cts.xport_specific.sata.mode = mode; 348199747Smav cts.xport_specific.sata.valid = CTS_SATA_VALID_MODE; 349199747Smav } 350199747Smav xpt_action((union ccb *)&cts); 351200171Smav /* Fetch current modes from SIM. */ 352199747Smav bzero(&cts, sizeof(cts)); 353203108Smav xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE); 354199747Smav cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 355199747Smav cts.type = CTS_TYPE_CURRENT_SETTINGS; 356199747Smav xpt_action((union ccb *)&cts); 357199747Smav if (path->device->transport == XPORT_ATA) { 358199747Smav if (cts.xport_specific.ata.valid & CTS_ATA_VALID_MODE) 359199747Smav mode = cts.xport_specific.ata.mode; 360199747Smav } else { 361199747Smav if (cts.xport_specific.ata.valid & CTS_SATA_VALID_MODE) 362199747Smav mode = cts.xport_specific.sata.mode; 363199747Smav } 364199747Smav /* If SIM disagree - renegotiate. */ 365199747Smav if (mode != wantmode) 366199747Smav goto negotiate; 367195534Sscottl cam_fill_ataio(ataio, 368195534Sscottl 1, 369195534Sscottl probedone, 370196353Smav /*flags*/CAM_DIR_NONE, 371196353Smav 0, 372196353Smav /*data_ptr*/NULL, 373196353Smav /*dxfer_len*/0, 374195534Sscottl 30 * 1000); 375199747Smav ata_28bit_cmd(ataio, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode); 376195534Sscottl break; 377199747Smav } 378198708Smav case PROBE_SET_MULTI: 379198708Smav { 380200171Smav u_int sectors, bytecount; 381198708Smav 382200171Smav bytecount = 8192; /* SATA maximum */ 383200171Smav /* Fetch user bytecount from SIM. */ 384200171Smav bzero(&cts, sizeof(cts)); 385203108Smav xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE); 386200171Smav cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 387200171Smav cts.type = CTS_TYPE_USER_SETTINGS; 388200171Smav xpt_action((union ccb *)&cts); 389200171Smav if (path->device->transport == XPORT_ATA) { 390200171Smav if (cts.xport_specific.ata.valid & CTS_ATA_VALID_BYTECOUNT) 391200171Smav bytecount = cts.xport_specific.ata.bytecount; 392200171Smav } else { 393200171Smav if (cts.xport_specific.sata.valid & CTS_SATA_VALID_BYTECOUNT) 394200171Smav bytecount = cts.xport_specific.sata.bytecount; 395200171Smav } 396200171Smav /* Honor device capabilities. */ 397200171Smav sectors = max(1, min(ident_buf->sectors_intr & 0xff, 398200171Smav bytecount / ata_logical_sector_size(ident_buf))); 399198708Smav /* Report bytecount to SIM. */ 400198708Smav bzero(&cts, sizeof(cts)); 401203108Smav xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE); 402198708Smav cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 403198708Smav cts.type = CTS_TYPE_CURRENT_SETTINGS; 404198708Smav if (path->device->transport == XPORT_ATA) { 405198897Smav cts.xport_specific.ata.bytecount = sectors * 406198897Smav ata_logical_sector_size(ident_buf); 407198708Smav cts.xport_specific.ata.valid = CTS_ATA_VALID_BYTECOUNT; 408198708Smav } else { 409198897Smav cts.xport_specific.sata.bytecount = sectors * 410198897Smav ata_logical_sector_size(ident_buf); 411198708Smav cts.xport_specific.sata.valid = CTS_SATA_VALID_BYTECOUNT; 412198708Smav } 413198708Smav xpt_action((union ccb *)&cts); 414200171Smav /* Fetch current bytecount from SIM. */ 415200171Smav bzero(&cts, sizeof(cts)); 416203108Smav xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE); 417200171Smav cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 418200171Smav cts.type = CTS_TYPE_CURRENT_SETTINGS; 419200171Smav xpt_action((union ccb *)&cts); 420200171Smav if (path->device->transport == XPORT_ATA) { 421200171Smav if (cts.xport_specific.ata.valid & CTS_ATA_VALID_BYTECOUNT) 422200171Smav bytecount = cts.xport_specific.ata.bytecount; 423200171Smav } else { 424200171Smav if (cts.xport_specific.sata.valid & CTS_SATA_VALID_BYTECOUNT) 425200171Smav bytecount = cts.xport_specific.sata.bytecount; 426200171Smav } 427200171Smav sectors = bytecount / ata_logical_sector_size(ident_buf); 428198708Smav 429198708Smav cam_fill_ataio(ataio, 430198708Smav 1, 431198708Smav probedone, 432198708Smav CAM_DIR_NONE, 433198708Smav 0, 434198708Smav NULL, 435198708Smav 0, 436198708Smav 30*1000); 437198708Smav ata_28bit_cmd(ataio, ATA_SET_MULTI, 0, 0, sectors); 438198708Smav break; 439195534Sscottl } 440195534Sscottl case PROBE_INQUIRY: 441200171Smav { 442200171Smav u_int bytecount; 443200171Smav 444200171Smav bytecount = 8192; /* SATA maximum */ 445200171Smav /* Fetch user bytecount from SIM. */ 446200171Smav bzero(&cts, sizeof(cts)); 447203108Smav xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE); 448200171Smav cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 449200171Smav cts.type = CTS_TYPE_USER_SETTINGS; 450200171Smav xpt_action((union ccb *)&cts); 451200171Smav if (path->device->transport == XPORT_ATA) { 452200171Smav if (cts.xport_specific.ata.valid & CTS_ATA_VALID_BYTECOUNT) 453200171Smav bytecount = cts.xport_specific.ata.bytecount; 454200171Smav } else { 455200171Smav if (cts.xport_specific.sata.valid & CTS_SATA_VALID_BYTECOUNT) 456200171Smav bytecount = cts.xport_specific.sata.bytecount; 457200171Smav } 458200171Smav /* Honor device capabilities. */ 459200171Smav bytecount &= ~1; 460200171Smav bytecount = max(2, min(65534, bytecount)); 461200171Smav if (ident_buf->satacapabilities != 0x0000 && 462200171Smav ident_buf->satacapabilities != 0xffff) { 463200171Smav bytecount = min(8192, bytecount); 464200171Smav } 465200171Smav /* Report bytecount to SIM. */ 466200171Smav bzero(&cts, sizeof(cts)); 467203108Smav xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE); 468200171Smav cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 469200171Smav cts.type = CTS_TYPE_CURRENT_SETTINGS; 470200171Smav if (path->device->transport == XPORT_ATA) { 471200171Smav cts.xport_specific.ata.bytecount = bytecount; 472200171Smav cts.xport_specific.ata.valid = CTS_ATA_VALID_BYTECOUNT; 473200171Smav } else { 474200171Smav cts.xport_specific.sata.bytecount = bytecount; 475200171Smav cts.xport_specific.sata.valid = CTS_SATA_VALID_BYTECOUNT; 476200171Smav } 477200171Smav xpt_action((union ccb *)&cts); 478200171Smav /* FALLTHROUGH */ 479200171Smav } 480195534Sscottl case PROBE_FULL_INQUIRY: 481195534Sscottl { 482195534Sscottl u_int inquiry_len; 483195534Sscottl struct scsi_inquiry_data *inq_buf = 484195534Sscottl &periph->path->device->inq_data; 485195534Sscottl 486195534Sscottl if (softc->action == PROBE_INQUIRY) 487195534Sscottl inquiry_len = SHORT_INQUIRY_LENGTH; 488195534Sscottl else 489195534Sscottl inquiry_len = SID_ADDITIONAL_LENGTH(inq_buf); 490195534Sscottl /* 491195534Sscottl * Some parallel SCSI devices fail to send an 492195534Sscottl * ignore wide residue message when dealing with 493195534Sscottl * odd length inquiry requests. Round up to be 494195534Sscottl * safe. 495195534Sscottl */ 496195534Sscottl inquiry_len = roundup2(inquiry_len, 2); 497195534Sscottl scsi_inquiry(csio, 498195534Sscottl /*retries*/1, 499195534Sscottl probedone, 500195534Sscottl MSG_SIMPLE_Q_TAG, 501195534Sscottl (u_int8_t *)inq_buf, 502195534Sscottl inquiry_len, 503195534Sscottl /*evpd*/FALSE, 504195534Sscottl /*page_code*/0, 505195534Sscottl SSD_MIN_SIZE, 506195534Sscottl /*timeout*/60 * 1000); 507195534Sscottl break; 508195534Sscottl } 509195534Sscottl case PROBE_PM_PID: 510195534Sscottl cam_fill_ataio(ataio, 511195534Sscottl 1, 512195534Sscottl probedone, 513195534Sscottl /*flags*/CAM_DIR_NONE, 514198389Smav 0, 515195534Sscottl /*data_ptr*/NULL, 516195534Sscottl /*dxfer_len*/0, 517195534Sscottl 10 * 1000); 518195534Sscottl ata_pm_read_cmd(ataio, 0, 15); 519195534Sscottl break; 520195534Sscottl case PROBE_PM_PRV: 521195534Sscottl cam_fill_ataio(ataio, 522195534Sscottl 1, 523195534Sscottl probedone, 524195534Sscottl /*flags*/CAM_DIR_NONE, 525198389Smav 0, 526195534Sscottl /*data_ptr*/NULL, 527195534Sscottl /*dxfer_len*/0, 528195534Sscottl 10 * 1000); 529195534Sscottl ata_pm_read_cmd(ataio, 1, 15); 530195534Sscottl break; 531195534Sscottl case PROBE_INVALID: 532198708Smav CAM_DEBUG(path, CAM_DEBUG_INFO, 533195534Sscottl ("probestart: invalid action state\n")); 534195534Sscottl default: 535195534Sscottl break; 536195534Sscottl } 537195534Sscottl xpt_action(start_ccb); 538195534Sscottl} 539195534Sscottl#if 0 540195534Sscottlstatic void 541195534Sscottlproberequestdefaultnegotiation(struct cam_periph *periph) 542195534Sscottl{ 543195534Sscottl struct ccb_trans_settings cts; 544195534Sscottl 545203108Smav xpt_setup_ccb(&cts.ccb_h, periph->path, CAM_PRIORITY_NONE); 546195534Sscottl cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 547195534Sscottl cts.type = CTS_TYPE_USER_SETTINGS; 548195534Sscottl xpt_action((union ccb *)&cts); 549195534Sscottl if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 550195534Sscottl return; 551195534Sscottl } 552195534Sscottl cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 553195534Sscottl cts.type = CTS_TYPE_CURRENT_SETTINGS; 554195534Sscottl xpt_action((union ccb *)&cts); 555195534Sscottl} 556195534Sscottl 557195534Sscottl/* 558195534Sscottl * Backoff Negotiation Code- only pertinent for SPI devices. 559195534Sscottl */ 560195534Sscottlstatic int 561195534Sscottlproberequestbackoff(struct cam_periph *periph, struct cam_ed *device) 562195534Sscottl{ 563195534Sscottl struct ccb_trans_settings cts; 564195534Sscottl struct ccb_trans_settings_spi *spi; 565195534Sscottl 566195534Sscottl memset(&cts, 0, sizeof (cts)); 567203108Smav xpt_setup_ccb(&cts.ccb_h, periph->path, CAM_PRIORITY_NONE); 568195534Sscottl cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 569195534Sscottl cts.type = CTS_TYPE_CURRENT_SETTINGS; 570195534Sscottl xpt_action((union ccb *)&cts); 571195534Sscottl if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 572195534Sscottl if (bootverbose) { 573195534Sscottl xpt_print(periph->path, 574195534Sscottl "failed to get current device settings\n"); 575195534Sscottl } 576195534Sscottl return (0); 577195534Sscottl } 578195534Sscottl if (cts.transport != XPORT_SPI) { 579195534Sscottl if (bootverbose) { 580195534Sscottl xpt_print(periph->path, "not SPI transport\n"); 581195534Sscottl } 582195534Sscottl return (0); 583195534Sscottl } 584195534Sscottl spi = &cts.xport_specific.spi; 585195534Sscottl 586195534Sscottl /* 587195534Sscottl * We cannot renegotiate sync rate if we don't have one. 588195534Sscottl */ 589195534Sscottl if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0) { 590195534Sscottl if (bootverbose) { 591195534Sscottl xpt_print(periph->path, "no sync rate known\n"); 592195534Sscottl } 593195534Sscottl return (0); 594195534Sscottl } 595195534Sscottl 596195534Sscottl /* 597195534Sscottl * We'll assert that we don't have to touch PPR options- the 598195534Sscottl * SIM will see what we do with period and offset and adjust 599195534Sscottl * the PPR options as appropriate. 600195534Sscottl */ 601195534Sscottl 602195534Sscottl /* 603195534Sscottl * A sync rate with unknown or zero offset is nonsensical. 604195534Sscottl * A sync period of zero means Async. 605195534Sscottl */ 606195534Sscottl if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0 607195534Sscottl || spi->sync_offset == 0 || spi->sync_period == 0) { 608195534Sscottl if (bootverbose) { 609195534Sscottl xpt_print(periph->path, "no sync rate available\n"); 610195534Sscottl } 611195534Sscottl return (0); 612195534Sscottl } 613195534Sscottl 614195534Sscottl if (device->flags & CAM_DEV_DV_HIT_BOTTOM) { 615195534Sscottl CAM_DEBUG(periph->path, CAM_DEBUG_INFO, 616195534Sscottl ("hit async: giving up on DV\n")); 617195534Sscottl return (0); 618195534Sscottl } 619195534Sscottl 620195534Sscottl 621195534Sscottl /* 622195534Sscottl * Jump sync_period up by one, but stop at 5MHz and fall back to Async. 623195534Sscottl * We don't try to remember 'last' settings to see if the SIM actually 624195534Sscottl * gets into the speed we want to set. We check on the SIM telling 625195534Sscottl * us that a requested speed is bad, but otherwise don't try and 626195534Sscottl * check the speed due to the asynchronous and handshake nature 627195534Sscottl * of speed setting. 628195534Sscottl */ 629195534Sscottl spi->valid = CTS_SPI_VALID_SYNC_RATE | CTS_SPI_VALID_SYNC_OFFSET; 630195534Sscottl for (;;) { 631195534Sscottl spi->sync_period++; 632195534Sscottl if (spi->sync_period >= 0xf) { 633195534Sscottl spi->sync_period = 0; 634195534Sscottl spi->sync_offset = 0; 635195534Sscottl CAM_DEBUG(periph->path, CAM_DEBUG_INFO, 636195534Sscottl ("setting to async for DV\n")); 637195534Sscottl /* 638195534Sscottl * Once we hit async, we don't want to try 639195534Sscottl * any more settings. 640195534Sscottl */ 641195534Sscottl device->flags |= CAM_DEV_DV_HIT_BOTTOM; 642195534Sscottl } else if (bootverbose) { 643195534Sscottl CAM_DEBUG(periph->path, CAM_DEBUG_INFO, 644195534Sscottl ("DV: period 0x%x\n", spi->sync_period)); 645195534Sscottl printf("setting period to 0x%x\n", spi->sync_period); 646195534Sscottl } 647195534Sscottl cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 648195534Sscottl cts.type = CTS_TYPE_CURRENT_SETTINGS; 649195534Sscottl xpt_action((union ccb *)&cts); 650195534Sscottl if ((cts.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 651195534Sscottl break; 652195534Sscottl } 653195534Sscottl CAM_DEBUG(periph->path, CAM_DEBUG_INFO, 654195534Sscottl ("DV: failed to set period 0x%x\n", spi->sync_period)); 655195534Sscottl if (spi->sync_period == 0) { 656195534Sscottl return (0); 657195534Sscottl } 658195534Sscottl } 659195534Sscottl return (1); 660195534Sscottl} 661195534Sscottl#endif 662195534Sscottlstatic void 663195534Sscottlprobedone(struct cam_periph *periph, union ccb *done_ccb) 664195534Sscottl{ 665199747Smav struct ccb_trans_settings cts; 666195534Sscottl struct ata_params *ident_buf; 667195534Sscottl probe_softc *softc; 668195534Sscottl struct cam_path *path; 669195534Sscottl u_int32_t priority; 670198389Smav int found = 1; 671195534Sscottl 672195534Sscottl CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probedone\n")); 673195534Sscottl 674195534Sscottl softc = (probe_softc *)periph->softc; 675195534Sscottl path = done_ccb->ccb_h.path; 676195534Sscottl priority = done_ccb->ccb_h.pinfo.priority; 677195534Sscottl ident_buf = &path->device->ident_data; 678195534Sscottl 679198708Smav if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 680203385Smavdevice_fail: if (cam_periph_error(done_ccb, 0, 0, NULL) == ERESTART) { 681195534Sscottl return; 682195534Sscottl } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 683195534Sscottl /* Don't wedge the queue */ 684195534Sscottl xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, 685195534Sscottl /*run_queue*/TRUE); 686195534Sscottl } 687198708Smav /* Old PIO2 devices may not support mode setting. */ 688198708Smav if (softc->action == PROBE_SETMODE && 689198708Smav ata_max_pmode(ident_buf) <= ATA_PIO2 && 690198708Smav (ident_buf->capabilities1 & ATA_SUPPORT_IORDY) == 0) 691198708Smav goto noerror; 692198708Smav /* 693198708Smav * If we get to this point, we got an error status back 694198708Smav * from the inquiry and the error status doesn't require 695198708Smav * automatically retrying the command. Therefore, the 696198708Smav * inquiry failed. If we had inquiry information before 697198708Smav * for this device, but this latest inquiry command failed, 698198708Smav * the device has probably gone away. If this device isn't 699198708Smav * already marked unconfigured, notify the peripheral 700198708Smav * drivers that this device is no more. 701198708Smav */ 702198708Smav if ((path->device->flags & CAM_DEV_UNCONFIGURED) == 0) 703198708Smav xpt_async(AC_LOST_DEVICE, path, NULL); 704198708Smav found = 0; 705198708Smav goto done; 706198708Smav } 707198708Smavnoerror: 708203385Smav if (softc->restart) 709203385Smav goto done; 710198708Smav switch (softc->action) { 711198708Smav case PROBE_RESET: 712195534Sscottl { 713198708Smav int sign = (done_ccb->ataio.res.lba_high << 8) + 714198708Smav done_ccb->ataio.res.lba_mid; 715200218Smav if (bootverbose) 716200218Smav xpt_print(path, "SIGNATURE: %04x\n", sign); 717198708Smav if (sign == 0x0000 && 718198708Smav done_ccb->ccb_h.target_id != 15) { 719198708Smav path->device->protocol = PROTO_ATA; 720198708Smav PROBE_SET_ACTION(softc, PROBE_IDENTIFY); 721198708Smav } else if (sign == 0x9669 && 722198708Smav done_ccb->ccb_h.target_id == 15) { 723199747Smav /* Report SIM that PM is present. */ 724198708Smav bzero(&cts, sizeof(cts)); 725203108Smav xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE); 726198708Smav cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 727198708Smav cts.type = CTS_TYPE_CURRENT_SETTINGS; 728198708Smav cts.xport_specific.sata.pm_present = 1; 729198708Smav cts.xport_specific.sata.valid = CTS_SATA_VALID_PM; 730198708Smav xpt_action((union ccb *)&cts); 731198708Smav path->device->protocol = PROTO_SATAPM; 732198708Smav PROBE_SET_ACTION(softc, PROBE_PM_PID); 733198708Smav } else if (sign == 0xeb14 && 734198708Smav done_ccb->ccb_h.target_id != 15) { 735198708Smav path->device->protocol = PROTO_SCSI; 736198708Smav PROBE_SET_ACTION(softc, PROBE_IDENTIFY); 737198708Smav } else { 738198708Smav if (done_ccb->ccb_h.target_id != 15) { 739198708Smav xpt_print(path, 740198708Smav "Unexpected signature 0x%04x\n", sign); 741195534Sscottl } 742198708Smav goto device_fail; 743198708Smav } 744198708Smav xpt_release_ccb(done_ccb); 745198708Smav xpt_schedule(periph, priority); 746198708Smav return; 747198708Smav } 748198708Smav case PROBE_IDENTIFY: 749198708Smav { 750198708Smav int16_t *ptr; 751195534Sscottl 752203385Smav ident_buf = &softc->ident_data; 753198708Smav for (ptr = (int16_t *)ident_buf; 754198708Smav ptr < (int16_t *)ident_buf + sizeof(struct ata_params)/2; ptr++) { 755198708Smav *ptr = le16toh(*ptr); 756198708Smav } 757198708Smav if (strncmp(ident_buf->model, "FX", 2) && 758198708Smav strncmp(ident_buf->model, "NEC", 3) && 759198708Smav strncmp(ident_buf->model, "Pioneer", 7) && 760198708Smav strncmp(ident_buf->model, "SHARP", 5)) { 761198708Smav ata_bswap(ident_buf->model, sizeof(ident_buf->model)); 762198708Smav ata_bswap(ident_buf->revision, sizeof(ident_buf->revision)); 763198708Smav ata_bswap(ident_buf->serial, sizeof(ident_buf->serial)); 764198708Smav } 765198708Smav ata_btrim(ident_buf->model, sizeof(ident_buf->model)); 766198708Smav ata_bpack(ident_buf->model, ident_buf->model, sizeof(ident_buf->model)); 767198708Smav ata_btrim(ident_buf->revision, sizeof(ident_buf->revision)); 768198708Smav ata_bpack(ident_buf->revision, ident_buf->revision, sizeof(ident_buf->revision)); 769198708Smav ata_btrim(ident_buf->serial, sizeof(ident_buf->serial)); 770198708Smav ata_bpack(ident_buf->serial, ident_buf->serial, sizeof(ident_buf->serial)); 771203385Smav ident_buf = &path->device->ident_data; 772195534Sscottl 773198708Smav if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) == 0) { 774198708Smav /* Check that it is the same device. */ 775203385Smav if (bcmp(softc->ident_data.model, ident_buf->model, 776203385Smav sizeof(ident_buf->model)) || 777203385Smav bcmp(softc->ident_data.revision, ident_buf->revision, 778203385Smav sizeof(ident_buf->revision)) || 779203385Smav bcmp(softc->ident_data.serial, ident_buf->serial, 780203385Smav sizeof(ident_buf->serial))) { 781198708Smav /* Device changed. */ 782198708Smav xpt_async(AC_LOST_DEVICE, path, NULL); 783203385Smav } else 784203385Smav bcopy(&softc->ident_data, ident_buf, sizeof(struct ata_params)); 785198708Smav } else { 786203385Smav bcopy(&softc->ident_data, ident_buf, sizeof(struct ata_params)); 787195534Sscottl /* Clean up from previous instance of this device */ 788195534Sscottl if (path->device->serial_num != NULL) { 789195534Sscottl free(path->device->serial_num, M_CAMXPT); 790195534Sscottl path->device->serial_num = NULL; 791195534Sscottl path->device->serial_num_len = 0; 792195534Sscottl } 793195534Sscottl path->device->serial_num = 794195534Sscottl (u_int8_t *)malloc((sizeof(ident_buf->serial) + 1), 795198708Smav M_CAMXPT, M_NOWAIT); 796195534Sscottl if (path->device->serial_num != NULL) { 797195534Sscottl bcopy(ident_buf->serial, 798195534Sscottl path->device->serial_num, 799195534Sscottl sizeof(ident_buf->serial)); 800195534Sscottl path->device->serial_num[sizeof(ident_buf->serial)] 801195534Sscottl = '\0'; 802195534Sscottl path->device->serial_num_len = 803195534Sscottl strlen(path->device->serial_num); 804195534Sscottl } 805195534Sscottl 806198331Smav path->device->flags |= CAM_DEV_IDENTIFY_DATA_VALID; 807195534Sscottl } 808199178Smav if (ident_buf->satacapabilities & ATA_SUPPORT_NCQ) { 809199178Smav path->device->mintags = path->device->maxtags = 810199178Smav ATA_QUEUE_LEN(ident_buf->queue) + 1; 811199178Smav } 812199178Smav ata_find_quirk(path->device); 813199263Smav if (path->device->mintags != 0 && 814199263Smav path->bus->sim->max_tagged_dev_openings != 0) { 815199747Smav /* Report SIM which tags are allowed. */ 816199747Smav bzero(&cts, sizeof(cts)); 817203108Smav xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE); 818199747Smav cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 819199747Smav cts.type = CTS_TYPE_CURRENT_SETTINGS; 820199747Smav cts.xport_specific.sata.tags = path->device->maxtags; 821199747Smav cts.xport_specific.sata.valid = CTS_SATA_VALID_TAGS; 822199747Smav xpt_action((union ccb *)&cts); 823199747Smav /* Reconfigure queues for tagged queueing. */ 824199178Smav xpt_start_tags(path); 825199178Smav } 826198708Smav ata_device_transport(path); 827198708Smav PROBE_SET_ACTION(softc, PROBE_SETMODE); 828195534Sscottl xpt_release_ccb(done_ccb); 829198708Smav xpt_schedule(periph, priority); 830198708Smav return; 831195534Sscottl } 832195534Sscottl case PROBE_SETMODE: 833198708Smav if (path->device->protocol == PROTO_ATA) { 834198708Smav PROBE_SET_ACTION(softc, PROBE_SET_MULTI); 835198708Smav } else { 836198708Smav PROBE_SET_ACTION(softc, PROBE_INQUIRY); 837195534Sscottl } 838198708Smav xpt_release_ccb(done_ccb); 839198708Smav xpt_schedule(periph, priority); 840198708Smav return; 841198708Smav case PROBE_SET_MULTI: 842198708Smav if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) { 843198708Smav path->device->flags &= ~CAM_DEV_UNCONFIGURED; 844198748Smav xpt_acquire_device(path->device); 845198708Smav done_ccb->ccb_h.func_code = XPT_GDEV_TYPE; 846198708Smav xpt_action(done_ccb); 847198708Smav xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path, 848198708Smav done_ccb); 849198708Smav } 850198708Smav break; 851195534Sscottl case PROBE_INQUIRY: 852195534Sscottl case PROBE_FULL_INQUIRY: 853195534Sscottl { 854198708Smav struct scsi_inquiry_data *inq_buf; 855198708Smav u_int8_t periph_qual, len; 856195534Sscottl 857198708Smav path->device->flags |= CAM_DEV_INQUIRY_DATA_VALID; 858198708Smav inq_buf = &path->device->inq_data; 859195534Sscottl 860198708Smav periph_qual = SID_QUAL(inq_buf); 861195534Sscottl 862198708Smav if (periph_qual != SID_QUAL_LU_CONNECTED) 863198708Smav break; 864195534Sscottl 865198708Smav /* 866198708Smav * We conservatively request only 867198708Smav * SHORT_INQUIRY_LEN bytes of inquiry 868198708Smav * information during our first try 869198708Smav * at sending an INQUIRY. If the device 870198708Smav * has more information to give, 871198708Smav * perform a second request specifying 872198708Smav * the amount of information the device 873198708Smav * is willing to give. 874198708Smav */ 875198708Smav len = inq_buf->additional_length 876198708Smav + offsetof(struct scsi_inquiry_data, additional_length) + 1; 877198708Smav if (softc->action == PROBE_INQUIRY 878198708Smav && len > SHORT_INQUIRY_LENGTH) { 879198708Smav PROBE_SET_ACTION(softc, PROBE_FULL_INQUIRY); 880198708Smav xpt_release_ccb(done_ccb); 881198708Smav xpt_schedule(periph, priority); 882195534Sscottl return; 883195534Sscottl } 884198708Smav 885198708Smav ata_device_transport(path); 886198708Smav if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) { 887198708Smav path->device->flags &= ~CAM_DEV_UNCONFIGURED; 888198748Smav xpt_acquire_device(path->device); 889198708Smav done_ccb->ccb_h.func_code = XPT_GDEV_TYPE; 890198708Smav xpt_action(done_ccb); 891198708Smav xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path, done_ccb); 892198708Smav } 893198708Smav break; 894195534Sscottl } 895195534Sscottl case PROBE_PM_PID: 896198708Smav if ((path->device->flags & CAM_DEV_IDENTIFY_DATA_VALID) == 0) 897198708Smav bzero(ident_buf, sizeof(*ident_buf)); 898198708Smav softc->pm_pid = (done_ccb->ataio.res.lba_high << 24) + 899198708Smav (done_ccb->ataio.res.lba_mid << 16) + 900198708Smav (done_ccb->ataio.res.lba_low << 8) + 901198708Smav done_ccb->ataio.res.sector_count; 902198708Smav ((uint32_t *)ident_buf)[0] = softc->pm_pid; 903198708Smav snprintf(ident_buf->model, sizeof(ident_buf->model), 904198708Smav "Port Multiplier %08x", softc->pm_pid); 905198708Smav PROBE_SET_ACTION(softc, PROBE_PM_PRV); 906198708Smav xpt_release_ccb(done_ccb); 907198708Smav xpt_schedule(periph, priority); 908198708Smav return; 909195534Sscottl case PROBE_PM_PRV: 910198708Smav softc->pm_prv = (done_ccb->ataio.res.lba_high << 24) + 911198708Smav (done_ccb->ataio.res.lba_mid << 16) + 912198708Smav (done_ccb->ataio.res.lba_low << 8) + 913198708Smav done_ccb->ataio.res.sector_count; 914198708Smav ((uint32_t *)ident_buf)[1] = softc->pm_prv; 915198708Smav snprintf(ident_buf->revision, sizeof(ident_buf->revision), 916198708Smav "%04x", softc->pm_prv); 917198708Smav path->device->flags |= CAM_DEV_IDENTIFY_DATA_VALID; 918198708Smav if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) { 919198708Smav path->device->flags &= ~CAM_DEV_UNCONFIGURED; 920198748Smav xpt_acquire_device(path->device); 921198708Smav done_ccb->ccb_h.func_code = XPT_GDEV_TYPE; 922198708Smav xpt_action(done_ccb); 923198708Smav xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path, 924198708Smav done_ccb); 925198708Smav } else { 926198708Smav done_ccb->ccb_h.func_code = XPT_GDEV_TYPE; 927198708Smav xpt_action(done_ccb); 928198708Smav xpt_async(AC_SCSI_AEN, done_ccb->ccb_h.path, done_ccb); 929195534Sscottl } 930198708Smav break; 931195534Sscottl case PROBE_INVALID: 932195534Sscottl CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_INFO, 933195534Sscottl ("probedone: invalid action state\n")); 934195534Sscottl default: 935195534Sscottl break; 936195534Sscottl } 937198708Smavdone: 938203108Smav if (softc->restart) { 939203108Smav softc->restart = 0; 940203108Smav xpt_release_ccb(done_ccb); 941195534Sscottl probeschedule(periph); 942203108Smav return; 943195534Sscottl } 944203108Smav xpt_release_ccb(done_ccb); 945203108Smav while ((done_ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs))) { 946203108Smav TAILQ_REMOVE(&softc->request_ccbs, 947203108Smav &done_ccb->ccb_h, periph_links.tqe); 948203108Smav done_ccb->ccb_h.status = found ? CAM_REQ_CMP : CAM_REQ_CMP_ERR; 949203108Smav xpt_done(done_ccb); 950203108Smav } 951203108Smav cam_release_devq(periph->path, 952203108Smav RELSIM_RELEASE_RUNLEVEL, 0, CAM_RL_XPT + 1, FALSE); 953203108Smav cam_periph_invalidate(periph); 954203108Smav cam_periph_release_locked(periph); 955195534Sscottl} 956195534Sscottl 957195534Sscottlstatic void 958195534Sscottlprobecleanup(struct cam_periph *periph) 959195534Sscottl{ 960195534Sscottl free(periph->softc, M_CAMXPT); 961195534Sscottl} 962195534Sscottl 963195534Sscottlstatic void 964199178Smavata_find_quirk(struct cam_ed *device) 965195534Sscottl{ 966199178Smav struct ata_quirk_entry *quirk; 967195534Sscottl caddr_t match; 968195534Sscottl 969199178Smav match = cam_quirkmatch((caddr_t)&device->ident_data, 970199178Smav (caddr_t)ata_quirk_table, 971199178Smav ata_quirk_table_size, 972199178Smav sizeof(*ata_quirk_table), ata_identify_match); 973195534Sscottl 974195534Sscottl if (match == NULL) 975195534Sscottl panic("xpt_find_quirk: device didn't match wildcard entry!!"); 976195534Sscottl 977199178Smav quirk = (struct ata_quirk_entry *)match; 978195534Sscottl device->quirk = quirk; 979199178Smav if (quirk->quirks & CAM_QUIRK_MAXTAGS) 980199178Smav device->mintags = device->maxtags = quirk->maxtags; 981195534Sscottl} 982195534Sscottl 983195534Sscottltypedef struct { 984195534Sscottl union ccb *request_ccb; 985195534Sscottl struct ccb_pathinq *cpi; 986195534Sscottl int counter; 987195534Sscottl} ata_scan_bus_info; 988195534Sscottl 989195534Sscottl/* 990195534Sscottl * To start a scan, request_ccb is an XPT_SCAN_BUS ccb. 991195534Sscottl * As the scan progresses, xpt_scan_bus is used as the 992195534Sscottl * callback on completion function. 993195534Sscottl */ 994195534Sscottlstatic void 995195534Sscottlata_scan_bus(struct cam_periph *periph, union ccb *request_ccb) 996195534Sscottl{ 997195534Sscottl struct cam_path *path; 998195534Sscottl ata_scan_bus_info *scan_info; 999203108Smav union ccb *work_ccb, *reset_ccb; 1000195534Sscottl cam_status status; 1001195534Sscottl 1002195534Sscottl CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_TRACE, 1003195534Sscottl ("xpt_scan_bus\n")); 1004195534Sscottl switch (request_ccb->ccb_h.func_code) { 1005195534Sscottl case XPT_SCAN_BUS: 1006195534Sscottl /* Find out the characteristics of the bus */ 1007195534Sscottl work_ccb = xpt_alloc_ccb_nowait(); 1008195534Sscottl if (work_ccb == NULL) { 1009195534Sscottl request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 1010195534Sscottl xpt_done(request_ccb); 1011195534Sscottl return; 1012195534Sscottl } 1013195534Sscottl xpt_setup_ccb(&work_ccb->ccb_h, request_ccb->ccb_h.path, 1014195534Sscottl request_ccb->ccb_h.pinfo.priority); 1015195534Sscottl work_ccb->ccb_h.func_code = XPT_PATH_INQ; 1016195534Sscottl xpt_action(work_ccb); 1017195534Sscottl if (work_ccb->ccb_h.status != CAM_REQ_CMP) { 1018195534Sscottl request_ccb->ccb_h.status = work_ccb->ccb_h.status; 1019195534Sscottl xpt_free_ccb(work_ccb); 1020195534Sscottl xpt_done(request_ccb); 1021195534Sscottl return; 1022195534Sscottl } 1023195534Sscottl 1024203108Smav /* We may need to reset bus first, if we haven't done it yet. */ 1025203108Smav if ((work_ccb->cpi.hba_inquiry & 1026203108Smav (PI_WIDE_32|PI_WIDE_16|PI_SDTR_ABLE)) && 1027203108Smav !(work_ccb->cpi.hba_misc & PIM_NOBUSRESET) && 1028203108Smav !timevalisset(&request_ccb->ccb_h.path->bus->last_reset)) { 1029203108Smav reset_ccb = xpt_alloc_ccb_nowait(); 1030203108Smav xpt_setup_ccb(&reset_ccb->ccb_h, request_ccb->ccb_h.path, 1031203108Smav CAM_PRIORITY_NONE); 1032203108Smav reset_ccb->ccb_h.func_code = XPT_RESET_BUS; 1033203108Smav xpt_action(reset_ccb); 1034203108Smav if (reset_ccb->ccb_h.status != CAM_REQ_CMP) { 1035203108Smav request_ccb->ccb_h.status = reset_ccb->ccb_h.status; 1036203108Smav xpt_free_ccb(reset_ccb); 1037203108Smav xpt_free_ccb(work_ccb); 1038203108Smav xpt_done(request_ccb); 1039203108Smav return; 1040203108Smav } 1041203108Smav xpt_free_ccb(reset_ccb); 1042203108Smav } 1043203108Smav 1044195534Sscottl /* Save some state for use while we probe for devices */ 1045195534Sscottl scan_info = (ata_scan_bus_info *) 1046195534Sscottl malloc(sizeof(ata_scan_bus_info), M_CAMXPT, M_NOWAIT); 1047195534Sscottl if (scan_info == NULL) { 1048195534Sscottl request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 1049195534Sscottl xpt_done(request_ccb); 1050195534Sscottl return; 1051195534Sscottl } 1052195534Sscottl scan_info->request_ccb = request_ccb; 1053195534Sscottl scan_info->cpi = &work_ccb->cpi; 1054195534Sscottl /* If PM supported, probe it first. */ 1055195534Sscottl if (scan_info->cpi->hba_inquiry & PI_SATAPM) 1056201990Smav scan_info->counter = scan_info->cpi->max_target; 1057201990Smav else 1058201990Smav scan_info->counter = 0; 1059195534Sscottl 1060195534Sscottl work_ccb = xpt_alloc_ccb_nowait(); 1061195534Sscottl if (work_ccb == NULL) { 1062195534Sscottl free(scan_info, M_CAMXPT); 1063195534Sscottl request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 1064195534Sscottl xpt_done(request_ccb); 1065195534Sscottl break; 1066195534Sscottl } 1067195534Sscottl goto scan_next; 1068195534Sscottl case XPT_SCAN_LUN: 1069195534Sscottl work_ccb = request_ccb; 1070195534Sscottl /* Reuse the same CCB to query if a device was really found */ 1071195534Sscottl scan_info = (ata_scan_bus_info *)work_ccb->ccb_h.ppriv_ptr0; 1072195534Sscottl /* Free the current request path- we're done with it. */ 1073195534Sscottl xpt_free_path(work_ccb->ccb_h.path); 1074198389Smav /* If there is PMP... */ 1075201990Smav if ((scan_info->cpi->hba_inquiry & PI_SATAPM) && 1076201990Smav (scan_info->counter == scan_info->cpi->max_target)) { 1077203108Smav if (work_ccb->ccb_h.status == CAM_REQ_CMP) { 1078198389Smav /* everything else willbe probed by it */ 1079201990Smav goto done; 1080195534Sscottl } else { 1081195534Sscottl struct ccb_trans_settings cts; 1082195534Sscottl 1083195534Sscottl /* Report SIM that PM is absent. */ 1084195534Sscottl bzero(&cts, sizeof(cts)); 1085195534Sscottl xpt_setup_ccb(&cts.ccb_h, 1086195534Sscottl scan_info->request_ccb->ccb_h.path, 1); 1087195534Sscottl cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 1088195534Sscottl cts.type = CTS_TYPE_CURRENT_SETTINGS; 1089195665Smav cts.xport_specific.sata.pm_present = 0; 1090195534Sscottl cts.xport_specific.sata.valid = CTS_SATA_VALID_PM; 1091195534Sscottl xpt_action((union ccb *)&cts); 1092195534Sscottl } 1093195534Sscottl } 1094201990Smav if (scan_info->counter == 1095201990Smav ((scan_info->cpi->hba_inquiry & PI_SATAPM) ? 1096201990Smav 0 : scan_info->cpi->max_target)) { 1097201990Smavdone: 1098195534Sscottl xpt_free_ccb(work_ccb); 1099195534Sscottl xpt_free_ccb((union ccb *)scan_info->cpi); 1100195534Sscottl request_ccb = scan_info->request_ccb; 1101195534Sscottl free(scan_info, M_CAMXPT); 1102195534Sscottl request_ccb->ccb_h.status = CAM_REQ_CMP; 1103195534Sscottl xpt_done(request_ccb); 1104195534Sscottl break; 1105195534Sscottl } 1106201990Smav /* Take next device. Wrap from max (PMP) to 0. */ 1107201990Smav scan_info->counter = (scan_info->counter + 1 ) % 1108201990Smav (scan_info->cpi->max_target + 1); 1109195534Sscottlscan_next: 1110195534Sscottl status = xpt_create_path(&path, xpt_periph, 1111195534Sscottl scan_info->request_ccb->ccb_h.path_id, 1112195534Sscottl scan_info->counter, 0); 1113195534Sscottl if (status != CAM_REQ_CMP) { 1114195534Sscottl printf("xpt_scan_bus: xpt_create_path failed" 1115195534Sscottl " with status %#x, bus scan halted\n", 1116195534Sscottl status); 1117195534Sscottl xpt_free_ccb(work_ccb); 1118195534Sscottl xpt_free_ccb((union ccb *)scan_info->cpi); 1119195534Sscottl request_ccb = scan_info->request_ccb; 1120195534Sscottl free(scan_info, M_CAMXPT); 1121195534Sscottl request_ccb->ccb_h.status = status; 1122195534Sscottl xpt_done(request_ccb); 1123195534Sscottl break; 1124195534Sscottl } 1125195534Sscottl xpt_setup_ccb(&work_ccb->ccb_h, path, 1126195534Sscottl scan_info->request_ccb->ccb_h.pinfo.priority); 1127195534Sscottl work_ccb->ccb_h.func_code = XPT_SCAN_LUN; 1128195534Sscottl work_ccb->ccb_h.cbfcnp = ata_scan_bus; 1129195534Sscottl work_ccb->ccb_h.ppriv_ptr0 = scan_info; 1130195534Sscottl work_ccb->crcn.flags = scan_info->request_ccb->crcn.flags; 1131195534Sscottl xpt_action(work_ccb); 1132195534Sscottl break; 1133195534Sscottl default: 1134195534Sscottl break; 1135195534Sscottl } 1136195534Sscottl} 1137195534Sscottl 1138195534Sscottlstatic void 1139195534Sscottlata_scan_lun(struct cam_periph *periph, struct cam_path *path, 1140195534Sscottl cam_flags flags, union ccb *request_ccb) 1141195534Sscottl{ 1142195534Sscottl struct ccb_pathinq cpi; 1143195534Sscottl cam_status status; 1144195534Sscottl struct cam_path *new_path; 1145195534Sscottl struct cam_periph *old_periph; 1146195534Sscottl 1147203108Smav CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_scan_lun\n")); 1148195534Sscottl 1149203108Smav xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NONE); 1150195534Sscottl cpi.ccb_h.func_code = XPT_PATH_INQ; 1151195534Sscottl xpt_action((union ccb *)&cpi); 1152195534Sscottl 1153195534Sscottl if (cpi.ccb_h.status != CAM_REQ_CMP) { 1154195534Sscottl if (request_ccb != NULL) { 1155195534Sscottl request_ccb->ccb_h.status = cpi.ccb_h.status; 1156195534Sscottl xpt_done(request_ccb); 1157195534Sscottl } 1158195534Sscottl return; 1159195534Sscottl } 1160195534Sscottl 1161195534Sscottl if (request_ccb == NULL) { 1162195534Sscottl request_ccb = malloc(sizeof(union ccb), M_CAMXPT, M_NOWAIT); 1163195534Sscottl if (request_ccb == NULL) { 1164195534Sscottl xpt_print(path, "xpt_scan_lun: can't allocate CCB, " 1165195534Sscottl "can't continue\n"); 1166195534Sscottl return; 1167195534Sscottl } 1168195534Sscottl new_path = malloc(sizeof(*new_path), M_CAMXPT, M_NOWAIT); 1169195534Sscottl if (new_path == NULL) { 1170195534Sscottl xpt_print(path, "xpt_scan_lun: can't allocate path, " 1171195534Sscottl "can't continue\n"); 1172195534Sscottl free(request_ccb, M_CAMXPT); 1173195534Sscottl return; 1174195534Sscottl } 1175195534Sscottl status = xpt_compile_path(new_path, xpt_periph, 1176195534Sscottl path->bus->path_id, 1177195534Sscottl path->target->target_id, 1178195534Sscottl path->device->lun_id); 1179195534Sscottl 1180195534Sscottl if (status != CAM_REQ_CMP) { 1181195534Sscottl xpt_print(path, "xpt_scan_lun: can't compile path, " 1182195534Sscottl "can't continue\n"); 1183195534Sscottl free(request_ccb, M_CAMXPT); 1184195534Sscottl free(new_path, M_CAMXPT); 1185195534Sscottl return; 1186195534Sscottl } 1187203108Smav xpt_setup_ccb(&request_ccb->ccb_h, new_path, CAM_PRIORITY_XPT); 1188195534Sscottl request_ccb->ccb_h.cbfcnp = xptscandone; 1189195534Sscottl request_ccb->ccb_h.func_code = XPT_SCAN_LUN; 1190195534Sscottl request_ccb->crcn.flags = flags; 1191195534Sscottl } 1192195534Sscottl 1193195653Smav if ((old_periph = cam_periph_find(path, "aprobe")) != NULL) { 1194195534Sscottl probe_softc *softc; 1195195534Sscottl 1196195534Sscottl softc = (probe_softc *)old_periph->softc; 1197195534Sscottl TAILQ_INSERT_TAIL(&softc->request_ccbs, &request_ccb->ccb_h, 1198195534Sscottl periph_links.tqe); 1199203108Smav softc->restart = 1; 1200195534Sscottl } else { 1201195534Sscottl status = cam_periph_alloc(proberegister, NULL, probecleanup, 1202195653Smav probestart, "aprobe", 1203195534Sscottl CAM_PERIPH_BIO, 1204195534Sscottl request_ccb->ccb_h.path, NULL, 0, 1205195534Sscottl request_ccb); 1206195534Sscottl 1207195534Sscottl if (status != CAM_REQ_CMP) { 1208195534Sscottl xpt_print(path, "xpt_scan_lun: cam_alloc_periph " 1209195534Sscottl "returned an error, can't continue probe\n"); 1210195534Sscottl request_ccb->ccb_h.status = status; 1211195534Sscottl xpt_done(request_ccb); 1212195534Sscottl } 1213195534Sscottl } 1214195534Sscottl} 1215195534Sscottl 1216195534Sscottlstatic void 1217195534Sscottlxptscandone(struct cam_periph *periph, union ccb *done_ccb) 1218195534Sscottl{ 1219195534Sscottl xpt_release_path(done_ccb->ccb_h.path); 1220195534Sscottl free(done_ccb->ccb_h.path, M_CAMXPT); 1221195534Sscottl free(done_ccb, M_CAMXPT); 1222195534Sscottl} 1223195534Sscottl 1224195534Sscottlstatic struct cam_ed * 1225195534Sscottlata_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id) 1226195534Sscottl{ 1227195534Sscottl struct cam_path path; 1228199178Smav struct ata_quirk_entry *quirk; 1229195534Sscottl struct cam_ed *device; 1230195534Sscottl struct cam_ed *cur_device; 1231195534Sscottl 1232195534Sscottl device = xpt_alloc_device(bus, target, lun_id); 1233195534Sscottl if (device == NULL) 1234195534Sscottl return (NULL); 1235195534Sscottl 1236195534Sscottl /* 1237195534Sscottl * Take the default quirk entry until we have inquiry 1238195534Sscottl * data and can determine a better quirk to use. 1239195534Sscottl */ 1240199178Smav quirk = &ata_quirk_table[ata_quirk_table_size - 1]; 1241195534Sscottl device->quirk = (void *)quirk; 1242199178Smav device->mintags = 0; 1243199178Smav device->maxtags = 0; 1244195534Sscottl bzero(&device->inq_data, sizeof(device->inq_data)); 1245195534Sscottl device->inq_flags = 0; 1246195534Sscottl device->queue_flags = 0; 1247195534Sscottl device->serial_num = NULL; 1248195534Sscottl device->serial_num_len = 0; 1249195534Sscottl 1250195534Sscottl /* 1251195534Sscottl * XXX should be limited by number of CCBs this bus can 1252195534Sscottl * do. 1253195534Sscottl */ 1254195534Sscottl bus->sim->max_ccbs += device->ccbq.devq_openings; 1255195534Sscottl /* Insertion sort into our target's device list */ 1256195534Sscottl cur_device = TAILQ_FIRST(&target->ed_entries); 1257195534Sscottl while (cur_device != NULL && cur_device->lun_id < lun_id) 1258195534Sscottl cur_device = TAILQ_NEXT(cur_device, links); 1259195534Sscottl if (cur_device != NULL) { 1260195534Sscottl TAILQ_INSERT_BEFORE(cur_device, device, links); 1261195534Sscottl } else { 1262195534Sscottl TAILQ_INSERT_TAIL(&target->ed_entries, device, links); 1263195534Sscottl } 1264195534Sscottl target->generation++; 1265195534Sscottl if (lun_id != CAM_LUN_WILDCARD) { 1266195534Sscottl xpt_compile_path(&path, 1267195534Sscottl NULL, 1268195534Sscottl bus->path_id, 1269195534Sscottl target->target_id, 1270195534Sscottl lun_id); 1271195534Sscottl ata_device_transport(&path); 1272195534Sscottl xpt_release_path(&path); 1273195534Sscottl } 1274195534Sscottl 1275195534Sscottl return (device); 1276195534Sscottl} 1277195534Sscottl 1278195534Sscottlstatic void 1279195534Sscottlata_device_transport(struct cam_path *path) 1280195534Sscottl{ 1281195534Sscottl struct ccb_pathinq cpi; 1282198331Smav struct ccb_trans_settings cts; 1283198331Smav struct scsi_inquiry_data *inq_buf = NULL; 1284198331Smav struct ata_params *ident_buf = NULL; 1285195534Sscottl 1286195534Sscottl /* Get transport information from the SIM */ 1287203108Smav xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NONE); 1288195534Sscottl cpi.ccb_h.func_code = XPT_PATH_INQ; 1289195534Sscottl xpt_action((union ccb *)&cpi); 1290195534Sscottl 1291195534Sscottl path->device->transport = cpi.transport; 1292198331Smav if ((path->device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0) 1293198331Smav inq_buf = &path->device->inq_data; 1294198331Smav if ((path->device->flags & CAM_DEV_IDENTIFY_DATA_VALID) != 0) 1295198331Smav ident_buf = &path->device->ident_data; 1296198331Smav if (path->device->protocol == PROTO_ATA) { 1297198331Smav path->device->protocol_version = ident_buf ? 1298198331Smav ata_version(ident_buf->version_major) : cpi.protocol_version; 1299198331Smav } else if (path->device->protocol == PROTO_SCSI) { 1300198331Smav path->device->protocol_version = inq_buf ? 1301198331Smav SID_ANSI_REV(inq_buf) : cpi.protocol_version; 1302195534Sscottl } 1303198331Smav path->device->transport_version = ident_buf ? 1304198331Smav ata_version(ident_buf->version_major) : cpi.transport_version; 1305195534Sscottl 1306195534Sscottl /* Tell the controller what we think */ 1307203108Smav xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE); 1308195534Sscottl cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 1309195534Sscottl cts.type = CTS_TYPE_CURRENT_SETTINGS; 1310195534Sscottl cts.transport = path->device->transport; 1311195534Sscottl cts.transport_version = path->device->transport_version; 1312195534Sscottl cts.protocol = path->device->protocol; 1313195534Sscottl cts.protocol_version = path->device->protocol_version; 1314195534Sscottl cts.proto_specific.valid = 0; 1315203376Smav if (ident_buf) { 1316203376Smav if (path->device->transport == XPORT_ATA) { 1317203376Smav cts.xport_specific.ata.atapi = 1318203376Smav ((ident_buf->config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_16) ? 16 : 1319203376Smav ((ident_buf->config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_12) ? 12 : 0; 1320203376Smav cts.xport_specific.ata.valid = CTS_ATA_VALID_ATAPI; 1321203376Smav } else { 1322203376Smav cts.xport_specific.sata.atapi = 1323203376Smav ((ident_buf->config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_16) ? 16 : 1324203376Smav ((ident_buf->config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_12) ? 12 : 0; 1325203376Smav cts.xport_specific.sata.valid = CTS_SATA_VALID_ATAPI; 1326203376Smav } 1327203376Smav } else 1328203376Smav cts.xport_specific.valid = 0; 1329195534Sscottl xpt_action((union ccb *)&cts); 1330195534Sscottl} 1331195534Sscottl 1332195534Sscottlstatic void 1333195534Sscottlata_action(union ccb *start_ccb) 1334195534Sscottl{ 1335195534Sscottl 1336195534Sscottl switch (start_ccb->ccb_h.func_code) { 1337195534Sscottl case XPT_SET_TRAN_SETTINGS: 1338195534Sscottl { 1339199178Smav ata_set_transfer_settings(&start_ccb->cts, 1340195534Sscottl start_ccb->ccb_h.path->device, 1341195534Sscottl /*async_update*/FALSE); 1342195534Sscottl break; 1343195534Sscottl } 1344195534Sscottl case XPT_SCAN_BUS: 1345195534Sscottl ata_scan_bus(start_ccb->ccb_h.path->periph, start_ccb); 1346195534Sscottl break; 1347195534Sscottl case XPT_SCAN_LUN: 1348195534Sscottl ata_scan_lun(start_ccb->ccb_h.path->periph, 1349195534Sscottl start_ccb->ccb_h.path, start_ccb->crcn.flags, 1350195534Sscottl start_ccb); 1351195534Sscottl break; 1352195534Sscottl case XPT_GET_TRAN_SETTINGS: 1353195534Sscottl { 1354195534Sscottl struct cam_sim *sim; 1355195534Sscottl 1356195534Sscottl sim = start_ccb->ccb_h.path->bus->sim; 1357195534Sscottl (*(sim->sim_action))(sim, start_ccb); 1358195534Sscottl break; 1359195534Sscottl } 1360203376Smav case XPT_SCSI_IO: 1361203376Smav { 1362203376Smav struct cam_ed *device; 1363203376Smav u_int maxlen = 0; 1364203376Smav 1365203376Smav device = start_ccb->ccb_h.path->device; 1366203376Smav if (device->protocol == PROTO_SCSI && 1367203376Smav (device->flags & CAM_DEV_IDENTIFY_DATA_VALID)) { 1368203376Smav uint16_t p = 1369203376Smav device->ident_data.config & ATA_PROTO_MASK; 1370203376Smav 1371203376Smav maxlen = (p == ATA_PROTO_ATAPI_16) ? 16 : 1372203376Smav (p == ATA_PROTO_ATAPI_12) ? 12 : 0; 1373203376Smav } 1374203376Smav if (start_ccb->csio.cdb_len > maxlen) { 1375203376Smav start_ccb->ccb_h.status = CAM_REQ_INVALID; 1376203376Smav xpt_done(start_ccb); 1377203376Smav break; 1378203376Smav } 1379203376Smav /* FALLTHROUGH */ 1380203376Smav } 1381195534Sscottl default: 1382195534Sscottl xpt_action_default(start_ccb); 1383195534Sscottl break; 1384195534Sscottl } 1385195534Sscottl} 1386195534Sscottl 1387195534Sscottlstatic void 1388199178Smavata_set_transfer_settings(struct ccb_trans_settings *cts, struct cam_ed *device, 1389195534Sscottl int async_update) 1390195534Sscottl{ 1391195534Sscottl struct ccb_pathinq cpi; 1392195534Sscottl struct ccb_trans_settings cur_cts; 1393195534Sscottl struct ccb_trans_settings_scsi *scsi; 1394195534Sscottl struct ccb_trans_settings_scsi *cur_scsi; 1395195534Sscottl struct cam_sim *sim; 1396195534Sscottl struct scsi_inquiry_data *inq_data; 1397195534Sscottl 1398195534Sscottl if (device == NULL) { 1399195534Sscottl cts->ccb_h.status = CAM_PATH_INVALID; 1400195534Sscottl xpt_done((union ccb *)cts); 1401195534Sscottl return; 1402195534Sscottl } 1403195534Sscottl 1404195534Sscottl if (cts->protocol == PROTO_UNKNOWN 1405195534Sscottl || cts->protocol == PROTO_UNSPECIFIED) { 1406195534Sscottl cts->protocol = device->protocol; 1407195534Sscottl cts->protocol_version = device->protocol_version; 1408195534Sscottl } 1409195534Sscottl 1410195534Sscottl if (cts->protocol_version == PROTO_VERSION_UNKNOWN 1411195534Sscottl || cts->protocol_version == PROTO_VERSION_UNSPECIFIED) 1412195534Sscottl cts->protocol_version = device->protocol_version; 1413195534Sscottl 1414195534Sscottl if (cts->protocol != device->protocol) { 1415195534Sscottl xpt_print(cts->ccb_h.path, "Uninitialized Protocol %x:%x?\n", 1416195534Sscottl cts->protocol, device->protocol); 1417195534Sscottl cts->protocol = device->protocol; 1418195534Sscottl } 1419195534Sscottl 1420195534Sscottl if (cts->protocol_version > device->protocol_version) { 1421195534Sscottl if (bootverbose) { 1422195534Sscottl xpt_print(cts->ccb_h.path, "Down reving Protocol " 1423195534Sscottl "Version from %d to %d?\n", cts->protocol_version, 1424195534Sscottl device->protocol_version); 1425195534Sscottl } 1426195534Sscottl cts->protocol_version = device->protocol_version; 1427195534Sscottl } 1428195534Sscottl 1429195534Sscottl if (cts->transport == XPORT_UNKNOWN 1430195534Sscottl || cts->transport == XPORT_UNSPECIFIED) { 1431195534Sscottl cts->transport = device->transport; 1432195534Sscottl cts->transport_version = device->transport_version; 1433195534Sscottl } 1434195534Sscottl 1435195534Sscottl if (cts->transport_version == XPORT_VERSION_UNKNOWN 1436195534Sscottl || cts->transport_version == XPORT_VERSION_UNSPECIFIED) 1437195534Sscottl cts->transport_version = device->transport_version; 1438195534Sscottl 1439195534Sscottl if (cts->transport != device->transport) { 1440195534Sscottl xpt_print(cts->ccb_h.path, "Uninitialized Transport %x:%x?\n", 1441195534Sscottl cts->transport, device->transport); 1442195534Sscottl cts->transport = device->transport; 1443195534Sscottl } 1444195534Sscottl 1445195534Sscottl if (cts->transport_version > device->transport_version) { 1446195534Sscottl if (bootverbose) { 1447195534Sscottl xpt_print(cts->ccb_h.path, "Down reving Transport " 1448195534Sscottl "Version from %d to %d?\n", cts->transport_version, 1449195534Sscottl device->transport_version); 1450195534Sscottl } 1451195534Sscottl cts->transport_version = device->transport_version; 1452195534Sscottl } 1453195534Sscottl 1454195534Sscottl sim = cts->ccb_h.path->bus->sim; 1455195534Sscottl 1456195534Sscottl /* 1457195534Sscottl * Nothing more of interest to do unless 1458195534Sscottl * this is a device connected via the 1459195534Sscottl * SCSI protocol. 1460195534Sscottl */ 1461195534Sscottl if (cts->protocol != PROTO_SCSI) { 1462195534Sscottl if (async_update == FALSE) 1463195534Sscottl (*(sim->sim_action))(sim, (union ccb *)cts); 1464195534Sscottl return; 1465195534Sscottl } 1466195534Sscottl 1467195534Sscottl inq_data = &device->inq_data; 1468195534Sscottl scsi = &cts->proto_specific.scsi; 1469203108Smav xpt_setup_ccb(&cpi.ccb_h, cts->ccb_h.path, CAM_PRIORITY_NONE); 1470195534Sscottl cpi.ccb_h.func_code = XPT_PATH_INQ; 1471195534Sscottl xpt_action((union ccb *)&cpi); 1472195534Sscottl 1473195534Sscottl /* SCSI specific sanity checking */ 1474195534Sscottl if ((cpi.hba_inquiry & PI_TAG_ABLE) == 0 1475195534Sscottl || (INQ_DATA_TQ_ENABLED(inq_data)) == 0 1476195534Sscottl || (device->queue_flags & SCP_QUEUE_DQUE) != 0 1477195534Sscottl || (device->mintags == 0)) { 1478195534Sscottl /* 1479195534Sscottl * Can't tag on hardware that doesn't support tags, 1480195534Sscottl * doesn't have it enabled, or has broken tag support. 1481195534Sscottl */ 1482195534Sscottl scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 1483195534Sscottl } 1484195534Sscottl 1485195534Sscottl if (async_update == FALSE) { 1486195534Sscottl /* 1487195534Sscottl * Perform sanity checking against what the 1488195534Sscottl * controller and device can do. 1489195534Sscottl */ 1490203108Smav xpt_setup_ccb(&cur_cts.ccb_h, cts->ccb_h.path, CAM_PRIORITY_NONE); 1491195534Sscottl cur_cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 1492195534Sscottl cur_cts.type = cts->type; 1493195534Sscottl xpt_action((union ccb *)&cur_cts); 1494195534Sscottl if ((cur_cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 1495195534Sscottl return; 1496195534Sscottl } 1497195534Sscottl cur_scsi = &cur_cts.proto_specific.scsi; 1498195534Sscottl if ((scsi->valid & CTS_SCSI_VALID_TQ) == 0) { 1499195534Sscottl scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 1500195534Sscottl scsi->flags |= cur_scsi->flags & CTS_SCSI_FLAGS_TAG_ENB; 1501195534Sscottl } 1502195534Sscottl if ((cur_scsi->valid & CTS_SCSI_VALID_TQ) == 0) 1503195534Sscottl scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 1504195534Sscottl } 1505195534Sscottl 1506195534Sscottl if (cts->type == CTS_TYPE_CURRENT_SETTINGS 1507195534Sscottl && (scsi->valid & CTS_SCSI_VALID_TQ) != 0) { 1508195534Sscottl int device_tagenb; 1509195534Sscottl 1510195534Sscottl /* 1511195534Sscottl * If we are transitioning from tags to no-tags or 1512195534Sscottl * vice-versa, we need to carefully freeze and restart 1513195534Sscottl * the queue so that we don't overlap tagged and non-tagged 1514195534Sscottl * commands. We also temporarily stop tags if there is 1515195534Sscottl * a change in transfer negotiation settings to allow 1516195534Sscottl * "tag-less" negotiation. 1517195534Sscottl */ 1518195534Sscottl if ((device->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 1519195534Sscottl || (device->inq_flags & SID_CmdQue) != 0) 1520195534Sscottl device_tagenb = TRUE; 1521195534Sscottl else 1522195534Sscottl device_tagenb = FALSE; 1523195534Sscottl 1524195534Sscottl if (((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0 1525195534Sscottl && device_tagenb == FALSE) 1526195534Sscottl || ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) == 0 1527195534Sscottl && device_tagenb == TRUE)) { 1528195534Sscottl 1529195534Sscottl if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) { 1530195534Sscottl /* 1531195534Sscottl * Delay change to use tags until after a 1532195534Sscottl * few commands have gone to this device so 1533195534Sscottl * the controller has time to perform transfer 1534195534Sscottl * negotiations without tagged messages getting 1535195534Sscottl * in the way. 1536195534Sscottl */ 1537195534Sscottl device->tag_delay_count = CAM_TAG_DELAY_COUNT; 1538195534Sscottl device->flags |= CAM_DEV_TAG_AFTER_COUNT; 1539195534Sscottl } else { 1540199178Smav xpt_stop_tags(cts->ccb_h.path); 1541195534Sscottl } 1542195534Sscottl } 1543195534Sscottl } 1544195534Sscottl if (async_update == FALSE) 1545195534Sscottl (*(sim->sim_action))(sim, (union ccb *)cts); 1546195534Sscottl} 1547195534Sscottl 1548195534Sscottl/* 1549195534Sscottl * Handle any per-device event notifications that require action by the XPT. 1550195534Sscottl */ 1551195534Sscottlstatic void 1552195534Sscottlata_dev_async(u_int32_t async_code, struct cam_eb *bus, struct cam_et *target, 1553195534Sscottl struct cam_ed *device, void *async_arg) 1554195534Sscottl{ 1555195534Sscottl cam_status status; 1556195534Sscottl struct cam_path newpath; 1557195534Sscottl 1558195534Sscottl /* 1559195534Sscottl * We only need to handle events for real devices. 1560195534Sscottl */ 1561195534Sscottl if (target->target_id == CAM_TARGET_WILDCARD 1562195534Sscottl || device->lun_id == CAM_LUN_WILDCARD) 1563195534Sscottl return; 1564195534Sscottl 1565195534Sscottl /* 1566195534Sscottl * We need our own path with wildcards expanded to 1567195534Sscottl * handle certain types of events. 1568195534Sscottl */ 1569195534Sscottl if ((async_code == AC_SENT_BDR) 1570195534Sscottl || (async_code == AC_BUS_RESET) 1571195534Sscottl || (async_code == AC_INQ_CHANGED)) 1572195534Sscottl status = xpt_compile_path(&newpath, NULL, 1573195534Sscottl bus->path_id, 1574195534Sscottl target->target_id, 1575195534Sscottl device->lun_id); 1576195534Sscottl else 1577195534Sscottl status = CAM_REQ_CMP_ERR; 1578195534Sscottl 1579195534Sscottl if (status == CAM_REQ_CMP) { 1580195534Sscottl if (async_code == AC_INQ_CHANGED) { 1581195534Sscottl /* 1582195534Sscottl * We've sent a start unit command, or 1583195534Sscottl * something similar to a device that 1584195534Sscottl * may have caused its inquiry data to 1585195534Sscottl * change. So we re-scan the device to 1586195534Sscottl * refresh the inquiry data for it. 1587195534Sscottl */ 1588195534Sscottl ata_scan_lun(newpath.periph, &newpath, 1589195534Sscottl CAM_EXPECT_INQ_CHANGE, NULL); 1590203108Smav } else { 1591203108Smav /* We need to reinitialize device after reset. */ 1592203108Smav ata_scan_lun(newpath.periph, &newpath, 1593203108Smav 0, NULL); 1594195534Sscottl } 1595195534Sscottl xpt_release_path(&newpath); 1596198748Smav } else if (async_code == AC_LOST_DEVICE && 1597198748Smav (device->flags & CAM_DEV_UNCONFIGURED) == 0) { 1598195534Sscottl device->flags |= CAM_DEV_UNCONFIGURED; 1599198748Smav xpt_release_device(device); 1600195534Sscottl } else if (async_code == AC_TRANSFER_NEG) { 1601195534Sscottl struct ccb_trans_settings *settings; 1602195534Sscottl 1603195534Sscottl settings = (struct ccb_trans_settings *)async_arg; 1604199178Smav ata_set_transfer_settings(settings, device, 1605195534Sscottl /*async_update*/TRUE); 1606195534Sscottl } 1607195534Sscottl} 1608195534Sscottl 1609