152c9ce25SScott Long /*- 252c9ce25SScott Long * Copyright (c) 2009 Alexander Motin <mav@FreeBSD.org> 352c9ce25SScott Long * All rights reserved. 452c9ce25SScott Long * 552c9ce25SScott Long * Redistribution and use in source and binary forms, with or without 652c9ce25SScott Long * modification, are permitted provided that the following conditions 752c9ce25SScott Long * are met: 852c9ce25SScott Long * 1. Redistributions of source code must retain the above copyright 952c9ce25SScott Long * notice, this list of conditions and the following disclaimer, 1052c9ce25SScott Long * without modification, immediately at the beginning of the file. 1152c9ce25SScott Long * 2. Redistributions in binary form must reproduce the above copyright 1252c9ce25SScott Long * notice, this list of conditions and the following disclaimer in the 1352c9ce25SScott Long * documentation and/or other materials provided with the distribution. 1452c9ce25SScott Long * 1552c9ce25SScott Long * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1652c9ce25SScott Long * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1752c9ce25SScott Long * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1852c9ce25SScott Long * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1952c9ce25SScott Long * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2052c9ce25SScott Long * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2152c9ce25SScott Long * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2252c9ce25SScott Long * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2352c9ce25SScott Long * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2452c9ce25SScott Long * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2552c9ce25SScott Long */ 2652c9ce25SScott Long 2752c9ce25SScott Long #include <sys/cdefs.h> 2852c9ce25SScott Long __FBSDID("$FreeBSD$"); 2952c9ce25SScott Long 3052c9ce25SScott Long #include <sys/param.h> 3152c9ce25SScott Long #include <sys/bus.h> 3252c9ce25SScott Long #include <sys/endian.h> 3352c9ce25SScott Long #include <sys/systm.h> 3452c9ce25SScott Long #include <sys/types.h> 3552c9ce25SScott Long #include <sys/malloc.h> 3652c9ce25SScott Long #include <sys/kernel.h> 3752c9ce25SScott Long #include <sys/time.h> 3852c9ce25SScott Long #include <sys/conf.h> 3952c9ce25SScott Long #include <sys/fcntl.h> 4052c9ce25SScott Long #include <sys/md5.h> 4152c9ce25SScott Long #include <sys/interrupt.h> 4252c9ce25SScott Long #include <sys/sbuf.h> 4352c9ce25SScott Long 4452c9ce25SScott Long #include <sys/lock.h> 4552c9ce25SScott Long #include <sys/mutex.h> 4652c9ce25SScott Long #include <sys/sysctl.h> 4752c9ce25SScott Long 4852c9ce25SScott Long #ifdef PC98 4952c9ce25SScott Long #include <pc98/pc98/pc98_machdep.h> /* geometry translation */ 5052c9ce25SScott Long #endif 5152c9ce25SScott Long 5252c9ce25SScott Long #include <cam/cam.h> 5352c9ce25SScott Long #include <cam/cam_ccb.h> 5452c9ce25SScott Long #include <cam/cam_queue.h> 5552c9ce25SScott Long #include <cam/cam_periph.h> 5652c9ce25SScott Long #include <cam/cam_sim.h> 5752c9ce25SScott Long #include <cam/cam_xpt.h> 5852c9ce25SScott Long #include <cam/cam_xpt_sim.h> 5952c9ce25SScott Long #include <cam/cam_xpt_periph.h> 6052c9ce25SScott Long #include <cam/cam_xpt_internal.h> 6152c9ce25SScott Long #include <cam/cam_debug.h> 6252c9ce25SScott Long 6352c9ce25SScott Long #include <cam/scsi/scsi_all.h> 6452c9ce25SScott Long #include <cam/scsi/scsi_message.h> 6552c9ce25SScott Long #include <cam/scsi/scsi_pass.h> 6652c9ce25SScott Long #include <cam/ata/ata_all.h> 6752c9ce25SScott Long #include <machine/stdarg.h> /* for xpt_print below */ 6852c9ce25SScott Long #include "opt_cam.h" 6952c9ce25SScott Long 7052c9ce25SScott Long struct scsi_quirk_entry { 7152c9ce25SScott Long struct scsi_inquiry_pattern inq_pat; 7252c9ce25SScott Long u_int8_t quirks; 7352c9ce25SScott Long #define CAM_QUIRK_NOLUNS 0x01 7452c9ce25SScott Long #define CAM_QUIRK_NOSERIAL 0x02 7552c9ce25SScott Long #define CAM_QUIRK_HILUNS 0x04 7652c9ce25SScott Long #define CAM_QUIRK_NOHILUNS 0x08 7752c9ce25SScott Long u_int mintags; 7852c9ce25SScott Long u_int maxtags; 7952c9ce25SScott Long }; 8052c9ce25SScott Long #define SCSI_QUIRK(dev) ((struct scsi_quirk_entry *)((dev)->quirk)) 8152c9ce25SScott Long 8252c9ce25SScott Long static periph_init_t probe_periph_init; 8352c9ce25SScott Long 8452c9ce25SScott Long static struct periph_driver probe_driver = 8552c9ce25SScott Long { 86f09f8e3eSAlexander Motin probe_periph_init, "aprobe", 8752c9ce25SScott Long TAILQ_HEAD_INITIALIZER(probe_driver.units) 8852c9ce25SScott Long }; 8952c9ce25SScott Long 90f09f8e3eSAlexander Motin PERIPHDRIVER_DECLARE(aprobe, probe_driver); 9152c9ce25SScott Long 9252c9ce25SScott Long typedef enum { 9352c9ce25SScott Long PROBE_RESET, 9452c9ce25SScott Long PROBE_IDENTIFY, 9552c9ce25SScott Long PROBE_SETMODE, 9652c9ce25SScott Long PROBE_INQUIRY, 9752c9ce25SScott Long PROBE_FULL_INQUIRY, 9852c9ce25SScott Long PROBE_PM_PID, 9952c9ce25SScott Long PROBE_PM_PRV, 10052c9ce25SScott Long PROBE_PM_PORTS, 10152c9ce25SScott Long PROBE_PM_RESET, 10252c9ce25SScott Long PROBE_PM_CONNECT, 10352c9ce25SScott Long PROBE_PM_CHECK, 10452c9ce25SScott Long PROBE_PM_CLEAR, 10552c9ce25SScott Long PROBE_INVALID 10652c9ce25SScott Long } probe_action; 10752c9ce25SScott Long 10852c9ce25SScott Long static char *probe_action_text[] = { 10952c9ce25SScott Long "PROBE_RESET", 11052c9ce25SScott Long "PROBE_IDENTIFY", 11152c9ce25SScott Long "PROBE_SETMODE", 11252c9ce25SScott Long "PROBE_INQUIRY", 11352c9ce25SScott Long "PROBE_FULL_INQUIRY", 11452c9ce25SScott Long "PROBE_PM_PID", 11552c9ce25SScott Long "PROBE_PM_PRV", 11652c9ce25SScott Long "PROBE_PM_PORTS", 11752c9ce25SScott Long "PROBE_PM_RESET", 11852c9ce25SScott Long "PROBE_PM_CONNECT", 11952c9ce25SScott Long "PROBE_PM_CHECK", 12052c9ce25SScott Long "PROBE_PM_CLEAR", 12152c9ce25SScott Long "PROBE_INVALID" 12252c9ce25SScott Long }; 12352c9ce25SScott Long 12452c9ce25SScott Long #define PROBE_SET_ACTION(softc, newaction) \ 12552c9ce25SScott Long do { \ 12652c9ce25SScott Long char **text; \ 12752c9ce25SScott Long text = probe_action_text; \ 12852c9ce25SScott Long CAM_DEBUG((softc)->periph->path, CAM_DEBUG_INFO, \ 12952c9ce25SScott Long ("Probe %s to %s\n", text[(softc)->action], \ 13052c9ce25SScott Long text[(newaction)])); \ 13152c9ce25SScott Long (softc)->action = (newaction); \ 13252c9ce25SScott Long } while(0) 13352c9ce25SScott Long 13452c9ce25SScott Long typedef enum { 13552c9ce25SScott Long PROBE_NO_ANNOUNCE = 0x04 13652c9ce25SScott Long } probe_flags; 13752c9ce25SScott Long 13852c9ce25SScott Long typedef struct { 13952c9ce25SScott Long TAILQ_HEAD(, ccb_hdr) request_ccbs; 14052c9ce25SScott Long probe_action action; 14152c9ce25SScott Long union ccb saved_ccb; 14252c9ce25SScott Long probe_flags flags; 14352c9ce25SScott Long u_int8_t digest[16]; 14452c9ce25SScott Long uint32_t pm_pid; 14552c9ce25SScott Long uint32_t pm_prv; 14652c9ce25SScott Long int pm_ports; 14752c9ce25SScott Long int pm_step; 14852c9ce25SScott Long int pm_try; 14952c9ce25SScott Long struct cam_periph *periph; 15052c9ce25SScott Long } probe_softc; 15152c9ce25SScott Long 15252c9ce25SScott Long static struct scsi_quirk_entry scsi_quirk_table[] = 15352c9ce25SScott Long { 15452c9ce25SScott Long { 15552c9ce25SScott Long /* Default tagged queuing parameters for all devices */ 15652c9ce25SScott Long { 15752c9ce25SScott Long T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED, 15852c9ce25SScott Long /*vendor*/"*", /*product*/"*", /*revision*/"*" 15952c9ce25SScott Long }, 16052c9ce25SScott Long /*quirks*/0, /*mintags*/2, /*maxtags*/32 16152c9ce25SScott Long }, 16252c9ce25SScott Long }; 16352c9ce25SScott Long 16452c9ce25SScott Long static const int scsi_quirk_table_size = 16552c9ce25SScott Long sizeof(scsi_quirk_table) / sizeof(*scsi_quirk_table); 16652c9ce25SScott Long 16752c9ce25SScott Long static cam_status proberegister(struct cam_periph *periph, 16852c9ce25SScott Long void *arg); 16952c9ce25SScott Long static void probeschedule(struct cam_periph *probe_periph); 17052c9ce25SScott Long static void probestart(struct cam_periph *periph, union ccb *start_ccb); 17152c9ce25SScott Long //static void proberequestdefaultnegotiation(struct cam_periph *periph); 17252c9ce25SScott Long //static int proberequestbackoff(struct cam_periph *periph, 17352c9ce25SScott Long // struct cam_ed *device); 17452c9ce25SScott Long static void probedone(struct cam_periph *periph, union ccb *done_ccb); 17552c9ce25SScott Long static void probecleanup(struct cam_periph *periph); 17652c9ce25SScott Long static void scsi_find_quirk(struct cam_ed *device); 17752c9ce25SScott Long static void ata_scan_bus(struct cam_periph *periph, union ccb *ccb); 17852c9ce25SScott Long static void ata_scan_lun(struct cam_periph *periph, 17952c9ce25SScott Long struct cam_path *path, cam_flags flags, 18052c9ce25SScott Long union ccb *ccb); 18152c9ce25SScott Long static void xptscandone(struct cam_periph *periph, union ccb *done_ccb); 18252c9ce25SScott Long static struct cam_ed * 18352c9ce25SScott Long ata_alloc_device(struct cam_eb *bus, struct cam_et *target, 18452c9ce25SScott Long lun_id_t lun_id); 18552c9ce25SScott Long static void ata_device_transport(struct cam_path *path); 18652c9ce25SScott Long static void scsi_set_transfer_settings(struct ccb_trans_settings *cts, 18752c9ce25SScott Long struct cam_ed *device, 18852c9ce25SScott Long int async_update); 18952c9ce25SScott Long static void scsi_toggle_tags(struct cam_path *path); 19052c9ce25SScott Long static void ata_dev_async(u_int32_t async_code, 19152c9ce25SScott Long struct cam_eb *bus, 19252c9ce25SScott Long struct cam_et *target, 19352c9ce25SScott Long struct cam_ed *device, 19452c9ce25SScott Long void *async_arg); 19552c9ce25SScott Long static void ata_action(union ccb *start_ccb); 19652c9ce25SScott Long 19752c9ce25SScott Long static struct xpt_xport ata_xport = { 19852c9ce25SScott Long .alloc_device = ata_alloc_device, 19952c9ce25SScott Long .action = ata_action, 20052c9ce25SScott Long .async = ata_dev_async, 20152c9ce25SScott Long }; 20252c9ce25SScott Long 20352c9ce25SScott Long struct xpt_xport * 20452c9ce25SScott Long ata_get_xport(void) 20552c9ce25SScott Long { 20652c9ce25SScott Long return (&ata_xport); 20752c9ce25SScott Long } 20852c9ce25SScott Long 20952c9ce25SScott Long static void 21052c9ce25SScott Long probe_periph_init() 21152c9ce25SScott Long { 21252c9ce25SScott Long } 21352c9ce25SScott Long 21452c9ce25SScott Long static cam_status 21552c9ce25SScott Long proberegister(struct cam_periph *periph, void *arg) 21652c9ce25SScott Long { 21752c9ce25SScott Long union ccb *request_ccb; /* CCB representing the probe request */ 21852c9ce25SScott Long cam_status status; 21952c9ce25SScott Long probe_softc *softc; 22052c9ce25SScott Long 22152c9ce25SScott Long request_ccb = (union ccb *)arg; 22252c9ce25SScott Long if (periph == NULL) { 22352c9ce25SScott Long printf("proberegister: periph was NULL!!\n"); 22452c9ce25SScott Long return(CAM_REQ_CMP_ERR); 22552c9ce25SScott Long } 22652c9ce25SScott Long 22752c9ce25SScott Long if (request_ccb == NULL) { 22852c9ce25SScott Long printf("proberegister: no probe CCB, " 22952c9ce25SScott Long "can't register device\n"); 23052c9ce25SScott Long return(CAM_REQ_CMP_ERR); 23152c9ce25SScott Long } 23252c9ce25SScott Long 23352c9ce25SScott Long softc = (probe_softc *)malloc(sizeof(*softc), M_CAMXPT, M_NOWAIT); 23452c9ce25SScott Long 23552c9ce25SScott Long if (softc == NULL) { 23652c9ce25SScott Long printf("proberegister: Unable to probe new device. " 23752c9ce25SScott Long "Unable to allocate softc\n"); 23852c9ce25SScott Long return(CAM_REQ_CMP_ERR); 23952c9ce25SScott Long } 24052c9ce25SScott Long TAILQ_INIT(&softc->request_ccbs); 24152c9ce25SScott Long TAILQ_INSERT_TAIL(&softc->request_ccbs, &request_ccb->ccb_h, 24252c9ce25SScott Long periph_links.tqe); 24352c9ce25SScott Long softc->flags = 0; 24452c9ce25SScott Long periph->softc = softc; 24552c9ce25SScott Long softc->periph = periph; 24652c9ce25SScott Long softc->action = PROBE_INVALID; 24752c9ce25SScott Long status = cam_periph_acquire(periph); 24852c9ce25SScott Long if (status != CAM_REQ_CMP) { 24952c9ce25SScott Long return (status); 25052c9ce25SScott Long } 25152c9ce25SScott Long 25252c9ce25SScott Long 25352c9ce25SScott Long /* 25452c9ce25SScott Long * Ensure we've waited at least a bus settle 25552c9ce25SScott Long * delay before attempting to probe the device. 25652c9ce25SScott Long * For HBAs that don't do bus resets, this won't make a difference. 25752c9ce25SScott Long */ 25852c9ce25SScott Long cam_periph_freeze_after_event(periph, &periph->path->bus->last_reset, 25952c9ce25SScott Long scsi_delay); 26052c9ce25SScott Long probeschedule(periph); 26152c9ce25SScott Long return(CAM_REQ_CMP); 26252c9ce25SScott Long } 26352c9ce25SScott Long 26452c9ce25SScott Long static void 26552c9ce25SScott Long probeschedule(struct cam_periph *periph) 26652c9ce25SScott Long { 26752c9ce25SScott Long struct ccb_pathinq cpi; 26852c9ce25SScott Long union ccb *ccb; 26952c9ce25SScott Long probe_softc *softc; 27052c9ce25SScott Long 27152c9ce25SScott Long softc = (probe_softc *)periph->softc; 27252c9ce25SScott Long ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs); 27352c9ce25SScott Long 27452c9ce25SScott Long xpt_setup_ccb(&cpi.ccb_h, periph->path, /*priority*/1); 27552c9ce25SScott Long cpi.ccb_h.func_code = XPT_PATH_INQ; 27652c9ce25SScott Long xpt_action((union ccb *)&cpi); 27752c9ce25SScott Long 27852c9ce25SScott Long if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) 27952c9ce25SScott Long PROBE_SET_ACTION(softc, PROBE_RESET); 28052c9ce25SScott Long else if (periph->path->device->protocol == PROTO_SATAPM) 28152c9ce25SScott Long PROBE_SET_ACTION(softc, PROBE_PM_PID); 28252c9ce25SScott Long else 28352c9ce25SScott Long PROBE_SET_ACTION(softc, PROBE_IDENTIFY); 28452c9ce25SScott Long 28552c9ce25SScott Long if (ccb->crcn.flags & CAM_EXPECT_INQ_CHANGE) 28652c9ce25SScott Long softc->flags |= PROBE_NO_ANNOUNCE; 28752c9ce25SScott Long else 28852c9ce25SScott Long softc->flags &= ~PROBE_NO_ANNOUNCE; 28952c9ce25SScott Long 29052c9ce25SScott Long xpt_schedule(periph, ccb->ccb_h.pinfo.priority); 29152c9ce25SScott Long } 29252c9ce25SScott Long 29352c9ce25SScott Long static void 29452c9ce25SScott Long probestart(struct cam_periph *periph, union ccb *start_ccb) 29552c9ce25SScott Long { 29652c9ce25SScott Long /* Probe the device that our peripheral driver points to */ 29752c9ce25SScott Long struct ccb_ataio *ataio; 29852c9ce25SScott Long struct ccb_scsiio *csio; 29952c9ce25SScott Long struct ccb_trans_settings cts; 30052c9ce25SScott Long probe_softc *softc; 30152c9ce25SScott Long 30252c9ce25SScott Long CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probestart\n")); 30352c9ce25SScott Long 30452c9ce25SScott Long softc = (probe_softc *)periph->softc; 30552c9ce25SScott Long ataio = &start_ccb->ataio; 30652c9ce25SScott Long csio = &start_ccb->csio; 30752c9ce25SScott Long 30852c9ce25SScott Long switch (softc->action) { 30952c9ce25SScott Long case PROBE_RESET: 31052c9ce25SScott Long if (start_ccb->ccb_h.target_id == 15) { 31152c9ce25SScott Long /* Report SIM that we have no knowledge about PM presence. */ 31252c9ce25SScott Long bzero(&cts, sizeof(cts)); 31352c9ce25SScott Long xpt_setup_ccb(&cts.ccb_h, start_ccb->ccb_h.path, 1); 31452c9ce25SScott Long cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 31552c9ce25SScott Long cts.type = CTS_TYPE_CURRENT_SETTINGS; 31652c9ce25SScott Long cts.xport_specific.sata.pm_present = 0; 31752c9ce25SScott Long cts.xport_specific.sata.valid = CTS_SATA_VALID_PM; 31852c9ce25SScott Long xpt_action((union ccb *)&cts); 31952c9ce25SScott Long } 32052c9ce25SScott Long cam_fill_ataio(ataio, 32152c9ce25SScott Long 0, 32252c9ce25SScott Long probedone, 32352c9ce25SScott Long /*flags*/CAM_DIR_NONE, 32452c9ce25SScott Long MSG_SIMPLE_Q_TAG, 32552c9ce25SScott Long /*data_ptr*/NULL, 32652c9ce25SScott Long /*dxfer_len*/0, 32752c9ce25SScott Long (start_ccb->ccb_h.target_id == 15 ? 3 : 15) * 1000); 32852c9ce25SScott Long ata_reset_cmd(ataio); 32952c9ce25SScott Long break; 33052c9ce25SScott Long case PROBE_IDENTIFY: 33152c9ce25SScott Long { 33252c9ce25SScott Long struct ata_params *ident_buf = 33352c9ce25SScott Long &periph->path->device->ident_data; 33452c9ce25SScott Long 33552c9ce25SScott Long if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) == 0) { 33652c9ce25SScott Long /* Prepare check that it is the same device. */ 33752c9ce25SScott Long MD5_CTX context; 33852c9ce25SScott Long 33952c9ce25SScott Long MD5Init(&context); 34052c9ce25SScott Long MD5Update(&context, 34152c9ce25SScott Long (unsigned char *)ident_buf->model, 34252c9ce25SScott Long sizeof(ident_buf->model)); 34352c9ce25SScott Long MD5Update(&context, 34452c9ce25SScott Long (unsigned char *)ident_buf->revision, 34552c9ce25SScott Long sizeof(ident_buf->revision)); 34652c9ce25SScott Long MD5Update(&context, 34752c9ce25SScott Long (unsigned char *)ident_buf->serial, 34852c9ce25SScott Long sizeof(ident_buf->serial)); 34952c9ce25SScott Long MD5Final(softc->digest, &context); 35052c9ce25SScott Long } 35152c9ce25SScott Long cam_fill_ataio(ataio, 35252c9ce25SScott Long 1, 35352c9ce25SScott Long probedone, 35452c9ce25SScott Long /*flags*/CAM_DIR_IN, 35552c9ce25SScott Long MSG_SIMPLE_Q_TAG, 35652c9ce25SScott Long /*data_ptr*/(u_int8_t *)ident_buf, 35752c9ce25SScott Long /*dxfer_len*/sizeof(struct ata_params), 35852c9ce25SScott Long 30 * 1000); 35952c9ce25SScott Long if (periph->path->device->protocol == PROTO_ATA) 36052c9ce25SScott Long ata_36bit_cmd(ataio, ATA_ATA_IDENTIFY, 0, 0, 0); 36152c9ce25SScott Long else 36252c9ce25SScott Long ata_36bit_cmd(ataio, ATA_ATAPI_IDENTIFY, 0, 0, 0); 36352c9ce25SScott Long break; 36452c9ce25SScott Long } 36552c9ce25SScott Long case PROBE_SETMODE: 36652c9ce25SScott Long { 36752c9ce25SScott Long struct ata_params *ident_buf = 36852c9ce25SScott Long &periph->path->device->ident_data; 36952c9ce25SScott Long 37052c9ce25SScott Long cam_fill_ataio(ataio, 37152c9ce25SScott Long 1, 37252c9ce25SScott Long probedone, 3735daa555dSAlexander Motin /*flags*/CAM_DIR_NONE, 3745daa555dSAlexander Motin 0, 3755daa555dSAlexander Motin /*data_ptr*/NULL, 3765daa555dSAlexander Motin /*dxfer_len*/0, 37752c9ce25SScott Long 30 * 1000); 37852c9ce25SScott Long ata_36bit_cmd(ataio, ATA_SETFEATURES, ATA_SF_SETXFER, 0, 37952c9ce25SScott Long ata_max_mode(ident_buf, ATA_UDMA6, ATA_UDMA6)); 38052c9ce25SScott Long break; 38152c9ce25SScott Long } 38252c9ce25SScott Long case PROBE_INQUIRY: 38352c9ce25SScott Long case PROBE_FULL_INQUIRY: 38452c9ce25SScott Long { 38552c9ce25SScott Long u_int inquiry_len; 38652c9ce25SScott Long struct scsi_inquiry_data *inq_buf = 38752c9ce25SScott Long &periph->path->device->inq_data; 38852c9ce25SScott Long 38952c9ce25SScott Long if (softc->action == PROBE_INQUIRY) 39052c9ce25SScott Long inquiry_len = SHORT_INQUIRY_LENGTH; 39152c9ce25SScott Long else 39252c9ce25SScott Long inquiry_len = SID_ADDITIONAL_LENGTH(inq_buf); 39352c9ce25SScott Long /* 39452c9ce25SScott Long * Some parallel SCSI devices fail to send an 39552c9ce25SScott Long * ignore wide residue message when dealing with 39652c9ce25SScott Long * odd length inquiry requests. Round up to be 39752c9ce25SScott Long * safe. 39852c9ce25SScott Long */ 39952c9ce25SScott Long inquiry_len = roundup2(inquiry_len, 2); 40052c9ce25SScott Long scsi_inquiry(csio, 40152c9ce25SScott Long /*retries*/1, 40252c9ce25SScott Long probedone, 40352c9ce25SScott Long MSG_SIMPLE_Q_TAG, 40452c9ce25SScott Long (u_int8_t *)inq_buf, 40552c9ce25SScott Long inquiry_len, 40652c9ce25SScott Long /*evpd*/FALSE, 40752c9ce25SScott Long /*page_code*/0, 40852c9ce25SScott Long SSD_MIN_SIZE, 40952c9ce25SScott Long /*timeout*/60 * 1000); 41052c9ce25SScott Long break; 41152c9ce25SScott Long } 41252c9ce25SScott Long case PROBE_PM_PID: 41352c9ce25SScott Long cam_fill_ataio(ataio, 41452c9ce25SScott Long 1, 41552c9ce25SScott Long probedone, 41652c9ce25SScott Long /*flags*/CAM_DIR_NONE, 41752c9ce25SScott Long MSG_SIMPLE_Q_TAG, 41852c9ce25SScott Long /*data_ptr*/NULL, 41952c9ce25SScott Long /*dxfer_len*/0, 42052c9ce25SScott Long 10 * 1000); 42152c9ce25SScott Long ata_pm_read_cmd(ataio, 0, 15); 42252c9ce25SScott Long break; 42352c9ce25SScott Long case PROBE_PM_PRV: 42452c9ce25SScott Long cam_fill_ataio(ataio, 42552c9ce25SScott Long 1, 42652c9ce25SScott Long probedone, 42752c9ce25SScott Long /*flags*/CAM_DIR_NONE, 42852c9ce25SScott Long MSG_SIMPLE_Q_TAG, 42952c9ce25SScott Long /*data_ptr*/NULL, 43052c9ce25SScott Long /*dxfer_len*/0, 43152c9ce25SScott Long 10 * 1000); 43252c9ce25SScott Long ata_pm_read_cmd(ataio, 1, 15); 43352c9ce25SScott Long break; 43452c9ce25SScott Long case PROBE_PM_PORTS: 43552c9ce25SScott Long cam_fill_ataio(ataio, 43652c9ce25SScott Long 1, 43752c9ce25SScott Long probedone, 43852c9ce25SScott Long /*flags*/CAM_DIR_NONE, 43952c9ce25SScott Long MSG_SIMPLE_Q_TAG, 44052c9ce25SScott Long /*data_ptr*/NULL, 44152c9ce25SScott Long /*dxfer_len*/0, 44252c9ce25SScott Long 10 * 1000); 44352c9ce25SScott Long ata_pm_read_cmd(ataio, 2, 15); 44452c9ce25SScott Long break; 44552c9ce25SScott Long case PROBE_PM_RESET: 44652c9ce25SScott Long { 44752c9ce25SScott Long struct ata_params *ident_buf = 44852c9ce25SScott Long &periph->path->device->ident_data; 44952c9ce25SScott Long cam_fill_ataio(ataio, 45052c9ce25SScott Long 1, 45152c9ce25SScott Long probedone, 45252c9ce25SScott Long /*flags*/CAM_DIR_NONE, 45352c9ce25SScott Long MSG_SIMPLE_Q_TAG, 45452c9ce25SScott Long /*data_ptr*/NULL, 45552c9ce25SScott Long /*dxfer_len*/0, 45652c9ce25SScott Long 10 * 1000); 45752c9ce25SScott Long ata_pm_write_cmd(ataio, 2, softc->pm_step, 45852c9ce25SScott Long (ident_buf->cylinders & (1 << softc->pm_step)) ? 0 : 1); 45952c9ce25SScott Long printf("PM RESET %d %04x %d\n", softc->pm_step, ident_buf->cylinders, 46052c9ce25SScott Long (ident_buf->cylinders & (1 << softc->pm_step)) ? 0 : 1); 46152c9ce25SScott Long break; 46252c9ce25SScott Long } 46352c9ce25SScott Long case PROBE_PM_CONNECT: 46452c9ce25SScott Long cam_fill_ataio(ataio, 46552c9ce25SScott Long 1, 46652c9ce25SScott Long probedone, 46752c9ce25SScott Long /*flags*/CAM_DIR_NONE, 46852c9ce25SScott Long MSG_SIMPLE_Q_TAG, 46952c9ce25SScott Long /*data_ptr*/NULL, 47052c9ce25SScott Long /*dxfer_len*/0, 47152c9ce25SScott Long 10 * 1000); 47252c9ce25SScott Long ata_pm_write_cmd(ataio, 2, softc->pm_step, 0); 47352c9ce25SScott Long break; 47452c9ce25SScott Long case PROBE_PM_CHECK: 47552c9ce25SScott Long cam_fill_ataio(ataio, 47652c9ce25SScott Long 1, 47752c9ce25SScott Long probedone, 47852c9ce25SScott Long /*flags*/CAM_DIR_NONE, 47952c9ce25SScott Long MSG_SIMPLE_Q_TAG, 48052c9ce25SScott Long /*data_ptr*/NULL, 48152c9ce25SScott Long /*dxfer_len*/0, 48252c9ce25SScott Long 10 * 1000); 48352c9ce25SScott Long ata_pm_read_cmd(ataio, 0, softc->pm_step); 48452c9ce25SScott Long break; 48552c9ce25SScott Long case PROBE_PM_CLEAR: 48652c9ce25SScott Long cam_fill_ataio(ataio, 48752c9ce25SScott Long 1, 48852c9ce25SScott Long probedone, 48952c9ce25SScott Long /*flags*/CAM_DIR_NONE, 49052c9ce25SScott Long MSG_SIMPLE_Q_TAG, 49152c9ce25SScott Long /*data_ptr*/NULL, 49252c9ce25SScott Long /*dxfer_len*/0, 49352c9ce25SScott Long 10 * 1000); 49452c9ce25SScott Long ata_pm_write_cmd(ataio, 1, softc->pm_step, 0xFFFFFFFF); 49552c9ce25SScott Long break; 49652c9ce25SScott Long case PROBE_INVALID: 49752c9ce25SScott Long CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_INFO, 49852c9ce25SScott Long ("probestart: invalid action state\n")); 49952c9ce25SScott Long default: 50052c9ce25SScott Long break; 50152c9ce25SScott Long } 50252c9ce25SScott Long xpt_action(start_ccb); 50352c9ce25SScott Long } 50452c9ce25SScott Long #if 0 50552c9ce25SScott Long static void 50652c9ce25SScott Long proberequestdefaultnegotiation(struct cam_periph *periph) 50752c9ce25SScott Long { 50852c9ce25SScott Long struct ccb_trans_settings cts; 50952c9ce25SScott Long 51052c9ce25SScott Long xpt_setup_ccb(&cts.ccb_h, periph->path, /*priority*/1); 51152c9ce25SScott Long cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 51252c9ce25SScott Long cts.type = CTS_TYPE_USER_SETTINGS; 51352c9ce25SScott Long xpt_action((union ccb *)&cts); 51452c9ce25SScott Long if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 51552c9ce25SScott Long return; 51652c9ce25SScott Long } 51752c9ce25SScott Long cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 51852c9ce25SScott Long cts.type = CTS_TYPE_CURRENT_SETTINGS; 51952c9ce25SScott Long xpt_action((union ccb *)&cts); 52052c9ce25SScott Long } 52152c9ce25SScott Long 52252c9ce25SScott Long /* 52352c9ce25SScott Long * Backoff Negotiation Code- only pertinent for SPI devices. 52452c9ce25SScott Long */ 52552c9ce25SScott Long static int 52652c9ce25SScott Long proberequestbackoff(struct cam_periph *periph, struct cam_ed *device) 52752c9ce25SScott Long { 52852c9ce25SScott Long struct ccb_trans_settings cts; 52952c9ce25SScott Long struct ccb_trans_settings_spi *spi; 53052c9ce25SScott Long 53152c9ce25SScott Long memset(&cts, 0, sizeof (cts)); 53252c9ce25SScott Long xpt_setup_ccb(&cts.ccb_h, periph->path, /*priority*/1); 53352c9ce25SScott Long cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 53452c9ce25SScott Long cts.type = CTS_TYPE_CURRENT_SETTINGS; 53552c9ce25SScott Long xpt_action((union ccb *)&cts); 53652c9ce25SScott Long if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 53752c9ce25SScott Long if (bootverbose) { 53852c9ce25SScott Long xpt_print(periph->path, 53952c9ce25SScott Long "failed to get current device settings\n"); 54052c9ce25SScott Long } 54152c9ce25SScott Long return (0); 54252c9ce25SScott Long } 54352c9ce25SScott Long if (cts.transport != XPORT_SPI) { 54452c9ce25SScott Long if (bootverbose) { 54552c9ce25SScott Long xpt_print(periph->path, "not SPI transport\n"); 54652c9ce25SScott Long } 54752c9ce25SScott Long return (0); 54852c9ce25SScott Long } 54952c9ce25SScott Long spi = &cts.xport_specific.spi; 55052c9ce25SScott Long 55152c9ce25SScott Long /* 55252c9ce25SScott Long * We cannot renegotiate sync rate if we don't have one. 55352c9ce25SScott Long */ 55452c9ce25SScott Long if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0) { 55552c9ce25SScott Long if (bootverbose) { 55652c9ce25SScott Long xpt_print(periph->path, "no sync rate known\n"); 55752c9ce25SScott Long } 55852c9ce25SScott Long return (0); 55952c9ce25SScott Long } 56052c9ce25SScott Long 56152c9ce25SScott Long /* 56252c9ce25SScott Long * We'll assert that we don't have to touch PPR options- the 56352c9ce25SScott Long * SIM will see what we do with period and offset and adjust 56452c9ce25SScott Long * the PPR options as appropriate. 56552c9ce25SScott Long */ 56652c9ce25SScott Long 56752c9ce25SScott Long /* 56852c9ce25SScott Long * A sync rate with unknown or zero offset is nonsensical. 56952c9ce25SScott Long * A sync period of zero means Async. 57052c9ce25SScott Long */ 57152c9ce25SScott Long if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0 57252c9ce25SScott Long || spi->sync_offset == 0 || spi->sync_period == 0) { 57352c9ce25SScott Long if (bootverbose) { 57452c9ce25SScott Long xpt_print(periph->path, "no sync rate available\n"); 57552c9ce25SScott Long } 57652c9ce25SScott Long return (0); 57752c9ce25SScott Long } 57852c9ce25SScott Long 57952c9ce25SScott Long if (device->flags & CAM_DEV_DV_HIT_BOTTOM) { 58052c9ce25SScott Long CAM_DEBUG(periph->path, CAM_DEBUG_INFO, 58152c9ce25SScott Long ("hit async: giving up on DV\n")); 58252c9ce25SScott Long return (0); 58352c9ce25SScott Long } 58452c9ce25SScott Long 58552c9ce25SScott Long 58652c9ce25SScott Long /* 58752c9ce25SScott Long * Jump sync_period up by one, but stop at 5MHz and fall back to Async. 58852c9ce25SScott Long * We don't try to remember 'last' settings to see if the SIM actually 58952c9ce25SScott Long * gets into the speed we want to set. We check on the SIM telling 59052c9ce25SScott Long * us that a requested speed is bad, but otherwise don't try and 59152c9ce25SScott Long * check the speed due to the asynchronous and handshake nature 59252c9ce25SScott Long * of speed setting. 59352c9ce25SScott Long */ 59452c9ce25SScott Long spi->valid = CTS_SPI_VALID_SYNC_RATE | CTS_SPI_VALID_SYNC_OFFSET; 59552c9ce25SScott Long for (;;) { 59652c9ce25SScott Long spi->sync_period++; 59752c9ce25SScott Long if (spi->sync_period >= 0xf) { 59852c9ce25SScott Long spi->sync_period = 0; 59952c9ce25SScott Long spi->sync_offset = 0; 60052c9ce25SScott Long CAM_DEBUG(periph->path, CAM_DEBUG_INFO, 60152c9ce25SScott Long ("setting to async for DV\n")); 60252c9ce25SScott Long /* 60352c9ce25SScott Long * Once we hit async, we don't want to try 60452c9ce25SScott Long * any more settings. 60552c9ce25SScott Long */ 60652c9ce25SScott Long device->flags |= CAM_DEV_DV_HIT_BOTTOM; 60752c9ce25SScott Long } else if (bootverbose) { 60852c9ce25SScott Long CAM_DEBUG(periph->path, CAM_DEBUG_INFO, 60952c9ce25SScott Long ("DV: period 0x%x\n", spi->sync_period)); 61052c9ce25SScott Long printf("setting period to 0x%x\n", spi->sync_period); 61152c9ce25SScott Long } 61252c9ce25SScott Long cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 61352c9ce25SScott Long cts.type = CTS_TYPE_CURRENT_SETTINGS; 61452c9ce25SScott Long xpt_action((union ccb *)&cts); 61552c9ce25SScott Long if ((cts.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 61652c9ce25SScott Long break; 61752c9ce25SScott Long } 61852c9ce25SScott Long CAM_DEBUG(periph->path, CAM_DEBUG_INFO, 61952c9ce25SScott Long ("DV: failed to set period 0x%x\n", spi->sync_period)); 62052c9ce25SScott Long if (spi->sync_period == 0) { 62152c9ce25SScott Long return (0); 62252c9ce25SScott Long } 62352c9ce25SScott Long } 62452c9ce25SScott Long return (1); 62552c9ce25SScott Long } 62652c9ce25SScott Long #endif 62752c9ce25SScott Long static void 62852c9ce25SScott Long probedone(struct cam_periph *periph, union ccb *done_ccb) 62952c9ce25SScott Long { 63052c9ce25SScott Long struct ata_params *ident_buf; 63152c9ce25SScott Long probe_softc *softc; 63252c9ce25SScott Long struct cam_path *path; 63352c9ce25SScott Long u_int32_t priority; 63452c9ce25SScott Long int found = 0; 63552c9ce25SScott Long 63652c9ce25SScott Long CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probedone\n")); 63752c9ce25SScott Long 63852c9ce25SScott Long softc = (probe_softc *)periph->softc; 63952c9ce25SScott Long path = done_ccb->ccb_h.path; 64052c9ce25SScott Long priority = done_ccb->ccb_h.pinfo.priority; 64152c9ce25SScott Long ident_buf = &path->device->ident_data; 64252c9ce25SScott Long 64352c9ce25SScott Long switch (softc->action) { 64452c9ce25SScott Long case PROBE_RESET: 64552c9ce25SScott Long if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 64652c9ce25SScott Long int sign = (done_ccb->ataio.res.lba_high << 8) + 64752c9ce25SScott Long done_ccb->ataio.res.lba_mid; 64852c9ce25SScott Long xpt_print(path, "SIGNATURE: %04x\n", sign); 64952c9ce25SScott Long if (sign == 0x0000 && 65052c9ce25SScott Long done_ccb->ccb_h.target_id != 15) { 65152c9ce25SScott Long path->device->protocol = PROTO_ATA; 65252c9ce25SScott Long PROBE_SET_ACTION(softc, PROBE_IDENTIFY); 65352c9ce25SScott Long } else if (sign == 0x9669 && 65452c9ce25SScott Long done_ccb->ccb_h.target_id == 15) { 65552c9ce25SScott Long struct ccb_trans_settings cts; 65652c9ce25SScott Long 65752c9ce25SScott Long /* Report SIM that PM is present. */ 65852c9ce25SScott Long bzero(&cts, sizeof(cts)); 65952c9ce25SScott Long xpt_setup_ccb(&cts.ccb_h, path, 1); 66052c9ce25SScott Long cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 66152c9ce25SScott Long cts.type = CTS_TYPE_CURRENT_SETTINGS; 66252c9ce25SScott Long cts.xport_specific.sata.pm_present = 1; 66352c9ce25SScott Long cts.xport_specific.sata.valid = CTS_SATA_VALID_PM; 66452c9ce25SScott Long xpt_action((union ccb *)&cts); 66552c9ce25SScott Long path->device->protocol = PROTO_SATAPM; 66652c9ce25SScott Long PROBE_SET_ACTION(softc, PROBE_PM_PID); 66752c9ce25SScott Long } else if (sign == 0xeb14 && 66852c9ce25SScott Long done_ccb->ccb_h.target_id != 15) { 66952c9ce25SScott Long path->device->protocol = PROTO_SCSI; 67052c9ce25SScott Long PROBE_SET_ACTION(softc, PROBE_IDENTIFY); 67152c9ce25SScott Long } else { 67252c9ce25SScott Long if (done_ccb->ccb_h.target_id != 15) { 67352c9ce25SScott Long xpt_print(path, 67452c9ce25SScott Long "Unexpected signature 0x%04x\n", sign); 67552c9ce25SScott Long } 67652c9ce25SScott Long xpt_release_ccb(done_ccb); 67752c9ce25SScott Long break; 67852c9ce25SScott Long } 67952c9ce25SScott Long xpt_release_ccb(done_ccb); 68052c9ce25SScott Long xpt_schedule(periph, priority); 68152c9ce25SScott Long return; 68252c9ce25SScott Long } else if (cam_periph_error(done_ccb, 0, 0, 68352c9ce25SScott Long &softc->saved_ccb) == ERESTART) { 68452c9ce25SScott Long return; 68552c9ce25SScott Long } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 68652c9ce25SScott Long /* Don't wedge the queue */ 68752c9ce25SScott Long xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, 68852c9ce25SScott Long /*run_queue*/TRUE); 68952c9ce25SScott Long } 69052c9ce25SScott Long goto device_fail; 69152c9ce25SScott Long case PROBE_IDENTIFY: 69252c9ce25SScott Long { 69352c9ce25SScott Long if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 69452c9ce25SScott Long int16_t *ptr; 69552c9ce25SScott Long 69652c9ce25SScott Long for (ptr = (int16_t *)ident_buf; 69752c9ce25SScott Long ptr < (int16_t *)ident_buf + sizeof(struct ata_params)/2; ptr++) { 69852c9ce25SScott Long *ptr = le16toh(*ptr); 69952c9ce25SScott Long } 70052c9ce25SScott Long if (strncmp(ident_buf->model, "FX", 2) && 70152c9ce25SScott Long strncmp(ident_buf->model, "NEC", 3) && 70252c9ce25SScott Long strncmp(ident_buf->model, "Pioneer", 7) && 70352c9ce25SScott Long strncmp(ident_buf->model, "SHARP", 5)) { 70452c9ce25SScott Long ata_bswap(ident_buf->model, sizeof(ident_buf->model)); 70552c9ce25SScott Long ata_bswap(ident_buf->revision, sizeof(ident_buf->revision)); 70652c9ce25SScott Long ata_bswap(ident_buf->serial, sizeof(ident_buf->serial)); 70752c9ce25SScott Long } 70852c9ce25SScott Long ata_btrim(ident_buf->model, sizeof(ident_buf->model)); 70952c9ce25SScott Long ata_bpack(ident_buf->model, ident_buf->model, sizeof(ident_buf->model)); 71052c9ce25SScott Long ata_btrim(ident_buf->revision, sizeof(ident_buf->revision)); 71152c9ce25SScott Long ata_bpack(ident_buf->revision, ident_buf->revision, sizeof(ident_buf->revision)); 71252c9ce25SScott Long ata_btrim(ident_buf->serial, sizeof(ident_buf->serial)); 71352c9ce25SScott Long ata_bpack(ident_buf->serial, ident_buf->serial, sizeof(ident_buf->serial)); 71452c9ce25SScott Long 71552c9ce25SScott Long if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) == 0) { 71652c9ce25SScott Long /* Check that it is the same device. */ 71752c9ce25SScott Long MD5_CTX context; 71852c9ce25SScott Long u_int8_t digest[16]; 71952c9ce25SScott Long 72052c9ce25SScott Long MD5Init(&context); 72152c9ce25SScott Long MD5Update(&context, 72252c9ce25SScott Long (unsigned char *)ident_buf->model, 72352c9ce25SScott Long sizeof(ident_buf->model)); 72452c9ce25SScott Long MD5Update(&context, 72552c9ce25SScott Long (unsigned char *)ident_buf->revision, 72652c9ce25SScott Long sizeof(ident_buf->revision)); 72752c9ce25SScott Long MD5Update(&context, 72852c9ce25SScott Long (unsigned char *)ident_buf->serial, 72952c9ce25SScott Long sizeof(ident_buf->serial)); 73052c9ce25SScott Long MD5Final(digest, &context); 73152c9ce25SScott Long if (bcmp(digest, softc->digest, sizeof(digest))) { 73252c9ce25SScott Long /* Device changed. */ 73352c9ce25SScott Long xpt_async(AC_LOST_DEVICE, path, NULL); 73452c9ce25SScott Long } 73552c9ce25SScott Long xpt_release_ccb(done_ccb); 73652c9ce25SScott Long break; 73752c9ce25SScott Long } 73852c9ce25SScott Long 73952c9ce25SScott Long /* Clean up from previous instance of this device */ 74052c9ce25SScott Long if (path->device->serial_num != NULL) { 74152c9ce25SScott Long free(path->device->serial_num, M_CAMXPT); 74252c9ce25SScott Long path->device->serial_num = NULL; 74352c9ce25SScott Long path->device->serial_num_len = 0; 74452c9ce25SScott Long } 74552c9ce25SScott Long path->device->serial_num = 74652c9ce25SScott Long (u_int8_t *)malloc((sizeof(ident_buf->serial) + 1), 74752c9ce25SScott Long M_CAMXPT, M_NOWAIT); 74852c9ce25SScott Long if (path->device->serial_num != NULL) { 74952c9ce25SScott Long bcopy(ident_buf->serial, 75052c9ce25SScott Long path->device->serial_num, 75152c9ce25SScott Long sizeof(ident_buf->serial)); 75252c9ce25SScott Long path->device->serial_num[sizeof(ident_buf->serial)] 75352c9ce25SScott Long = '\0'; 75452c9ce25SScott Long path->device->serial_num_len = 75552c9ce25SScott Long strlen(path->device->serial_num); 75652c9ce25SScott Long } 75752c9ce25SScott Long 75852c9ce25SScott Long path->device->flags |= CAM_DEV_INQUIRY_DATA_VALID; 75952c9ce25SScott Long 76052c9ce25SScott Long scsi_find_quirk(path->device); 76152c9ce25SScott Long ata_device_transport(path); 76252c9ce25SScott Long 76352c9ce25SScott Long PROBE_SET_ACTION(softc, PROBE_SETMODE); 76452c9ce25SScott Long xpt_release_ccb(done_ccb); 76552c9ce25SScott Long xpt_schedule(periph, priority); 76652c9ce25SScott Long return; 76752c9ce25SScott Long } else if (cam_periph_error(done_ccb, 0, 0, 76852c9ce25SScott Long &softc->saved_ccb) == ERESTART) { 76952c9ce25SScott Long return; 77052c9ce25SScott Long } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 77152c9ce25SScott Long /* Don't wedge the queue */ 77252c9ce25SScott Long xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, 77352c9ce25SScott Long /*run_queue*/TRUE); 77452c9ce25SScott Long } 77552c9ce25SScott Long device_fail: 77652c9ce25SScott Long /* 77752c9ce25SScott Long * If we get to this point, we got an error status back 77852c9ce25SScott Long * from the inquiry and the error status doesn't require 77952c9ce25SScott Long * automatically retrying the command. Therefore, the 78052c9ce25SScott Long * inquiry failed. If we had inquiry information before 78152c9ce25SScott Long * for this device, but this latest inquiry command failed, 78252c9ce25SScott Long * the device has probably gone away. If this device isn't 78352c9ce25SScott Long * already marked unconfigured, notify the peripheral 78452c9ce25SScott Long * drivers that this device is no more. 78552c9ce25SScott Long */ 78652c9ce25SScott Long if ((path->device->flags & CAM_DEV_UNCONFIGURED) == 0) 78752c9ce25SScott Long /* Send the async notification. */ 78852c9ce25SScott Long xpt_async(AC_LOST_DEVICE, path, NULL); 78952c9ce25SScott Long 79052c9ce25SScott Long xpt_release_ccb(done_ccb); 79152c9ce25SScott Long break; 79252c9ce25SScott Long } 79352c9ce25SScott Long case PROBE_SETMODE: 79452c9ce25SScott Long { 79552c9ce25SScott Long if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 79652c9ce25SScott Long if (path->device->protocol == PROTO_ATA) { 79752c9ce25SScott Long path->device->flags &= ~CAM_DEV_UNCONFIGURED; 79852c9ce25SScott Long done_ccb->ccb_h.func_code = XPT_GDEV_TYPE; 79952c9ce25SScott Long xpt_action(done_ccb); 80052c9ce25SScott Long xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path, 80152c9ce25SScott Long done_ccb); 80252c9ce25SScott Long xpt_release_ccb(done_ccb); 80352c9ce25SScott Long break; 80452c9ce25SScott Long } else { 80552c9ce25SScott Long PROBE_SET_ACTION(softc, PROBE_INQUIRY); 80652c9ce25SScott Long xpt_release_ccb(done_ccb); 80752c9ce25SScott Long xpt_schedule(periph, priority); 80852c9ce25SScott Long return; 80952c9ce25SScott Long } 81052c9ce25SScott Long } else if (cam_periph_error(done_ccb, 0, 0, 81152c9ce25SScott Long &softc->saved_ccb) == ERESTART) { 81252c9ce25SScott Long return; 81352c9ce25SScott Long } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 81452c9ce25SScott Long /* Don't wedge the queue */ 81552c9ce25SScott Long xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, 81652c9ce25SScott Long /*run_queue*/TRUE); 81752c9ce25SScott Long } 81852c9ce25SScott Long goto device_fail; 81952c9ce25SScott Long } 82052c9ce25SScott Long case PROBE_INQUIRY: 82152c9ce25SScott Long case PROBE_FULL_INQUIRY: 82252c9ce25SScott Long { 82352c9ce25SScott Long if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 82452c9ce25SScott Long struct scsi_inquiry_data *inq_buf; 82552c9ce25SScott Long u_int8_t periph_qual; 82652c9ce25SScott Long 82752c9ce25SScott Long path->device->flags |= CAM_DEV_INQUIRY_DATA_VALID; 82852c9ce25SScott Long inq_buf = &path->device->inq_data; 82952c9ce25SScott Long 83052c9ce25SScott Long periph_qual = SID_QUAL(inq_buf); 83152c9ce25SScott Long 83252c9ce25SScott Long if (periph_qual == SID_QUAL_LU_CONNECTED) { 83352c9ce25SScott Long u_int8_t len; 83452c9ce25SScott Long 83552c9ce25SScott Long /* 83652c9ce25SScott Long * We conservatively request only 83752c9ce25SScott Long * SHORT_INQUIRY_LEN bytes of inquiry 83852c9ce25SScott Long * information during our first try 83952c9ce25SScott Long * at sending an INQUIRY. If the device 84052c9ce25SScott Long * has more information to give, 84152c9ce25SScott Long * perform a second request specifying 84252c9ce25SScott Long * the amount of information the device 84352c9ce25SScott Long * is willing to give. 84452c9ce25SScott Long */ 84552c9ce25SScott Long len = inq_buf->additional_length 84652c9ce25SScott Long + offsetof(struct scsi_inquiry_data, 84752c9ce25SScott Long additional_length) + 1; 84852c9ce25SScott Long if (softc->action == PROBE_INQUIRY 84952c9ce25SScott Long && len > SHORT_INQUIRY_LENGTH) { 85052c9ce25SScott Long PROBE_SET_ACTION(softc, PROBE_FULL_INQUIRY); 85152c9ce25SScott Long xpt_release_ccb(done_ccb); 85252c9ce25SScott Long xpt_schedule(periph, priority); 85352c9ce25SScott Long return; 85452c9ce25SScott Long } 85552c9ce25SScott Long 85652c9ce25SScott Long scsi_find_quirk(path->device); 85752c9ce25SScott Long 85852c9ce25SScott Long // scsi_devise_transport(path); 85952c9ce25SScott Long path->device->flags &= ~CAM_DEV_UNCONFIGURED; 86052c9ce25SScott Long done_ccb->ccb_h.func_code = XPT_GDEV_TYPE; 86152c9ce25SScott Long xpt_action(done_ccb); 86252c9ce25SScott Long xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path, 86352c9ce25SScott Long done_ccb); 86452c9ce25SScott Long xpt_release_ccb(done_ccb); 86552c9ce25SScott Long break; 86652c9ce25SScott Long } 86752c9ce25SScott Long } else if (cam_periph_error(done_ccb, 0, 0, 86852c9ce25SScott Long &softc->saved_ccb) == ERESTART) { 86952c9ce25SScott Long return; 87052c9ce25SScott Long } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 87152c9ce25SScott Long /* Don't wedge the queue */ 87252c9ce25SScott Long xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, 87352c9ce25SScott Long /*run_queue*/TRUE); 87452c9ce25SScott Long } 87552c9ce25SScott Long goto device_fail; 87652c9ce25SScott Long } 87752c9ce25SScott Long case PROBE_PM_PID: 87852c9ce25SScott Long if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 87952c9ce25SScott Long if ((path->device->flags & CAM_DEV_INQUIRY_DATA_VALID) == 0) 88052c9ce25SScott Long bzero(ident_buf, sizeof(*ident_buf)); 88152c9ce25SScott Long softc->pm_pid = (done_ccb->ataio.res.lba_high << 24) + 88252c9ce25SScott Long (done_ccb->ataio.res.lba_mid << 16) + 88352c9ce25SScott Long (done_ccb->ataio.res.lba_low << 8) + 88452c9ce25SScott Long done_ccb->ataio.res.sector_count; 88552c9ce25SScott Long printf("PM Product ID: %08x\n", softc->pm_pid); 88652c9ce25SScott Long snprintf(ident_buf->model, sizeof(ident_buf->model), 88752c9ce25SScott Long "Port Multiplier %08x", softc->pm_pid); 88852c9ce25SScott Long PROBE_SET_ACTION(softc, PROBE_PM_PRV); 88952c9ce25SScott Long xpt_release_ccb(done_ccb); 89052c9ce25SScott Long xpt_schedule(periph, priority); 89152c9ce25SScott Long return; 89252c9ce25SScott Long } else if (cam_periph_error(done_ccb, 0, 0, 89352c9ce25SScott Long &softc->saved_ccb) == ERESTART) { 89452c9ce25SScott Long return; 89552c9ce25SScott Long } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 89652c9ce25SScott Long /* Don't wedge the queue */ 89752c9ce25SScott Long xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, 89852c9ce25SScott Long /*run_queue*/TRUE); 89952c9ce25SScott Long } 90052c9ce25SScott Long goto device_fail; 90152c9ce25SScott Long case PROBE_PM_PRV: 90252c9ce25SScott Long if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 90352c9ce25SScott Long softc->pm_prv = (done_ccb->ataio.res.lba_high << 24) + 90452c9ce25SScott Long (done_ccb->ataio.res.lba_mid << 16) + 90552c9ce25SScott Long (done_ccb->ataio.res.lba_low << 8) + 90652c9ce25SScott Long done_ccb->ataio.res.sector_count; 90752c9ce25SScott Long printf("PM Revision: %08x\n", softc->pm_prv); 90852c9ce25SScott Long snprintf(ident_buf->revision, sizeof(ident_buf->revision), 90952c9ce25SScott Long "%04x", softc->pm_prv); 91052c9ce25SScott Long PROBE_SET_ACTION(softc, PROBE_PM_PORTS); 91152c9ce25SScott Long xpt_release_ccb(done_ccb); 91252c9ce25SScott Long xpt_schedule(periph, priority); 91352c9ce25SScott Long return; 91452c9ce25SScott Long } else if (cam_periph_error(done_ccb, 0, 0, 91552c9ce25SScott Long &softc->saved_ccb) == ERESTART) { 91652c9ce25SScott Long return; 91752c9ce25SScott Long } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 91852c9ce25SScott Long /* Don't wedge the queue */ 91952c9ce25SScott Long xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, 92052c9ce25SScott Long /*run_queue*/TRUE); 92152c9ce25SScott Long } 92252c9ce25SScott Long goto device_fail; 92352c9ce25SScott Long case PROBE_PM_PORTS: 92452c9ce25SScott Long if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 92552c9ce25SScott Long softc->pm_ports = (done_ccb->ataio.res.lba_high << 24) + 92652c9ce25SScott Long (done_ccb->ataio.res.lba_mid << 16) + 92752c9ce25SScott Long (done_ccb->ataio.res.lba_low << 8) + 92852c9ce25SScott Long done_ccb->ataio.res.sector_count; 92952c9ce25SScott Long /* This PM declares 6 ports, while only 5 of them are real. 93052c9ce25SScott Long * Port 5 is enclosure management bridge port, which has implementation 93152c9ce25SScott Long * problems, causing probe faults. Hide it for now. */ 93252c9ce25SScott Long if (softc->pm_pid == 0x37261095 && softc->pm_ports == 6) 93352c9ce25SScott Long softc->pm_ports = 5; 93452c9ce25SScott Long /* This PM declares 7 ports, while only 5 of them are real. 93552c9ce25SScott Long * Port 5 is some fake "Config Disk" with 640 sectors size, 93652c9ce25SScott Long * port 6 is enclosure management bridge port. 93752c9ce25SScott Long * Both fake ports has implementation problems, causing 93852c9ce25SScott Long * probe faults. Hide them for now. */ 93952c9ce25SScott Long if (softc->pm_pid == 0x47261095 && softc->pm_ports == 7) 94052c9ce25SScott Long softc->pm_ports = 5; 94152c9ce25SScott Long printf("PM ports: %d\n", softc->pm_ports); 94252c9ce25SScott Long ident_buf->config = softc->pm_ports; 94352c9ce25SScott Long path->device->flags |= CAM_DEV_INQUIRY_DATA_VALID; 94452c9ce25SScott Long softc->pm_step = 0; 94552c9ce25SScott Long PROBE_SET_ACTION(softc, PROBE_PM_RESET); 94652c9ce25SScott Long xpt_release_ccb(done_ccb); 94752c9ce25SScott Long xpt_schedule(periph, priority); 94852c9ce25SScott Long return; 94952c9ce25SScott Long } else if (cam_periph_error(done_ccb, 0, 0, 95052c9ce25SScott Long &softc->saved_ccb) == ERESTART) { 95152c9ce25SScott Long return; 95252c9ce25SScott Long } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 95352c9ce25SScott Long /* Don't wedge the queue */ 95452c9ce25SScott Long xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, 95552c9ce25SScott Long /*run_queue*/TRUE); 95652c9ce25SScott Long } 95752c9ce25SScott Long goto device_fail; 95852c9ce25SScott Long case PROBE_PM_RESET: 95952c9ce25SScott Long if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 96052c9ce25SScott Long softc->pm_step++; 96152c9ce25SScott Long if (softc->pm_step < softc->pm_ports) { 96252c9ce25SScott Long xpt_release_ccb(done_ccb); 96352c9ce25SScott Long xpt_schedule(periph, priority); 96452c9ce25SScott Long return; 96552c9ce25SScott Long } else { 96652c9ce25SScott Long softc->pm_step = 0; 96752c9ce25SScott Long DELAY(5000); 96852c9ce25SScott Long printf("PM reset done\n"); 96952c9ce25SScott Long PROBE_SET_ACTION(softc, PROBE_PM_CONNECT); 97052c9ce25SScott Long xpt_release_ccb(done_ccb); 97152c9ce25SScott Long xpt_schedule(periph, priority); 97252c9ce25SScott Long return; 97352c9ce25SScott Long } 97452c9ce25SScott Long } else if (cam_periph_error(done_ccb, 0, 0, 97552c9ce25SScott Long &softc->saved_ccb) == ERESTART) { 97652c9ce25SScott Long return; 97752c9ce25SScott Long } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 97852c9ce25SScott Long /* Don't wedge the queue */ 97952c9ce25SScott Long xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, 98052c9ce25SScott Long /*run_queue*/TRUE); 98152c9ce25SScott Long } 98252c9ce25SScott Long goto device_fail; 98352c9ce25SScott Long case PROBE_PM_CONNECT: 98452c9ce25SScott Long if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 98552c9ce25SScott Long softc->pm_step++; 98652c9ce25SScott Long if (softc->pm_step < softc->pm_ports) { 98752c9ce25SScott Long xpt_release_ccb(done_ccb); 98852c9ce25SScott Long xpt_schedule(periph, priority); 98952c9ce25SScott Long return; 99052c9ce25SScott Long } else { 99152c9ce25SScott Long softc->pm_step = 0; 99252c9ce25SScott Long softc->pm_try = 0; 99352c9ce25SScott Long printf("PM connect done\n"); 99452c9ce25SScott Long PROBE_SET_ACTION(softc, PROBE_PM_CHECK); 99552c9ce25SScott Long xpt_release_ccb(done_ccb); 99652c9ce25SScott Long xpt_schedule(periph, priority); 99752c9ce25SScott Long return; 99852c9ce25SScott Long } 99952c9ce25SScott Long } else if (cam_periph_error(done_ccb, 0, 0, 100052c9ce25SScott Long &softc->saved_ccb) == ERESTART) { 100152c9ce25SScott Long return; 100252c9ce25SScott Long } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 100352c9ce25SScott Long /* Don't wedge the queue */ 100452c9ce25SScott Long xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, 100552c9ce25SScott Long /*run_queue*/TRUE); 100652c9ce25SScott Long } 100752c9ce25SScott Long goto device_fail; 100852c9ce25SScott Long case PROBE_PM_CHECK: 100952c9ce25SScott Long if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 101052c9ce25SScott Long int res = (done_ccb->ataio.res.lba_high << 24) + 101152c9ce25SScott Long (done_ccb->ataio.res.lba_mid << 16) + 101252c9ce25SScott Long (done_ccb->ataio.res.lba_low << 8) + 101352c9ce25SScott Long done_ccb->ataio.res.sector_count; 101452c9ce25SScott Long if ((res & 0xf0f) == 0x103 && (res & 0x0f0) != 0) { 101552c9ce25SScott Long printf("PM status: %d - %08x\n", softc->pm_step, res); 101652c9ce25SScott Long ident_buf->cylinders |= (1 << softc->pm_step); 101752c9ce25SScott Long softc->pm_step++; 101852c9ce25SScott Long } else { 101952c9ce25SScott Long if (softc->pm_try < 100) { 102052c9ce25SScott Long DELAY(10000); 102152c9ce25SScott Long softc->pm_try++; 102252c9ce25SScott Long } else { 102352c9ce25SScott Long printf("PM status: %d - %08x\n", softc->pm_step, res); 102452c9ce25SScott Long ident_buf->cylinders &= ~(1 << softc->pm_step); 102552c9ce25SScott Long softc->pm_step++; 102652c9ce25SScott Long } 102752c9ce25SScott Long } 102852c9ce25SScott Long if (softc->pm_step < softc->pm_ports) { 102952c9ce25SScott Long xpt_release_ccb(done_ccb); 103052c9ce25SScott Long xpt_schedule(periph, priority); 103152c9ce25SScott Long return; 103252c9ce25SScott Long } else { 103352c9ce25SScott Long softc->pm_step = 0; 103452c9ce25SScott Long PROBE_SET_ACTION(softc, PROBE_PM_CLEAR); 103552c9ce25SScott Long xpt_release_ccb(done_ccb); 103652c9ce25SScott Long xpt_schedule(periph, priority); 103752c9ce25SScott Long return; 103852c9ce25SScott Long } 103952c9ce25SScott Long } else if (cam_periph_error(done_ccb, 0, 0, 104052c9ce25SScott Long &softc->saved_ccb) == ERESTART) { 104152c9ce25SScott Long return; 104252c9ce25SScott Long } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 104352c9ce25SScott Long /* Don't wedge the queue */ 104452c9ce25SScott Long xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, 104552c9ce25SScott Long /*run_queue*/TRUE); 104652c9ce25SScott Long } 104752c9ce25SScott Long goto device_fail; 104852c9ce25SScott Long case PROBE_PM_CLEAR: 104952c9ce25SScott Long if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 105052c9ce25SScott Long softc->pm_step++; 105152c9ce25SScott Long if (softc->pm_step < softc->pm_ports) { 105252c9ce25SScott Long xpt_release_ccb(done_ccb); 105352c9ce25SScott Long xpt_schedule(periph, priority); 105452c9ce25SScott Long return; 105552c9ce25SScott Long } 105652c9ce25SScott Long found = ident_buf->cylinders | 0x8000; 105752c9ce25SScott Long if (path->device->flags & CAM_DEV_UNCONFIGURED) { 105852c9ce25SScott Long path->device->flags &= ~CAM_DEV_UNCONFIGURED; 105952c9ce25SScott Long done_ccb->ccb_h.func_code = XPT_GDEV_TYPE; 106052c9ce25SScott Long xpt_action(done_ccb); 106152c9ce25SScott Long xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path, 106252c9ce25SScott Long done_ccb); 106352c9ce25SScott Long xpt_release_ccb(done_ccb); 106452c9ce25SScott Long } 106552c9ce25SScott Long break; 106652c9ce25SScott Long } else if (cam_periph_error(done_ccb, 0, 0, 106752c9ce25SScott Long &softc->saved_ccb) == ERESTART) { 106852c9ce25SScott Long return; 106952c9ce25SScott Long } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 107052c9ce25SScott Long /* Don't wedge the queue */ 107152c9ce25SScott Long xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, 107252c9ce25SScott Long /*run_queue*/TRUE); 107352c9ce25SScott Long } 107452c9ce25SScott Long goto device_fail; 107552c9ce25SScott Long case PROBE_INVALID: 107652c9ce25SScott Long CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_INFO, 107752c9ce25SScott Long ("probedone: invalid action state\n")); 107852c9ce25SScott Long default: 107952c9ce25SScott Long break; 108052c9ce25SScott Long } 108152c9ce25SScott Long done_ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs); 108252c9ce25SScott Long TAILQ_REMOVE(&softc->request_ccbs, &done_ccb->ccb_h, periph_links.tqe); 108352c9ce25SScott Long done_ccb->ccb_h.status = CAM_REQ_CMP; 108452c9ce25SScott Long done_ccb->ccb_h.ppriv_field1 = found; 108552c9ce25SScott Long xpt_done(done_ccb); 108652c9ce25SScott Long if (TAILQ_FIRST(&softc->request_ccbs) == NULL) { 108752c9ce25SScott Long cam_periph_invalidate(periph); 108852c9ce25SScott Long cam_periph_release_locked(periph); 108952c9ce25SScott Long } else { 109052c9ce25SScott Long probeschedule(periph); 109152c9ce25SScott Long } 109252c9ce25SScott Long } 109352c9ce25SScott Long 109452c9ce25SScott Long static void 109552c9ce25SScott Long probecleanup(struct cam_periph *periph) 109652c9ce25SScott Long { 109752c9ce25SScott Long free(periph->softc, M_CAMXPT); 109852c9ce25SScott Long } 109952c9ce25SScott Long 110052c9ce25SScott Long static void 110152c9ce25SScott Long scsi_find_quirk(struct cam_ed *device) 110252c9ce25SScott Long { 110352c9ce25SScott Long struct scsi_quirk_entry *quirk; 110452c9ce25SScott Long caddr_t match; 110552c9ce25SScott Long 110652c9ce25SScott Long match = cam_quirkmatch((caddr_t)&device->inq_data, 110752c9ce25SScott Long (caddr_t)scsi_quirk_table, 110852c9ce25SScott Long sizeof(scsi_quirk_table) / 110952c9ce25SScott Long sizeof(*scsi_quirk_table), 111052c9ce25SScott Long sizeof(*scsi_quirk_table), scsi_inquiry_match); 111152c9ce25SScott Long 111252c9ce25SScott Long if (match == NULL) 111352c9ce25SScott Long panic("xpt_find_quirk: device didn't match wildcard entry!!"); 111452c9ce25SScott Long 111552c9ce25SScott Long quirk = (struct scsi_quirk_entry *)match; 111652c9ce25SScott Long device->quirk = quirk; 111752c9ce25SScott Long device->mintags = quirk->mintags; 111852c9ce25SScott Long device->maxtags = quirk->maxtags; 111952c9ce25SScott Long } 112052c9ce25SScott Long 112152c9ce25SScott Long typedef struct { 112252c9ce25SScott Long union ccb *request_ccb; 112352c9ce25SScott Long struct ccb_pathinq *cpi; 112452c9ce25SScott Long int counter; 112552c9ce25SScott Long int found; 112652c9ce25SScott Long } ata_scan_bus_info; 112752c9ce25SScott Long 112852c9ce25SScott Long /* 112952c9ce25SScott Long * To start a scan, request_ccb is an XPT_SCAN_BUS ccb. 113052c9ce25SScott Long * As the scan progresses, xpt_scan_bus is used as the 113152c9ce25SScott Long * callback on completion function. 113252c9ce25SScott Long */ 113352c9ce25SScott Long static void 113452c9ce25SScott Long ata_scan_bus(struct cam_periph *periph, union ccb *request_ccb) 113552c9ce25SScott Long { 113652c9ce25SScott Long struct cam_path *path; 113752c9ce25SScott Long ata_scan_bus_info *scan_info; 113852c9ce25SScott Long union ccb *work_ccb; 113952c9ce25SScott Long cam_status status; 114052c9ce25SScott Long 114152c9ce25SScott Long CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_TRACE, 114252c9ce25SScott Long ("xpt_scan_bus\n")); 114352c9ce25SScott Long switch (request_ccb->ccb_h.func_code) { 114452c9ce25SScott Long case XPT_SCAN_BUS: 114552c9ce25SScott Long /* Find out the characteristics of the bus */ 114652c9ce25SScott Long work_ccb = xpt_alloc_ccb_nowait(); 114752c9ce25SScott Long if (work_ccb == NULL) { 114852c9ce25SScott Long request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 114952c9ce25SScott Long xpt_done(request_ccb); 115052c9ce25SScott Long return; 115152c9ce25SScott Long } 115252c9ce25SScott Long xpt_setup_ccb(&work_ccb->ccb_h, request_ccb->ccb_h.path, 115352c9ce25SScott Long request_ccb->ccb_h.pinfo.priority); 115452c9ce25SScott Long work_ccb->ccb_h.func_code = XPT_PATH_INQ; 115552c9ce25SScott Long xpt_action(work_ccb); 115652c9ce25SScott Long if (work_ccb->ccb_h.status != CAM_REQ_CMP) { 115752c9ce25SScott Long request_ccb->ccb_h.status = work_ccb->ccb_h.status; 115852c9ce25SScott Long xpt_free_ccb(work_ccb); 115952c9ce25SScott Long xpt_done(request_ccb); 116052c9ce25SScott Long return; 116152c9ce25SScott Long } 116252c9ce25SScott Long 116352c9ce25SScott Long /* Save some state for use while we probe for devices */ 116452c9ce25SScott Long scan_info = (ata_scan_bus_info *) 116552c9ce25SScott Long malloc(sizeof(ata_scan_bus_info), M_CAMXPT, M_NOWAIT); 116652c9ce25SScott Long if (scan_info == NULL) { 116752c9ce25SScott Long request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 116852c9ce25SScott Long xpt_done(request_ccb); 116952c9ce25SScott Long return; 117052c9ce25SScott Long } 117152c9ce25SScott Long scan_info->request_ccb = request_ccb; 117252c9ce25SScott Long scan_info->cpi = &work_ccb->cpi; 117352c9ce25SScott Long scan_info->found = 0x8001; 117452c9ce25SScott Long scan_info->counter = 0; 117552c9ce25SScott Long /* If PM supported, probe it first. */ 117652c9ce25SScott Long if (scan_info->cpi->hba_inquiry & PI_SATAPM) 117752c9ce25SScott Long scan_info->counter = 15; 117852c9ce25SScott Long 117952c9ce25SScott Long work_ccb = xpt_alloc_ccb_nowait(); 118052c9ce25SScott Long if (work_ccb == NULL) { 118152c9ce25SScott Long free(scan_info, M_CAMXPT); 118252c9ce25SScott Long request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 118352c9ce25SScott Long xpt_done(request_ccb); 118452c9ce25SScott Long break; 118552c9ce25SScott Long } 118652c9ce25SScott Long goto scan_next; 118752c9ce25SScott Long case XPT_SCAN_LUN: 118852c9ce25SScott Long work_ccb = request_ccb; 118952c9ce25SScott Long /* Reuse the same CCB to query if a device was really found */ 119052c9ce25SScott Long scan_info = (ata_scan_bus_info *)work_ccb->ccb_h.ppriv_ptr0; 119152c9ce25SScott Long /* Free the current request path- we're done with it. */ 119252c9ce25SScott Long xpt_free_path(work_ccb->ccb_h.path); 119352c9ce25SScott Long /* If there is PM... */ 119452c9ce25SScott Long if (scan_info->counter == 15) { 119552c9ce25SScott Long if (work_ccb->ccb_h.ppriv_field1 != 0) { 119652c9ce25SScott Long /* Save PM probe result. */ 119752c9ce25SScott Long scan_info->found = work_ccb->ccb_h.ppriv_field1; 119852c9ce25SScott Long } else { 119952c9ce25SScott Long struct ccb_trans_settings cts; 120052c9ce25SScott Long 120152c9ce25SScott Long /* Report SIM that PM is absent. */ 120252c9ce25SScott Long bzero(&cts, sizeof(cts)); 120352c9ce25SScott Long xpt_setup_ccb(&cts.ccb_h, 120452c9ce25SScott Long scan_info->request_ccb->ccb_h.path, 1); 120552c9ce25SScott Long cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 120652c9ce25SScott Long cts.type = CTS_TYPE_CURRENT_SETTINGS; 12073ccda2f3SAlexander Motin cts.xport_specific.sata.pm_present = 0; 120852c9ce25SScott Long cts.xport_specific.sata.valid = CTS_SATA_VALID_PM; 120952c9ce25SScott Long xpt_action((union ccb *)&cts); 121052c9ce25SScott Long } 121152c9ce25SScott Long } 121252c9ce25SScott Long take_next: 121352c9ce25SScott Long /* Take next device. Wrap from 15 (PM) to 0. */ 121452c9ce25SScott Long scan_info->counter = (scan_info->counter + 1 ) & 0x0f; 121552c9ce25SScott Long if (scan_info->counter >= scan_info->cpi->max_target+1) { 121652c9ce25SScott Long xpt_free_ccb(work_ccb); 121752c9ce25SScott Long xpt_free_ccb((union ccb *)scan_info->cpi); 121852c9ce25SScott Long request_ccb = scan_info->request_ccb; 121952c9ce25SScott Long free(scan_info, M_CAMXPT); 122052c9ce25SScott Long request_ccb->ccb_h.status = CAM_REQ_CMP; 122152c9ce25SScott Long xpt_done(request_ccb); 122252c9ce25SScott Long break; 122352c9ce25SScott Long } 122452c9ce25SScott Long scan_next: 122552c9ce25SScott Long status = xpt_create_path(&path, xpt_periph, 122652c9ce25SScott Long scan_info->request_ccb->ccb_h.path_id, 122752c9ce25SScott Long scan_info->counter, 0); 122852c9ce25SScott Long if (status != CAM_REQ_CMP) { 122952c9ce25SScott Long printf("xpt_scan_bus: xpt_create_path failed" 123052c9ce25SScott Long " with status %#x, bus scan halted\n", 123152c9ce25SScott Long status); 123252c9ce25SScott Long xpt_free_ccb(work_ccb); 123352c9ce25SScott Long xpt_free_ccb((union ccb *)scan_info->cpi); 123452c9ce25SScott Long request_ccb = scan_info->request_ccb; 123552c9ce25SScott Long free(scan_info, M_CAMXPT); 123652c9ce25SScott Long request_ccb->ccb_h.status = status; 123752c9ce25SScott Long xpt_done(request_ccb); 123852c9ce25SScott Long break; 123952c9ce25SScott Long } 124052c9ce25SScott Long if ((scan_info->found & (1 << scan_info->counter)) == 0) { 124152c9ce25SScott Long xpt_async(AC_LOST_DEVICE, path, NULL); 124252c9ce25SScott Long xpt_free_path(path); 124352c9ce25SScott Long goto take_next; 124452c9ce25SScott Long } 124552c9ce25SScott Long xpt_setup_ccb(&work_ccb->ccb_h, path, 124652c9ce25SScott Long scan_info->request_ccb->ccb_h.pinfo.priority); 124752c9ce25SScott Long work_ccb->ccb_h.func_code = XPT_SCAN_LUN; 124852c9ce25SScott Long work_ccb->ccb_h.cbfcnp = ata_scan_bus; 124952c9ce25SScott Long work_ccb->ccb_h.ppriv_ptr0 = scan_info; 125052c9ce25SScott Long work_ccb->crcn.flags = scan_info->request_ccb->crcn.flags; 125152c9ce25SScott Long xpt_action(work_ccb); 125252c9ce25SScott Long break; 125352c9ce25SScott Long default: 125452c9ce25SScott Long break; 125552c9ce25SScott Long } 125652c9ce25SScott Long } 125752c9ce25SScott Long 125852c9ce25SScott Long static void 125952c9ce25SScott Long ata_scan_lun(struct cam_periph *periph, struct cam_path *path, 126052c9ce25SScott Long cam_flags flags, union ccb *request_ccb) 126152c9ce25SScott Long { 126252c9ce25SScott Long struct ccb_pathinq cpi; 126352c9ce25SScott Long cam_status status; 126452c9ce25SScott Long struct cam_path *new_path; 126552c9ce25SScott Long struct cam_periph *old_periph; 126652c9ce25SScott Long 126752c9ce25SScott Long CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_TRACE, 126852c9ce25SScott Long ("xpt_scan_lun\n")); 126952c9ce25SScott Long 127052c9ce25SScott Long xpt_setup_ccb(&cpi.ccb_h, path, /*priority*/1); 127152c9ce25SScott Long cpi.ccb_h.func_code = XPT_PATH_INQ; 127252c9ce25SScott Long xpt_action((union ccb *)&cpi); 127352c9ce25SScott Long 127452c9ce25SScott Long if (cpi.ccb_h.status != CAM_REQ_CMP) { 127552c9ce25SScott Long if (request_ccb != NULL) { 127652c9ce25SScott Long request_ccb->ccb_h.status = cpi.ccb_h.status; 127752c9ce25SScott Long xpt_done(request_ccb); 127852c9ce25SScott Long } 127952c9ce25SScott Long return; 128052c9ce25SScott Long } 128152c9ce25SScott Long 128252c9ce25SScott Long if (request_ccb == NULL) { 128352c9ce25SScott Long request_ccb = malloc(sizeof(union ccb), M_CAMXPT, M_NOWAIT); 128452c9ce25SScott Long if (request_ccb == NULL) { 128552c9ce25SScott Long xpt_print(path, "xpt_scan_lun: can't allocate CCB, " 128652c9ce25SScott Long "can't continue\n"); 128752c9ce25SScott Long return; 128852c9ce25SScott Long } 128952c9ce25SScott Long new_path = malloc(sizeof(*new_path), M_CAMXPT, M_NOWAIT); 129052c9ce25SScott Long if (new_path == NULL) { 129152c9ce25SScott Long xpt_print(path, "xpt_scan_lun: can't allocate path, " 129252c9ce25SScott Long "can't continue\n"); 129352c9ce25SScott Long free(request_ccb, M_CAMXPT); 129452c9ce25SScott Long return; 129552c9ce25SScott Long } 129652c9ce25SScott Long status = xpt_compile_path(new_path, xpt_periph, 129752c9ce25SScott Long path->bus->path_id, 129852c9ce25SScott Long path->target->target_id, 129952c9ce25SScott Long path->device->lun_id); 130052c9ce25SScott Long 130152c9ce25SScott Long if (status != CAM_REQ_CMP) { 130252c9ce25SScott Long xpt_print(path, "xpt_scan_lun: can't compile path, " 130352c9ce25SScott Long "can't continue\n"); 130452c9ce25SScott Long free(request_ccb, M_CAMXPT); 130552c9ce25SScott Long free(new_path, M_CAMXPT); 130652c9ce25SScott Long return; 130752c9ce25SScott Long } 130852c9ce25SScott Long xpt_setup_ccb(&request_ccb->ccb_h, new_path, /*priority*/ 1); 130952c9ce25SScott Long request_ccb->ccb_h.cbfcnp = xptscandone; 131052c9ce25SScott Long request_ccb->ccb_h.func_code = XPT_SCAN_LUN; 131152c9ce25SScott Long request_ccb->crcn.flags = flags; 131252c9ce25SScott Long } 131352c9ce25SScott Long 1314f09f8e3eSAlexander Motin if ((old_periph = cam_periph_find(path, "aprobe")) != NULL) { 131552c9ce25SScott Long probe_softc *softc; 131652c9ce25SScott Long 131752c9ce25SScott Long softc = (probe_softc *)old_periph->softc; 131852c9ce25SScott Long TAILQ_INSERT_TAIL(&softc->request_ccbs, &request_ccb->ccb_h, 131952c9ce25SScott Long periph_links.tqe); 132052c9ce25SScott Long } else { 132152c9ce25SScott Long status = cam_periph_alloc(proberegister, NULL, probecleanup, 1322f09f8e3eSAlexander Motin probestart, "aprobe", 132352c9ce25SScott Long CAM_PERIPH_BIO, 132452c9ce25SScott Long request_ccb->ccb_h.path, NULL, 0, 132552c9ce25SScott Long request_ccb); 132652c9ce25SScott Long 132752c9ce25SScott Long if (status != CAM_REQ_CMP) { 132852c9ce25SScott Long xpt_print(path, "xpt_scan_lun: cam_alloc_periph " 132952c9ce25SScott Long "returned an error, can't continue probe\n"); 133052c9ce25SScott Long request_ccb->ccb_h.status = status; 133152c9ce25SScott Long xpt_done(request_ccb); 133252c9ce25SScott Long } 133352c9ce25SScott Long } 133452c9ce25SScott Long } 133552c9ce25SScott Long 133652c9ce25SScott Long static void 133752c9ce25SScott Long xptscandone(struct cam_periph *periph, union ccb *done_ccb) 133852c9ce25SScott Long { 133952c9ce25SScott Long xpt_release_path(done_ccb->ccb_h.path); 134052c9ce25SScott Long free(done_ccb->ccb_h.path, M_CAMXPT); 134152c9ce25SScott Long free(done_ccb, M_CAMXPT); 134252c9ce25SScott Long } 134352c9ce25SScott Long 134452c9ce25SScott Long static struct cam_ed * 134552c9ce25SScott Long ata_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id) 134652c9ce25SScott Long { 134752c9ce25SScott Long struct cam_path path; 134852c9ce25SScott Long struct scsi_quirk_entry *quirk; 134952c9ce25SScott Long struct cam_ed *device; 135052c9ce25SScott Long struct cam_ed *cur_device; 135152c9ce25SScott Long 135252c9ce25SScott Long device = xpt_alloc_device(bus, target, lun_id); 135352c9ce25SScott Long if (device == NULL) 135452c9ce25SScott Long return (NULL); 135552c9ce25SScott Long 135652c9ce25SScott Long /* 135752c9ce25SScott Long * Take the default quirk entry until we have inquiry 135852c9ce25SScott Long * data and can determine a better quirk to use. 135952c9ce25SScott Long */ 136052c9ce25SScott Long quirk = &scsi_quirk_table[scsi_quirk_table_size - 1]; 136152c9ce25SScott Long device->quirk = (void *)quirk; 136252c9ce25SScott Long device->mintags = quirk->mintags; 136352c9ce25SScott Long device->maxtags = quirk->maxtags; 136452c9ce25SScott Long bzero(&device->inq_data, sizeof(device->inq_data)); 136552c9ce25SScott Long device->inq_flags = 0; 136652c9ce25SScott Long device->queue_flags = 0; 136752c9ce25SScott Long device->serial_num = NULL; 136852c9ce25SScott Long device->serial_num_len = 0; 136952c9ce25SScott Long 137052c9ce25SScott Long /* 137152c9ce25SScott Long * XXX should be limited by number of CCBs this bus can 137252c9ce25SScott Long * do. 137352c9ce25SScott Long */ 137452c9ce25SScott Long bus->sim->max_ccbs += device->ccbq.devq_openings; 137552c9ce25SScott Long /* Insertion sort into our target's device list */ 137652c9ce25SScott Long cur_device = TAILQ_FIRST(&target->ed_entries); 137752c9ce25SScott Long while (cur_device != NULL && cur_device->lun_id < lun_id) 137852c9ce25SScott Long cur_device = TAILQ_NEXT(cur_device, links); 137952c9ce25SScott Long if (cur_device != NULL) { 138052c9ce25SScott Long TAILQ_INSERT_BEFORE(cur_device, device, links); 138152c9ce25SScott Long } else { 138252c9ce25SScott Long TAILQ_INSERT_TAIL(&target->ed_entries, device, links); 138352c9ce25SScott Long } 138452c9ce25SScott Long target->generation++; 138552c9ce25SScott Long if (lun_id != CAM_LUN_WILDCARD) { 138652c9ce25SScott Long xpt_compile_path(&path, 138752c9ce25SScott Long NULL, 138852c9ce25SScott Long bus->path_id, 138952c9ce25SScott Long target->target_id, 139052c9ce25SScott Long lun_id); 139152c9ce25SScott Long ata_device_transport(&path); 139252c9ce25SScott Long xpt_release_path(&path); 139352c9ce25SScott Long } 139452c9ce25SScott Long 139552c9ce25SScott Long return (device); 139652c9ce25SScott Long } 139752c9ce25SScott Long 139852c9ce25SScott Long static void 139952c9ce25SScott Long ata_device_transport(struct cam_path *path) 140052c9ce25SScott Long { 140152c9ce25SScott Long struct ccb_pathinq cpi; 140252c9ce25SScott Long // struct ccb_trans_settings cts; 140352c9ce25SScott Long struct scsi_inquiry_data *inq_buf; 140452c9ce25SScott Long 140552c9ce25SScott Long /* Get transport information from the SIM */ 140652c9ce25SScott Long xpt_setup_ccb(&cpi.ccb_h, path, /*priority*/1); 140752c9ce25SScott Long cpi.ccb_h.func_code = XPT_PATH_INQ; 140852c9ce25SScott Long xpt_action((union ccb *)&cpi); 140952c9ce25SScott Long 141052c9ce25SScott Long inq_buf = NULL; 141152c9ce25SScott Long // if ((path->device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0) 141252c9ce25SScott Long // inq_buf = &path->device->inq_data; 141352c9ce25SScott Long // path->device->protocol = cpi.protocol; 141452c9ce25SScott Long // path->device->protocol_version = 141552c9ce25SScott Long // inq_buf != NULL ? SID_ANSI_REV(inq_buf) : cpi.protocol_version; 141652c9ce25SScott Long path->device->transport = cpi.transport; 141752c9ce25SScott Long path->device->transport_version = cpi.transport_version; 141852c9ce25SScott Long #if 0 141952c9ce25SScott Long /* 142052c9ce25SScott Long * Any device not using SPI3 features should 142152c9ce25SScott Long * be considered SPI2 or lower. 142252c9ce25SScott Long */ 142352c9ce25SScott Long if (inq_buf != NULL) { 142452c9ce25SScott Long if (path->device->transport == XPORT_SPI 142552c9ce25SScott Long && (inq_buf->spi3data & SID_SPI_MASK) == 0 142652c9ce25SScott Long && path->device->transport_version > 2) 142752c9ce25SScott Long path->device->transport_version = 2; 142852c9ce25SScott Long } else { 142952c9ce25SScott Long struct cam_ed* otherdev; 143052c9ce25SScott Long 143152c9ce25SScott Long for (otherdev = TAILQ_FIRST(&path->target->ed_entries); 143252c9ce25SScott Long otherdev != NULL; 143352c9ce25SScott Long otherdev = TAILQ_NEXT(otherdev, links)) { 143452c9ce25SScott Long if (otherdev != path->device) 143552c9ce25SScott Long break; 143652c9ce25SScott Long } 143752c9ce25SScott Long 143852c9ce25SScott Long if (otherdev != NULL) { 143952c9ce25SScott Long /* 144052c9ce25SScott Long * Initially assume the same versioning as 144152c9ce25SScott Long * prior luns for this target. 144252c9ce25SScott Long */ 144352c9ce25SScott Long path->device->protocol_version = 144452c9ce25SScott Long otherdev->protocol_version; 144552c9ce25SScott Long path->device->transport_version = 144652c9ce25SScott Long otherdev->transport_version; 144752c9ce25SScott Long } else { 144852c9ce25SScott Long /* Until we know better, opt for safty */ 144952c9ce25SScott Long path->device->protocol_version = 2; 145052c9ce25SScott Long if (path->device->transport == XPORT_SPI) 145152c9ce25SScott Long path->device->transport_version = 2; 145252c9ce25SScott Long else 145352c9ce25SScott Long path->device->transport_version = 0; 145452c9ce25SScott Long } 145552c9ce25SScott Long } 145652c9ce25SScott Long 145752c9ce25SScott Long /* 145852c9ce25SScott Long * XXX 145952c9ce25SScott Long * For a device compliant with SPC-2 we should be able 146052c9ce25SScott Long * to determine the transport version supported by 146152c9ce25SScott Long * scrutinizing the version descriptors in the 146252c9ce25SScott Long * inquiry buffer. 146352c9ce25SScott Long */ 146452c9ce25SScott Long 146552c9ce25SScott Long /* Tell the controller what we think */ 146652c9ce25SScott Long xpt_setup_ccb(&cts.ccb_h, path, /*priority*/1); 146752c9ce25SScott Long cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 146852c9ce25SScott Long cts.type = CTS_TYPE_CURRENT_SETTINGS; 146952c9ce25SScott Long cts.transport = path->device->transport; 147052c9ce25SScott Long cts.transport_version = path->device->transport_version; 147152c9ce25SScott Long cts.protocol = path->device->protocol; 147252c9ce25SScott Long cts.protocol_version = path->device->protocol_version; 147352c9ce25SScott Long cts.proto_specific.valid = 0; 147452c9ce25SScott Long cts.xport_specific.valid = 0; 147552c9ce25SScott Long xpt_action((union ccb *)&cts); 147652c9ce25SScott Long #endif 147752c9ce25SScott Long } 147852c9ce25SScott Long 147952c9ce25SScott Long static void 148052c9ce25SScott Long ata_action(union ccb *start_ccb) 148152c9ce25SScott Long { 148252c9ce25SScott Long 148352c9ce25SScott Long switch (start_ccb->ccb_h.func_code) { 148452c9ce25SScott Long case XPT_SET_TRAN_SETTINGS: 148552c9ce25SScott Long { 148652c9ce25SScott Long scsi_set_transfer_settings(&start_ccb->cts, 148752c9ce25SScott Long start_ccb->ccb_h.path->device, 148852c9ce25SScott Long /*async_update*/FALSE); 148952c9ce25SScott Long break; 149052c9ce25SScott Long } 149152c9ce25SScott Long case XPT_SCAN_BUS: 149252c9ce25SScott Long ata_scan_bus(start_ccb->ccb_h.path->periph, start_ccb); 149352c9ce25SScott Long break; 149452c9ce25SScott Long case XPT_SCAN_LUN: 149552c9ce25SScott Long ata_scan_lun(start_ccb->ccb_h.path->periph, 149652c9ce25SScott Long start_ccb->ccb_h.path, start_ccb->crcn.flags, 149752c9ce25SScott Long start_ccb); 149852c9ce25SScott Long break; 149952c9ce25SScott Long case XPT_GET_TRAN_SETTINGS: 150052c9ce25SScott Long { 150152c9ce25SScott Long struct cam_sim *sim; 150252c9ce25SScott Long 150352c9ce25SScott Long sim = start_ccb->ccb_h.path->bus->sim; 150452c9ce25SScott Long (*(sim->sim_action))(sim, start_ccb); 150552c9ce25SScott Long break; 150652c9ce25SScott Long } 150752c9ce25SScott Long default: 150852c9ce25SScott Long xpt_action_default(start_ccb); 150952c9ce25SScott Long break; 151052c9ce25SScott Long } 151152c9ce25SScott Long } 151252c9ce25SScott Long 151352c9ce25SScott Long static void 151452c9ce25SScott Long scsi_set_transfer_settings(struct ccb_trans_settings *cts, struct cam_ed *device, 151552c9ce25SScott Long int async_update) 151652c9ce25SScott Long { 151752c9ce25SScott Long struct ccb_pathinq cpi; 151852c9ce25SScott Long struct ccb_trans_settings cur_cts; 151952c9ce25SScott Long struct ccb_trans_settings_scsi *scsi; 152052c9ce25SScott Long struct ccb_trans_settings_scsi *cur_scsi; 152152c9ce25SScott Long struct cam_sim *sim; 152252c9ce25SScott Long struct scsi_inquiry_data *inq_data; 152352c9ce25SScott Long 152452c9ce25SScott Long if (device == NULL) { 152552c9ce25SScott Long cts->ccb_h.status = CAM_PATH_INVALID; 152652c9ce25SScott Long xpt_done((union ccb *)cts); 152752c9ce25SScott Long return; 152852c9ce25SScott Long } 152952c9ce25SScott Long 153052c9ce25SScott Long if (cts->protocol == PROTO_UNKNOWN 153152c9ce25SScott Long || cts->protocol == PROTO_UNSPECIFIED) { 153252c9ce25SScott Long cts->protocol = device->protocol; 153352c9ce25SScott Long cts->protocol_version = device->protocol_version; 153452c9ce25SScott Long } 153552c9ce25SScott Long 153652c9ce25SScott Long if (cts->protocol_version == PROTO_VERSION_UNKNOWN 153752c9ce25SScott Long || cts->protocol_version == PROTO_VERSION_UNSPECIFIED) 153852c9ce25SScott Long cts->protocol_version = device->protocol_version; 153952c9ce25SScott Long 154052c9ce25SScott Long if (cts->protocol != device->protocol) { 154152c9ce25SScott Long xpt_print(cts->ccb_h.path, "Uninitialized Protocol %x:%x?\n", 154252c9ce25SScott Long cts->protocol, device->protocol); 154352c9ce25SScott Long cts->protocol = device->protocol; 154452c9ce25SScott Long } 154552c9ce25SScott Long 154652c9ce25SScott Long if (cts->protocol_version > device->protocol_version) { 154752c9ce25SScott Long if (bootverbose) { 154852c9ce25SScott Long xpt_print(cts->ccb_h.path, "Down reving Protocol " 154952c9ce25SScott Long "Version from %d to %d?\n", cts->protocol_version, 155052c9ce25SScott Long device->protocol_version); 155152c9ce25SScott Long } 155252c9ce25SScott Long cts->protocol_version = device->protocol_version; 155352c9ce25SScott Long } 155452c9ce25SScott Long 155552c9ce25SScott Long if (cts->transport == XPORT_UNKNOWN 155652c9ce25SScott Long || cts->transport == XPORT_UNSPECIFIED) { 155752c9ce25SScott Long cts->transport = device->transport; 155852c9ce25SScott Long cts->transport_version = device->transport_version; 155952c9ce25SScott Long } 156052c9ce25SScott Long 156152c9ce25SScott Long if (cts->transport_version == XPORT_VERSION_UNKNOWN 156252c9ce25SScott Long || cts->transport_version == XPORT_VERSION_UNSPECIFIED) 156352c9ce25SScott Long cts->transport_version = device->transport_version; 156452c9ce25SScott Long 156552c9ce25SScott Long if (cts->transport != device->transport) { 156652c9ce25SScott Long xpt_print(cts->ccb_h.path, "Uninitialized Transport %x:%x?\n", 156752c9ce25SScott Long cts->transport, device->transport); 156852c9ce25SScott Long cts->transport = device->transport; 156952c9ce25SScott Long } 157052c9ce25SScott Long 157152c9ce25SScott Long if (cts->transport_version > device->transport_version) { 157252c9ce25SScott Long if (bootverbose) { 157352c9ce25SScott Long xpt_print(cts->ccb_h.path, "Down reving Transport " 157452c9ce25SScott Long "Version from %d to %d?\n", cts->transport_version, 157552c9ce25SScott Long device->transport_version); 157652c9ce25SScott Long } 157752c9ce25SScott Long cts->transport_version = device->transport_version; 157852c9ce25SScott Long } 157952c9ce25SScott Long 158052c9ce25SScott Long sim = cts->ccb_h.path->bus->sim; 158152c9ce25SScott Long 158252c9ce25SScott Long /* 158352c9ce25SScott Long * Nothing more of interest to do unless 158452c9ce25SScott Long * this is a device connected via the 158552c9ce25SScott Long * SCSI protocol. 158652c9ce25SScott Long */ 158752c9ce25SScott Long if (cts->protocol != PROTO_SCSI) { 158852c9ce25SScott Long if (async_update == FALSE) 158952c9ce25SScott Long (*(sim->sim_action))(sim, (union ccb *)cts); 159052c9ce25SScott Long return; 159152c9ce25SScott Long } 159252c9ce25SScott Long 159352c9ce25SScott Long inq_data = &device->inq_data; 159452c9ce25SScott Long scsi = &cts->proto_specific.scsi; 159552c9ce25SScott Long xpt_setup_ccb(&cpi.ccb_h, cts->ccb_h.path, /*priority*/1); 159652c9ce25SScott Long cpi.ccb_h.func_code = XPT_PATH_INQ; 159752c9ce25SScott Long xpt_action((union ccb *)&cpi); 159852c9ce25SScott Long 159952c9ce25SScott Long /* SCSI specific sanity checking */ 160052c9ce25SScott Long if ((cpi.hba_inquiry & PI_TAG_ABLE) == 0 160152c9ce25SScott Long || (INQ_DATA_TQ_ENABLED(inq_data)) == 0 160252c9ce25SScott Long || (device->queue_flags & SCP_QUEUE_DQUE) != 0 160352c9ce25SScott Long || (device->mintags == 0)) { 160452c9ce25SScott Long /* 160552c9ce25SScott Long * Can't tag on hardware that doesn't support tags, 160652c9ce25SScott Long * doesn't have it enabled, or has broken tag support. 160752c9ce25SScott Long */ 160852c9ce25SScott Long scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 160952c9ce25SScott Long } 161052c9ce25SScott Long 161152c9ce25SScott Long if (async_update == FALSE) { 161252c9ce25SScott Long /* 161352c9ce25SScott Long * Perform sanity checking against what the 161452c9ce25SScott Long * controller and device can do. 161552c9ce25SScott Long */ 161652c9ce25SScott Long xpt_setup_ccb(&cur_cts.ccb_h, cts->ccb_h.path, /*priority*/1); 161752c9ce25SScott Long cur_cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 161852c9ce25SScott Long cur_cts.type = cts->type; 161952c9ce25SScott Long xpt_action((union ccb *)&cur_cts); 162052c9ce25SScott Long if ((cur_cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 162152c9ce25SScott Long return; 162252c9ce25SScott Long } 162352c9ce25SScott Long cur_scsi = &cur_cts.proto_specific.scsi; 162452c9ce25SScott Long if ((scsi->valid & CTS_SCSI_VALID_TQ) == 0) { 162552c9ce25SScott Long scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 162652c9ce25SScott Long scsi->flags |= cur_scsi->flags & CTS_SCSI_FLAGS_TAG_ENB; 162752c9ce25SScott Long } 162852c9ce25SScott Long if ((cur_scsi->valid & CTS_SCSI_VALID_TQ) == 0) 162952c9ce25SScott Long scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 163052c9ce25SScott Long } 163152c9ce25SScott Long 163252c9ce25SScott Long /* SPI specific sanity checking */ 163352c9ce25SScott Long if (cts->transport == XPORT_SPI && async_update == FALSE) { 163452c9ce25SScott Long u_int spi3caps; 163552c9ce25SScott Long struct ccb_trans_settings_spi *spi; 163652c9ce25SScott Long struct ccb_trans_settings_spi *cur_spi; 163752c9ce25SScott Long 163852c9ce25SScott Long spi = &cts->xport_specific.spi; 163952c9ce25SScott Long 164052c9ce25SScott Long cur_spi = &cur_cts.xport_specific.spi; 164152c9ce25SScott Long 164252c9ce25SScott Long /* Fill in any gaps in what the user gave us */ 164352c9ce25SScott Long if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0) 164452c9ce25SScott Long spi->sync_period = cur_spi->sync_period; 164552c9ce25SScott Long if ((cur_spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0) 164652c9ce25SScott Long spi->sync_period = 0; 164752c9ce25SScott Long if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0) 164852c9ce25SScott Long spi->sync_offset = cur_spi->sync_offset; 164952c9ce25SScott Long if ((cur_spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0) 165052c9ce25SScott Long spi->sync_offset = 0; 165152c9ce25SScott Long if ((spi->valid & CTS_SPI_VALID_PPR_OPTIONS) == 0) 165252c9ce25SScott Long spi->ppr_options = cur_spi->ppr_options; 165352c9ce25SScott Long if ((cur_spi->valid & CTS_SPI_VALID_PPR_OPTIONS) == 0) 165452c9ce25SScott Long spi->ppr_options = 0; 165552c9ce25SScott Long if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) == 0) 165652c9ce25SScott Long spi->bus_width = cur_spi->bus_width; 165752c9ce25SScott Long if ((cur_spi->valid & CTS_SPI_VALID_BUS_WIDTH) == 0) 165852c9ce25SScott Long spi->bus_width = 0; 165952c9ce25SScott Long if ((spi->valid & CTS_SPI_VALID_DISC) == 0) { 166052c9ce25SScott Long spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB; 166152c9ce25SScott Long spi->flags |= cur_spi->flags & CTS_SPI_FLAGS_DISC_ENB; 166252c9ce25SScott Long } 166352c9ce25SScott Long if ((cur_spi->valid & CTS_SPI_VALID_DISC) == 0) 166452c9ce25SScott Long spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB; 166552c9ce25SScott Long if (((device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0 166652c9ce25SScott Long && (inq_data->flags & SID_Sync) == 0 166752c9ce25SScott Long && cts->type == CTS_TYPE_CURRENT_SETTINGS) 166852c9ce25SScott Long || ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0)) { 166952c9ce25SScott Long /* Force async */ 167052c9ce25SScott Long spi->sync_period = 0; 167152c9ce25SScott Long spi->sync_offset = 0; 167252c9ce25SScott Long } 167352c9ce25SScott Long 167452c9ce25SScott Long switch (spi->bus_width) { 167552c9ce25SScott Long case MSG_EXT_WDTR_BUS_32_BIT: 167652c9ce25SScott Long if (((device->flags & CAM_DEV_INQUIRY_DATA_VALID) == 0 167752c9ce25SScott Long || (inq_data->flags & SID_WBus32) != 0 167852c9ce25SScott Long || cts->type == CTS_TYPE_USER_SETTINGS) 167952c9ce25SScott Long && (cpi.hba_inquiry & PI_WIDE_32) != 0) 168052c9ce25SScott Long break; 168152c9ce25SScott Long /* Fall Through to 16-bit */ 168252c9ce25SScott Long case MSG_EXT_WDTR_BUS_16_BIT: 168352c9ce25SScott Long if (((device->flags & CAM_DEV_INQUIRY_DATA_VALID) == 0 168452c9ce25SScott Long || (inq_data->flags & SID_WBus16) != 0 168552c9ce25SScott Long || cts->type == CTS_TYPE_USER_SETTINGS) 168652c9ce25SScott Long && (cpi.hba_inquiry & PI_WIDE_16) != 0) { 168752c9ce25SScott Long spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 168852c9ce25SScott Long break; 168952c9ce25SScott Long } 169052c9ce25SScott Long /* Fall Through to 8-bit */ 169152c9ce25SScott Long default: /* New bus width?? */ 169252c9ce25SScott Long case MSG_EXT_WDTR_BUS_8_BIT: 169352c9ce25SScott Long /* All targets can do this */ 169452c9ce25SScott Long spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 169552c9ce25SScott Long break; 169652c9ce25SScott Long } 169752c9ce25SScott Long 169852c9ce25SScott Long spi3caps = cpi.xport_specific.spi.ppr_options; 169952c9ce25SScott Long if ((device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0 170052c9ce25SScott Long && cts->type == CTS_TYPE_CURRENT_SETTINGS) 170152c9ce25SScott Long spi3caps &= inq_data->spi3data; 170252c9ce25SScott Long 170352c9ce25SScott Long if ((spi3caps & SID_SPI_CLOCK_DT) == 0) 170452c9ce25SScott Long spi->ppr_options &= ~MSG_EXT_PPR_DT_REQ; 170552c9ce25SScott Long 170652c9ce25SScott Long if ((spi3caps & SID_SPI_IUS) == 0) 170752c9ce25SScott Long spi->ppr_options &= ~MSG_EXT_PPR_IU_REQ; 170852c9ce25SScott Long 170952c9ce25SScott Long if ((spi3caps & SID_SPI_QAS) == 0) 171052c9ce25SScott Long spi->ppr_options &= ~MSG_EXT_PPR_QAS_REQ; 171152c9ce25SScott Long 171252c9ce25SScott Long /* No SPI Transfer settings are allowed unless we are wide */ 171352c9ce25SScott Long if (spi->bus_width == 0) 171452c9ce25SScott Long spi->ppr_options = 0; 171552c9ce25SScott Long 171652c9ce25SScott Long if ((spi->valid & CTS_SPI_VALID_DISC) 171752c9ce25SScott Long && ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) == 0)) { 171852c9ce25SScott Long /* 171952c9ce25SScott Long * Can't tag queue without disconnection. 172052c9ce25SScott Long */ 172152c9ce25SScott Long scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 172252c9ce25SScott Long scsi->valid |= CTS_SCSI_VALID_TQ; 172352c9ce25SScott Long } 172452c9ce25SScott Long 172552c9ce25SScott Long /* 172652c9ce25SScott Long * If we are currently performing tagged transactions to 172752c9ce25SScott Long * this device and want to change its negotiation parameters, 172852c9ce25SScott Long * go non-tagged for a bit to give the controller a chance to 172952c9ce25SScott Long * negotiate unhampered by tag messages. 173052c9ce25SScott Long */ 173152c9ce25SScott Long if (cts->type == CTS_TYPE_CURRENT_SETTINGS 173252c9ce25SScott Long && (device->inq_flags & SID_CmdQue) != 0 173352c9ce25SScott Long && (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0 173452c9ce25SScott Long && (spi->flags & (CTS_SPI_VALID_SYNC_RATE| 173552c9ce25SScott Long CTS_SPI_VALID_SYNC_OFFSET| 173652c9ce25SScott Long CTS_SPI_VALID_BUS_WIDTH)) != 0) 173752c9ce25SScott Long scsi_toggle_tags(cts->ccb_h.path); 173852c9ce25SScott Long } 173952c9ce25SScott Long 174052c9ce25SScott Long if (cts->type == CTS_TYPE_CURRENT_SETTINGS 174152c9ce25SScott Long && (scsi->valid & CTS_SCSI_VALID_TQ) != 0) { 174252c9ce25SScott Long int device_tagenb; 174352c9ce25SScott Long 174452c9ce25SScott Long /* 174552c9ce25SScott Long * If we are transitioning from tags to no-tags or 174652c9ce25SScott Long * vice-versa, we need to carefully freeze and restart 174752c9ce25SScott Long * the queue so that we don't overlap tagged and non-tagged 174852c9ce25SScott Long * commands. We also temporarily stop tags if there is 174952c9ce25SScott Long * a change in transfer negotiation settings to allow 175052c9ce25SScott Long * "tag-less" negotiation. 175152c9ce25SScott Long */ 175252c9ce25SScott Long if ((device->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 175352c9ce25SScott Long || (device->inq_flags & SID_CmdQue) != 0) 175452c9ce25SScott Long device_tagenb = TRUE; 175552c9ce25SScott Long else 175652c9ce25SScott Long device_tagenb = FALSE; 175752c9ce25SScott Long 175852c9ce25SScott Long if (((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0 175952c9ce25SScott Long && device_tagenb == FALSE) 176052c9ce25SScott Long || ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) == 0 176152c9ce25SScott Long && device_tagenb == TRUE)) { 176252c9ce25SScott Long 176352c9ce25SScott Long if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) { 176452c9ce25SScott Long /* 176552c9ce25SScott Long * Delay change to use tags until after a 176652c9ce25SScott Long * few commands have gone to this device so 176752c9ce25SScott Long * the controller has time to perform transfer 176852c9ce25SScott Long * negotiations without tagged messages getting 176952c9ce25SScott Long * in the way. 177052c9ce25SScott Long */ 177152c9ce25SScott Long device->tag_delay_count = CAM_TAG_DELAY_COUNT; 177252c9ce25SScott Long device->flags |= CAM_DEV_TAG_AFTER_COUNT; 177352c9ce25SScott Long } else { 177452c9ce25SScott Long struct ccb_relsim crs; 177552c9ce25SScott Long 177652c9ce25SScott Long xpt_freeze_devq(cts->ccb_h.path, /*count*/1); 177752c9ce25SScott Long device->inq_flags &= ~SID_CmdQue; 177852c9ce25SScott Long xpt_dev_ccbq_resize(cts->ccb_h.path, 177952c9ce25SScott Long sim->max_dev_openings); 178052c9ce25SScott Long device->flags &= ~CAM_DEV_TAG_AFTER_COUNT; 178152c9ce25SScott Long device->tag_delay_count = 0; 178252c9ce25SScott Long 178352c9ce25SScott Long xpt_setup_ccb(&crs.ccb_h, cts->ccb_h.path, 178452c9ce25SScott Long /*priority*/1); 178552c9ce25SScott Long crs.ccb_h.func_code = XPT_REL_SIMQ; 178652c9ce25SScott Long crs.release_flags = RELSIM_RELEASE_AFTER_QEMPTY; 178752c9ce25SScott Long crs.openings 178852c9ce25SScott Long = crs.release_timeout 178952c9ce25SScott Long = crs.qfrozen_cnt 179052c9ce25SScott Long = 0; 179152c9ce25SScott Long xpt_action((union ccb *)&crs); 179252c9ce25SScott Long } 179352c9ce25SScott Long } 179452c9ce25SScott Long } 179552c9ce25SScott Long if (async_update == FALSE) 179652c9ce25SScott Long (*(sim->sim_action))(sim, (union ccb *)cts); 179752c9ce25SScott Long } 179852c9ce25SScott Long 179952c9ce25SScott Long static void 180052c9ce25SScott Long scsi_toggle_tags(struct cam_path *path) 180152c9ce25SScott Long { 180252c9ce25SScott Long struct cam_ed *dev; 180352c9ce25SScott Long 180452c9ce25SScott Long /* 180552c9ce25SScott Long * Give controllers a chance to renegotiate 180652c9ce25SScott Long * before starting tag operations. We 180752c9ce25SScott Long * "toggle" tagged queuing off then on 180852c9ce25SScott Long * which causes the tag enable command delay 180952c9ce25SScott Long * counter to come into effect. 181052c9ce25SScott Long */ 181152c9ce25SScott Long dev = path->device; 181252c9ce25SScott Long if ((dev->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 181352c9ce25SScott Long || ((dev->inq_flags & SID_CmdQue) != 0 181452c9ce25SScott Long && (dev->inq_flags & (SID_Sync|SID_WBus16|SID_WBus32)) != 0)) { 181552c9ce25SScott Long struct ccb_trans_settings cts; 181652c9ce25SScott Long 181752c9ce25SScott Long xpt_setup_ccb(&cts.ccb_h, path, 1); 181852c9ce25SScott Long cts.protocol = PROTO_SCSI; 181952c9ce25SScott Long cts.protocol_version = PROTO_VERSION_UNSPECIFIED; 182052c9ce25SScott Long cts.transport = XPORT_UNSPECIFIED; 182152c9ce25SScott Long cts.transport_version = XPORT_VERSION_UNSPECIFIED; 182252c9ce25SScott Long cts.proto_specific.scsi.flags = 0; 182352c9ce25SScott Long cts.proto_specific.scsi.valid = CTS_SCSI_VALID_TQ; 182452c9ce25SScott Long scsi_set_transfer_settings(&cts, path->device, 182552c9ce25SScott Long /*async_update*/TRUE); 182652c9ce25SScott Long cts.proto_specific.scsi.flags = CTS_SCSI_FLAGS_TAG_ENB; 182752c9ce25SScott Long scsi_set_transfer_settings(&cts, path->device, 182852c9ce25SScott Long /*async_update*/TRUE); 182952c9ce25SScott Long } 183052c9ce25SScott Long } 183152c9ce25SScott Long 183252c9ce25SScott Long /* 183352c9ce25SScott Long * Handle any per-device event notifications that require action by the XPT. 183452c9ce25SScott Long */ 183552c9ce25SScott Long static void 183652c9ce25SScott Long ata_dev_async(u_int32_t async_code, struct cam_eb *bus, struct cam_et *target, 183752c9ce25SScott Long struct cam_ed *device, void *async_arg) 183852c9ce25SScott Long { 183952c9ce25SScott Long cam_status status; 184052c9ce25SScott Long struct cam_path newpath; 184152c9ce25SScott Long 184252c9ce25SScott Long /* 184352c9ce25SScott Long * We only need to handle events for real devices. 184452c9ce25SScott Long */ 184552c9ce25SScott Long if (target->target_id == CAM_TARGET_WILDCARD 184652c9ce25SScott Long || device->lun_id == CAM_LUN_WILDCARD) 184752c9ce25SScott Long return; 184852c9ce25SScott Long 184952c9ce25SScott Long /* 185052c9ce25SScott Long * We need our own path with wildcards expanded to 185152c9ce25SScott Long * handle certain types of events. 185252c9ce25SScott Long */ 185352c9ce25SScott Long if ((async_code == AC_SENT_BDR) 185452c9ce25SScott Long || (async_code == AC_BUS_RESET) 185552c9ce25SScott Long || (async_code == AC_INQ_CHANGED)) 185652c9ce25SScott Long status = xpt_compile_path(&newpath, NULL, 185752c9ce25SScott Long bus->path_id, 185852c9ce25SScott Long target->target_id, 185952c9ce25SScott Long device->lun_id); 186052c9ce25SScott Long else 186152c9ce25SScott Long status = CAM_REQ_CMP_ERR; 186252c9ce25SScott Long 186352c9ce25SScott Long if (status == CAM_REQ_CMP) { 186452c9ce25SScott Long 186552c9ce25SScott Long /* 186652c9ce25SScott Long * Allow transfer negotiation to occur in a 186752c9ce25SScott Long * tag free environment. 186852c9ce25SScott Long */ 186952c9ce25SScott Long if (async_code == AC_SENT_BDR 187052c9ce25SScott Long || async_code == AC_BUS_RESET) 187152c9ce25SScott Long scsi_toggle_tags(&newpath); 187252c9ce25SScott Long 187352c9ce25SScott Long if (async_code == AC_INQ_CHANGED) { 187452c9ce25SScott Long /* 187552c9ce25SScott Long * We've sent a start unit command, or 187652c9ce25SScott Long * something similar to a device that 187752c9ce25SScott Long * may have caused its inquiry data to 187852c9ce25SScott Long * change. So we re-scan the device to 187952c9ce25SScott Long * refresh the inquiry data for it. 188052c9ce25SScott Long */ 188152c9ce25SScott Long ata_scan_lun(newpath.periph, &newpath, 188252c9ce25SScott Long CAM_EXPECT_INQ_CHANGE, NULL); 188352c9ce25SScott Long } 188452c9ce25SScott Long xpt_release_path(&newpath); 188552c9ce25SScott Long } else if (async_code == AC_LOST_DEVICE) { 188652c9ce25SScott Long device->flags |= CAM_DEV_UNCONFIGURED; 188752c9ce25SScott Long } else if (async_code == AC_TRANSFER_NEG) { 188852c9ce25SScott Long struct ccb_trans_settings *settings; 188952c9ce25SScott Long 189052c9ce25SScott Long settings = (struct ccb_trans_settings *)async_arg; 189152c9ce25SScott Long scsi_set_transfer_settings(settings, device, 189252c9ce25SScott Long /*async_update*/TRUE); 189352c9ce25SScott Long } 189452c9ce25SScott Long } 189552c9ce25SScott Long 1896