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