ata_xpt.c revision 198897
1170530Ssam/*- 2178354Ssam * Copyright (c) 2009 Alexander Motin <mav@FreeBSD.org> 3170530Ssam * All rights reserved. 4170530Ssam * 5170530Ssam * Redistribution and use in source and binary forms, with or without 6170530Ssam * modification, are permitted provided that the following conditions 7170530Ssam * are met: 8170530Ssam * 1. Redistributions of source code must retain the above copyright 9170530Ssam * notice, this list of conditions and the following disclaimer, 10170530Ssam * without modification, immediately at the beginning of the file. 11170530Ssam * 2. Redistributions in binary form must reproduce the above copyright 12170530Ssam * notice, this list of conditions and the following disclaimer in the 13170530Ssam * documentation and/or other materials provided with the distribution. 14170530Ssam * 15170530Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16170530Ssam * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17170530Ssam * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18170530Ssam * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19170530Ssam * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20170530Ssam * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21170530Ssam * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22170530Ssam * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23170530Ssam * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24170530Ssam * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25170530Ssam */ 26170530Ssam 27170530Ssam#include <sys/cdefs.h> 28170530Ssam__FBSDID("$FreeBSD: head/sys/cam/ata/ata_xpt.c 198897 2009-11-04 15:24:32Z mav $"); 29170530Ssam 30170530Ssam#include <sys/param.h> 31170530Ssam#include <sys/bus.h> 32178354Ssam#include <sys/endian.h> 33178354Ssam#include <sys/systm.h> 34170530Ssam#include <sys/types.h> 35170530Ssam#include <sys/malloc.h> 36170530Ssam#include <sys/kernel.h> 37170530Ssam#include <sys/time.h> 38170530Ssam#include <sys/conf.h> 39170530Ssam#include <sys/fcntl.h> 40170530Ssam#include <sys/md5.h> 41170530Ssam#include <sys/interrupt.h> 42170530Ssam#include <sys/sbuf.h> 43170530Ssam 44170530Ssam#include <sys/lock.h> 45170530Ssam#include <sys/mutex.h> 46178354Ssam#include <sys/sysctl.h> 47178354Ssam 48170530Ssam#ifdef PC98 49170530Ssam#include <pc98/pc98/pc98_machdep.h> /* geometry translation */ 50170530Ssam#endif 51170530Ssam 52170530Ssam#include <cam/cam.h> 53170530Ssam#include <cam/cam_ccb.h> 54170530Ssam#include <cam/cam_queue.h> 55170530Ssam#include <cam/cam_periph.h> 56170530Ssam#include <cam/cam_sim.h> 57170530Ssam#include <cam/cam_xpt.h> 58170530Ssam#include <cam/cam_xpt_sim.h> 59170530Ssam#include <cam/cam_xpt_periph.h> 60170530Ssam#include <cam/cam_xpt_internal.h> 61170530Ssam#include <cam/cam_debug.h> 62170530Ssam 63170530Ssam#include <cam/scsi/scsi_all.h> 64170530Ssam#include <cam/scsi/scsi_message.h> 65170530Ssam#include <cam/ata/ata_all.h> 66170530Ssam#include <machine/stdarg.h> /* for xpt_print below */ 67170530Ssam#include "opt_cam.h" 68170530Ssam 69170530Ssamstruct scsi_quirk_entry { 70170530Ssam struct scsi_inquiry_pattern inq_pat; 71170530Ssam u_int8_t quirks; 72170530Ssam#define CAM_QUIRK_NOLUNS 0x01 73170530Ssam#define CAM_QUIRK_NOSERIAL 0x02 74170530Ssam#define CAM_QUIRK_HILUNS 0x04 75170530Ssam#define CAM_QUIRK_NOHILUNS 0x08 76178354Ssam u_int mintags; 77178354Ssam u_int maxtags; 78170530Ssam}; 79170530Ssam#define SCSI_QUIRK(dev) ((struct scsi_quirk_entry *)((dev)->quirk)) 80170530Ssam 81170530Ssamstatic periph_init_t probe_periph_init; 82170530Ssam 83178354Ssamstatic struct periph_driver probe_driver = 84170530Ssam{ 85170530Ssam probe_periph_init, "aprobe", 86170530Ssam TAILQ_HEAD_INITIALIZER(probe_driver.units), /* generation */ 0, 87170530Ssam CAM_PERIPH_DRV_EARLY 88170530Ssam}; 89170530Ssam 90170530SsamPERIPHDRIVER_DECLARE(aprobe, probe_driver); 91170530Ssam 92170530Ssamtypedef enum { 93170530Ssam PROBE_RESET, 94170530Ssam PROBE_IDENTIFY, 95178354Ssam PROBE_SETMODE, 96178354Ssam PROBE_SET_MULTI, 97178354Ssam PROBE_INQUIRY, 98170530Ssam PROBE_FULL_INQUIRY, 99178354Ssam PROBE_PM_PID, 100178354Ssam PROBE_PM_PRV, 101170530Ssam PROBE_INVALID 102170530Ssam} probe_action; 103170530Ssam 104171409Ssamstatic char *probe_action_text[] = { 105171409Ssam "PROBE_RESET", 106171409Ssam "PROBE_IDENTIFY", 107171409Ssam "PROBE_SETMODE", 108171409Ssam "PROBE_SET_MULTI", 109171409Ssam "PROBE_INQUIRY", 110171409Ssam "PROBE_FULL_INQUIRY", 111171409Ssam "PROBE_PM_PID", 112171409Ssam "PROBE_PM_PRV", 113171409Ssam "PROBE_INVALID" 114171409Ssam}; 115171409Ssam 116171409Ssam#define PROBE_SET_ACTION(softc, newaction) \ 117171409Ssamdo { \ 118171409Ssam char **text; \ 119178354Ssam text = probe_action_text; \ 120178354Ssam CAM_DEBUG((softc)->periph->path, CAM_DEBUG_INFO, \ 121170530Ssam ("Probe %s to %s\n", text[(softc)->action], \ 122178354Ssam text[(newaction)])); \ 123170530Ssam (softc)->action = (newaction); \ 124178354Ssam} while(0) 125178354Ssam 126178354Ssamtypedef enum { 127178354Ssam PROBE_NO_ANNOUNCE = 0x04 128178354Ssam} probe_flags; 129178354Ssam 130170530Ssamtypedef struct { 131170530Ssam TAILQ_HEAD(, ccb_hdr) request_ccbs; 132170530Ssam probe_action action; 133170530Ssam union ccb saved_ccb; 134170530Ssam probe_flags flags; 135170530Ssam u_int8_t digest[16]; 136170530Ssam uint32_t pm_pid; 137170530Ssam uint32_t pm_prv; 138170530Ssam struct cam_periph *periph; 139170530Ssam} probe_softc; 140170530Ssam 141170530Ssamstatic struct scsi_quirk_entry scsi_quirk_table[] = 142170530Ssam{ 143170530Ssam { 144170530Ssam /* Default tagged queuing parameters for all devices */ 145170530Ssam { 146170530Ssam T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED, 147170530Ssam /*vendor*/"*", /*product*/"*", /*revision*/"*" 148170530Ssam }, 149170530Ssam /*quirks*/0, /*mintags*/2, /*maxtags*/32 150170530Ssam }, 151170530Ssam}; 152170530Ssam 153170530Ssamstatic const int scsi_quirk_table_size = 154170530Ssam sizeof(scsi_quirk_table) / sizeof(*scsi_quirk_table); 155170530Ssam 156170530Ssamstatic cam_status proberegister(struct cam_periph *periph, 157170530Ssam void *arg); 158170530Ssamstatic void probeschedule(struct cam_periph *probe_periph); 159170530Ssamstatic void probestart(struct cam_periph *periph, union ccb *start_ccb); 160170530Ssam//static void proberequestdefaultnegotiation(struct cam_periph *periph); 161170530Ssam//static int proberequestbackoff(struct cam_periph *periph, 162170530Ssam// struct cam_ed *device); 163170530Ssamstatic void probedone(struct cam_periph *periph, union ccb *done_ccb); 164170530Ssamstatic void probecleanup(struct cam_periph *periph); 165170530Ssamstatic void scsi_find_quirk(struct cam_ed *device); 166170530Ssamstatic void ata_scan_bus(struct cam_periph *periph, union ccb *ccb); 167170530Ssamstatic void ata_scan_lun(struct cam_periph *periph, 168170530Ssam struct cam_path *path, cam_flags flags, 169170530Ssam union ccb *ccb); 170170530Ssamstatic void xptscandone(struct cam_periph *periph, union ccb *done_ccb); 171170530Ssamstatic struct cam_ed * 172170530Ssam ata_alloc_device(struct cam_eb *bus, struct cam_et *target, 173170530Ssam lun_id_t lun_id); 174170530Ssamstatic void ata_device_transport(struct cam_path *path); 175170530Ssamstatic void scsi_set_transfer_settings(struct ccb_trans_settings *cts, 176170530Ssam struct cam_ed *device, 177170530Ssam int async_update); 178170530Ssamstatic void scsi_toggle_tags(struct cam_path *path); 179170530Ssamstatic void ata_dev_async(u_int32_t async_code, 180170530Ssam struct cam_eb *bus, 181170530Ssam struct cam_et *target, 182170530Ssam struct cam_ed *device, 183170530Ssam void *async_arg); 184170530Ssamstatic void ata_action(union ccb *start_ccb); 185170530Ssam 186170530Ssamstatic struct xpt_xport ata_xport = { 187170530Ssam .alloc_device = ata_alloc_device, 188170530Ssam .action = ata_action, 189170530Ssam .async = ata_dev_async, 190170530Ssam}; 191170530Ssam 192170530Ssamstruct xpt_xport * 193170530Ssamata_get_xport(void) 194170530Ssam{ 195170530Ssam return (&ata_xport); 196170530Ssam} 197170530Ssam 198178354Ssamstatic void 199170530Ssamprobe_periph_init() 200170530Ssam{ 201178354Ssam} 202170530Ssam 203170530Ssamstatic cam_status 204170530Ssamproberegister(struct cam_periph *periph, void *arg) 205170530Ssam{ 206170530Ssam union ccb *request_ccb; /* CCB representing the probe request */ 207170530Ssam cam_status status; 208170530Ssam probe_softc *softc; 209170530Ssam 210170530Ssam request_ccb = (union ccb *)arg; 211170530Ssam if (periph == NULL) { 212170530Ssam printf("proberegister: periph was NULL!!\n"); 213170530Ssam return(CAM_REQ_CMP_ERR); 214170530Ssam } 215170530Ssam 216170530Ssam if (request_ccb == NULL) { 217170530Ssam printf("proberegister: no probe CCB, " 218170530Ssam "can't register device\n"); 219170530Ssam return(CAM_REQ_CMP_ERR); 220178354Ssam } 221178354Ssam 222170530Ssam softc = (probe_softc *)malloc(sizeof(*softc), M_CAMXPT, M_NOWAIT); 223170530Ssam 224178354Ssam if (softc == NULL) { 225170530Ssam printf("proberegister: Unable to probe new device. " 226170530Ssam "Unable to allocate softc\n"); 227170530Ssam return(CAM_REQ_CMP_ERR); 228170530Ssam } 229170530Ssam TAILQ_INIT(&softc->request_ccbs); 230170530Ssam TAILQ_INSERT_TAIL(&softc->request_ccbs, &request_ccb->ccb_h, 231170530Ssam periph_links.tqe); 232170530Ssam softc->flags = 0; 233170530Ssam periph->softc = softc; 234170530Ssam softc->periph = periph; 235170530Ssam softc->action = PROBE_INVALID; 236170530Ssam status = cam_periph_acquire(periph); 237170530Ssam if (status != CAM_REQ_CMP) { 238178354Ssam return (status); 239178354Ssam } 240170530Ssam 241170530Ssam 242170530Ssam /* 243170530Ssam * Ensure we've waited at least a bus settle 244170530Ssam * delay before attempting to probe the device. 245170530Ssam * For HBAs that don't do bus resets, this won't make a difference. 246170530Ssam */ 247170530Ssam cam_periph_freeze_after_event(periph, &periph->path->bus->last_reset, 248170530Ssam scsi_delay); 249170530Ssam probeschedule(periph); 250170530Ssam return(CAM_REQ_CMP); 251170530Ssam} 252170530Ssam 253170530Ssamstatic void 254178354Ssamprobeschedule(struct cam_periph *periph) 255170530Ssam{ 256170530Ssam struct ccb_pathinq cpi; 257170530Ssam union ccb *ccb; 258170530Ssam probe_softc *softc; 259170530Ssam 260178354Ssam softc = (probe_softc *)periph->softc; 261173368Ssam ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs); 262173368Ssam 263173368Ssam xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 264173368Ssam cpi.ccb_h.func_code = XPT_PATH_INQ; 265173368Ssam xpt_action((union ccb *)&cpi); 266173368Ssam 267178354Ssam if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) || 268178354Ssam periph->path->device->protocol == PROTO_SATAPM) 269173368Ssam PROBE_SET_ACTION(softc, PROBE_RESET); 270173368Ssam else 271170530Ssam PROBE_SET_ACTION(softc, PROBE_IDENTIFY); 272170530Ssam 273170530Ssam if (ccb->crcn.flags & CAM_EXPECT_INQ_CHANGE) 274170530Ssam softc->flags |= PROBE_NO_ANNOUNCE; 275173368Ssam else 276173368Ssam softc->flags &= ~PROBE_NO_ANNOUNCE; 277173368Ssam 278178354Ssam xpt_schedule(periph, ccb->ccb_h.pinfo.priority); 279173368Ssam} 280178354Ssam 281173862Ssamstatic void 282173368Ssamprobestart(struct cam_periph *periph, union ccb *start_ccb) 283173862Ssam{ 284178354Ssam /* Probe the device that our peripheral driver points to */ 285178354Ssam struct ccb_ataio *ataio; 286178354Ssam struct ccb_scsiio *csio; 287173368Ssam probe_softc *softc; 288178354Ssam struct cam_path *path; 289178354Ssam struct ata_params *ident_buf; 290173956Ssam 291173956Ssam CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probestart\n")); 292173956Ssam 293173862Ssam softc = (probe_softc *)periph->softc; 294178354Ssam path = start_ccb->ccb_h.path; 295173862Ssam ataio = &start_ccb->ataio; 296173862Ssam csio = &start_ccb->csio; 297178354Ssam ident_buf = &periph->path->device->ident_data; 298170530Ssam 299170530Ssam switch (softc->action) { 300170530Ssam case PROBE_RESET: 301170530Ssam cam_fill_ataio(ataio, 302170530Ssam 0, 303170530Ssam probedone, 304170530Ssam /*flags*/CAM_DIR_NONE, 305170530Ssam 0, 306170530Ssam /*data_ptr*/NULL, 307178354Ssam /*dxfer_len*/0, 308178354Ssam (start_ccb->ccb_h.target_id == 15 ? 3 : 15) * 1000); 309178354Ssam ata_reset_cmd(ataio); 310178354Ssam break; 311178354Ssam case PROBE_IDENTIFY: 312178354Ssam if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) == 0) { 313178354Ssam /* Prepare check that it is the same device. */ 314178354Ssam MD5_CTX context; 315178354Ssam 316178354Ssam MD5Init(&context); 317178354Ssam MD5Update(&context, 318178354Ssam (unsigned char *)ident_buf->model, 319178354Ssam sizeof(ident_buf->model)); 320178354Ssam MD5Update(&context, 321178354Ssam (unsigned char *)ident_buf->revision, 322178354Ssam sizeof(ident_buf->revision)); 323178354Ssam MD5Update(&context, 324178354Ssam (unsigned char *)ident_buf->serial, 325178354Ssam sizeof(ident_buf->serial)); 326178354Ssam MD5Final(softc->digest, &context); 327178354Ssam } 328178354Ssam cam_fill_ataio(ataio, 329178354Ssam 1, 330178354Ssam probedone, 331178354Ssam /*flags*/CAM_DIR_IN, 332178354Ssam 0, 333178354Ssam /*data_ptr*/(u_int8_t *)ident_buf, 334178354Ssam /*dxfer_len*/sizeof(struct ata_params), 335170530Ssam 30 * 1000); 336170530Ssam if (periph->path->device->protocol == PROTO_ATA) 337170530Ssam ata_28bit_cmd(ataio, ATA_ATA_IDENTIFY, 0, 0, 0); 338170530Ssam else 339178354Ssam ata_28bit_cmd(ataio, ATA_ATAPI_IDENTIFY, 0, 0, 0); 340170530Ssam break; 341170530Ssam case PROBE_SETMODE: 342170530Ssam cam_fill_ataio(ataio, 343170530Ssam 1, 344170530Ssam probedone, 345170530Ssam /*flags*/CAM_DIR_NONE, 346170530Ssam 0, 347178354Ssam /*data_ptr*/NULL, 348178354Ssam /*dxfer_len*/0, 349178354Ssam 30 * 1000); 350170530Ssam ata_28bit_cmd(ataio, ATA_SETFEATURES, ATA_SF_SETXFER, 0, 351170530Ssam ata_max_mode(ident_buf, ATA_UDMA6, ATA_UDMA6)); 352170530Ssam break; 353170530Ssam case PROBE_SET_MULTI: 354170530Ssam { 355170530Ssam struct ccb_trans_settings cts; 356178354Ssam u_int sectors; 357170530Ssam 358170530Ssam sectors = max(1, min(ident_buf->sectors_intr & 0xff, 16)); 359170530Ssam 360170530Ssam /* Report bytecount to SIM. */ 361170530Ssam bzero(&cts, sizeof(cts)); 362170530Ssam xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL); 363170530Ssam cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 364170530Ssam cts.type = CTS_TYPE_CURRENT_SETTINGS; 365170530Ssam if (path->device->transport == XPORT_ATA) { 366170530Ssam cts.xport_specific.ata.bytecount = sectors * 367170530Ssam ata_logical_sector_size(ident_buf); 368178354Ssam cts.xport_specific.ata.valid = CTS_ATA_VALID_BYTECOUNT; 369170530Ssam } else { 370178354Ssam cts.xport_specific.sata.bytecount = sectors * 371178354Ssam ata_logical_sector_size(ident_buf); 372178354Ssam cts.xport_specific.sata.valid = CTS_SATA_VALID_BYTECOUNT; 373170530Ssam } 374170530Ssam xpt_action((union ccb *)&cts); 375170530Ssam 376170530Ssam cam_fill_ataio(ataio, 377170530Ssam 1, 378170530Ssam probedone, 379170530Ssam CAM_DIR_NONE, 380170530Ssam 0, 381170530Ssam NULL, 382170530Ssam 0, 383170530Ssam 30*1000); 384170530Ssam ata_28bit_cmd(ataio, ATA_SET_MULTI, 0, 0, sectors); 385170530Ssam break; 386170530Ssam } 387170530Ssam case PROBE_INQUIRY: 388170530Ssam case PROBE_FULL_INQUIRY: 389170530Ssam { 390170530Ssam u_int inquiry_len; 391170530Ssam struct scsi_inquiry_data *inq_buf = 392170530Ssam &periph->path->device->inq_data; 393170530Ssam 394170530Ssam if (softc->action == PROBE_INQUIRY) 395170530Ssam inquiry_len = SHORT_INQUIRY_LENGTH; 396170530Ssam else 397170530Ssam inquiry_len = SID_ADDITIONAL_LENGTH(inq_buf); 398170530Ssam /* 399170530Ssam * Some parallel SCSI devices fail to send an 400170530Ssam * ignore wide residue message when dealing with 401170530Ssam * odd length inquiry requests. Round up to be 402170530Ssam * safe. 403170530Ssam */ 404170530Ssam inquiry_len = roundup2(inquiry_len, 2); 405170530Ssam scsi_inquiry(csio, 406170530Ssam /*retries*/1, 407170530Ssam probedone, 408170530Ssam MSG_SIMPLE_Q_TAG, 409170530Ssam (u_int8_t *)inq_buf, 410170530Ssam inquiry_len, 411170530Ssam /*evpd*/FALSE, 412178354Ssam /*page_code*/0, 413170530Ssam SSD_MIN_SIZE, 414170530Ssam /*timeout*/60 * 1000); 415170530Ssam break; 416170530Ssam } 417178354Ssam case PROBE_PM_PID: 418170530Ssam cam_fill_ataio(ataio, 419170530Ssam 1, 420170530Ssam probedone, 421170530Ssam /*flags*/CAM_DIR_NONE, 422170530Ssam 0, 423170530Ssam /*data_ptr*/NULL, 424170530Ssam /*dxfer_len*/0, 425170530Ssam 10 * 1000); 426170530Ssam ata_pm_read_cmd(ataio, 0, 15); 427170530Ssam break; 428170530Ssam case PROBE_PM_PRV: 429178354Ssam cam_fill_ataio(ataio, 430170530Ssam 1, 431170530Ssam probedone, 432170530Ssam /*flags*/CAM_DIR_NONE, 433170530Ssam 0, 434178354Ssam /*data_ptr*/NULL, 435170530Ssam /*dxfer_len*/0, 436178354Ssam 10 * 1000); 437178354Ssam ata_pm_read_cmd(ataio, 1, 15); 438178354Ssam break; 439170530Ssam case PROBE_INVALID: 440170530Ssam CAM_DEBUG(path, CAM_DEBUG_INFO, 441170530Ssam ("probestart: invalid action state\n")); 442170530Ssam default: 443170530Ssam break; 444170530Ssam } 445170530Ssam xpt_action(start_ccb); 446170530Ssam} 447170530Ssam#if 0 448170530Ssamstatic void 449170530Ssamproberequestdefaultnegotiation(struct cam_periph *periph) 450170530Ssam{ 451170530Ssam struct ccb_trans_settings cts; 452170530Ssam 453170530Ssam xpt_setup_ccb(&cts.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 454170530Ssam cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 455170530Ssam cts.type = CTS_TYPE_USER_SETTINGS; 456170530Ssam xpt_action((union ccb *)&cts); 457170530Ssam if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 458170530Ssam return; 459170530Ssam } 460170530Ssam cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 461170530Ssam cts.type = CTS_TYPE_CURRENT_SETTINGS; 462170530Ssam xpt_action((union ccb *)&cts); 463170530Ssam} 464176653Ssam 465178354Ssam/* 466176653Ssam * Backoff Negotiation Code- only pertinent for SPI devices. 467176653Ssam */ 468178354Ssamstatic int 469176653Ssamproberequestbackoff(struct cam_periph *periph, struct cam_ed *device) 470176653Ssam{ 471176653Ssam struct ccb_trans_settings cts; 472176653Ssam struct ccb_trans_settings_spi *spi; 473176653Ssam 474176653Ssam memset(&cts, 0, sizeof (cts)); 475176653Ssam xpt_setup_ccb(&cts.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 476176653Ssam cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 477176653Ssam cts.type = CTS_TYPE_CURRENT_SETTINGS; 478176653Ssam xpt_action((union ccb *)&cts); 479176653Ssam if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 480176653Ssam if (bootverbose) { 481176653Ssam xpt_print(periph->path, 482176653Ssam "failed to get current device settings\n"); 483176653Ssam } 484176653Ssam return (0); 485176653Ssam } 486176653Ssam if (cts.transport != XPORT_SPI) { 487176653Ssam if (bootverbose) { 488176653Ssam xpt_print(periph->path, "not SPI transport\n"); 489176653Ssam } 490178354Ssam return (0); 491178354Ssam } 492176653Ssam spi = &cts.xport_specific.spi; 493176653Ssam 494176653Ssam /* 495176653Ssam * We cannot renegotiate sync rate if we don't have one. 496176653Ssam */ 497178354Ssam if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0) { 498176653Ssam if (bootverbose) { 499176653Ssam xpt_print(periph->path, "no sync rate known\n"); 500176653Ssam } 501176653Ssam return (0); 502176653Ssam } 503176653Ssam 504176653Ssam /* 505176653Ssam * We'll assert that we don't have to touch PPR options- the 506176653Ssam * SIM will see what we do with period and offset and adjust 507176653Ssam * the PPR options as appropriate. 508176653Ssam */ 509176653Ssam 510176653Ssam /* 511176653Ssam * A sync rate with unknown or zero offset is nonsensical. 512176653Ssam * A sync period of zero means Async. 513176653Ssam */ 514178354Ssam if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0 515178354Ssam || spi->sync_offset == 0 || spi->sync_period == 0) { 516178354Ssam if (bootverbose) { 517170530Ssam xpt_print(periph->path, "no sync rate available\n"); 518170530Ssam } 519170530Ssam return (0); 520170530Ssam } 521170530Ssam 522170530Ssam if (device->flags & CAM_DEV_DV_HIT_BOTTOM) { 523170530Ssam CAM_DEBUG(periph->path, CAM_DEBUG_INFO, 524170530Ssam ("hit async: giving up on DV\n")); 525170530Ssam return (0); 526170530Ssam } 527178354Ssam 528170530Ssam 529178354Ssam /* 530170530Ssam * Jump sync_period up by one, but stop at 5MHz and fall back to Async. 531170530Ssam * We don't try to remember 'last' settings to see if the SIM actually 532170530Ssam * gets into the speed we want to set. We check on the SIM telling 533170530Ssam * us that a requested speed is bad, but otherwise don't try and 534178354Ssam * check the speed due to the asynchronous and handshake nature 535170530Ssam * of speed setting. 536170530Ssam */ 537170530Ssam spi->valid = CTS_SPI_VALID_SYNC_RATE | CTS_SPI_VALID_SYNC_OFFSET; 538170530Ssam for (;;) { 539170530Ssam spi->sync_period++; 540178354Ssam if (spi->sync_period >= 0xf) { 541170530Ssam spi->sync_period = 0; 542170530Ssam spi->sync_offset = 0; 543170530Ssam CAM_DEBUG(periph->path, CAM_DEBUG_INFO, 544170530Ssam ("setting to async for DV\n")); 545170530Ssam /* 546170530Ssam * Once we hit async, we don't want to try 547170530Ssam * any more settings. 548170530Ssam */ 549170530Ssam device->flags |= CAM_DEV_DV_HIT_BOTTOM; 550170530Ssam } else if (bootverbose) { 551170530Ssam CAM_DEBUG(periph->path, CAM_DEBUG_INFO, 552170530Ssam ("DV: period 0x%x\n", spi->sync_period)); 553170530Ssam printf("setting period to 0x%x\n", spi->sync_period); 554170530Ssam } 555178354Ssam cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 556170530Ssam cts.type = CTS_TYPE_CURRENT_SETTINGS; 557170530Ssam xpt_action((union ccb *)&cts); 558170530Ssam if ((cts.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 559170530Ssam break; 560170530Ssam } 561170530Ssam CAM_DEBUG(periph->path, CAM_DEBUG_INFO, 562170530Ssam ("DV: failed to set period 0x%x\n", spi->sync_period)); 563170530Ssam if (spi->sync_period == 0) { 564170530Ssam return (0); 565178354Ssam } 566170530Ssam } 567170530Ssam return (1); 568170530Ssam} 569178354Ssam#endif 570178354Ssamstatic void 571170530Ssamprobedone(struct cam_periph *periph, union ccb *done_ccb) 572178354Ssam{ 573178354Ssam struct ata_params *ident_buf; 574170530Ssam probe_softc *softc; 575178354Ssam struct cam_path *path; 576178354Ssam u_int32_t priority; 577178354Ssam int found = 1; 578178354Ssam 579178354Ssam CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probedone\n")); 580178354Ssam 581178354Ssam softc = (probe_softc *)periph->softc; 582178354Ssam path = done_ccb->ccb_h.path; 583178354Ssam priority = done_ccb->ccb_h.pinfo.priority; 584178354Ssam ident_buf = &path->device->ident_data; 585178354Ssam 586178354Ssam if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 587178354Ssamdevice_fail: if (cam_periph_error(done_ccb, 0, 0, 588178354Ssam &softc->saved_ccb) == ERESTART) { 589178354Ssam return; 590178354Ssam } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 591178354Ssam /* Don't wedge the queue */ 592178354Ssam xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, 593178354Ssam /*run_queue*/TRUE); 594178354Ssam } 595178354Ssam /* Old PIO2 devices may not support mode setting. */ 596178354Ssam if (softc->action == PROBE_SETMODE && 597178354Ssam ata_max_pmode(ident_buf) <= ATA_PIO2 && 598178354Ssam (ident_buf->capabilities1 & ATA_SUPPORT_IORDY) == 0) 599178354Ssam goto noerror; 600178354Ssam /* 601178354Ssam * If we get to this point, we got an error status back 602178354Ssam * from the inquiry and the error status doesn't require 603178354Ssam * automatically retrying the command. Therefore, the 604178354Ssam * inquiry failed. If we had inquiry information before 605170530Ssam * for this device, but this latest inquiry command failed, 606178354Ssam * the device has probably gone away. If this device isn't 607170530Ssam * already marked unconfigured, notify the peripheral 608178354Ssam * drivers that this device is no more. 609178354Ssam */ 610178354Ssam if ((path->device->flags & CAM_DEV_UNCONFIGURED) == 0) 611178354Ssam xpt_async(AC_LOST_DEVICE, path, NULL); 612178354Ssam found = 0; 613178354Ssam goto done; 614178354Ssam } 615178354Ssamnoerror: 616178354Ssam switch (softc->action) { 617178354Ssam case PROBE_RESET: 618178354Ssam { 619178354Ssam int sign = (done_ccb->ataio.res.lba_high << 8) + 620178354Ssam done_ccb->ataio.res.lba_mid; 621178354Ssam xpt_print(path, "SIGNATURE: %04x\n", sign); 622178354Ssam if (sign == 0x0000 && 623178354Ssam done_ccb->ccb_h.target_id != 15) { 624178354Ssam path->device->protocol = PROTO_ATA; 625178354Ssam PROBE_SET_ACTION(softc, PROBE_IDENTIFY); 626178354Ssam } else if (sign == 0x9669 && 627178354Ssam done_ccb->ccb_h.target_id == 15) { 628178354Ssam struct ccb_trans_settings cts; 629178354Ssam 630178354Ssam /* Report SIM that PM is present. */ 631178354Ssam bzero(&cts, sizeof(cts)); 632178354Ssam xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL); 633178354Ssam cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 634178354Ssam cts.type = CTS_TYPE_CURRENT_SETTINGS; 635178354Ssam cts.xport_specific.sata.pm_present = 1; 636178354Ssam cts.xport_specific.sata.valid = CTS_SATA_VALID_PM; 637178354Ssam xpt_action((union ccb *)&cts); 638178354Ssam path->device->protocol = PROTO_SATAPM; 639178354Ssam PROBE_SET_ACTION(softc, PROBE_PM_PID); 640178354Ssam } else if (sign == 0xeb14 && 641178354Ssam done_ccb->ccb_h.target_id != 15) { 642178354Ssam path->device->protocol = PROTO_SCSI; 643178354Ssam PROBE_SET_ACTION(softc, PROBE_IDENTIFY); 644178354Ssam } else { 645178354Ssam if (done_ccb->ccb_h.target_id != 15) { 646170530Ssam xpt_print(path, 647170530Ssam "Unexpected signature 0x%04x\n", sign); 648170530Ssam } 649170530Ssam goto device_fail; 650170530Ssam } 651170530Ssam xpt_release_ccb(done_ccb); 652178354Ssam xpt_schedule(periph, priority); 653178354Ssam return; 654170530Ssam } 655170530Ssam case PROBE_IDENTIFY: 656178354Ssam { 657170530Ssam int16_t *ptr; 658170530Ssam 659170530Ssam for (ptr = (int16_t *)ident_buf; 660170530Ssam ptr < (int16_t *)ident_buf + sizeof(struct ata_params)/2; ptr++) { 661170530Ssam *ptr = le16toh(*ptr); 662170530Ssam } 663170530Ssam if (strncmp(ident_buf->model, "FX", 2) && 664170530Ssam strncmp(ident_buf->model, "NEC", 3) && 665170530Ssam strncmp(ident_buf->model, "Pioneer", 7) && 666170530Ssam strncmp(ident_buf->model, "SHARP", 5)) { 667170530Ssam ata_bswap(ident_buf->model, sizeof(ident_buf->model)); 668178354Ssam ata_bswap(ident_buf->revision, sizeof(ident_buf->revision)); 669170530Ssam ata_bswap(ident_buf->serial, sizeof(ident_buf->serial)); 670170530Ssam } 671170530Ssam ata_btrim(ident_buf->model, sizeof(ident_buf->model)); 672170530Ssam ata_bpack(ident_buf->model, ident_buf->model, sizeof(ident_buf->model)); 673178354Ssam ata_btrim(ident_buf->revision, sizeof(ident_buf->revision)); 674178354Ssam ata_bpack(ident_buf->revision, ident_buf->revision, sizeof(ident_buf->revision)); 675178354Ssam ata_btrim(ident_buf->serial, sizeof(ident_buf->serial)); 676178354Ssam ata_bpack(ident_buf->serial, ident_buf->serial, sizeof(ident_buf->serial)); 677178354Ssam 678178354Ssam if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) == 0) { 679178354Ssam /* Check that it is the same device. */ 680170530Ssam MD5_CTX context; 681170530Ssam u_int8_t digest[16]; 682178354Ssam 683178354Ssam MD5Init(&context); 684178354Ssam MD5Update(&context, 685178354Ssam (unsigned char *)ident_buf->model, 686170530Ssam sizeof(ident_buf->model)); 687170530Ssam MD5Update(&context, 688178354Ssam (unsigned char *)ident_buf->revision, 689178354Ssam sizeof(ident_buf->revision)); 690178354Ssam MD5Update(&context, 691178354Ssam (unsigned char *)ident_buf->serial, 692178354Ssam sizeof(ident_buf->serial)); 693178354Ssam MD5Final(digest, &context); 694178354Ssam if (bcmp(digest, softc->digest, sizeof(digest))) { 695178354Ssam /* Device changed. */ 696178354Ssam xpt_async(AC_LOST_DEVICE, path, NULL); 697178354Ssam } 698178354Ssam } else { 699178354Ssam /* Clean up from previous instance of this device */ 700178354Ssam if (path->device->serial_num != NULL) { 701178354Ssam free(path->device->serial_num, M_CAMXPT); 702178354Ssam path->device->serial_num = NULL; 703178354Ssam path->device->serial_num_len = 0; 704178354Ssam } 705178354Ssam path->device->serial_num = 706170530Ssam (u_int8_t *)malloc((sizeof(ident_buf->serial) + 1), 707170530Ssam M_CAMXPT, M_NOWAIT); 708170530Ssam if (path->device->serial_num != NULL) { 709170530Ssam bcopy(ident_buf->serial, 710170530Ssam path->device->serial_num, 711170530Ssam sizeof(ident_buf->serial)); 712170530Ssam path->device->serial_num[sizeof(ident_buf->serial)] 713170530Ssam = '\0'; 714170530Ssam path->device->serial_num_len = 715170530Ssam strlen(path->device->serial_num); 716170530Ssam } 717170530Ssam 718170530Ssam path->device->flags |= CAM_DEV_IDENTIFY_DATA_VALID; 719170530Ssam } 720170530Ssam ata_device_transport(path); 721170530Ssam PROBE_SET_ACTION(softc, PROBE_SETMODE); 722170530Ssam xpt_release_ccb(done_ccb); 723170530Ssam xpt_schedule(periph, priority); 724170530Ssam return; 725170530Ssam } 726170530Ssam case PROBE_SETMODE: 727170530Ssam if (path->device->protocol == PROTO_ATA) { 728170530Ssam PROBE_SET_ACTION(softc, PROBE_SET_MULTI); 729170530Ssam } else { 730170530Ssam PROBE_SET_ACTION(softc, PROBE_INQUIRY); 731170530Ssam } 732170530Ssam xpt_release_ccb(done_ccb); 733178354Ssam xpt_schedule(periph, priority); 734170530Ssam return; 735170530Ssam case PROBE_SET_MULTI: 736170530Ssam if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) { 737170530Ssam path->device->flags &= ~CAM_DEV_UNCONFIGURED; 738170530Ssam xpt_acquire_device(path->device); 739170530Ssam done_ccb->ccb_h.func_code = XPT_GDEV_TYPE; 740170530Ssam xpt_action(done_ccb); 741170530Ssam xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path, 742170530Ssam done_ccb); 743170530Ssam } 744170530Ssam break; 745170530Ssam case PROBE_INQUIRY: 746170530Ssam case PROBE_FULL_INQUIRY: 747170530Ssam { 748170530Ssam struct scsi_inquiry_data *inq_buf; 749170530Ssam u_int8_t periph_qual, len; 750170530Ssam 751170530Ssam path->device->flags |= CAM_DEV_INQUIRY_DATA_VALID; 752170530Ssam inq_buf = &path->device->inq_data; 753170530Ssam 754170530Ssam periph_qual = SID_QUAL(inq_buf); 755170530Ssam 756170530Ssam if (periph_qual != SID_QUAL_LU_CONNECTED) 757170530Ssam break; 758170530Ssam 759170530Ssam /* 760170530Ssam * We conservatively request only 761170530Ssam * SHORT_INQUIRY_LEN bytes of inquiry 762170530Ssam * information during our first try 763170530Ssam * at sending an INQUIRY. If the device 764178354Ssam * has more information to give, 765178354Ssam * perform a second request specifying 766170530Ssam * the amount of information the device 767170530Ssam * is willing to give. 768170530Ssam */ 769170530Ssam len = inq_buf->additional_length 770170530Ssam + offsetof(struct scsi_inquiry_data, additional_length) + 1; 771170530Ssam if (softc->action == PROBE_INQUIRY 772170530Ssam && len > SHORT_INQUIRY_LENGTH) { 773170530Ssam PROBE_SET_ACTION(softc, PROBE_FULL_INQUIRY); 774178354Ssam xpt_release_ccb(done_ccb); 775170530Ssam xpt_schedule(periph, priority); 776170530Ssam return; 777178354Ssam } 778170530Ssam 779170530Ssam scsi_find_quirk(path->device); 780170530Ssam ata_device_transport(path); 781178354Ssam if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) { 782170530Ssam path->device->flags &= ~CAM_DEV_UNCONFIGURED; 783170530Ssam xpt_acquire_device(path->device); 784178354Ssam done_ccb->ccb_h.func_code = XPT_GDEV_TYPE; 785170530Ssam xpt_action(done_ccb); 786178354Ssam xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path, done_ccb); 787170530Ssam } 788170530Ssam break; 789178354Ssam } 790178354Ssam case PROBE_PM_PID: 791170530Ssam if ((path->device->flags & CAM_DEV_IDENTIFY_DATA_VALID) == 0) 792170530Ssam bzero(ident_buf, sizeof(*ident_buf)); 793170530Ssam softc->pm_pid = (done_ccb->ataio.res.lba_high << 24) + 794170530Ssam (done_ccb->ataio.res.lba_mid << 16) + 795170530Ssam (done_ccb->ataio.res.lba_low << 8) + 796170530Ssam done_ccb->ataio.res.sector_count; 797170530Ssam ((uint32_t *)ident_buf)[0] = softc->pm_pid; 798170530Ssam printf("PM Product ID: %08x\n", softc->pm_pid); 799178354Ssam snprintf(ident_buf->model, sizeof(ident_buf->model), 800170530Ssam "Port Multiplier %08x", softc->pm_pid); 801170530Ssam PROBE_SET_ACTION(softc, PROBE_PM_PRV); 802170530Ssam xpt_release_ccb(done_ccb); 803170530Ssam xpt_schedule(periph, priority); 804170530Ssam return; 805170530Ssam case PROBE_PM_PRV: 806170530Ssam softc->pm_prv = (done_ccb->ataio.res.lba_high << 24) + 807170530Ssam (done_ccb->ataio.res.lba_mid << 16) + 808170530Ssam (done_ccb->ataio.res.lba_low << 8) + 809170530Ssam done_ccb->ataio.res.sector_count; 810170530Ssam ((uint32_t *)ident_buf)[1] = softc->pm_prv; 811170530Ssam printf("PM Revision: %08x\n", softc->pm_prv); 812170530Ssam snprintf(ident_buf->revision, sizeof(ident_buf->revision), 813170530Ssam "%04x", softc->pm_prv); 814170530Ssam path->device->flags |= CAM_DEV_IDENTIFY_DATA_VALID; 815170530Ssam if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) { 816170530Ssam path->device->flags &= ~CAM_DEV_UNCONFIGURED; 817170530Ssam xpt_acquire_device(path->device); 818170530Ssam done_ccb->ccb_h.func_code = XPT_GDEV_TYPE; 819170530Ssam xpt_action(done_ccb); 820170530Ssam xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path, 821170530Ssam done_ccb); 822170530Ssam } else { 823170530Ssam done_ccb->ccb_h.func_code = XPT_GDEV_TYPE; 824170530Ssam xpt_action(done_ccb); 825170530Ssam xpt_async(AC_SCSI_AEN, done_ccb->ccb_h.path, done_ccb); 826170530Ssam } 827170530Ssam break; 828178354Ssam case PROBE_INVALID: 829170530Ssam CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_INFO, 830170530Ssam ("probedone: invalid action state\n")); 831170530Ssam default: 832170530Ssam break; 833170530Ssam } 834170530Ssamdone: 835170530Ssam xpt_release_ccb(done_ccb); 836170530Ssam done_ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs); 837170530Ssam TAILQ_REMOVE(&softc->request_ccbs, &done_ccb->ccb_h, periph_links.tqe); 838170530Ssam done_ccb->ccb_h.status = CAM_REQ_CMP; 839170530Ssam done_ccb->ccb_h.ppriv_field1 = found; 840170530Ssam xpt_done(done_ccb); 841170530Ssam if (TAILQ_FIRST(&softc->request_ccbs) == NULL) { 842170530Ssam cam_periph_invalidate(periph); 843170530Ssam cam_periph_release_locked(periph); 844170530Ssam } else { 845170530Ssam probeschedule(periph); 846170530Ssam } 847170530Ssam} 848170530Ssam 849170530Ssamstatic void 850170530Ssamprobecleanup(struct cam_periph *periph) 851170530Ssam{ 852170530Ssam free(periph->softc, M_CAMXPT); 853178354Ssam} 854170530Ssam 855170530Ssamstatic void 856170530Ssamscsi_find_quirk(struct cam_ed *device) 857178354Ssam{ 858170530Ssam struct scsi_quirk_entry *quirk; 859178354Ssam caddr_t match; 860178354Ssam 861170530Ssam match = cam_quirkmatch((caddr_t)&device->inq_data, 862170530Ssam (caddr_t)scsi_quirk_table, 863170530Ssam sizeof(scsi_quirk_table) / 864171409Ssam sizeof(*scsi_quirk_table), 865170530Ssam sizeof(*scsi_quirk_table), scsi_inquiry_match); 866170530Ssam 867170530Ssam if (match == NULL) 868170530Ssam panic("xpt_find_quirk: device didn't match wildcard entry!!"); 869170530Ssam 870170530Ssam quirk = (struct scsi_quirk_entry *)match; 871170530Ssam device->quirk = quirk; 872178354Ssam device->mintags = quirk->mintags; 873170530Ssam device->maxtags = quirk->maxtags; 874178354Ssam} 875171409Ssam 876178354Ssamtypedef struct { 877170530Ssam union ccb *request_ccb; 878171409Ssam struct ccb_pathinq *cpi; 879170530Ssam int counter; 880170530Ssam int found; 881171409Ssam} ata_scan_bus_info; 882178354Ssam 883178354Ssam/* 884178354Ssam * To start a scan, request_ccb is an XPT_SCAN_BUS ccb. 885178354Ssam * As the scan progresses, xpt_scan_bus is used as the 886178354Ssam * callback on completion function. 887178354Ssam */ 888178354Ssamstatic void 889178354Ssamata_scan_bus(struct cam_periph *periph, union ccb *request_ccb) 890178354Ssam{ 891178354Ssam struct cam_path *path; 892178354Ssam ata_scan_bus_info *scan_info; 893178354Ssam union ccb *work_ccb; 894178354Ssam cam_status status; 895178354Ssam 896178354Ssam CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_TRACE, 897170530Ssam ("xpt_scan_bus\n")); 898178354Ssam switch (request_ccb->ccb_h.func_code) { 899170530Ssam case XPT_SCAN_BUS: 900171409Ssam /* Find out the characteristics of the bus */ 901170530Ssam work_ccb = xpt_alloc_ccb_nowait(); 902170530Ssam if (work_ccb == NULL) { 903170530Ssam request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 904171409Ssam xpt_done(request_ccb); 905170530Ssam return; 906178354Ssam } 907170530Ssam xpt_setup_ccb(&work_ccb->ccb_h, request_ccb->ccb_h.path, 908171409Ssam request_ccb->ccb_h.pinfo.priority); 909170530Ssam work_ccb->ccb_h.func_code = XPT_PATH_INQ; 910171409Ssam xpt_action(work_ccb); 911171409Ssam if (work_ccb->ccb_h.status != CAM_REQ_CMP) { 912178354Ssam request_ccb->ccb_h.status = work_ccb->ccb_h.status; 913178354Ssam xpt_free_ccb(work_ccb); 914178354Ssam xpt_done(request_ccb); 915170530Ssam return; 916171409Ssam } 917170530Ssam 918171409Ssam /* Save some state for use while we probe for devices */ 919170530Ssam scan_info = (ata_scan_bus_info *) 920171409Ssam malloc(sizeof(ata_scan_bus_info), M_CAMXPT, M_NOWAIT); 921170530Ssam if (scan_info == NULL) { 922178354Ssam request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 923170530Ssam xpt_done(request_ccb); 924171409Ssam return; 925171409Ssam } 926178354Ssam scan_info->request_ccb = request_ccb; 927171409Ssam scan_info->cpi = &work_ccb->cpi; 928170530Ssam if (scan_info->cpi->transport == XPORT_ATA) 929171409Ssam scan_info->found = 0x0003; 930170530Ssam else 931171409Ssam scan_info->found = 0x8001; 932171409Ssam scan_info->counter = 0; 933170530Ssam /* If PM supported, probe it first. */ 934171409Ssam if (scan_info->cpi->hba_inquiry & PI_SATAPM) 935170530Ssam scan_info->counter = 15; 936170530Ssam 937170530Ssam work_ccb = xpt_alloc_ccb_nowait(); 938170530Ssam if (work_ccb == NULL) { 939171409Ssam free(scan_info, M_CAMXPT); 940170530Ssam request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 941170530Ssam xpt_done(request_ccb); 942170530Ssam break; 943171409Ssam } 944170530Ssam goto scan_next; 945171409Ssam case XPT_SCAN_LUN: 946170530Ssam work_ccb = request_ccb; 947170530Ssam /* Reuse the same CCB to query if a device was really found */ 948170530Ssam scan_info = (ata_scan_bus_info *)work_ccb->ccb_h.ppriv_ptr0; 949170530Ssam /* Free the current request path- we're done with it. */ 950170530Ssam xpt_free_path(work_ccb->ccb_h.path); 951170530Ssam /* If there is PMP... */ 952170530Ssam if (scan_info->counter == 15) { 953170530Ssam if (work_ccb->ccb_h.ppriv_field1 != 0) { 954170530Ssam /* everything else willbe probed by it */ 955170530Ssam scan_info->found = 0x8000; 956170530Ssam } else { 957170530Ssam struct ccb_trans_settings cts; 958170530Ssam 959170530Ssam /* Report SIM that PM is absent. */ 960170530Ssam bzero(&cts, sizeof(cts)); 961170530Ssam xpt_setup_ccb(&cts.ccb_h, 962170530Ssam scan_info->request_ccb->ccb_h.path, 1); 963170530Ssam cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 964170530Ssam cts.type = CTS_TYPE_CURRENT_SETTINGS; 965170530Ssam cts.xport_specific.sata.pm_present = 0; 966170530Ssam cts.xport_specific.sata.valid = CTS_SATA_VALID_PM; 967170530Ssam xpt_action((union ccb *)&cts); 968170530Ssam } 969170530Ssam } 970170530Ssamtake_next: 971170530Ssam /* Take next device. Wrap from 15 (PM) to 0. */ 972170530Ssam scan_info->counter = (scan_info->counter + 1 ) & 0x0f; 973170530Ssam if (scan_info->counter > scan_info->cpi->max_target - 974170530Ssam ((scan_info->cpi->hba_inquiry & PI_SATAPM) ? 1 : 0)) { 975170530Ssam xpt_free_ccb(work_ccb); 976170530Ssam xpt_free_ccb((union ccb *)scan_info->cpi); 977170530Ssam request_ccb = scan_info->request_ccb; 978170530Ssam free(scan_info, M_CAMXPT); 979170530Ssam request_ccb->ccb_h.status = CAM_REQ_CMP; 980170530Ssam xpt_done(request_ccb); 981170530Ssam break; 982170530Ssam } 983170530Ssamscan_next: 984170530Ssam if ((scan_info->found & (1 << scan_info->counter)) == 0) 985170530Ssam goto take_next; 986178354Ssam status = xpt_create_path(&path, xpt_periph, 987170530Ssam scan_info->request_ccb->ccb_h.path_id, 988170530Ssam scan_info->counter, 0); 989170530Ssam if (status != CAM_REQ_CMP) { 990170530Ssam printf("xpt_scan_bus: xpt_create_path failed" 991178354Ssam " with status %#x, bus scan halted\n", 992170530Ssam status); 993170530Ssam xpt_free_ccb(work_ccb); 994170530Ssam xpt_free_ccb((union ccb *)scan_info->cpi); 995178354Ssam request_ccb = scan_info->request_ccb; 996178354Ssam free(scan_info, M_CAMXPT); 997170530Ssam request_ccb->ccb_h.status = status; 998170530Ssam xpt_done(request_ccb); 999170530Ssam break; 1000170530Ssam } 1001170530Ssam xpt_setup_ccb(&work_ccb->ccb_h, path, 1002170530Ssam scan_info->request_ccb->ccb_h.pinfo.priority); 1003170530Ssam work_ccb->ccb_h.func_code = XPT_SCAN_LUN; 1004170530Ssam work_ccb->ccb_h.cbfcnp = ata_scan_bus; 1005170530Ssam work_ccb->ccb_h.ppriv_ptr0 = scan_info; 1006170530Ssam work_ccb->crcn.flags = scan_info->request_ccb->crcn.flags; 1007170530Ssam xpt_action(work_ccb); 1008170530Ssam break; 1009170530Ssam default: 1010170530Ssam break; 1011170530Ssam } 1012170530Ssam} 1013178354Ssam 1014170530Ssamstatic void 1015170530Ssamata_scan_lun(struct cam_periph *periph, struct cam_path *path, 1016170530Ssam cam_flags flags, union ccb *request_ccb) 1017170530Ssam{ 1018178354Ssam struct ccb_pathinq cpi; 1019178354Ssam cam_status status; 1020170530Ssam struct cam_path *new_path; 1021170530Ssam struct cam_periph *old_periph; 1022170530Ssam 1023170530Ssam CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_TRACE, 1024170530Ssam ("xpt_scan_lun\n")); 1025170530Ssam 1026170530Ssam xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NORMAL); 1027170530Ssam cpi.ccb_h.func_code = XPT_PATH_INQ; 1028170530Ssam xpt_action((union ccb *)&cpi); 1029170530Ssam 1030170530Ssam if (cpi.ccb_h.status != CAM_REQ_CMP) { 1031170530Ssam if (request_ccb != NULL) { 1032170530Ssam request_ccb->ccb_h.status = cpi.ccb_h.status; 1033170530Ssam xpt_done(request_ccb); 1034170530Ssam } 1035170530Ssam return; 1036170530Ssam } 1037170530Ssam 1038170530Ssam if (request_ccb == NULL) { 1039170530Ssam request_ccb = malloc(sizeof(union ccb), M_CAMXPT, M_NOWAIT); 1040178354Ssam if (request_ccb == NULL) { 1041170530Ssam xpt_print(path, "xpt_scan_lun: can't allocate CCB, " 1042178354Ssam "can't continue\n"); 1043178354Ssam return; 1044170530Ssam } 1045170530Ssam new_path = malloc(sizeof(*new_path), M_CAMXPT, M_NOWAIT); 1046170530Ssam if (new_path == NULL) { 1047170530Ssam xpt_print(path, "xpt_scan_lun: can't allocate path, " 1048170530Ssam "can't continue\n"); 1049170530Ssam free(request_ccb, M_CAMXPT); 1050170530Ssam return; 1051170530Ssam } 1052170530Ssam status = xpt_compile_path(new_path, xpt_periph, 1053170530Ssam path->bus->path_id, 1054170530Ssam path->target->target_id, 1055170530Ssam path->device->lun_id); 1056178354Ssam 1057178354Ssam if (status != CAM_REQ_CMP) { 1058178354Ssam xpt_print(path, "xpt_scan_lun: can't compile path, " 1059178354Ssam "can't continue\n"); 1060170530Ssam free(request_ccb, M_CAMXPT); 1061170530Ssam free(new_path, M_CAMXPT); 1062170530Ssam return; 1063170530Ssam } 1064170530Ssam xpt_setup_ccb(&request_ccb->ccb_h, new_path, CAM_PRIORITY_NORMAL); 1065170530Ssam request_ccb->ccb_h.cbfcnp = xptscandone; 1066170530Ssam request_ccb->ccb_h.func_code = XPT_SCAN_LUN; 1067170530Ssam request_ccb->crcn.flags = flags; 1068170530Ssam } 1069170530Ssam 1070170530Ssam if ((old_periph = cam_periph_find(path, "aprobe")) != NULL) { 1071170530Ssam probe_softc *softc; 1072170530Ssam 1073170530Ssam softc = (probe_softc *)old_periph->softc; 1074170530Ssam TAILQ_INSERT_TAIL(&softc->request_ccbs, &request_ccb->ccb_h, 1075170530Ssam periph_links.tqe); 1076170530Ssam } else { 1077170530Ssam status = cam_periph_alloc(proberegister, NULL, probecleanup, 1078170530Ssam probestart, "aprobe", 1079170530Ssam CAM_PERIPH_BIO, 1080170530Ssam request_ccb->ccb_h.path, NULL, 0, 1081170530Ssam request_ccb); 1082170530Ssam 1083170530Ssam if (status != CAM_REQ_CMP) { 1084170530Ssam xpt_print(path, "xpt_scan_lun: cam_alloc_periph " 1085170530Ssam "returned an error, can't continue probe\n"); 1086178354Ssam request_ccb->ccb_h.status = status; 1087170530Ssam xpt_done(request_ccb); 1088178354Ssam } 1089178354Ssam } 1090170530Ssam} 1091178354Ssam 1092170530Ssamstatic void 1093178354Ssamxptscandone(struct cam_periph *periph, union ccb *done_ccb) 1094170530Ssam{ 1095170530Ssam xpt_release_path(done_ccb->ccb_h.path); 1096170530Ssam free(done_ccb->ccb_h.path, M_CAMXPT); 1097170530Ssam free(done_ccb, M_CAMXPT); 1098170530Ssam} 1099170530Ssam 1100170530Ssamstatic struct cam_ed * 1101170530Ssamata_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id) 1102178354Ssam{ 1103178354Ssam struct cam_path path; 1104178354Ssam struct scsi_quirk_entry *quirk; 1105178354Ssam struct cam_ed *device; 1106170530Ssam struct cam_ed *cur_device; 1107170530Ssam 1108178354Ssam device = xpt_alloc_device(bus, target, lun_id); 1109178354Ssam if (device == NULL) 1110178354Ssam return (NULL); 1111178354Ssam 1112170530Ssam /* 1113170530Ssam * Take the default quirk entry until we have inquiry 1114170530Ssam * data and can determine a better quirk to use. 1115170530Ssam */ 1116178354Ssam quirk = &scsi_quirk_table[scsi_quirk_table_size - 1]; 1117170530Ssam device->quirk = (void *)quirk; 1118170530Ssam device->mintags = quirk->mintags; 1119170530Ssam device->maxtags = quirk->maxtags; 1120170530Ssam bzero(&device->inq_data, sizeof(device->inq_data)); 1121170530Ssam device->inq_flags = 0; 1122170530Ssam device->queue_flags = 0; 1123170530Ssam device->serial_num = NULL; 1124178354Ssam device->serial_num_len = 0; 1125170530Ssam 1126170530Ssam /* 1127170530Ssam * XXX should be limited by number of CCBs this bus can 1128170530Ssam * do. 1129170530Ssam */ 1130170530Ssam bus->sim->max_ccbs += device->ccbq.devq_openings; 1131170530Ssam /* Insertion sort into our target's device list */ 1132170530Ssam cur_device = TAILQ_FIRST(&target->ed_entries); 1133170530Ssam while (cur_device != NULL && cur_device->lun_id < lun_id) 1134178354Ssam cur_device = TAILQ_NEXT(cur_device, links); 1135178354Ssam if (cur_device != NULL) { 1136170530Ssam TAILQ_INSERT_BEFORE(cur_device, device, links); 1137170530Ssam } else { 1138170530Ssam TAILQ_INSERT_TAIL(&target->ed_entries, device, links); 1139178354Ssam } 1140170530Ssam target->generation++; 1141178354Ssam if (lun_id != CAM_LUN_WILDCARD) { 1142170530Ssam xpt_compile_path(&path, 1143170530Ssam NULL, 1144170530Ssam bus->path_id, 1145170530Ssam target->target_id, 1146178354Ssam lun_id); 1147170530Ssam ata_device_transport(&path); 1148170530Ssam xpt_release_path(&path); 1149170530Ssam } 1150170530Ssam 1151170530Ssam return (device); 1152170530Ssam} 1153170530Ssam 1154170530Ssamstatic void 1155170530Ssamata_device_transport(struct cam_path *path) 1156170530Ssam{ 1157170530Ssam struct ccb_pathinq cpi; 1158178354Ssam struct ccb_trans_settings cts; 1159170530Ssam struct scsi_inquiry_data *inq_buf = NULL; 1160178354Ssam struct ata_params *ident_buf = NULL; 1161170530Ssam 1162170530Ssam /* Get transport information from the SIM */ 1163170530Ssam xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NORMAL); 1164170530Ssam cpi.ccb_h.func_code = XPT_PATH_INQ; 1165170530Ssam xpt_action((union ccb *)&cpi); 1166170530Ssam 1167170530Ssam path->device->transport = cpi.transport; 1168170530Ssam if ((path->device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0) 1169170530Ssam inq_buf = &path->device->inq_data; 1170178354Ssam if ((path->device->flags & CAM_DEV_IDENTIFY_DATA_VALID) != 0) 1171178354Ssam ident_buf = &path->device->ident_data; 1172178354Ssam if (path->device->protocol == PROTO_ATA) { 1173178354Ssam path->device->protocol_version = ident_buf ? 1174178354Ssam ata_version(ident_buf->version_major) : cpi.protocol_version; 1175170530Ssam } else if (path->device->protocol == PROTO_SCSI) { 1176178354Ssam path->device->protocol_version = inq_buf ? 1177170530Ssam SID_ANSI_REV(inq_buf) : cpi.protocol_version; 1178170530Ssam } 1179170530Ssam path->device->transport_version = ident_buf ? 1180170530Ssam ata_version(ident_buf->version_major) : cpi.transport_version; 1181170530Ssam 1182170530Ssam /* Tell the controller what we think */ 1183170530Ssam xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL); 1184170530Ssam cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 1185170530Ssam cts.type = CTS_TYPE_CURRENT_SETTINGS; 1186170530Ssam cts.transport = path->device->transport; 1187170530Ssam cts.transport_version = path->device->transport_version; 1188170530Ssam cts.protocol = path->device->protocol; 1189170530Ssam cts.protocol_version = path->device->protocol_version; 1190170530Ssam cts.proto_specific.valid = 0; 1191170530Ssam cts.xport_specific.valid = 0; 1192178354Ssam xpt_action((union ccb *)&cts); 1193170530Ssam} 1194170530Ssam 1195170530Ssamstatic void 1196170530Ssamata_action(union ccb *start_ccb) 1197170530Ssam{ 1198170530Ssam 1199170530Ssam switch (start_ccb->ccb_h.func_code) { 1200170530Ssam case XPT_SET_TRAN_SETTINGS: 1201170530Ssam { 1202170530Ssam scsi_set_transfer_settings(&start_ccb->cts, 1203170530Ssam start_ccb->ccb_h.path->device, 1204170530Ssam /*async_update*/FALSE); 1205170530Ssam break; 1206170530Ssam } 1207170530Ssam case XPT_SCAN_BUS: 1208170530Ssam ata_scan_bus(start_ccb->ccb_h.path->periph, start_ccb); 1209170530Ssam break; 1210170530Ssam case XPT_SCAN_LUN: 1211170530Ssam ata_scan_lun(start_ccb->ccb_h.path->periph, 1212170530Ssam start_ccb->ccb_h.path, start_ccb->crcn.flags, 1213170530Ssam start_ccb); 1214170530Ssam break; 1215170530Ssam case XPT_GET_TRAN_SETTINGS: 1216170530Ssam { 1217170530Ssam struct cam_sim *sim; 1218170530Ssam 1219170530Ssam sim = start_ccb->ccb_h.path->bus->sim; 1220170530Ssam (*(sim->sim_action))(sim, start_ccb); 1221178354Ssam break; 1222170530Ssam } 1223170530Ssam default: 1224170530Ssam xpt_action_default(start_ccb); 1225170530Ssam break; 1226170530Ssam } 1227170530Ssam} 1228170530Ssam 1229170530Ssamstatic void 1230170530Ssamscsi_set_transfer_settings(struct ccb_trans_settings *cts, struct cam_ed *device, 1231170530Ssam int async_update) 1232170530Ssam{ 1233170530Ssam struct ccb_pathinq cpi; 1234170530Ssam struct ccb_trans_settings cur_cts; 1235170530Ssam struct ccb_trans_settings_scsi *scsi; 1236170530Ssam struct ccb_trans_settings_scsi *cur_scsi; 1237170530Ssam struct cam_sim *sim; 1238178354Ssam struct scsi_inquiry_data *inq_data; 1239170530Ssam 1240170530Ssam if (device == NULL) { 1241170530Ssam cts->ccb_h.status = CAM_PATH_INVALID; 1242170530Ssam xpt_done((union ccb *)cts); 1243170530Ssam return; 1244170530Ssam } 1245170530Ssam 1246170530Ssam if (cts->protocol == PROTO_UNKNOWN 1247170530Ssam || cts->protocol == PROTO_UNSPECIFIED) { 1248170530Ssam cts->protocol = device->protocol; 1249170530Ssam cts->protocol_version = device->protocol_version; 1250170530Ssam } 1251170530Ssam 1252170530Ssam if (cts->protocol_version == PROTO_VERSION_UNKNOWN 1253170530Ssam || cts->protocol_version == PROTO_VERSION_UNSPECIFIED) 1254170530Ssam cts->protocol_version = device->protocol_version; 1255170530Ssam 1256170530Ssam if (cts->protocol != device->protocol) { 1257170530Ssam xpt_print(cts->ccb_h.path, "Uninitialized Protocol %x:%x?\n", 1258170530Ssam cts->protocol, device->protocol); 1259170530Ssam cts->protocol = device->protocol; 1260170530Ssam } 1261170530Ssam 1262170530Ssam if (cts->protocol_version > device->protocol_version) { 1263170530Ssam if (bootverbose) { 1264170530Ssam xpt_print(cts->ccb_h.path, "Down reving Protocol " 1265170530Ssam "Version from %d to %d?\n", cts->protocol_version, 1266170530Ssam device->protocol_version); 1267170530Ssam } 1268170530Ssam cts->protocol_version = device->protocol_version; 1269170530Ssam } 1270170530Ssam 1271170530Ssam if (cts->transport == XPORT_UNKNOWN 1272170530Ssam || cts->transport == XPORT_UNSPECIFIED) { 1273170530Ssam cts->transport = device->transport; 1274170530Ssam cts->transport_version = device->transport_version; 1275170530Ssam } 1276170530Ssam 1277170530Ssam if (cts->transport_version == XPORT_VERSION_UNKNOWN 1278170530Ssam || cts->transport_version == XPORT_VERSION_UNSPECIFIED) 1279170530Ssam cts->transport_version = device->transport_version; 1280170530Ssam 1281170530Ssam if (cts->transport != device->transport) { 1282170530Ssam xpt_print(cts->ccb_h.path, "Uninitialized Transport %x:%x?\n", 1283170530Ssam cts->transport, device->transport); 1284170530Ssam cts->transport = device->transport; 1285170530Ssam } 1286170530Ssam 1287170530Ssam if (cts->transport_version > device->transport_version) { 1288178354Ssam if (bootverbose) { 1289170530Ssam xpt_print(cts->ccb_h.path, "Down reving Transport " 1290170530Ssam "Version from %d to %d?\n", cts->transport_version, 1291170530Ssam device->transport_version); 1292178354Ssam } 1293176653Ssam cts->transport_version = device->transport_version; 1294178354Ssam } 1295178354Ssam 1296178354Ssam sim = cts->ccb_h.path->bus->sim; 1297178354Ssam 1298176653Ssam /* 1299178354Ssam * Nothing more of interest to do unless 1300170530Ssam * this is a device connected via the 1301170530Ssam * SCSI protocol. 1302170530Ssam */ 1303170530Ssam if (cts->protocol != PROTO_SCSI) { 1304170530Ssam if (async_update == FALSE) 1305170530Ssam (*(sim->sim_action))(sim, (union ccb *)cts); 1306170530Ssam return; 1307170530Ssam } 1308170530Ssam 1309170530Ssam inq_data = &device->inq_data; 1310170530Ssam scsi = &cts->proto_specific.scsi; 1311178354Ssam xpt_setup_ccb(&cpi.ccb_h, cts->ccb_h.path, CAM_PRIORITY_NORMAL); 1312170530Ssam cpi.ccb_h.func_code = XPT_PATH_INQ; 1313170530Ssam xpt_action((union ccb *)&cpi); 1314170530Ssam 1315170530Ssam /* SCSI specific sanity checking */ 1316170530Ssam if ((cpi.hba_inquiry & PI_TAG_ABLE) == 0 1317170530Ssam || (INQ_DATA_TQ_ENABLED(inq_data)) == 0 1318170530Ssam || (device->queue_flags & SCP_QUEUE_DQUE) != 0 1319170530Ssam || (device->mintags == 0)) { 1320170530Ssam /* 1321170530Ssam * Can't tag on hardware that doesn't support tags, 1322170530Ssam * doesn't have it enabled, or has broken tag support. 1323170530Ssam */ 1324178354Ssam scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 1325178354Ssam } 1326176653Ssam 1327178354Ssam if (async_update == FALSE) { 1328178354Ssam /* 1329178354Ssam * Perform sanity checking against what the 1330178354Ssam * controller and device can do. 1331178354Ssam */ 1332178354Ssam xpt_setup_ccb(&cur_cts.ccb_h, cts->ccb_h.path, CAM_PRIORITY_NORMAL); 1333170530Ssam cur_cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 1334170530Ssam cur_cts.type = cts->type; 1335170530Ssam xpt_action((union ccb *)&cur_cts); 1336170530Ssam if ((cur_cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 1337170530Ssam return; 1338170530Ssam } 1339170530Ssam cur_scsi = &cur_cts.proto_specific.scsi; 1340170530Ssam if ((scsi->valid & CTS_SCSI_VALID_TQ) == 0) { 1341170530Ssam scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 1342170530Ssam scsi->flags |= cur_scsi->flags & CTS_SCSI_FLAGS_TAG_ENB; 1343170530Ssam } 1344170530Ssam if ((cur_scsi->valid & CTS_SCSI_VALID_TQ) == 0) 1345170530Ssam scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 1346170530Ssam } 1347170530Ssam 1348170530Ssam if (cts->type == CTS_TYPE_CURRENT_SETTINGS 1349170530Ssam && (scsi->valid & CTS_SCSI_VALID_TQ) != 0) { 1350170530Ssam int device_tagenb; 1351170530Ssam 1352170530Ssam /* 1353178354Ssam * If we are transitioning from tags to no-tags or 1354170530Ssam * vice-versa, we need to carefully freeze and restart 1355170530Ssam * the queue so that we don't overlap tagged and non-tagged 1356170530Ssam * commands. We also temporarily stop tags if there is 1357170530Ssam * a change in transfer negotiation settings to allow 1358170530Ssam * "tag-less" negotiation. 1359178354Ssam */ 1360178354Ssam if ((device->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 1361178354Ssam || (device->inq_flags & SID_CmdQue) != 0) 1362170530Ssam device_tagenb = TRUE; 1363170530Ssam else 1364170530Ssam device_tagenb = FALSE; 1365170530Ssam 1366170530Ssam if (((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0 1367170530Ssam && device_tagenb == FALSE) 1368170530Ssam || ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) == 0 1369170530Ssam && device_tagenb == TRUE)) { 1370170530Ssam 1371170530Ssam if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) { 1372170530Ssam /* 1373170530Ssam * Delay change to use tags until after a 1374170530Ssam * few commands have gone to this device so 1375170530Ssam * the controller has time to perform transfer 1376170530Ssam * negotiations without tagged messages getting 1377170530Ssam * in the way. 1378170530Ssam */ 1379170530Ssam device->tag_delay_count = CAM_TAG_DELAY_COUNT; 1380170530Ssam device->flags |= CAM_DEV_TAG_AFTER_COUNT; 1381170530Ssam } else { 1382178354Ssam struct ccb_relsim crs; 1383170530Ssam 1384178354Ssam xpt_freeze_devq(cts->ccb_h.path, /*count*/1); 1385178354Ssam device->inq_flags &= ~SID_CmdQue; 1386170530Ssam xpt_dev_ccbq_resize(cts->ccb_h.path, 1387178354Ssam sim->max_dev_openings); 1388170530Ssam device->flags &= ~CAM_DEV_TAG_AFTER_COUNT; 1389170530Ssam device->tag_delay_count = 0; 1390170530Ssam 1391170530Ssam xpt_setup_ccb(&crs.ccb_h, cts->ccb_h.path, 1392170530Ssam CAM_PRIORITY_NORMAL); 1393178354Ssam crs.ccb_h.func_code = XPT_REL_SIMQ; 1394178354Ssam crs.release_flags = RELSIM_RELEASE_AFTER_QEMPTY; 1395183421Ssam crs.openings 1396183421Ssam = crs.release_timeout 1397183421Ssam = crs.qfrozen_cnt 1398183421Ssam = 0; 1399183421Ssam xpt_action((union ccb *)&crs); 1400183421Ssam } 1401178354Ssam } 1402178354Ssam } 1403170530Ssam if (async_update == FALSE) 1404178354Ssam (*(sim->sim_action))(sim, (union ccb *)cts); 1405170530Ssam} 1406170530Ssam 1407170530Ssamstatic void 1408170530Ssamscsi_toggle_tags(struct cam_path *path) 1409170530Ssam{ 1410170530Ssam struct cam_ed *dev; 1411170530Ssam 1412170530Ssam /* 1413170530Ssam * Give controllers a chance to renegotiate 1414170530Ssam * before starting tag operations. We 1415170530Ssam * "toggle" tagged queuing off then on 1416170530Ssam * which causes the tag enable command delay 1417170530Ssam * counter to come into effect. 1418170530Ssam */ 1419178354Ssam dev = path->device; 1420178354Ssam if ((dev->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 1421178354Ssam || ((dev->inq_flags & SID_CmdQue) != 0 1422178354Ssam && (dev->inq_flags & (SID_Sync|SID_WBus16|SID_WBus32)) != 0)) { 1423170530Ssam struct ccb_trans_settings cts; 1424170530Ssam 1425170530Ssam xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL); 1426170530Ssam cts.protocol = PROTO_SCSI; 1427170530Ssam cts.protocol_version = PROTO_VERSION_UNSPECIFIED; 1428170530Ssam cts.transport = XPORT_UNSPECIFIED; 1429170530Ssam cts.transport_version = XPORT_VERSION_UNSPECIFIED; 1430170530Ssam cts.proto_specific.scsi.flags = 0; 1431170530Ssam cts.proto_specific.scsi.valid = CTS_SCSI_VALID_TQ; 1432170530Ssam scsi_set_transfer_settings(&cts, path->device, 1433170530Ssam /*async_update*/TRUE); 1434170530Ssam cts.proto_specific.scsi.flags = CTS_SCSI_FLAGS_TAG_ENB; 1435170530Ssam scsi_set_transfer_settings(&cts, path->device, 1436170530Ssam /*async_update*/TRUE); 1437170530Ssam } 1438170530Ssam} 1439170530Ssam 1440170530Ssam/* 1441178354Ssam * Handle any per-device event notifications that require action by the XPT. 1442170530Ssam */ 1443170530Ssamstatic void 1444170530Ssamata_dev_async(u_int32_t async_code, struct cam_eb *bus, struct cam_et *target, 1445170530Ssam struct cam_ed *device, void *async_arg) 1446170530Ssam{ 1447170530Ssam cam_status status; 1448170530Ssam struct cam_path newpath; 1449170530Ssam 1450170530Ssam /* 1451170530Ssam * We only need to handle events for real devices. 1452170530Ssam */ 1453170530Ssam if (target->target_id == CAM_TARGET_WILDCARD 1454170530Ssam || device->lun_id == CAM_LUN_WILDCARD) 1455170530Ssam return; 1456170530Ssam 1457178354Ssam /* 1458170530Ssam * We need our own path with wildcards expanded to 1459170530Ssam * handle certain types of events. 1460170530Ssam */ 1461170530Ssam if ((async_code == AC_SENT_BDR) 1462170530Ssam || (async_code == AC_BUS_RESET) 1463170530Ssam || (async_code == AC_INQ_CHANGED)) 1464170530Ssam status = xpt_compile_path(&newpath, NULL, 1465178354Ssam bus->path_id, 1466178354Ssam target->target_id, 1467178354Ssam device->lun_id); 1468178354Ssam else 1469178354Ssam status = CAM_REQ_CMP_ERR; 1470178354Ssam 1471178354Ssam if (status == CAM_REQ_CMP) { 1472178354Ssam 1473178354Ssam /* 1474178354Ssam * Allow transfer negotiation to occur in a 1475178354Ssam * tag free environment. 1476178354Ssam */ 1477178354Ssam if (async_code == AC_SENT_BDR 1478178354Ssam || async_code == AC_BUS_RESET) 1479178354Ssam scsi_toggle_tags(&newpath); 1480178354Ssam 1481178354Ssam if (async_code == AC_INQ_CHANGED) { 1482178354Ssam /* 1483178354Ssam * We've sent a start unit command, or 1484178354Ssam * something similar to a device that 1485178354Ssam * may have caused its inquiry data to 1486178354Ssam * change. So we re-scan the device to 1487178354Ssam * refresh the inquiry data for it. 1488178354Ssam */ 1489178354Ssam ata_scan_lun(newpath.periph, &newpath, 1490178354Ssam CAM_EXPECT_INQ_CHANGE, NULL); 1491178354Ssam } 1492178354Ssam xpt_release_path(&newpath); 1493178354Ssam } else if (async_code == AC_LOST_DEVICE && 1494178354Ssam (device->flags & CAM_DEV_UNCONFIGURED) == 0) { 1495178354Ssam device->flags |= CAM_DEV_UNCONFIGURED; 1496178354Ssam xpt_release_device(device); 1497178354Ssam } else if (async_code == AC_TRANSFER_NEG) { 1498178354Ssam struct ccb_trans_settings *settings; 1499178354Ssam 1500178354Ssam settings = (struct ccb_trans_settings *)async_arg; 1501178354Ssam scsi_set_transfer_settings(settings, device, 1502178354Ssam /*async_update*/TRUE); 1503178354Ssam } 1504170530Ssam} 1505178354Ssam 1506170530Ssam