ata_xpt.c revision 196659
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 196659 2009-08-30 16:31:25Z 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/md5.h> 41195534Sscottl#include <sys/interrupt.h> 42195534Sscottl#include <sys/sbuf.h> 43195534Sscottl 44195534Sscottl#include <sys/lock.h> 45195534Sscottl#include <sys/mutex.h> 46195534Sscottl#include <sys/sysctl.h> 47195534Sscottl 48195534Sscottl#ifdef PC98 49195534Sscottl#include <pc98/pc98/pc98_machdep.h> /* geometry translation */ 50195534Sscottl#endif 51195534Sscottl 52195534Sscottl#include <cam/cam.h> 53195534Sscottl#include <cam/cam_ccb.h> 54195534Sscottl#include <cam/cam_queue.h> 55195534Sscottl#include <cam/cam_periph.h> 56195534Sscottl#include <cam/cam_sim.h> 57195534Sscottl#include <cam/cam_xpt.h> 58195534Sscottl#include <cam/cam_xpt_sim.h> 59195534Sscottl#include <cam/cam_xpt_periph.h> 60195534Sscottl#include <cam/cam_xpt_internal.h> 61195534Sscottl#include <cam/cam_debug.h> 62195534Sscottl 63195534Sscottl#include <cam/scsi/scsi_all.h> 64195534Sscottl#include <cam/scsi/scsi_message.h> 65195534Sscottl#include <cam/scsi/scsi_pass.h> 66195534Sscottl#include <cam/ata/ata_all.h> 67195534Sscottl#include <machine/stdarg.h> /* for xpt_print below */ 68195534Sscottl#include "opt_cam.h" 69195534Sscottl 70195534Sscottlstruct scsi_quirk_entry { 71195534Sscottl struct scsi_inquiry_pattern inq_pat; 72195534Sscottl u_int8_t quirks; 73195534Sscottl#define CAM_QUIRK_NOLUNS 0x01 74195534Sscottl#define CAM_QUIRK_NOSERIAL 0x02 75195534Sscottl#define CAM_QUIRK_HILUNS 0x04 76195534Sscottl#define CAM_QUIRK_NOHILUNS 0x08 77195534Sscottl u_int mintags; 78195534Sscottl u_int maxtags; 79195534Sscottl}; 80195534Sscottl#define SCSI_QUIRK(dev) ((struct scsi_quirk_entry *)((dev)->quirk)) 81195534Sscottl 82195534Sscottlstatic periph_init_t probe_periph_init; 83195534Sscottl 84195534Sscottlstatic struct periph_driver probe_driver = 85195534Sscottl{ 86195653Smav probe_periph_init, "aprobe", 87195534Sscottl TAILQ_HEAD_INITIALIZER(probe_driver.units) 88195534Sscottl}; 89195534Sscottl 90195653SmavPERIPHDRIVER_DECLARE(aprobe, probe_driver); 91195534Sscottl 92195534Sscottltypedef enum { 93195534Sscottl PROBE_RESET, 94195534Sscottl PROBE_IDENTIFY, 95195534Sscottl PROBE_SETMODE, 96195534Sscottl PROBE_INQUIRY, 97195534Sscottl PROBE_FULL_INQUIRY, 98195534Sscottl PROBE_PM_PID, 99195534Sscottl PROBE_PM_PRV, 100195534Sscottl PROBE_PM_PORTS, 101195534Sscottl PROBE_PM_RESET, 102195534Sscottl PROBE_PM_CONNECT, 103195534Sscottl PROBE_PM_CHECK, 104195534Sscottl PROBE_PM_CLEAR, 105195534Sscottl PROBE_INVALID 106195534Sscottl} probe_action; 107195534Sscottl 108195534Sscottlstatic char *probe_action_text[] = { 109195534Sscottl "PROBE_RESET", 110195534Sscottl "PROBE_IDENTIFY", 111195534Sscottl "PROBE_SETMODE", 112195534Sscottl "PROBE_INQUIRY", 113195534Sscottl "PROBE_FULL_INQUIRY", 114195534Sscottl "PROBE_PM_PID", 115195534Sscottl "PROBE_PM_PRV", 116195534Sscottl "PROBE_PM_PORTS", 117195534Sscottl "PROBE_PM_RESET", 118195534Sscottl "PROBE_PM_CONNECT", 119195534Sscottl "PROBE_PM_CHECK", 120195534Sscottl "PROBE_PM_CLEAR", 121195534Sscottl "PROBE_INVALID" 122195534Sscottl}; 123195534Sscottl 124195534Sscottl#define PROBE_SET_ACTION(softc, newaction) \ 125195534Sscottldo { \ 126195534Sscottl char **text; \ 127195534Sscottl text = probe_action_text; \ 128195534Sscottl CAM_DEBUG((softc)->periph->path, CAM_DEBUG_INFO, \ 129195534Sscottl ("Probe %s to %s\n", text[(softc)->action], \ 130195534Sscottl text[(newaction)])); \ 131195534Sscottl (softc)->action = (newaction); \ 132195534Sscottl} while(0) 133195534Sscottl 134195534Sscottltypedef enum { 135195534Sscottl PROBE_NO_ANNOUNCE = 0x04 136195534Sscottl} probe_flags; 137195534Sscottl 138195534Sscottltypedef struct { 139195534Sscottl TAILQ_HEAD(, ccb_hdr) request_ccbs; 140195534Sscottl probe_action action; 141195534Sscottl union ccb saved_ccb; 142195534Sscottl probe_flags flags; 143195534Sscottl u_int8_t digest[16]; 144195534Sscottl uint32_t pm_pid; 145195534Sscottl uint32_t pm_prv; 146195534Sscottl int pm_ports; 147195534Sscottl int pm_step; 148195534Sscottl int pm_try; 149195534Sscottl struct cam_periph *periph; 150195534Sscottl} probe_softc; 151195534Sscottl 152195534Sscottlstatic struct scsi_quirk_entry scsi_quirk_table[] = 153195534Sscottl{ 154195534Sscottl { 155195534Sscottl /* Default tagged queuing parameters for all devices */ 156195534Sscottl { 157195534Sscottl T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED, 158195534Sscottl /*vendor*/"*", /*product*/"*", /*revision*/"*" 159195534Sscottl }, 160195534Sscottl /*quirks*/0, /*mintags*/2, /*maxtags*/32 161195534Sscottl }, 162195534Sscottl}; 163195534Sscottl 164195534Sscottlstatic const int scsi_quirk_table_size = 165195534Sscottl sizeof(scsi_quirk_table) / sizeof(*scsi_quirk_table); 166195534Sscottl 167195534Sscottlstatic cam_status proberegister(struct cam_periph *periph, 168195534Sscottl void *arg); 169195534Sscottlstatic void probeschedule(struct cam_periph *probe_periph); 170195534Sscottlstatic void probestart(struct cam_periph *periph, union ccb *start_ccb); 171195534Sscottl//static void proberequestdefaultnegotiation(struct cam_periph *periph); 172195534Sscottl//static int proberequestbackoff(struct cam_periph *periph, 173195534Sscottl// struct cam_ed *device); 174195534Sscottlstatic void probedone(struct cam_periph *periph, union ccb *done_ccb); 175195534Sscottlstatic void probecleanup(struct cam_periph *periph); 176195534Sscottlstatic void scsi_find_quirk(struct cam_ed *device); 177195534Sscottlstatic void ata_scan_bus(struct cam_periph *periph, union ccb *ccb); 178195534Sscottlstatic void ata_scan_lun(struct cam_periph *periph, 179195534Sscottl struct cam_path *path, cam_flags flags, 180195534Sscottl union ccb *ccb); 181195534Sscottlstatic void xptscandone(struct cam_periph *periph, union ccb *done_ccb); 182195534Sscottlstatic struct cam_ed * 183195534Sscottl ata_alloc_device(struct cam_eb *bus, struct cam_et *target, 184195534Sscottl lun_id_t lun_id); 185195534Sscottlstatic void ata_device_transport(struct cam_path *path); 186195534Sscottlstatic void scsi_set_transfer_settings(struct ccb_trans_settings *cts, 187195534Sscottl struct cam_ed *device, 188195534Sscottl int async_update); 189195534Sscottlstatic void scsi_toggle_tags(struct cam_path *path); 190195534Sscottlstatic void ata_dev_async(u_int32_t async_code, 191195534Sscottl struct cam_eb *bus, 192195534Sscottl struct cam_et *target, 193195534Sscottl struct cam_ed *device, 194195534Sscottl void *async_arg); 195195534Sscottlstatic void ata_action(union ccb *start_ccb); 196195534Sscottl 197195534Sscottlstatic struct xpt_xport ata_xport = { 198195534Sscottl .alloc_device = ata_alloc_device, 199195534Sscottl .action = ata_action, 200195534Sscottl .async = ata_dev_async, 201195534Sscottl}; 202195534Sscottl 203195534Sscottlstruct xpt_xport * 204195534Sscottlata_get_xport(void) 205195534Sscottl{ 206195534Sscottl return (&ata_xport); 207195534Sscottl} 208195534Sscottl 209195534Sscottlstatic void 210195534Sscottlprobe_periph_init() 211195534Sscottl{ 212195534Sscottl} 213195534Sscottl 214195534Sscottlstatic cam_status 215195534Sscottlproberegister(struct cam_periph *periph, void *arg) 216195534Sscottl{ 217195534Sscottl union ccb *request_ccb; /* CCB representing the probe request */ 218195534Sscottl cam_status status; 219195534Sscottl probe_softc *softc; 220195534Sscottl 221195534Sscottl request_ccb = (union ccb *)arg; 222195534Sscottl if (periph == NULL) { 223195534Sscottl printf("proberegister: periph was NULL!!\n"); 224195534Sscottl return(CAM_REQ_CMP_ERR); 225195534Sscottl } 226195534Sscottl 227195534Sscottl if (request_ccb == NULL) { 228195534Sscottl printf("proberegister: no probe CCB, " 229195534Sscottl "can't register device\n"); 230195534Sscottl return(CAM_REQ_CMP_ERR); 231195534Sscottl } 232195534Sscottl 233195534Sscottl softc = (probe_softc *)malloc(sizeof(*softc), M_CAMXPT, M_NOWAIT); 234195534Sscottl 235195534Sscottl if (softc == NULL) { 236195534Sscottl printf("proberegister: Unable to probe new device. " 237195534Sscottl "Unable to allocate softc\n"); 238195534Sscottl return(CAM_REQ_CMP_ERR); 239195534Sscottl } 240195534Sscottl TAILQ_INIT(&softc->request_ccbs); 241195534Sscottl TAILQ_INSERT_TAIL(&softc->request_ccbs, &request_ccb->ccb_h, 242195534Sscottl periph_links.tqe); 243195534Sscottl softc->flags = 0; 244195534Sscottl periph->softc = softc; 245195534Sscottl softc->periph = periph; 246195534Sscottl softc->action = PROBE_INVALID; 247195534Sscottl status = cam_periph_acquire(periph); 248195534Sscottl if (status != CAM_REQ_CMP) { 249195534Sscottl return (status); 250195534Sscottl } 251195534Sscottl 252195534Sscottl 253195534Sscottl /* 254195534Sscottl * Ensure we've waited at least a bus settle 255195534Sscottl * delay before attempting to probe the device. 256195534Sscottl * For HBAs that don't do bus resets, this won't make a difference. 257195534Sscottl */ 258195534Sscottl cam_periph_freeze_after_event(periph, &periph->path->bus->last_reset, 259195534Sscottl scsi_delay); 260195534Sscottl probeschedule(periph); 261195534Sscottl return(CAM_REQ_CMP); 262195534Sscottl} 263195534Sscottl 264195534Sscottlstatic void 265195534Sscottlprobeschedule(struct cam_periph *periph) 266195534Sscottl{ 267195534Sscottl struct ccb_pathinq cpi; 268195534Sscottl union ccb *ccb; 269195534Sscottl probe_softc *softc; 270195534Sscottl 271195534Sscottl softc = (probe_softc *)periph->softc; 272195534Sscottl ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs); 273195534Sscottl 274195534Sscottl xpt_setup_ccb(&cpi.ccb_h, periph->path, /*priority*/1); 275195534Sscottl cpi.ccb_h.func_code = XPT_PATH_INQ; 276195534Sscottl xpt_action((union ccb *)&cpi); 277195534Sscottl 278195534Sscottl if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) 279195534Sscottl PROBE_SET_ACTION(softc, PROBE_RESET); 280195534Sscottl else if (periph->path->device->protocol == PROTO_SATAPM) 281195534Sscottl PROBE_SET_ACTION(softc, PROBE_PM_PID); 282195534Sscottl else 283195534Sscottl PROBE_SET_ACTION(softc, PROBE_IDENTIFY); 284195534Sscottl 285195534Sscottl if (ccb->crcn.flags & CAM_EXPECT_INQ_CHANGE) 286195534Sscottl softc->flags |= PROBE_NO_ANNOUNCE; 287195534Sscottl else 288195534Sscottl softc->flags &= ~PROBE_NO_ANNOUNCE; 289195534Sscottl 290195534Sscottl xpt_schedule(periph, ccb->ccb_h.pinfo.priority); 291195534Sscottl} 292195534Sscottl 293195534Sscottlstatic void 294195534Sscottlprobestart(struct cam_periph *periph, union ccb *start_ccb) 295195534Sscottl{ 296195534Sscottl /* Probe the device that our peripheral driver points to */ 297195534Sscottl struct ccb_ataio *ataio; 298195534Sscottl struct ccb_scsiio *csio; 299195534Sscottl struct ccb_trans_settings cts; 300195534Sscottl probe_softc *softc; 301195534Sscottl 302195534Sscottl CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probestart\n")); 303195534Sscottl 304195534Sscottl softc = (probe_softc *)periph->softc; 305195534Sscottl ataio = &start_ccb->ataio; 306195534Sscottl csio = &start_ccb->csio; 307195534Sscottl 308195534Sscottl switch (softc->action) { 309195534Sscottl case PROBE_RESET: 310195534Sscottl if (start_ccb->ccb_h.target_id == 15) { 311195534Sscottl /* Report SIM that we have no knowledge about PM presence. */ 312195534Sscottl bzero(&cts, sizeof(cts)); 313195534Sscottl xpt_setup_ccb(&cts.ccb_h, start_ccb->ccb_h.path, 1); 314195534Sscottl cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 315195534Sscottl cts.type = CTS_TYPE_CURRENT_SETTINGS; 316195534Sscottl cts.xport_specific.sata.pm_present = 0; 317195534Sscottl cts.xport_specific.sata.valid = CTS_SATA_VALID_PM; 318195534Sscottl xpt_action((union ccb *)&cts); 319195534Sscottl } 320195534Sscottl cam_fill_ataio(ataio, 321195534Sscottl 0, 322195534Sscottl probedone, 323195534Sscottl /*flags*/CAM_DIR_NONE, 324195534Sscottl MSG_SIMPLE_Q_TAG, 325195534Sscottl /*data_ptr*/NULL, 326195534Sscottl /*dxfer_len*/0, 327195534Sscottl (start_ccb->ccb_h.target_id == 15 ? 3 : 15) * 1000); 328195534Sscottl ata_reset_cmd(ataio); 329195534Sscottl break; 330195534Sscottl case PROBE_IDENTIFY: 331195534Sscottl { 332195534Sscottl struct ata_params *ident_buf = 333195534Sscottl &periph->path->device->ident_data; 334195534Sscottl 335195534Sscottl if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) == 0) { 336195534Sscottl /* Prepare check that it is the same device. */ 337195534Sscottl MD5_CTX context; 338195534Sscottl 339195534Sscottl MD5Init(&context); 340195534Sscottl MD5Update(&context, 341195534Sscottl (unsigned char *)ident_buf->model, 342195534Sscottl sizeof(ident_buf->model)); 343195534Sscottl MD5Update(&context, 344195534Sscottl (unsigned char *)ident_buf->revision, 345195534Sscottl sizeof(ident_buf->revision)); 346195534Sscottl MD5Update(&context, 347195534Sscottl (unsigned char *)ident_buf->serial, 348195534Sscottl sizeof(ident_buf->serial)); 349195534Sscottl MD5Final(softc->digest, &context); 350195534Sscottl } 351195534Sscottl cam_fill_ataio(ataio, 352195534Sscottl 1, 353195534Sscottl probedone, 354195534Sscottl /*flags*/CAM_DIR_IN, 355195534Sscottl MSG_SIMPLE_Q_TAG, 356195534Sscottl /*data_ptr*/(u_int8_t *)ident_buf, 357195534Sscottl /*dxfer_len*/sizeof(struct ata_params), 358195534Sscottl 30 * 1000); 359195534Sscottl if (periph->path->device->protocol == PROTO_ATA) 360196659Smav ata_28bit_cmd(ataio, ATA_ATA_IDENTIFY, 0, 0, 0); 361195534Sscottl else 362196659Smav ata_28bit_cmd(ataio, ATA_ATAPI_IDENTIFY, 0, 0, 0); 363195534Sscottl break; 364195534Sscottl } 365195534Sscottl case PROBE_SETMODE: 366195534Sscottl { 367195534Sscottl struct ata_params *ident_buf = 368195534Sscottl &periph->path->device->ident_data; 369195534Sscottl 370195534Sscottl cam_fill_ataio(ataio, 371195534Sscottl 1, 372195534Sscottl probedone, 373196353Smav /*flags*/CAM_DIR_NONE, 374196353Smav 0, 375196353Smav /*data_ptr*/NULL, 376196353Smav /*dxfer_len*/0, 377195534Sscottl 30 * 1000); 378196659Smav ata_28bit_cmd(ataio, ATA_SETFEATURES, ATA_SF_SETXFER, 0, 379195534Sscottl ata_max_mode(ident_buf, ATA_UDMA6, ATA_UDMA6)); 380195534Sscottl break; 381195534Sscottl } 382195534Sscottl case PROBE_INQUIRY: 383195534Sscottl case PROBE_FULL_INQUIRY: 384195534Sscottl { 385195534Sscottl u_int inquiry_len; 386195534Sscottl struct scsi_inquiry_data *inq_buf = 387195534Sscottl &periph->path->device->inq_data; 388195534Sscottl 389195534Sscottl if (softc->action == PROBE_INQUIRY) 390195534Sscottl inquiry_len = SHORT_INQUIRY_LENGTH; 391195534Sscottl else 392195534Sscottl inquiry_len = SID_ADDITIONAL_LENGTH(inq_buf); 393195534Sscottl /* 394195534Sscottl * Some parallel SCSI devices fail to send an 395195534Sscottl * ignore wide residue message when dealing with 396195534Sscottl * odd length inquiry requests. Round up to be 397195534Sscottl * safe. 398195534Sscottl */ 399195534Sscottl inquiry_len = roundup2(inquiry_len, 2); 400195534Sscottl scsi_inquiry(csio, 401195534Sscottl /*retries*/1, 402195534Sscottl probedone, 403195534Sscottl MSG_SIMPLE_Q_TAG, 404195534Sscottl (u_int8_t *)inq_buf, 405195534Sscottl inquiry_len, 406195534Sscottl /*evpd*/FALSE, 407195534Sscottl /*page_code*/0, 408195534Sscottl SSD_MIN_SIZE, 409195534Sscottl /*timeout*/60 * 1000); 410195534Sscottl break; 411195534Sscottl } 412195534Sscottl case PROBE_PM_PID: 413195534Sscottl cam_fill_ataio(ataio, 414195534Sscottl 1, 415195534Sscottl probedone, 416195534Sscottl /*flags*/CAM_DIR_NONE, 417195534Sscottl MSG_SIMPLE_Q_TAG, 418195534Sscottl /*data_ptr*/NULL, 419195534Sscottl /*dxfer_len*/0, 420195534Sscottl 10 * 1000); 421195534Sscottl ata_pm_read_cmd(ataio, 0, 15); 422195534Sscottl break; 423195534Sscottl case PROBE_PM_PRV: 424195534Sscottl cam_fill_ataio(ataio, 425195534Sscottl 1, 426195534Sscottl probedone, 427195534Sscottl /*flags*/CAM_DIR_NONE, 428195534Sscottl MSG_SIMPLE_Q_TAG, 429195534Sscottl /*data_ptr*/NULL, 430195534Sscottl /*dxfer_len*/0, 431195534Sscottl 10 * 1000); 432195534Sscottl ata_pm_read_cmd(ataio, 1, 15); 433195534Sscottl break; 434195534Sscottl case PROBE_PM_PORTS: 435195534Sscottl cam_fill_ataio(ataio, 436195534Sscottl 1, 437195534Sscottl probedone, 438195534Sscottl /*flags*/CAM_DIR_NONE, 439195534Sscottl MSG_SIMPLE_Q_TAG, 440195534Sscottl /*data_ptr*/NULL, 441195534Sscottl /*dxfer_len*/0, 442195534Sscottl 10 * 1000); 443195534Sscottl ata_pm_read_cmd(ataio, 2, 15); 444195534Sscottl break; 445195534Sscottl case PROBE_PM_RESET: 446195534Sscottl { 447195534Sscottl struct ata_params *ident_buf = 448195534Sscottl &periph->path->device->ident_data; 449195534Sscottl cam_fill_ataio(ataio, 450195534Sscottl 1, 451195534Sscottl probedone, 452195534Sscottl /*flags*/CAM_DIR_NONE, 453195534Sscottl MSG_SIMPLE_Q_TAG, 454195534Sscottl /*data_ptr*/NULL, 455195534Sscottl /*dxfer_len*/0, 456195534Sscottl 10 * 1000); 457195534Sscottl ata_pm_write_cmd(ataio, 2, softc->pm_step, 458195534Sscottl (ident_buf->cylinders & (1 << softc->pm_step)) ? 0 : 1); 459195534Sscottlprintf("PM RESET %d %04x %d\n", softc->pm_step, ident_buf->cylinders, 460195534Sscottl (ident_buf->cylinders & (1 << softc->pm_step)) ? 0 : 1); 461195534Sscottl break; 462195534Sscottl } 463195534Sscottl case PROBE_PM_CONNECT: 464195534Sscottl cam_fill_ataio(ataio, 465195534Sscottl 1, 466195534Sscottl probedone, 467195534Sscottl /*flags*/CAM_DIR_NONE, 468195534Sscottl MSG_SIMPLE_Q_TAG, 469195534Sscottl /*data_ptr*/NULL, 470195534Sscottl /*dxfer_len*/0, 471195534Sscottl 10 * 1000); 472195534Sscottl ata_pm_write_cmd(ataio, 2, softc->pm_step, 0); 473195534Sscottl break; 474195534Sscottl case PROBE_PM_CHECK: 475195534Sscottl cam_fill_ataio(ataio, 476195534Sscottl 1, 477195534Sscottl probedone, 478195534Sscottl /*flags*/CAM_DIR_NONE, 479195534Sscottl MSG_SIMPLE_Q_TAG, 480195534Sscottl /*data_ptr*/NULL, 481195534Sscottl /*dxfer_len*/0, 482195534Sscottl 10 * 1000); 483195534Sscottl ata_pm_read_cmd(ataio, 0, softc->pm_step); 484195534Sscottl break; 485195534Sscottl case PROBE_PM_CLEAR: 486195534Sscottl cam_fill_ataio(ataio, 487195534Sscottl 1, 488195534Sscottl probedone, 489195534Sscottl /*flags*/CAM_DIR_NONE, 490195534Sscottl MSG_SIMPLE_Q_TAG, 491195534Sscottl /*data_ptr*/NULL, 492195534Sscottl /*dxfer_len*/0, 493195534Sscottl 10 * 1000); 494195534Sscottl ata_pm_write_cmd(ataio, 1, softc->pm_step, 0xFFFFFFFF); 495195534Sscottl break; 496195534Sscottl case PROBE_INVALID: 497195534Sscottl CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_INFO, 498195534Sscottl ("probestart: invalid action state\n")); 499195534Sscottl default: 500195534Sscottl break; 501195534Sscottl } 502195534Sscottl xpt_action(start_ccb); 503195534Sscottl} 504195534Sscottl#if 0 505195534Sscottlstatic void 506195534Sscottlproberequestdefaultnegotiation(struct cam_periph *periph) 507195534Sscottl{ 508195534Sscottl struct ccb_trans_settings cts; 509195534Sscottl 510195534Sscottl xpt_setup_ccb(&cts.ccb_h, periph->path, /*priority*/1); 511195534Sscottl cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 512195534Sscottl cts.type = CTS_TYPE_USER_SETTINGS; 513195534Sscottl xpt_action((union ccb *)&cts); 514195534Sscottl if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 515195534Sscottl return; 516195534Sscottl } 517195534Sscottl cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 518195534Sscottl cts.type = CTS_TYPE_CURRENT_SETTINGS; 519195534Sscottl xpt_action((union ccb *)&cts); 520195534Sscottl} 521195534Sscottl 522195534Sscottl/* 523195534Sscottl * Backoff Negotiation Code- only pertinent for SPI devices. 524195534Sscottl */ 525195534Sscottlstatic int 526195534Sscottlproberequestbackoff(struct cam_periph *periph, struct cam_ed *device) 527195534Sscottl{ 528195534Sscottl struct ccb_trans_settings cts; 529195534Sscottl struct ccb_trans_settings_spi *spi; 530195534Sscottl 531195534Sscottl memset(&cts, 0, sizeof (cts)); 532195534Sscottl xpt_setup_ccb(&cts.ccb_h, periph->path, /*priority*/1); 533195534Sscottl cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 534195534Sscottl cts.type = CTS_TYPE_CURRENT_SETTINGS; 535195534Sscottl xpt_action((union ccb *)&cts); 536195534Sscottl if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 537195534Sscottl if (bootverbose) { 538195534Sscottl xpt_print(periph->path, 539195534Sscottl "failed to get current device settings\n"); 540195534Sscottl } 541195534Sscottl return (0); 542195534Sscottl } 543195534Sscottl if (cts.transport != XPORT_SPI) { 544195534Sscottl if (bootverbose) { 545195534Sscottl xpt_print(periph->path, "not SPI transport\n"); 546195534Sscottl } 547195534Sscottl return (0); 548195534Sscottl } 549195534Sscottl spi = &cts.xport_specific.spi; 550195534Sscottl 551195534Sscottl /* 552195534Sscottl * We cannot renegotiate sync rate if we don't have one. 553195534Sscottl */ 554195534Sscottl if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0) { 555195534Sscottl if (bootverbose) { 556195534Sscottl xpt_print(periph->path, "no sync rate known\n"); 557195534Sscottl } 558195534Sscottl return (0); 559195534Sscottl } 560195534Sscottl 561195534Sscottl /* 562195534Sscottl * We'll assert that we don't have to touch PPR options- the 563195534Sscottl * SIM will see what we do with period and offset and adjust 564195534Sscottl * the PPR options as appropriate. 565195534Sscottl */ 566195534Sscottl 567195534Sscottl /* 568195534Sscottl * A sync rate with unknown or zero offset is nonsensical. 569195534Sscottl * A sync period of zero means Async. 570195534Sscottl */ 571195534Sscottl if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0 572195534Sscottl || spi->sync_offset == 0 || spi->sync_period == 0) { 573195534Sscottl if (bootverbose) { 574195534Sscottl xpt_print(periph->path, "no sync rate available\n"); 575195534Sscottl } 576195534Sscottl return (0); 577195534Sscottl } 578195534Sscottl 579195534Sscottl if (device->flags & CAM_DEV_DV_HIT_BOTTOM) { 580195534Sscottl CAM_DEBUG(periph->path, CAM_DEBUG_INFO, 581195534Sscottl ("hit async: giving up on DV\n")); 582195534Sscottl return (0); 583195534Sscottl } 584195534Sscottl 585195534Sscottl 586195534Sscottl /* 587195534Sscottl * Jump sync_period up by one, but stop at 5MHz and fall back to Async. 588195534Sscottl * We don't try to remember 'last' settings to see if the SIM actually 589195534Sscottl * gets into the speed we want to set. We check on the SIM telling 590195534Sscottl * us that a requested speed is bad, but otherwise don't try and 591195534Sscottl * check the speed due to the asynchronous and handshake nature 592195534Sscottl * of speed setting. 593195534Sscottl */ 594195534Sscottl spi->valid = CTS_SPI_VALID_SYNC_RATE | CTS_SPI_VALID_SYNC_OFFSET; 595195534Sscottl for (;;) { 596195534Sscottl spi->sync_period++; 597195534Sscottl if (spi->sync_period >= 0xf) { 598195534Sscottl spi->sync_period = 0; 599195534Sscottl spi->sync_offset = 0; 600195534Sscottl CAM_DEBUG(periph->path, CAM_DEBUG_INFO, 601195534Sscottl ("setting to async for DV\n")); 602195534Sscottl /* 603195534Sscottl * Once we hit async, we don't want to try 604195534Sscottl * any more settings. 605195534Sscottl */ 606195534Sscottl device->flags |= CAM_DEV_DV_HIT_BOTTOM; 607195534Sscottl } else if (bootverbose) { 608195534Sscottl CAM_DEBUG(periph->path, CAM_DEBUG_INFO, 609195534Sscottl ("DV: period 0x%x\n", spi->sync_period)); 610195534Sscottl printf("setting period to 0x%x\n", spi->sync_period); 611195534Sscottl } 612195534Sscottl cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 613195534Sscottl cts.type = CTS_TYPE_CURRENT_SETTINGS; 614195534Sscottl xpt_action((union ccb *)&cts); 615195534Sscottl if ((cts.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 616195534Sscottl break; 617195534Sscottl } 618195534Sscottl CAM_DEBUG(periph->path, CAM_DEBUG_INFO, 619195534Sscottl ("DV: failed to set period 0x%x\n", spi->sync_period)); 620195534Sscottl if (spi->sync_period == 0) { 621195534Sscottl return (0); 622195534Sscottl } 623195534Sscottl } 624195534Sscottl return (1); 625195534Sscottl} 626195534Sscottl#endif 627195534Sscottlstatic void 628195534Sscottlprobedone(struct cam_periph *periph, union ccb *done_ccb) 629195534Sscottl{ 630195534Sscottl struct ata_params *ident_buf; 631195534Sscottl probe_softc *softc; 632195534Sscottl struct cam_path *path; 633195534Sscottl u_int32_t priority; 634195534Sscottl int found = 0; 635195534Sscottl 636195534Sscottl CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probedone\n")); 637195534Sscottl 638195534Sscottl softc = (probe_softc *)periph->softc; 639195534Sscottl path = done_ccb->ccb_h.path; 640195534Sscottl priority = done_ccb->ccb_h.pinfo.priority; 641195534Sscottl ident_buf = &path->device->ident_data; 642195534Sscottl 643195534Sscottl switch (softc->action) { 644195534Sscottl case PROBE_RESET: 645195534Sscottl if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 646195534Sscottl int sign = (done_ccb->ataio.res.lba_high << 8) + 647195534Sscottl done_ccb->ataio.res.lba_mid; 648195534Sscottl xpt_print(path, "SIGNATURE: %04x\n", sign); 649195534Sscottl if (sign == 0x0000 && 650195534Sscottl done_ccb->ccb_h.target_id != 15) { 651195534Sscottl path->device->protocol = PROTO_ATA; 652195534Sscottl PROBE_SET_ACTION(softc, PROBE_IDENTIFY); 653195534Sscottl } else if (sign == 0x9669 && 654195534Sscottl done_ccb->ccb_h.target_id == 15) { 655195534Sscottl struct ccb_trans_settings cts; 656195534Sscottl 657195534Sscottl /* Report SIM that PM is present. */ 658195534Sscottl bzero(&cts, sizeof(cts)); 659195534Sscottl xpt_setup_ccb(&cts.ccb_h, path, 1); 660195534Sscottl cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 661195534Sscottl cts.type = CTS_TYPE_CURRENT_SETTINGS; 662195534Sscottl cts.xport_specific.sata.pm_present = 1; 663195534Sscottl cts.xport_specific.sata.valid = CTS_SATA_VALID_PM; 664195534Sscottl xpt_action((union ccb *)&cts); 665195534Sscottl path->device->protocol = PROTO_SATAPM; 666195534Sscottl PROBE_SET_ACTION(softc, PROBE_PM_PID); 667195534Sscottl } else if (sign == 0xeb14 && 668195534Sscottl done_ccb->ccb_h.target_id != 15) { 669195534Sscottl path->device->protocol = PROTO_SCSI; 670195534Sscottl PROBE_SET_ACTION(softc, PROBE_IDENTIFY); 671195534Sscottl } else { 672195534Sscottl if (done_ccb->ccb_h.target_id != 15) { 673195534Sscottl xpt_print(path, 674195534Sscottl "Unexpected signature 0x%04x\n", sign); 675195534Sscottl } 676195534Sscottl xpt_release_ccb(done_ccb); 677195534Sscottl break; 678195534Sscottl } 679195534Sscottl xpt_release_ccb(done_ccb); 680195534Sscottl xpt_schedule(periph, priority); 681195534Sscottl return; 682195534Sscottl } else if (cam_periph_error(done_ccb, 0, 0, 683195534Sscottl &softc->saved_ccb) == ERESTART) { 684195534Sscottl return; 685195534Sscottl } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 686195534Sscottl /* Don't wedge the queue */ 687195534Sscottl xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, 688195534Sscottl /*run_queue*/TRUE); 689195534Sscottl } 690195534Sscottl goto device_fail; 691195534Sscottl case PROBE_IDENTIFY: 692195534Sscottl { 693195534Sscottl if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 694195534Sscottl int16_t *ptr; 695195534Sscottl 696195534Sscottl for (ptr = (int16_t *)ident_buf; 697195534Sscottl ptr < (int16_t *)ident_buf + sizeof(struct ata_params)/2; ptr++) { 698195534Sscottl *ptr = le16toh(*ptr); 699195534Sscottl } 700195534Sscottl if (strncmp(ident_buf->model, "FX", 2) && 701195534Sscottl strncmp(ident_buf->model, "NEC", 3) && 702195534Sscottl strncmp(ident_buf->model, "Pioneer", 7) && 703195534Sscottl strncmp(ident_buf->model, "SHARP", 5)) { 704195534Sscottl ata_bswap(ident_buf->model, sizeof(ident_buf->model)); 705195534Sscottl ata_bswap(ident_buf->revision, sizeof(ident_buf->revision)); 706195534Sscottl ata_bswap(ident_buf->serial, sizeof(ident_buf->serial)); 707195534Sscottl } 708195534Sscottl ata_btrim(ident_buf->model, sizeof(ident_buf->model)); 709195534Sscottl ata_bpack(ident_buf->model, ident_buf->model, sizeof(ident_buf->model)); 710195534Sscottl ata_btrim(ident_buf->revision, sizeof(ident_buf->revision)); 711195534Sscottl ata_bpack(ident_buf->revision, ident_buf->revision, sizeof(ident_buf->revision)); 712195534Sscottl ata_btrim(ident_buf->serial, sizeof(ident_buf->serial)); 713195534Sscottl ata_bpack(ident_buf->serial, ident_buf->serial, sizeof(ident_buf->serial)); 714195534Sscottl 715195534Sscottl if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) == 0) { 716195534Sscottl /* Check that it is the same device. */ 717195534Sscottl MD5_CTX context; 718195534Sscottl u_int8_t digest[16]; 719195534Sscottl 720195534Sscottl MD5Init(&context); 721195534Sscottl MD5Update(&context, 722195534Sscottl (unsigned char *)ident_buf->model, 723195534Sscottl sizeof(ident_buf->model)); 724195534Sscottl MD5Update(&context, 725195534Sscottl (unsigned char *)ident_buf->revision, 726195534Sscottl sizeof(ident_buf->revision)); 727195534Sscottl MD5Update(&context, 728195534Sscottl (unsigned char *)ident_buf->serial, 729195534Sscottl sizeof(ident_buf->serial)); 730195534Sscottl MD5Final(digest, &context); 731195534Sscottl if (bcmp(digest, softc->digest, sizeof(digest))) { 732195534Sscottl /* Device changed. */ 733195534Sscottl xpt_async(AC_LOST_DEVICE, path, NULL); 734195534Sscottl } 735195534Sscottl xpt_release_ccb(done_ccb); 736195534Sscottl break; 737195534Sscottl } 738195534Sscottl 739195534Sscottl /* Clean up from previous instance of this device */ 740195534Sscottl if (path->device->serial_num != NULL) { 741195534Sscottl free(path->device->serial_num, M_CAMXPT); 742195534Sscottl path->device->serial_num = NULL; 743195534Sscottl path->device->serial_num_len = 0; 744195534Sscottl } 745195534Sscottl path->device->serial_num = 746195534Sscottl (u_int8_t *)malloc((sizeof(ident_buf->serial) + 1), 747195534Sscottl M_CAMXPT, M_NOWAIT); 748195534Sscottl if (path->device->serial_num != NULL) { 749195534Sscottl bcopy(ident_buf->serial, 750195534Sscottl path->device->serial_num, 751195534Sscottl sizeof(ident_buf->serial)); 752195534Sscottl path->device->serial_num[sizeof(ident_buf->serial)] 753195534Sscottl = '\0'; 754195534Sscottl path->device->serial_num_len = 755195534Sscottl strlen(path->device->serial_num); 756195534Sscottl } 757195534Sscottl 758195534Sscottl path->device->flags |= CAM_DEV_INQUIRY_DATA_VALID; 759195534Sscottl 760195534Sscottl scsi_find_quirk(path->device); 761195534Sscottl ata_device_transport(path); 762195534Sscottl 763195534Sscottl PROBE_SET_ACTION(softc, PROBE_SETMODE); 764195534Sscottl xpt_release_ccb(done_ccb); 765195534Sscottl xpt_schedule(periph, priority); 766195534Sscottl return; 767195534Sscottl } else if (cam_periph_error(done_ccb, 0, 0, 768195534Sscottl &softc->saved_ccb) == ERESTART) { 769195534Sscottl return; 770195534Sscottl } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 771195534Sscottl /* Don't wedge the queue */ 772195534Sscottl xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, 773195534Sscottl /*run_queue*/TRUE); 774195534Sscottl } 775195534Sscottldevice_fail: 776195534Sscottl /* 777195534Sscottl * If we get to this point, we got an error status back 778195534Sscottl * from the inquiry and the error status doesn't require 779195534Sscottl * automatically retrying the command. Therefore, the 780195534Sscottl * inquiry failed. If we had inquiry information before 781195534Sscottl * for this device, but this latest inquiry command failed, 782195534Sscottl * the device has probably gone away. If this device isn't 783195534Sscottl * already marked unconfigured, notify the peripheral 784195534Sscottl * drivers that this device is no more. 785195534Sscottl */ 786195534Sscottl if ((path->device->flags & CAM_DEV_UNCONFIGURED) == 0) 787195534Sscottl /* Send the async notification. */ 788195534Sscottl xpt_async(AC_LOST_DEVICE, path, NULL); 789195534Sscottl 790195534Sscottl xpt_release_ccb(done_ccb); 791195534Sscottl break; 792195534Sscottl } 793195534Sscottl case PROBE_SETMODE: 794195534Sscottl { 795195534Sscottl if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 796195534Sscottl if (path->device->protocol == PROTO_ATA) { 797195534Sscottl path->device->flags &= ~CAM_DEV_UNCONFIGURED; 798195534Sscottl done_ccb->ccb_h.func_code = XPT_GDEV_TYPE; 799195534Sscottl xpt_action(done_ccb); 800195534Sscottl xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path, 801195534Sscottl done_ccb); 802195534Sscottl xpt_release_ccb(done_ccb); 803195534Sscottl break; 804195534Sscottl } else { 805195534Sscottl PROBE_SET_ACTION(softc, PROBE_INQUIRY); 806195534Sscottl xpt_release_ccb(done_ccb); 807195534Sscottl xpt_schedule(periph, priority); 808195534Sscottl return; 809195534Sscottl } 810195534Sscottl } else if (cam_periph_error(done_ccb, 0, 0, 811195534Sscottl &softc->saved_ccb) == ERESTART) { 812195534Sscottl return; 813195534Sscottl } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 814195534Sscottl /* Don't wedge the queue */ 815195534Sscottl xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, 816195534Sscottl /*run_queue*/TRUE); 817195534Sscottl } 818195534Sscottl goto device_fail; 819195534Sscottl } 820195534Sscottl case PROBE_INQUIRY: 821195534Sscottl case PROBE_FULL_INQUIRY: 822195534Sscottl { 823195534Sscottl if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 824195534Sscottl struct scsi_inquiry_data *inq_buf; 825195534Sscottl u_int8_t periph_qual; 826195534Sscottl 827195534Sscottl path->device->flags |= CAM_DEV_INQUIRY_DATA_VALID; 828195534Sscottl inq_buf = &path->device->inq_data; 829195534Sscottl 830195534Sscottl periph_qual = SID_QUAL(inq_buf); 831195534Sscottl 832195534Sscottl if (periph_qual == SID_QUAL_LU_CONNECTED) { 833195534Sscottl u_int8_t len; 834195534Sscottl 835195534Sscottl /* 836195534Sscottl * We conservatively request only 837195534Sscottl * SHORT_INQUIRY_LEN bytes of inquiry 838195534Sscottl * information during our first try 839195534Sscottl * at sending an INQUIRY. If the device 840195534Sscottl * has more information to give, 841195534Sscottl * perform a second request specifying 842195534Sscottl * the amount of information the device 843195534Sscottl * is willing to give. 844195534Sscottl */ 845195534Sscottl len = inq_buf->additional_length 846195534Sscottl + offsetof(struct scsi_inquiry_data, 847195534Sscottl additional_length) + 1; 848195534Sscottl if (softc->action == PROBE_INQUIRY 849195534Sscottl && len > SHORT_INQUIRY_LENGTH) { 850195534Sscottl PROBE_SET_ACTION(softc, PROBE_FULL_INQUIRY); 851195534Sscottl xpt_release_ccb(done_ccb); 852195534Sscottl xpt_schedule(periph, priority); 853195534Sscottl return; 854195534Sscottl } 855195534Sscottl 856195534Sscottl scsi_find_quirk(path->device); 857195534Sscottl 858195534Sscottl// scsi_devise_transport(path); 859195534Sscottl path->device->flags &= ~CAM_DEV_UNCONFIGURED; 860195534Sscottl done_ccb->ccb_h.func_code = XPT_GDEV_TYPE; 861195534Sscottl xpt_action(done_ccb); 862195534Sscottl xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path, 863195534Sscottl done_ccb); 864195534Sscottl xpt_release_ccb(done_ccb); 865195534Sscottl break; 866195534Sscottl } 867195534Sscottl } else if (cam_periph_error(done_ccb, 0, 0, 868195534Sscottl &softc->saved_ccb) == ERESTART) { 869195534Sscottl return; 870195534Sscottl } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 871195534Sscottl /* Don't wedge the queue */ 872195534Sscottl xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, 873195534Sscottl /*run_queue*/TRUE); 874195534Sscottl } 875195534Sscottl goto device_fail; 876195534Sscottl } 877195534Sscottl case PROBE_PM_PID: 878195534Sscottl if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 879195534Sscottl if ((path->device->flags & CAM_DEV_INQUIRY_DATA_VALID) == 0) 880195534Sscottl bzero(ident_buf, sizeof(*ident_buf)); 881195534Sscottl softc->pm_pid = (done_ccb->ataio.res.lba_high << 24) + 882195534Sscottl (done_ccb->ataio.res.lba_mid << 16) + 883195534Sscottl (done_ccb->ataio.res.lba_low << 8) + 884195534Sscottl done_ccb->ataio.res.sector_count; 885195534Sscottl printf("PM Product ID: %08x\n", softc->pm_pid); 886195534Sscottl snprintf(ident_buf->model, sizeof(ident_buf->model), 887195534Sscottl "Port Multiplier %08x", softc->pm_pid); 888195534Sscottl PROBE_SET_ACTION(softc, PROBE_PM_PRV); 889195534Sscottl xpt_release_ccb(done_ccb); 890195534Sscottl xpt_schedule(periph, priority); 891195534Sscottl return; 892195534Sscottl } else if (cam_periph_error(done_ccb, 0, 0, 893195534Sscottl &softc->saved_ccb) == ERESTART) { 894195534Sscottl return; 895195534Sscottl } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 896195534Sscottl /* Don't wedge the queue */ 897195534Sscottl xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, 898195534Sscottl /*run_queue*/TRUE); 899195534Sscottl } 900195534Sscottl goto device_fail; 901195534Sscottl case PROBE_PM_PRV: 902195534Sscottl if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 903195534Sscottl softc->pm_prv = (done_ccb->ataio.res.lba_high << 24) + 904195534Sscottl (done_ccb->ataio.res.lba_mid << 16) + 905195534Sscottl (done_ccb->ataio.res.lba_low << 8) + 906195534Sscottl done_ccb->ataio.res.sector_count; 907195534Sscottl printf("PM Revision: %08x\n", softc->pm_prv); 908195534Sscottl snprintf(ident_buf->revision, sizeof(ident_buf->revision), 909195534Sscottl "%04x", softc->pm_prv); 910195534Sscottl PROBE_SET_ACTION(softc, PROBE_PM_PORTS); 911195534Sscottl xpt_release_ccb(done_ccb); 912195534Sscottl xpt_schedule(periph, priority); 913195534Sscottl return; 914195534Sscottl } else if (cam_periph_error(done_ccb, 0, 0, 915195534Sscottl &softc->saved_ccb) == ERESTART) { 916195534Sscottl return; 917195534Sscottl } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 918195534Sscottl /* Don't wedge the queue */ 919195534Sscottl xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, 920195534Sscottl /*run_queue*/TRUE); 921195534Sscottl } 922195534Sscottl goto device_fail; 923195534Sscottl case PROBE_PM_PORTS: 924195534Sscottl if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 925195534Sscottl softc->pm_ports = (done_ccb->ataio.res.lba_high << 24) + 926195534Sscottl (done_ccb->ataio.res.lba_mid << 16) + 927195534Sscottl (done_ccb->ataio.res.lba_low << 8) + 928195534Sscottl done_ccb->ataio.res.sector_count; 929195534Sscottl /* This PM declares 6 ports, while only 5 of them are real. 930195534Sscottl * Port 5 is enclosure management bridge port, which has implementation 931195534Sscottl * problems, causing probe faults. Hide it for now. */ 932195534Sscottl if (softc->pm_pid == 0x37261095 && softc->pm_ports == 6) 933195534Sscottl softc->pm_ports = 5; 934195534Sscottl /* This PM declares 7 ports, while only 5 of them are real. 935195534Sscottl * Port 5 is some fake "Config Disk" with 640 sectors size, 936195534Sscottl * port 6 is enclosure management bridge port. 937195534Sscottl * Both fake ports has implementation problems, causing 938195534Sscottl * probe faults. Hide them for now. */ 939195534Sscottl if (softc->pm_pid == 0x47261095 && softc->pm_ports == 7) 940195534Sscottl softc->pm_ports = 5; 941195534Sscottl printf("PM ports: %d\n", softc->pm_ports); 942195534Sscottl ident_buf->config = softc->pm_ports; 943195534Sscottl path->device->flags |= CAM_DEV_INQUIRY_DATA_VALID; 944195534Sscottl softc->pm_step = 0; 945195534Sscottl PROBE_SET_ACTION(softc, PROBE_PM_RESET); 946195534Sscottl xpt_release_ccb(done_ccb); 947195534Sscottl xpt_schedule(periph, priority); 948195534Sscottl return; 949195534Sscottl } else if (cam_periph_error(done_ccb, 0, 0, 950195534Sscottl &softc->saved_ccb) == ERESTART) { 951195534Sscottl return; 952195534Sscottl } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 953195534Sscottl /* Don't wedge the queue */ 954195534Sscottl xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, 955195534Sscottl /*run_queue*/TRUE); 956195534Sscottl } 957195534Sscottl goto device_fail; 958195534Sscottl case PROBE_PM_RESET: 959195534Sscottl if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 960195534Sscottl softc->pm_step++; 961195534Sscottl if (softc->pm_step < softc->pm_ports) { 962195534Sscottl xpt_release_ccb(done_ccb); 963195534Sscottl xpt_schedule(periph, priority); 964195534Sscottl return; 965195534Sscottl } else { 966195534Sscottl softc->pm_step = 0; 967195534Sscottl DELAY(5000); 968195534Sscottl printf("PM reset done\n"); 969195534Sscottl PROBE_SET_ACTION(softc, PROBE_PM_CONNECT); 970195534Sscottl xpt_release_ccb(done_ccb); 971195534Sscottl xpt_schedule(periph, priority); 972195534Sscottl return; 973195534Sscottl } 974195534Sscottl } else if (cam_periph_error(done_ccb, 0, 0, 975195534Sscottl &softc->saved_ccb) == ERESTART) { 976195534Sscottl return; 977195534Sscottl } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 978195534Sscottl /* Don't wedge the queue */ 979195534Sscottl xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, 980195534Sscottl /*run_queue*/TRUE); 981195534Sscottl } 982195534Sscottl goto device_fail; 983195534Sscottl case PROBE_PM_CONNECT: 984195534Sscottl if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 985195534Sscottl softc->pm_step++; 986195534Sscottl if (softc->pm_step < softc->pm_ports) { 987195534Sscottl xpt_release_ccb(done_ccb); 988195534Sscottl xpt_schedule(periph, priority); 989195534Sscottl return; 990195534Sscottl } else { 991195534Sscottl softc->pm_step = 0; 992195534Sscottl softc->pm_try = 0; 993195534Sscottl printf("PM connect done\n"); 994195534Sscottl PROBE_SET_ACTION(softc, PROBE_PM_CHECK); 995195534Sscottl xpt_release_ccb(done_ccb); 996195534Sscottl xpt_schedule(periph, priority); 997195534Sscottl return; 998195534Sscottl } 999195534Sscottl } else if (cam_periph_error(done_ccb, 0, 0, 1000195534Sscottl &softc->saved_ccb) == ERESTART) { 1001195534Sscottl return; 1002195534Sscottl } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 1003195534Sscottl /* Don't wedge the queue */ 1004195534Sscottl xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, 1005195534Sscottl /*run_queue*/TRUE); 1006195534Sscottl } 1007195534Sscottl goto device_fail; 1008195534Sscottl case PROBE_PM_CHECK: 1009195534Sscottl if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 1010195534Sscottl int res = (done_ccb->ataio.res.lba_high << 24) + 1011195534Sscottl (done_ccb->ataio.res.lba_mid << 16) + 1012195534Sscottl (done_ccb->ataio.res.lba_low << 8) + 1013195534Sscottl done_ccb->ataio.res.sector_count; 1014195534Sscottl if ((res & 0xf0f) == 0x103 && (res & 0x0f0) != 0) { 1015195534Sscottl printf("PM status: %d - %08x\n", softc->pm_step, res); 1016195534Sscottl ident_buf->cylinders |= (1 << softc->pm_step); 1017195534Sscottl softc->pm_step++; 1018195534Sscottl } else { 1019195534Sscottl if (softc->pm_try < 100) { 1020195534Sscottl DELAY(10000); 1021195534Sscottl softc->pm_try++; 1022195534Sscottl } else { 1023195534Sscottl printf("PM status: %d - %08x\n", softc->pm_step, res); 1024195534Sscottl ident_buf->cylinders &= ~(1 << softc->pm_step); 1025195534Sscottl softc->pm_step++; 1026195534Sscottl } 1027195534Sscottl } 1028195534Sscottl if (softc->pm_step < softc->pm_ports) { 1029195534Sscottl xpt_release_ccb(done_ccb); 1030195534Sscottl xpt_schedule(periph, priority); 1031195534Sscottl return; 1032195534Sscottl } else { 1033195534Sscottl softc->pm_step = 0; 1034195534Sscottl PROBE_SET_ACTION(softc, PROBE_PM_CLEAR); 1035195534Sscottl xpt_release_ccb(done_ccb); 1036195534Sscottl xpt_schedule(periph, priority); 1037195534Sscottl return; 1038195534Sscottl } 1039195534Sscottl } else if (cam_periph_error(done_ccb, 0, 0, 1040195534Sscottl &softc->saved_ccb) == ERESTART) { 1041195534Sscottl return; 1042195534Sscottl } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 1043195534Sscottl /* Don't wedge the queue */ 1044195534Sscottl xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, 1045195534Sscottl /*run_queue*/TRUE); 1046195534Sscottl } 1047195534Sscottl goto device_fail; 1048195534Sscottl case PROBE_PM_CLEAR: 1049195534Sscottl if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 1050195534Sscottl softc->pm_step++; 1051195534Sscottl if (softc->pm_step < softc->pm_ports) { 1052195534Sscottl xpt_release_ccb(done_ccb); 1053195534Sscottl xpt_schedule(periph, priority); 1054195534Sscottl return; 1055195534Sscottl } 1056195534Sscottl found = ident_buf->cylinders | 0x8000; 1057195534Sscottl if (path->device->flags & CAM_DEV_UNCONFIGURED) { 1058195534Sscottl path->device->flags &= ~CAM_DEV_UNCONFIGURED; 1059195534Sscottl done_ccb->ccb_h.func_code = XPT_GDEV_TYPE; 1060195534Sscottl xpt_action(done_ccb); 1061195534Sscottl xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path, 1062195534Sscottl done_ccb); 1063195534Sscottl xpt_release_ccb(done_ccb); 1064195534Sscottl } 1065195534Sscottl break; 1066195534Sscottl } else if (cam_periph_error(done_ccb, 0, 0, 1067195534Sscottl &softc->saved_ccb) == ERESTART) { 1068195534Sscottl return; 1069195534Sscottl } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 1070195534Sscottl /* Don't wedge the queue */ 1071195534Sscottl xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, 1072195534Sscottl /*run_queue*/TRUE); 1073195534Sscottl } 1074195534Sscottl goto device_fail; 1075195534Sscottl case PROBE_INVALID: 1076195534Sscottl CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_INFO, 1077195534Sscottl ("probedone: invalid action state\n")); 1078195534Sscottl default: 1079195534Sscottl break; 1080195534Sscottl } 1081195534Sscottl done_ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs); 1082195534Sscottl TAILQ_REMOVE(&softc->request_ccbs, &done_ccb->ccb_h, periph_links.tqe); 1083195534Sscottl done_ccb->ccb_h.status = CAM_REQ_CMP; 1084195534Sscottl done_ccb->ccb_h.ppriv_field1 = found; 1085195534Sscottl xpt_done(done_ccb); 1086195534Sscottl if (TAILQ_FIRST(&softc->request_ccbs) == NULL) { 1087195534Sscottl cam_periph_invalidate(periph); 1088195534Sscottl cam_periph_release_locked(periph); 1089195534Sscottl } else { 1090195534Sscottl probeschedule(periph); 1091195534Sscottl } 1092195534Sscottl} 1093195534Sscottl 1094195534Sscottlstatic void 1095195534Sscottlprobecleanup(struct cam_periph *periph) 1096195534Sscottl{ 1097195534Sscottl free(periph->softc, M_CAMXPT); 1098195534Sscottl} 1099195534Sscottl 1100195534Sscottlstatic void 1101195534Sscottlscsi_find_quirk(struct cam_ed *device) 1102195534Sscottl{ 1103195534Sscottl struct scsi_quirk_entry *quirk; 1104195534Sscottl caddr_t match; 1105195534Sscottl 1106195534Sscottl match = cam_quirkmatch((caddr_t)&device->inq_data, 1107195534Sscottl (caddr_t)scsi_quirk_table, 1108195534Sscottl sizeof(scsi_quirk_table) / 1109195534Sscottl sizeof(*scsi_quirk_table), 1110195534Sscottl sizeof(*scsi_quirk_table), scsi_inquiry_match); 1111195534Sscottl 1112195534Sscottl if (match == NULL) 1113195534Sscottl panic("xpt_find_quirk: device didn't match wildcard entry!!"); 1114195534Sscottl 1115195534Sscottl quirk = (struct scsi_quirk_entry *)match; 1116195534Sscottl device->quirk = quirk; 1117195534Sscottl device->mintags = quirk->mintags; 1118195534Sscottl device->maxtags = quirk->maxtags; 1119195534Sscottl} 1120195534Sscottl 1121195534Sscottltypedef struct { 1122195534Sscottl union ccb *request_ccb; 1123195534Sscottl struct ccb_pathinq *cpi; 1124195534Sscottl int counter; 1125195534Sscottl int found; 1126195534Sscottl} ata_scan_bus_info; 1127195534Sscottl 1128195534Sscottl/* 1129195534Sscottl * To start a scan, request_ccb is an XPT_SCAN_BUS ccb. 1130195534Sscottl * As the scan progresses, xpt_scan_bus is used as the 1131195534Sscottl * callback on completion function. 1132195534Sscottl */ 1133195534Sscottlstatic void 1134195534Sscottlata_scan_bus(struct cam_periph *periph, union ccb *request_ccb) 1135195534Sscottl{ 1136195534Sscottl struct cam_path *path; 1137195534Sscottl ata_scan_bus_info *scan_info; 1138195534Sscottl union ccb *work_ccb; 1139195534Sscottl cam_status status; 1140195534Sscottl 1141195534Sscottl CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_TRACE, 1142195534Sscottl ("xpt_scan_bus\n")); 1143195534Sscottl switch (request_ccb->ccb_h.func_code) { 1144195534Sscottl case XPT_SCAN_BUS: 1145195534Sscottl /* Find out the characteristics of the bus */ 1146195534Sscottl work_ccb = xpt_alloc_ccb_nowait(); 1147195534Sscottl if (work_ccb == NULL) { 1148195534Sscottl request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 1149195534Sscottl xpt_done(request_ccb); 1150195534Sscottl return; 1151195534Sscottl } 1152195534Sscottl xpt_setup_ccb(&work_ccb->ccb_h, request_ccb->ccb_h.path, 1153195534Sscottl request_ccb->ccb_h.pinfo.priority); 1154195534Sscottl work_ccb->ccb_h.func_code = XPT_PATH_INQ; 1155195534Sscottl xpt_action(work_ccb); 1156195534Sscottl if (work_ccb->ccb_h.status != CAM_REQ_CMP) { 1157195534Sscottl request_ccb->ccb_h.status = work_ccb->ccb_h.status; 1158195534Sscottl xpt_free_ccb(work_ccb); 1159195534Sscottl xpt_done(request_ccb); 1160195534Sscottl return; 1161195534Sscottl } 1162195534Sscottl 1163195534Sscottl /* Save some state for use while we probe for devices */ 1164195534Sscottl scan_info = (ata_scan_bus_info *) 1165195534Sscottl malloc(sizeof(ata_scan_bus_info), M_CAMXPT, M_NOWAIT); 1166195534Sscottl if (scan_info == NULL) { 1167195534Sscottl request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 1168195534Sscottl xpt_done(request_ccb); 1169195534Sscottl return; 1170195534Sscottl } 1171195534Sscottl scan_info->request_ccb = request_ccb; 1172195534Sscottl scan_info->cpi = &work_ccb->cpi; 1173195534Sscottl scan_info->found = 0x8001; 1174195534Sscottl scan_info->counter = 0; 1175195534Sscottl /* If PM supported, probe it first. */ 1176195534Sscottl if (scan_info->cpi->hba_inquiry & PI_SATAPM) 1177195534Sscottl scan_info->counter = 15; 1178195534Sscottl 1179195534Sscottl work_ccb = xpt_alloc_ccb_nowait(); 1180195534Sscottl if (work_ccb == NULL) { 1181195534Sscottl free(scan_info, M_CAMXPT); 1182195534Sscottl request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 1183195534Sscottl xpt_done(request_ccb); 1184195534Sscottl break; 1185195534Sscottl } 1186195534Sscottl goto scan_next; 1187195534Sscottl case XPT_SCAN_LUN: 1188195534Sscottl work_ccb = request_ccb; 1189195534Sscottl /* Reuse the same CCB to query if a device was really found */ 1190195534Sscottl scan_info = (ata_scan_bus_info *)work_ccb->ccb_h.ppriv_ptr0; 1191195534Sscottl /* Free the current request path- we're done with it. */ 1192195534Sscottl xpt_free_path(work_ccb->ccb_h.path); 1193195534Sscottl /* If there is PM... */ 1194195534Sscottl if (scan_info->counter == 15) { 1195195534Sscottl if (work_ccb->ccb_h.ppriv_field1 != 0) { 1196195534Sscottl /* Save PM probe result. */ 1197195534Sscottl scan_info->found = work_ccb->ccb_h.ppriv_field1; 1198195534Sscottl } else { 1199195534Sscottl struct ccb_trans_settings cts; 1200195534Sscottl 1201195534Sscottl /* Report SIM that PM is absent. */ 1202195534Sscottl bzero(&cts, sizeof(cts)); 1203195534Sscottl xpt_setup_ccb(&cts.ccb_h, 1204195534Sscottl scan_info->request_ccb->ccb_h.path, 1); 1205195534Sscottl cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 1206195534Sscottl cts.type = CTS_TYPE_CURRENT_SETTINGS; 1207195665Smav cts.xport_specific.sata.pm_present = 0; 1208195534Sscottl cts.xport_specific.sata.valid = CTS_SATA_VALID_PM; 1209195534Sscottl xpt_action((union ccb *)&cts); 1210195534Sscottl } 1211195534Sscottl } 1212195534Sscottltake_next: 1213195534Sscottl /* Take next device. Wrap from 15 (PM) to 0. */ 1214195534Sscottl scan_info->counter = (scan_info->counter + 1 ) & 0x0f; 1215195534Sscottl if (scan_info->counter >= scan_info->cpi->max_target+1) { 1216195534Sscottl xpt_free_ccb(work_ccb); 1217195534Sscottl xpt_free_ccb((union ccb *)scan_info->cpi); 1218195534Sscottl request_ccb = scan_info->request_ccb; 1219195534Sscottl free(scan_info, M_CAMXPT); 1220195534Sscottl request_ccb->ccb_h.status = CAM_REQ_CMP; 1221195534Sscottl xpt_done(request_ccb); 1222195534Sscottl break; 1223195534Sscottl } 1224195534Sscottlscan_next: 1225195534Sscottl status = xpt_create_path(&path, xpt_periph, 1226195534Sscottl scan_info->request_ccb->ccb_h.path_id, 1227195534Sscottl scan_info->counter, 0); 1228195534Sscottl if (status != CAM_REQ_CMP) { 1229195534Sscottl printf("xpt_scan_bus: xpt_create_path failed" 1230195534Sscottl " with status %#x, bus scan halted\n", 1231195534Sscottl status); 1232195534Sscottl xpt_free_ccb(work_ccb); 1233195534Sscottl xpt_free_ccb((union ccb *)scan_info->cpi); 1234195534Sscottl request_ccb = scan_info->request_ccb; 1235195534Sscottl free(scan_info, M_CAMXPT); 1236195534Sscottl request_ccb->ccb_h.status = status; 1237195534Sscottl xpt_done(request_ccb); 1238195534Sscottl break; 1239195534Sscottl } 1240195534Sscottl if ((scan_info->found & (1 << scan_info->counter)) == 0) { 1241195534Sscottl xpt_async(AC_LOST_DEVICE, path, NULL); 1242195534Sscottl xpt_free_path(path); 1243195534Sscottl goto take_next; 1244195534Sscottl } 1245195534Sscottl xpt_setup_ccb(&work_ccb->ccb_h, path, 1246195534Sscottl scan_info->request_ccb->ccb_h.pinfo.priority); 1247195534Sscottl work_ccb->ccb_h.func_code = XPT_SCAN_LUN; 1248195534Sscottl work_ccb->ccb_h.cbfcnp = ata_scan_bus; 1249195534Sscottl work_ccb->ccb_h.ppriv_ptr0 = scan_info; 1250195534Sscottl work_ccb->crcn.flags = scan_info->request_ccb->crcn.flags; 1251195534Sscottl xpt_action(work_ccb); 1252195534Sscottl break; 1253195534Sscottl default: 1254195534Sscottl break; 1255195534Sscottl } 1256195534Sscottl} 1257195534Sscottl 1258195534Sscottlstatic void 1259195534Sscottlata_scan_lun(struct cam_periph *periph, struct cam_path *path, 1260195534Sscottl cam_flags flags, union ccb *request_ccb) 1261195534Sscottl{ 1262195534Sscottl struct ccb_pathinq cpi; 1263195534Sscottl cam_status status; 1264195534Sscottl struct cam_path *new_path; 1265195534Sscottl struct cam_periph *old_periph; 1266195534Sscottl 1267195534Sscottl CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_TRACE, 1268195534Sscottl ("xpt_scan_lun\n")); 1269195534Sscottl 1270195534Sscottl xpt_setup_ccb(&cpi.ccb_h, path, /*priority*/1); 1271195534Sscottl cpi.ccb_h.func_code = XPT_PATH_INQ; 1272195534Sscottl xpt_action((union ccb *)&cpi); 1273195534Sscottl 1274195534Sscottl if (cpi.ccb_h.status != CAM_REQ_CMP) { 1275195534Sscottl if (request_ccb != NULL) { 1276195534Sscottl request_ccb->ccb_h.status = cpi.ccb_h.status; 1277195534Sscottl xpt_done(request_ccb); 1278195534Sscottl } 1279195534Sscottl return; 1280195534Sscottl } 1281195534Sscottl 1282195534Sscottl if (request_ccb == NULL) { 1283195534Sscottl request_ccb = malloc(sizeof(union ccb), M_CAMXPT, M_NOWAIT); 1284195534Sscottl if (request_ccb == NULL) { 1285195534Sscottl xpt_print(path, "xpt_scan_lun: can't allocate CCB, " 1286195534Sscottl "can't continue\n"); 1287195534Sscottl return; 1288195534Sscottl } 1289195534Sscottl new_path = malloc(sizeof(*new_path), M_CAMXPT, M_NOWAIT); 1290195534Sscottl if (new_path == NULL) { 1291195534Sscottl xpt_print(path, "xpt_scan_lun: can't allocate path, " 1292195534Sscottl "can't continue\n"); 1293195534Sscottl free(request_ccb, M_CAMXPT); 1294195534Sscottl return; 1295195534Sscottl } 1296195534Sscottl status = xpt_compile_path(new_path, xpt_periph, 1297195534Sscottl path->bus->path_id, 1298195534Sscottl path->target->target_id, 1299195534Sscottl path->device->lun_id); 1300195534Sscottl 1301195534Sscottl if (status != CAM_REQ_CMP) { 1302195534Sscottl xpt_print(path, "xpt_scan_lun: can't compile path, " 1303195534Sscottl "can't continue\n"); 1304195534Sscottl free(request_ccb, M_CAMXPT); 1305195534Sscottl free(new_path, M_CAMXPT); 1306195534Sscottl return; 1307195534Sscottl } 1308195534Sscottl xpt_setup_ccb(&request_ccb->ccb_h, new_path, /*priority*/ 1); 1309195534Sscottl request_ccb->ccb_h.cbfcnp = xptscandone; 1310195534Sscottl request_ccb->ccb_h.func_code = XPT_SCAN_LUN; 1311195534Sscottl request_ccb->crcn.flags = flags; 1312195534Sscottl } 1313195534Sscottl 1314195653Smav if ((old_periph = cam_periph_find(path, "aprobe")) != NULL) { 1315195534Sscottl probe_softc *softc; 1316195534Sscottl 1317195534Sscottl softc = (probe_softc *)old_periph->softc; 1318195534Sscottl TAILQ_INSERT_TAIL(&softc->request_ccbs, &request_ccb->ccb_h, 1319195534Sscottl periph_links.tqe); 1320195534Sscottl } else { 1321195534Sscottl status = cam_periph_alloc(proberegister, NULL, probecleanup, 1322195653Smav probestart, "aprobe", 1323195534Sscottl CAM_PERIPH_BIO, 1324195534Sscottl request_ccb->ccb_h.path, NULL, 0, 1325195534Sscottl request_ccb); 1326195534Sscottl 1327195534Sscottl if (status != CAM_REQ_CMP) { 1328195534Sscottl xpt_print(path, "xpt_scan_lun: cam_alloc_periph " 1329195534Sscottl "returned an error, can't continue probe\n"); 1330195534Sscottl request_ccb->ccb_h.status = status; 1331195534Sscottl xpt_done(request_ccb); 1332195534Sscottl } 1333195534Sscottl } 1334195534Sscottl} 1335195534Sscottl 1336195534Sscottlstatic void 1337195534Sscottlxptscandone(struct cam_periph *periph, union ccb *done_ccb) 1338195534Sscottl{ 1339195534Sscottl xpt_release_path(done_ccb->ccb_h.path); 1340195534Sscottl free(done_ccb->ccb_h.path, M_CAMXPT); 1341195534Sscottl free(done_ccb, M_CAMXPT); 1342195534Sscottl} 1343195534Sscottl 1344195534Sscottlstatic struct cam_ed * 1345195534Sscottlata_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id) 1346195534Sscottl{ 1347195534Sscottl struct cam_path path; 1348195534Sscottl struct scsi_quirk_entry *quirk; 1349195534Sscottl struct cam_ed *device; 1350195534Sscottl struct cam_ed *cur_device; 1351195534Sscottl 1352195534Sscottl device = xpt_alloc_device(bus, target, lun_id); 1353195534Sscottl if (device == NULL) 1354195534Sscottl return (NULL); 1355195534Sscottl 1356195534Sscottl /* 1357195534Sscottl * Take the default quirk entry until we have inquiry 1358195534Sscottl * data and can determine a better quirk to use. 1359195534Sscottl */ 1360195534Sscottl quirk = &scsi_quirk_table[scsi_quirk_table_size - 1]; 1361195534Sscottl device->quirk = (void *)quirk; 1362195534Sscottl device->mintags = quirk->mintags; 1363195534Sscottl device->maxtags = quirk->maxtags; 1364195534Sscottl bzero(&device->inq_data, sizeof(device->inq_data)); 1365195534Sscottl device->inq_flags = 0; 1366195534Sscottl device->queue_flags = 0; 1367195534Sscottl device->serial_num = NULL; 1368195534Sscottl device->serial_num_len = 0; 1369195534Sscottl 1370195534Sscottl /* 1371195534Sscottl * XXX should be limited by number of CCBs this bus can 1372195534Sscottl * do. 1373195534Sscottl */ 1374195534Sscottl bus->sim->max_ccbs += device->ccbq.devq_openings; 1375195534Sscottl /* Insertion sort into our target's device list */ 1376195534Sscottl cur_device = TAILQ_FIRST(&target->ed_entries); 1377195534Sscottl while (cur_device != NULL && cur_device->lun_id < lun_id) 1378195534Sscottl cur_device = TAILQ_NEXT(cur_device, links); 1379195534Sscottl if (cur_device != NULL) { 1380195534Sscottl TAILQ_INSERT_BEFORE(cur_device, device, links); 1381195534Sscottl } else { 1382195534Sscottl TAILQ_INSERT_TAIL(&target->ed_entries, device, links); 1383195534Sscottl } 1384195534Sscottl target->generation++; 1385195534Sscottl if (lun_id != CAM_LUN_WILDCARD) { 1386195534Sscottl xpt_compile_path(&path, 1387195534Sscottl NULL, 1388195534Sscottl bus->path_id, 1389195534Sscottl target->target_id, 1390195534Sscottl lun_id); 1391195534Sscottl ata_device_transport(&path); 1392195534Sscottl xpt_release_path(&path); 1393195534Sscottl } 1394195534Sscottl 1395195534Sscottl return (device); 1396195534Sscottl} 1397195534Sscottl 1398195534Sscottlstatic void 1399195534Sscottlata_device_transport(struct cam_path *path) 1400195534Sscottl{ 1401195534Sscottl struct ccb_pathinq cpi; 1402195534Sscottl// struct ccb_trans_settings cts; 1403195534Sscottl struct scsi_inquiry_data *inq_buf; 1404195534Sscottl 1405195534Sscottl /* Get transport information from the SIM */ 1406195534Sscottl xpt_setup_ccb(&cpi.ccb_h, path, /*priority*/1); 1407195534Sscottl cpi.ccb_h.func_code = XPT_PATH_INQ; 1408195534Sscottl xpt_action((union ccb *)&cpi); 1409195534Sscottl 1410195534Sscottl inq_buf = NULL; 1411195534Sscottl// if ((path->device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0) 1412195534Sscottl// inq_buf = &path->device->inq_data; 1413195534Sscottl// path->device->protocol = cpi.protocol; 1414195534Sscottl// path->device->protocol_version = 1415195534Sscottl// inq_buf != NULL ? SID_ANSI_REV(inq_buf) : cpi.protocol_version; 1416195534Sscottl path->device->transport = cpi.transport; 1417195534Sscottl path->device->transport_version = cpi.transport_version; 1418195534Sscottl#if 0 1419195534Sscottl /* 1420195534Sscottl * Any device not using SPI3 features should 1421195534Sscottl * be considered SPI2 or lower. 1422195534Sscottl */ 1423195534Sscottl if (inq_buf != NULL) { 1424195534Sscottl if (path->device->transport == XPORT_SPI 1425195534Sscottl && (inq_buf->spi3data & SID_SPI_MASK) == 0 1426195534Sscottl && path->device->transport_version > 2) 1427195534Sscottl path->device->transport_version = 2; 1428195534Sscottl } else { 1429195534Sscottl struct cam_ed* otherdev; 1430195534Sscottl 1431195534Sscottl for (otherdev = TAILQ_FIRST(&path->target->ed_entries); 1432195534Sscottl otherdev != NULL; 1433195534Sscottl otherdev = TAILQ_NEXT(otherdev, links)) { 1434195534Sscottl if (otherdev != path->device) 1435195534Sscottl break; 1436195534Sscottl } 1437195534Sscottl 1438195534Sscottl if (otherdev != NULL) { 1439195534Sscottl /* 1440195534Sscottl * Initially assume the same versioning as 1441195534Sscottl * prior luns for this target. 1442195534Sscottl */ 1443195534Sscottl path->device->protocol_version = 1444195534Sscottl otherdev->protocol_version; 1445195534Sscottl path->device->transport_version = 1446195534Sscottl otherdev->transport_version; 1447195534Sscottl } else { 1448195534Sscottl /* Until we know better, opt for safty */ 1449195534Sscottl path->device->protocol_version = 2; 1450195534Sscottl if (path->device->transport == XPORT_SPI) 1451195534Sscottl path->device->transport_version = 2; 1452195534Sscottl else 1453195534Sscottl path->device->transport_version = 0; 1454195534Sscottl } 1455195534Sscottl } 1456195534Sscottl 1457195534Sscottl /* 1458195534Sscottl * XXX 1459195534Sscottl * For a device compliant with SPC-2 we should be able 1460195534Sscottl * to determine the transport version supported by 1461195534Sscottl * scrutinizing the version descriptors in the 1462195534Sscottl * inquiry buffer. 1463195534Sscottl */ 1464195534Sscottl 1465195534Sscottl /* Tell the controller what we think */ 1466195534Sscottl xpt_setup_ccb(&cts.ccb_h, path, /*priority*/1); 1467195534Sscottl cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 1468195534Sscottl cts.type = CTS_TYPE_CURRENT_SETTINGS; 1469195534Sscottl cts.transport = path->device->transport; 1470195534Sscottl cts.transport_version = path->device->transport_version; 1471195534Sscottl cts.protocol = path->device->protocol; 1472195534Sscottl cts.protocol_version = path->device->protocol_version; 1473195534Sscottl cts.proto_specific.valid = 0; 1474195534Sscottl cts.xport_specific.valid = 0; 1475195534Sscottl xpt_action((union ccb *)&cts); 1476195534Sscottl#endif 1477195534Sscottl} 1478195534Sscottl 1479195534Sscottlstatic void 1480195534Sscottlata_action(union ccb *start_ccb) 1481195534Sscottl{ 1482195534Sscottl 1483195534Sscottl switch (start_ccb->ccb_h.func_code) { 1484195534Sscottl case XPT_SET_TRAN_SETTINGS: 1485195534Sscottl { 1486195534Sscottl scsi_set_transfer_settings(&start_ccb->cts, 1487195534Sscottl start_ccb->ccb_h.path->device, 1488195534Sscottl /*async_update*/FALSE); 1489195534Sscottl break; 1490195534Sscottl } 1491195534Sscottl case XPT_SCAN_BUS: 1492195534Sscottl ata_scan_bus(start_ccb->ccb_h.path->periph, start_ccb); 1493195534Sscottl break; 1494195534Sscottl case XPT_SCAN_LUN: 1495195534Sscottl ata_scan_lun(start_ccb->ccb_h.path->periph, 1496195534Sscottl start_ccb->ccb_h.path, start_ccb->crcn.flags, 1497195534Sscottl start_ccb); 1498195534Sscottl break; 1499195534Sscottl case XPT_GET_TRAN_SETTINGS: 1500195534Sscottl { 1501195534Sscottl struct cam_sim *sim; 1502195534Sscottl 1503195534Sscottl sim = start_ccb->ccb_h.path->bus->sim; 1504195534Sscottl (*(sim->sim_action))(sim, start_ccb); 1505195534Sscottl break; 1506195534Sscottl } 1507195534Sscottl default: 1508195534Sscottl xpt_action_default(start_ccb); 1509195534Sscottl break; 1510195534Sscottl } 1511195534Sscottl} 1512195534Sscottl 1513195534Sscottlstatic void 1514195534Sscottlscsi_set_transfer_settings(struct ccb_trans_settings *cts, struct cam_ed *device, 1515195534Sscottl int async_update) 1516195534Sscottl{ 1517195534Sscottl struct ccb_pathinq cpi; 1518195534Sscottl struct ccb_trans_settings cur_cts; 1519195534Sscottl struct ccb_trans_settings_scsi *scsi; 1520195534Sscottl struct ccb_trans_settings_scsi *cur_scsi; 1521195534Sscottl struct cam_sim *sim; 1522195534Sscottl struct scsi_inquiry_data *inq_data; 1523195534Sscottl 1524195534Sscottl if (device == NULL) { 1525195534Sscottl cts->ccb_h.status = CAM_PATH_INVALID; 1526195534Sscottl xpt_done((union ccb *)cts); 1527195534Sscottl return; 1528195534Sscottl } 1529195534Sscottl 1530195534Sscottl if (cts->protocol == PROTO_UNKNOWN 1531195534Sscottl || cts->protocol == PROTO_UNSPECIFIED) { 1532195534Sscottl cts->protocol = device->protocol; 1533195534Sscottl cts->protocol_version = device->protocol_version; 1534195534Sscottl } 1535195534Sscottl 1536195534Sscottl if (cts->protocol_version == PROTO_VERSION_UNKNOWN 1537195534Sscottl || cts->protocol_version == PROTO_VERSION_UNSPECIFIED) 1538195534Sscottl cts->protocol_version = device->protocol_version; 1539195534Sscottl 1540195534Sscottl if (cts->protocol != device->protocol) { 1541195534Sscottl xpt_print(cts->ccb_h.path, "Uninitialized Protocol %x:%x?\n", 1542195534Sscottl cts->protocol, device->protocol); 1543195534Sscottl cts->protocol = device->protocol; 1544195534Sscottl } 1545195534Sscottl 1546195534Sscottl if (cts->protocol_version > device->protocol_version) { 1547195534Sscottl if (bootverbose) { 1548195534Sscottl xpt_print(cts->ccb_h.path, "Down reving Protocol " 1549195534Sscottl "Version from %d to %d?\n", cts->protocol_version, 1550195534Sscottl device->protocol_version); 1551195534Sscottl } 1552195534Sscottl cts->protocol_version = device->protocol_version; 1553195534Sscottl } 1554195534Sscottl 1555195534Sscottl if (cts->transport == XPORT_UNKNOWN 1556195534Sscottl || cts->transport == XPORT_UNSPECIFIED) { 1557195534Sscottl cts->transport = device->transport; 1558195534Sscottl cts->transport_version = device->transport_version; 1559195534Sscottl } 1560195534Sscottl 1561195534Sscottl if (cts->transport_version == XPORT_VERSION_UNKNOWN 1562195534Sscottl || cts->transport_version == XPORT_VERSION_UNSPECIFIED) 1563195534Sscottl cts->transport_version = device->transport_version; 1564195534Sscottl 1565195534Sscottl if (cts->transport != device->transport) { 1566195534Sscottl xpt_print(cts->ccb_h.path, "Uninitialized Transport %x:%x?\n", 1567195534Sscottl cts->transport, device->transport); 1568195534Sscottl cts->transport = device->transport; 1569195534Sscottl } 1570195534Sscottl 1571195534Sscottl if (cts->transport_version > device->transport_version) { 1572195534Sscottl if (bootverbose) { 1573195534Sscottl xpt_print(cts->ccb_h.path, "Down reving Transport " 1574195534Sscottl "Version from %d to %d?\n", cts->transport_version, 1575195534Sscottl device->transport_version); 1576195534Sscottl } 1577195534Sscottl cts->transport_version = device->transport_version; 1578195534Sscottl } 1579195534Sscottl 1580195534Sscottl sim = cts->ccb_h.path->bus->sim; 1581195534Sscottl 1582195534Sscottl /* 1583195534Sscottl * Nothing more of interest to do unless 1584195534Sscottl * this is a device connected via the 1585195534Sscottl * SCSI protocol. 1586195534Sscottl */ 1587195534Sscottl if (cts->protocol != PROTO_SCSI) { 1588195534Sscottl if (async_update == FALSE) 1589195534Sscottl (*(sim->sim_action))(sim, (union ccb *)cts); 1590195534Sscottl return; 1591195534Sscottl } 1592195534Sscottl 1593195534Sscottl inq_data = &device->inq_data; 1594195534Sscottl scsi = &cts->proto_specific.scsi; 1595195534Sscottl xpt_setup_ccb(&cpi.ccb_h, cts->ccb_h.path, /*priority*/1); 1596195534Sscottl cpi.ccb_h.func_code = XPT_PATH_INQ; 1597195534Sscottl xpt_action((union ccb *)&cpi); 1598195534Sscottl 1599195534Sscottl /* SCSI specific sanity checking */ 1600195534Sscottl if ((cpi.hba_inquiry & PI_TAG_ABLE) == 0 1601195534Sscottl || (INQ_DATA_TQ_ENABLED(inq_data)) == 0 1602195534Sscottl || (device->queue_flags & SCP_QUEUE_DQUE) != 0 1603195534Sscottl || (device->mintags == 0)) { 1604195534Sscottl /* 1605195534Sscottl * Can't tag on hardware that doesn't support tags, 1606195534Sscottl * doesn't have it enabled, or has broken tag support. 1607195534Sscottl */ 1608195534Sscottl scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 1609195534Sscottl } 1610195534Sscottl 1611195534Sscottl if (async_update == FALSE) { 1612195534Sscottl /* 1613195534Sscottl * Perform sanity checking against what the 1614195534Sscottl * controller and device can do. 1615195534Sscottl */ 1616195534Sscottl xpt_setup_ccb(&cur_cts.ccb_h, cts->ccb_h.path, /*priority*/1); 1617195534Sscottl cur_cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 1618195534Sscottl cur_cts.type = cts->type; 1619195534Sscottl xpt_action((union ccb *)&cur_cts); 1620195534Sscottl if ((cur_cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 1621195534Sscottl return; 1622195534Sscottl } 1623195534Sscottl cur_scsi = &cur_cts.proto_specific.scsi; 1624195534Sscottl if ((scsi->valid & CTS_SCSI_VALID_TQ) == 0) { 1625195534Sscottl scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 1626195534Sscottl scsi->flags |= cur_scsi->flags & CTS_SCSI_FLAGS_TAG_ENB; 1627195534Sscottl } 1628195534Sscottl if ((cur_scsi->valid & CTS_SCSI_VALID_TQ) == 0) 1629195534Sscottl scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 1630195534Sscottl } 1631195534Sscottl 1632195534Sscottl /* SPI specific sanity checking */ 1633195534Sscottl if (cts->transport == XPORT_SPI && async_update == FALSE) { 1634195534Sscottl u_int spi3caps; 1635195534Sscottl struct ccb_trans_settings_spi *spi; 1636195534Sscottl struct ccb_trans_settings_spi *cur_spi; 1637195534Sscottl 1638195534Sscottl spi = &cts->xport_specific.spi; 1639195534Sscottl 1640195534Sscottl cur_spi = &cur_cts.xport_specific.spi; 1641195534Sscottl 1642195534Sscottl /* Fill in any gaps in what the user gave us */ 1643195534Sscottl if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0) 1644195534Sscottl spi->sync_period = cur_spi->sync_period; 1645195534Sscottl if ((cur_spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0) 1646195534Sscottl spi->sync_period = 0; 1647195534Sscottl if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0) 1648195534Sscottl spi->sync_offset = cur_spi->sync_offset; 1649195534Sscottl if ((cur_spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0) 1650195534Sscottl spi->sync_offset = 0; 1651195534Sscottl if ((spi->valid & CTS_SPI_VALID_PPR_OPTIONS) == 0) 1652195534Sscottl spi->ppr_options = cur_spi->ppr_options; 1653195534Sscottl if ((cur_spi->valid & CTS_SPI_VALID_PPR_OPTIONS) == 0) 1654195534Sscottl spi->ppr_options = 0; 1655195534Sscottl if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) == 0) 1656195534Sscottl spi->bus_width = cur_spi->bus_width; 1657195534Sscottl if ((cur_spi->valid & CTS_SPI_VALID_BUS_WIDTH) == 0) 1658195534Sscottl spi->bus_width = 0; 1659195534Sscottl if ((spi->valid & CTS_SPI_VALID_DISC) == 0) { 1660195534Sscottl spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB; 1661195534Sscottl spi->flags |= cur_spi->flags & CTS_SPI_FLAGS_DISC_ENB; 1662195534Sscottl } 1663195534Sscottl if ((cur_spi->valid & CTS_SPI_VALID_DISC) == 0) 1664195534Sscottl spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB; 1665195534Sscottl if (((device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0 1666195534Sscottl && (inq_data->flags & SID_Sync) == 0 1667195534Sscottl && cts->type == CTS_TYPE_CURRENT_SETTINGS) 1668195534Sscottl || ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0)) { 1669195534Sscottl /* Force async */ 1670195534Sscottl spi->sync_period = 0; 1671195534Sscottl spi->sync_offset = 0; 1672195534Sscottl } 1673195534Sscottl 1674195534Sscottl switch (spi->bus_width) { 1675195534Sscottl case MSG_EXT_WDTR_BUS_32_BIT: 1676195534Sscottl if (((device->flags & CAM_DEV_INQUIRY_DATA_VALID) == 0 1677195534Sscottl || (inq_data->flags & SID_WBus32) != 0 1678195534Sscottl || cts->type == CTS_TYPE_USER_SETTINGS) 1679195534Sscottl && (cpi.hba_inquiry & PI_WIDE_32) != 0) 1680195534Sscottl break; 1681195534Sscottl /* Fall Through to 16-bit */ 1682195534Sscottl case MSG_EXT_WDTR_BUS_16_BIT: 1683195534Sscottl if (((device->flags & CAM_DEV_INQUIRY_DATA_VALID) == 0 1684195534Sscottl || (inq_data->flags & SID_WBus16) != 0 1685195534Sscottl || cts->type == CTS_TYPE_USER_SETTINGS) 1686195534Sscottl && (cpi.hba_inquiry & PI_WIDE_16) != 0) { 1687195534Sscottl spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 1688195534Sscottl break; 1689195534Sscottl } 1690195534Sscottl /* Fall Through to 8-bit */ 1691195534Sscottl default: /* New bus width?? */ 1692195534Sscottl case MSG_EXT_WDTR_BUS_8_BIT: 1693195534Sscottl /* All targets can do this */ 1694195534Sscottl spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 1695195534Sscottl break; 1696195534Sscottl } 1697195534Sscottl 1698195534Sscottl spi3caps = cpi.xport_specific.spi.ppr_options; 1699195534Sscottl if ((device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0 1700195534Sscottl && cts->type == CTS_TYPE_CURRENT_SETTINGS) 1701195534Sscottl spi3caps &= inq_data->spi3data; 1702195534Sscottl 1703195534Sscottl if ((spi3caps & SID_SPI_CLOCK_DT) == 0) 1704195534Sscottl spi->ppr_options &= ~MSG_EXT_PPR_DT_REQ; 1705195534Sscottl 1706195534Sscottl if ((spi3caps & SID_SPI_IUS) == 0) 1707195534Sscottl spi->ppr_options &= ~MSG_EXT_PPR_IU_REQ; 1708195534Sscottl 1709195534Sscottl if ((spi3caps & SID_SPI_QAS) == 0) 1710195534Sscottl spi->ppr_options &= ~MSG_EXT_PPR_QAS_REQ; 1711195534Sscottl 1712195534Sscottl /* No SPI Transfer settings are allowed unless we are wide */ 1713195534Sscottl if (spi->bus_width == 0) 1714195534Sscottl spi->ppr_options = 0; 1715195534Sscottl 1716195534Sscottl if ((spi->valid & CTS_SPI_VALID_DISC) 1717195534Sscottl && ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) == 0)) { 1718195534Sscottl /* 1719195534Sscottl * Can't tag queue without disconnection. 1720195534Sscottl */ 1721195534Sscottl scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 1722195534Sscottl scsi->valid |= CTS_SCSI_VALID_TQ; 1723195534Sscottl } 1724195534Sscottl 1725195534Sscottl /* 1726195534Sscottl * If we are currently performing tagged transactions to 1727195534Sscottl * this device and want to change its negotiation parameters, 1728195534Sscottl * go non-tagged for a bit to give the controller a chance to 1729195534Sscottl * negotiate unhampered by tag messages. 1730195534Sscottl */ 1731195534Sscottl if (cts->type == CTS_TYPE_CURRENT_SETTINGS 1732195534Sscottl && (device->inq_flags & SID_CmdQue) != 0 1733195534Sscottl && (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0 1734195534Sscottl && (spi->flags & (CTS_SPI_VALID_SYNC_RATE| 1735195534Sscottl CTS_SPI_VALID_SYNC_OFFSET| 1736195534Sscottl CTS_SPI_VALID_BUS_WIDTH)) != 0) 1737195534Sscottl scsi_toggle_tags(cts->ccb_h.path); 1738195534Sscottl } 1739195534Sscottl 1740195534Sscottl if (cts->type == CTS_TYPE_CURRENT_SETTINGS 1741195534Sscottl && (scsi->valid & CTS_SCSI_VALID_TQ) != 0) { 1742195534Sscottl int device_tagenb; 1743195534Sscottl 1744195534Sscottl /* 1745195534Sscottl * If we are transitioning from tags to no-tags or 1746195534Sscottl * vice-versa, we need to carefully freeze and restart 1747195534Sscottl * the queue so that we don't overlap tagged and non-tagged 1748195534Sscottl * commands. We also temporarily stop tags if there is 1749195534Sscottl * a change in transfer negotiation settings to allow 1750195534Sscottl * "tag-less" negotiation. 1751195534Sscottl */ 1752195534Sscottl if ((device->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 1753195534Sscottl || (device->inq_flags & SID_CmdQue) != 0) 1754195534Sscottl device_tagenb = TRUE; 1755195534Sscottl else 1756195534Sscottl device_tagenb = FALSE; 1757195534Sscottl 1758195534Sscottl if (((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0 1759195534Sscottl && device_tagenb == FALSE) 1760195534Sscottl || ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) == 0 1761195534Sscottl && device_tagenb == TRUE)) { 1762195534Sscottl 1763195534Sscottl if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) { 1764195534Sscottl /* 1765195534Sscottl * Delay change to use tags until after a 1766195534Sscottl * few commands have gone to this device so 1767195534Sscottl * the controller has time to perform transfer 1768195534Sscottl * negotiations without tagged messages getting 1769195534Sscottl * in the way. 1770195534Sscottl */ 1771195534Sscottl device->tag_delay_count = CAM_TAG_DELAY_COUNT; 1772195534Sscottl device->flags |= CAM_DEV_TAG_AFTER_COUNT; 1773195534Sscottl } else { 1774195534Sscottl struct ccb_relsim crs; 1775195534Sscottl 1776195534Sscottl xpt_freeze_devq(cts->ccb_h.path, /*count*/1); 1777195534Sscottl device->inq_flags &= ~SID_CmdQue; 1778195534Sscottl xpt_dev_ccbq_resize(cts->ccb_h.path, 1779195534Sscottl sim->max_dev_openings); 1780195534Sscottl device->flags &= ~CAM_DEV_TAG_AFTER_COUNT; 1781195534Sscottl device->tag_delay_count = 0; 1782195534Sscottl 1783195534Sscottl xpt_setup_ccb(&crs.ccb_h, cts->ccb_h.path, 1784195534Sscottl /*priority*/1); 1785195534Sscottl crs.ccb_h.func_code = XPT_REL_SIMQ; 1786195534Sscottl crs.release_flags = RELSIM_RELEASE_AFTER_QEMPTY; 1787195534Sscottl crs.openings 1788195534Sscottl = crs.release_timeout 1789195534Sscottl = crs.qfrozen_cnt 1790195534Sscottl = 0; 1791195534Sscottl xpt_action((union ccb *)&crs); 1792195534Sscottl } 1793195534Sscottl } 1794195534Sscottl } 1795195534Sscottl if (async_update == FALSE) 1796195534Sscottl (*(sim->sim_action))(sim, (union ccb *)cts); 1797195534Sscottl} 1798195534Sscottl 1799195534Sscottlstatic void 1800195534Sscottlscsi_toggle_tags(struct cam_path *path) 1801195534Sscottl{ 1802195534Sscottl struct cam_ed *dev; 1803195534Sscottl 1804195534Sscottl /* 1805195534Sscottl * Give controllers a chance to renegotiate 1806195534Sscottl * before starting tag operations. We 1807195534Sscottl * "toggle" tagged queuing off then on 1808195534Sscottl * which causes the tag enable command delay 1809195534Sscottl * counter to come into effect. 1810195534Sscottl */ 1811195534Sscottl dev = path->device; 1812195534Sscottl if ((dev->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 1813195534Sscottl || ((dev->inq_flags & SID_CmdQue) != 0 1814195534Sscottl && (dev->inq_flags & (SID_Sync|SID_WBus16|SID_WBus32)) != 0)) { 1815195534Sscottl struct ccb_trans_settings cts; 1816195534Sscottl 1817195534Sscottl xpt_setup_ccb(&cts.ccb_h, path, 1); 1818195534Sscottl cts.protocol = PROTO_SCSI; 1819195534Sscottl cts.protocol_version = PROTO_VERSION_UNSPECIFIED; 1820195534Sscottl cts.transport = XPORT_UNSPECIFIED; 1821195534Sscottl cts.transport_version = XPORT_VERSION_UNSPECIFIED; 1822195534Sscottl cts.proto_specific.scsi.flags = 0; 1823195534Sscottl cts.proto_specific.scsi.valid = CTS_SCSI_VALID_TQ; 1824195534Sscottl scsi_set_transfer_settings(&cts, path->device, 1825195534Sscottl /*async_update*/TRUE); 1826195534Sscottl cts.proto_specific.scsi.flags = CTS_SCSI_FLAGS_TAG_ENB; 1827195534Sscottl scsi_set_transfer_settings(&cts, path->device, 1828195534Sscottl /*async_update*/TRUE); 1829195534Sscottl } 1830195534Sscottl} 1831195534Sscottl 1832195534Sscottl/* 1833195534Sscottl * Handle any per-device event notifications that require action by the XPT. 1834195534Sscottl */ 1835195534Sscottlstatic void 1836195534Sscottlata_dev_async(u_int32_t async_code, struct cam_eb *bus, struct cam_et *target, 1837195534Sscottl struct cam_ed *device, void *async_arg) 1838195534Sscottl{ 1839195534Sscottl cam_status status; 1840195534Sscottl struct cam_path newpath; 1841195534Sscottl 1842195534Sscottl /* 1843195534Sscottl * We only need to handle events for real devices. 1844195534Sscottl */ 1845195534Sscottl if (target->target_id == CAM_TARGET_WILDCARD 1846195534Sscottl || device->lun_id == CAM_LUN_WILDCARD) 1847195534Sscottl return; 1848195534Sscottl 1849195534Sscottl /* 1850195534Sscottl * We need our own path with wildcards expanded to 1851195534Sscottl * handle certain types of events. 1852195534Sscottl */ 1853195534Sscottl if ((async_code == AC_SENT_BDR) 1854195534Sscottl || (async_code == AC_BUS_RESET) 1855195534Sscottl || (async_code == AC_INQ_CHANGED)) 1856195534Sscottl status = xpt_compile_path(&newpath, NULL, 1857195534Sscottl bus->path_id, 1858195534Sscottl target->target_id, 1859195534Sscottl device->lun_id); 1860195534Sscottl else 1861195534Sscottl status = CAM_REQ_CMP_ERR; 1862195534Sscottl 1863195534Sscottl if (status == CAM_REQ_CMP) { 1864195534Sscottl 1865195534Sscottl /* 1866195534Sscottl * Allow transfer negotiation to occur in a 1867195534Sscottl * tag free environment. 1868195534Sscottl */ 1869195534Sscottl if (async_code == AC_SENT_BDR 1870195534Sscottl || async_code == AC_BUS_RESET) 1871195534Sscottl scsi_toggle_tags(&newpath); 1872195534Sscottl 1873195534Sscottl if (async_code == AC_INQ_CHANGED) { 1874195534Sscottl /* 1875195534Sscottl * We've sent a start unit command, or 1876195534Sscottl * something similar to a device that 1877195534Sscottl * may have caused its inquiry data to 1878195534Sscottl * change. So we re-scan the device to 1879195534Sscottl * refresh the inquiry data for it. 1880195534Sscottl */ 1881195534Sscottl ata_scan_lun(newpath.periph, &newpath, 1882195534Sscottl CAM_EXPECT_INQ_CHANGE, NULL); 1883195534Sscottl } 1884195534Sscottl xpt_release_path(&newpath); 1885195534Sscottl } else if (async_code == AC_LOST_DEVICE) { 1886195534Sscottl device->flags |= CAM_DEV_UNCONFIGURED; 1887195534Sscottl } else if (async_code == AC_TRANSFER_NEG) { 1888195534Sscottl struct ccb_trans_settings *settings; 1889195534Sscottl 1890195534Sscottl settings = (struct ccb_trans_settings *)async_arg; 1891195534Sscottl scsi_set_transfer_settings(settings, device, 1892195534Sscottl /*async_update*/TRUE); 1893195534Sscottl } 1894195534Sscottl} 1895195534Sscottl 1896