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/interrupt.h> 4152c9ce25SScott Long #include <sys/sbuf.h> 4252c9ce25SScott Long 4352c9ce25SScott Long #include <sys/lock.h> 4452c9ce25SScott Long #include <sys/mutex.h> 4552c9ce25SScott Long #include <sys/sysctl.h> 4652c9ce25SScott Long 4752c9ce25SScott Long #include <cam/cam.h> 4852c9ce25SScott Long #include <cam/cam_ccb.h> 4952c9ce25SScott Long #include <cam/cam_queue.h> 5052c9ce25SScott Long #include <cam/cam_periph.h> 5152c9ce25SScott Long #include <cam/cam_sim.h> 5252c9ce25SScott Long #include <cam/cam_xpt.h> 5352c9ce25SScott Long #include <cam/cam_xpt_sim.h> 5452c9ce25SScott Long #include <cam/cam_xpt_periph.h> 5552c9ce25SScott Long #include <cam/cam_xpt_internal.h> 5652c9ce25SScott Long #include <cam/cam_debug.h> 5752c9ce25SScott Long 5852c9ce25SScott Long #include <cam/scsi/scsi_all.h> 5952c9ce25SScott Long #include <cam/scsi/scsi_message.h> 6052c9ce25SScott Long #include <cam/ata/ata_all.h> 6152c9ce25SScott Long #include <machine/stdarg.h> /* for xpt_print below */ 6252c9ce25SScott Long #include "opt_cam.h" 6352c9ce25SScott Long 6430a4094fSAlexander Motin struct ata_quirk_entry { 6552c9ce25SScott Long struct scsi_inquiry_pattern inq_pat; 6652c9ce25SScott Long u_int8_t quirks; 6730a4094fSAlexander Motin #define CAM_QUIRK_MAXTAGS 0x01 687dc3213dSAlexander Motin u_int mintags; 6952c9ce25SScott Long u_int maxtags; 7052c9ce25SScott Long }; 7152c9ce25SScott Long 7252c9ce25SScott Long static periph_init_t probe_periph_init; 7352c9ce25SScott Long 7452c9ce25SScott Long static struct periph_driver probe_driver = 7552c9ce25SScott Long { 76f09f8e3eSAlexander Motin probe_periph_init, "aprobe", 771e637ba6SAlexander Motin TAILQ_HEAD_INITIALIZER(probe_driver.units), /* generation */ 0, 781e637ba6SAlexander Motin CAM_PERIPH_DRV_EARLY 7952c9ce25SScott Long }; 8052c9ce25SScott Long 81f09f8e3eSAlexander Motin PERIPHDRIVER_DECLARE(aprobe, probe_driver); 8252c9ce25SScott Long 8352c9ce25SScott Long typedef enum { 8452c9ce25SScott Long PROBE_RESET, 8552c9ce25SScott Long PROBE_IDENTIFY, 864ef08dc5SAlexander Motin PROBE_SPINUP, 8752c9ce25SScott Long PROBE_SETMODE, 88da6808c1SAlexander Motin PROBE_SETPM, 89da6808c1SAlexander Motin PROBE_SETAPST, 90da6808c1SAlexander Motin PROBE_SETDMAAA, 918d169381SAlexander Motin PROBE_SETAN, 921e637ba6SAlexander Motin PROBE_SET_MULTI, 9352c9ce25SScott Long PROBE_INQUIRY, 9452c9ce25SScott Long PROBE_FULL_INQUIRY, 9552c9ce25SScott Long PROBE_PM_PID, 9652c9ce25SScott Long PROBE_PM_PRV, 973089bb2eSAlexander Motin PROBE_IDENTIFY_SES, 983089bb2eSAlexander Motin PROBE_IDENTIFY_SAFTE, 99a4d953c4SAlexander Motin PROBE_DONE, 10052c9ce25SScott Long PROBE_INVALID 10152c9ce25SScott Long } probe_action; 10252c9ce25SScott Long 10352c9ce25SScott Long static char *probe_action_text[] = { 10452c9ce25SScott Long "PROBE_RESET", 10552c9ce25SScott Long "PROBE_IDENTIFY", 1064ef08dc5SAlexander Motin "PROBE_SPINUP", 10752c9ce25SScott Long "PROBE_SETMODE", 108da6808c1SAlexander Motin "PROBE_SETPM", 109da6808c1SAlexander Motin "PROBE_SETAPST", 110da6808c1SAlexander Motin "PROBE_SETDMAAA", 1118d169381SAlexander Motin "PROBE_SETAN", 1121e637ba6SAlexander Motin "PROBE_SET_MULTI", 11352c9ce25SScott Long "PROBE_INQUIRY", 11452c9ce25SScott Long "PROBE_FULL_INQUIRY", 11552c9ce25SScott Long "PROBE_PM_PID", 11652c9ce25SScott Long "PROBE_PM_PRV", 1173089bb2eSAlexander Motin "PROBE_IDENTIFY_SES", 1183089bb2eSAlexander Motin "PROBE_IDENTIFY_SAFTE", 119a4d953c4SAlexander Motin "PROBE_DONE", 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; \ 127a4d953c4SAlexander Motin CAM_DEBUG((softc)->periph->path, CAM_DEBUG_PROBE, \ 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; 139a9b8edb1SAlexander Motin struct ata_params ident_data; 14052c9ce25SScott Long probe_action action; 14152c9ce25SScott Long probe_flags flags; 14252c9ce25SScott Long uint32_t pm_pid; 14352c9ce25SScott Long uint32_t pm_prv; 14483c5d981SAlexander Motin int restart; 1454ef08dc5SAlexander Motin int spinup; 14625a519a9SAlexander Motin int faults; 147da6808c1SAlexander Motin u_int caps; 14852c9ce25SScott Long struct cam_periph *periph; 14952c9ce25SScott Long } probe_softc; 15052c9ce25SScott Long 15130a4094fSAlexander Motin static struct ata_quirk_entry ata_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 }, 1597dc3213dSAlexander Motin /*quirks*/0, /*mintags*/0, /*maxtags*/0 16052c9ce25SScott Long }, 16152c9ce25SScott Long }; 16252c9ce25SScott Long 16330a4094fSAlexander Motin static const int ata_quirk_table_size = 16430a4094fSAlexander Motin sizeof(ata_quirk_table) / sizeof(*ata_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); 170b9c473b2SAlexander Motin static void proberequestdefaultnegotiation(struct cam_periph *periph); 17152c9ce25SScott Long static void probedone(struct cam_periph *periph, union ccb *done_ccb); 17252c9ce25SScott Long static void probecleanup(struct cam_periph *periph); 17330a4094fSAlexander Motin static void ata_find_quirk(struct cam_ed *device); 17452c9ce25SScott Long static void ata_scan_bus(struct cam_periph *periph, union ccb *ccb); 17552c9ce25SScott Long static void ata_scan_lun(struct cam_periph *periph, 17652c9ce25SScott Long struct cam_path *path, cam_flags flags, 17752c9ce25SScott Long union ccb *ccb); 17852c9ce25SScott Long static void xptscandone(struct cam_periph *periph, union ccb *done_ccb); 17952c9ce25SScott Long static struct cam_ed * 18052c9ce25SScott Long ata_alloc_device(struct cam_eb *bus, struct cam_et *target, 18152c9ce25SScott Long lun_id_t lun_id); 18252c9ce25SScott Long static void ata_device_transport(struct cam_path *path); 183b9c473b2SAlexander Motin static void ata_get_transfer_settings(struct ccb_trans_settings *cts); 18430a4094fSAlexander Motin static void ata_set_transfer_settings(struct ccb_trans_settings *cts, 18552c9ce25SScott Long struct cam_ed *device, 18652c9ce25SScott Long int async_update); 18752c9ce25SScott Long static void ata_dev_async(u_int32_t async_code, 18852c9ce25SScott Long struct cam_eb *bus, 18952c9ce25SScott Long struct cam_et *target, 19052c9ce25SScott Long struct cam_ed *device, 19152c9ce25SScott Long void *async_arg); 19252c9ce25SScott Long static void ata_action(union ccb *start_ccb); 19357079b17SAlexander Motin static void ata_announce_periph(struct cam_periph *periph); 19452c9ce25SScott Long 1952121d8a5SAlexander Motin static int ata_dma = 1; 1962121d8a5SAlexander Motin static int atapi_dma = 1; 1972121d8a5SAlexander Motin 1982121d8a5SAlexander Motin TUNABLE_INT("hw.ata.ata_dma", &ata_dma); 1992121d8a5SAlexander Motin TUNABLE_INT("hw.ata.atapi_dma", &atapi_dma); 2002121d8a5SAlexander Motin 20152c9ce25SScott Long static struct xpt_xport ata_xport = { 20252c9ce25SScott Long .alloc_device = ata_alloc_device, 20352c9ce25SScott Long .action = ata_action, 20452c9ce25SScott Long .async = ata_dev_async, 20557079b17SAlexander Motin .announce = ata_announce_periph, 20652c9ce25SScott Long }; 20752c9ce25SScott Long 20852c9ce25SScott Long struct xpt_xport * 20952c9ce25SScott Long ata_get_xport(void) 21052c9ce25SScott Long { 21152c9ce25SScott Long return (&ata_xport); 21252c9ce25SScott Long } 21352c9ce25SScott Long 21452c9ce25SScott Long static void 21552c9ce25SScott Long probe_periph_init() 21652c9ce25SScott Long { 21752c9ce25SScott Long } 21852c9ce25SScott Long 21952c9ce25SScott Long static cam_status 22052c9ce25SScott Long proberegister(struct cam_periph *periph, void *arg) 22152c9ce25SScott Long { 22252c9ce25SScott Long union ccb *request_ccb; /* CCB representing the probe request */ 22352c9ce25SScott Long cam_status status; 22452c9ce25SScott Long probe_softc *softc; 22552c9ce25SScott Long 22652c9ce25SScott Long request_ccb = (union ccb *)arg; 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 2334ef08dc5SAlexander Motin softc = (probe_softc *)malloc(sizeof(*softc), M_CAMXPT, M_ZERO | 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 } 251a4d953c4SAlexander Motin CAM_DEBUG(periph->path, CAM_DEBUG_PROBE, ("Probe started\n")); 25252c9ce25SScott Long probeschedule(periph); 25352c9ce25SScott Long return(CAM_REQ_CMP); 25452c9ce25SScott Long } 25552c9ce25SScott Long 25652c9ce25SScott Long static void 25752c9ce25SScott Long probeschedule(struct cam_periph *periph) 25852c9ce25SScott Long { 25952c9ce25SScott Long union ccb *ccb; 26052c9ce25SScott Long probe_softc *softc; 26152c9ce25SScott Long 26252c9ce25SScott Long softc = (probe_softc *)periph->softc; 26352c9ce25SScott Long ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs); 26452c9ce25SScott Long 26565d0fb03SAlexander Motin if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) || 2663089bb2eSAlexander Motin periph->path->device->protocol == PROTO_SATAPM || 2673089bb2eSAlexander Motin periph->path->device->protocol == PROTO_SEMB) 26852c9ce25SScott Long PROBE_SET_ACTION(softc, PROBE_RESET); 26952c9ce25SScott Long else 27052c9ce25SScott Long PROBE_SET_ACTION(softc, PROBE_IDENTIFY); 27152c9ce25SScott Long 27252c9ce25SScott Long if (ccb->crcn.flags & CAM_EXPECT_INQ_CHANGE) 27352c9ce25SScott Long softc->flags |= PROBE_NO_ANNOUNCE; 27452c9ce25SScott Long else 27552c9ce25SScott Long softc->flags &= ~PROBE_NO_ANNOUNCE; 27652c9ce25SScott Long 27783c5d981SAlexander Motin xpt_schedule(periph, CAM_PRIORITY_XPT); 27852c9ce25SScott Long } 27952c9ce25SScott Long 28052c9ce25SScott Long static void 28152c9ce25SScott Long probestart(struct cam_periph *periph, union ccb *start_ccb) 28252c9ce25SScott Long { 283c8039fc6SAlexander Motin struct ccb_trans_settings cts; 28452c9ce25SScott Long struct ccb_ataio *ataio; 28552c9ce25SScott Long struct ccb_scsiio *csio; 28652c9ce25SScott Long probe_softc *softc; 2871e637ba6SAlexander Motin struct cam_path *path; 2881e637ba6SAlexander Motin struct ata_params *ident_buf; 28952c9ce25SScott Long 29052c9ce25SScott Long CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probestart\n")); 29152c9ce25SScott Long 29252c9ce25SScott Long softc = (probe_softc *)periph->softc; 2931e637ba6SAlexander Motin path = start_ccb->ccb_h.path; 29452c9ce25SScott Long ataio = &start_ccb->ataio; 29552c9ce25SScott Long csio = &start_ccb->csio; 2961e637ba6SAlexander Motin ident_buf = &periph->path->device->ident_data; 29752c9ce25SScott Long 29883c5d981SAlexander Motin if (softc->restart) { 29983c5d981SAlexander Motin softc->restart = 0; 30083c5d981SAlexander Motin if ((path->device->flags & CAM_DEV_UNCONFIGURED) || 3013089bb2eSAlexander Motin path->device->protocol == PROTO_SATAPM || 3023089bb2eSAlexander Motin path->device->protocol == PROTO_SEMB) 30383c5d981SAlexander Motin softc->action = PROBE_RESET; 30483c5d981SAlexander Motin else 30583c5d981SAlexander Motin softc->action = PROBE_IDENTIFY; 30683c5d981SAlexander Motin } 30752c9ce25SScott Long switch (softc->action) { 30852c9ce25SScott Long case PROBE_RESET: 30952c9ce25SScott Long cam_fill_ataio(ataio, 31052c9ce25SScott Long 0, 31152c9ce25SScott Long probedone, 31252c9ce25SScott Long /*flags*/CAM_DIR_NONE, 31365d0fb03SAlexander Motin 0, 31452c9ce25SScott Long /*data_ptr*/NULL, 31552c9ce25SScott Long /*dxfer_len*/0, 31683c5d981SAlexander Motin 15 * 1000); 31752c9ce25SScott Long ata_reset_cmd(ataio); 31852c9ce25SScott Long break; 31952c9ce25SScott Long case PROBE_IDENTIFY: 32052c9ce25SScott Long cam_fill_ataio(ataio, 32152c9ce25SScott Long 1, 32252c9ce25SScott Long probedone, 32352c9ce25SScott Long /*flags*/CAM_DIR_IN, 32465d0fb03SAlexander Motin 0, 325a9b8edb1SAlexander Motin /*data_ptr*/(u_int8_t *)&softc->ident_data, 326a9b8edb1SAlexander Motin /*dxfer_len*/sizeof(softc->ident_data), 32752c9ce25SScott Long 30 * 1000); 32852c9ce25SScott Long if (periph->path->device->protocol == PROTO_ATA) 3297606b445SAlexander Motin ata_28bit_cmd(ataio, ATA_ATA_IDENTIFY, 0, 0, 0); 33052c9ce25SScott Long else 3317606b445SAlexander Motin ata_28bit_cmd(ataio, ATA_ATAPI_IDENTIFY, 0, 0, 0); 33252c9ce25SScott Long break; 3334ef08dc5SAlexander Motin case PROBE_SPINUP: 3344ef08dc5SAlexander Motin if (bootverbose) 3354ef08dc5SAlexander Motin xpt_print(path, "Spinning up device\n"); 3364ef08dc5SAlexander Motin cam_fill_ataio(ataio, 3374ef08dc5SAlexander Motin 1, 3384ef08dc5SAlexander Motin probedone, 3394ef08dc5SAlexander Motin /*flags*/CAM_DIR_NONE | CAM_HIGH_POWER, 3404ef08dc5SAlexander Motin 0, 3414ef08dc5SAlexander Motin /*data_ptr*/NULL, 3424ef08dc5SAlexander Motin /*dxfer_len*/0, 3434ef08dc5SAlexander Motin 30 * 1000); 3444ef08dc5SAlexander Motin ata_28bit_cmd(ataio, ATA_SETFEATURES, ATA_SF_PUIS_SPINUP, 0, 0); 3454ef08dc5SAlexander Motin break; 34652c9ce25SScott Long case PROBE_SETMODE: 347c8039fc6SAlexander Motin { 348c8039fc6SAlexander Motin int mode, wantmode; 349c8039fc6SAlexander Motin 350c8039fc6SAlexander Motin mode = 0; 351c8039fc6SAlexander Motin /* Fetch user modes from SIM. */ 352c8039fc6SAlexander Motin bzero(&cts, sizeof(cts)); 35383c5d981SAlexander Motin xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE); 354c8039fc6SAlexander Motin cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 355c8039fc6SAlexander Motin cts.type = CTS_TYPE_USER_SETTINGS; 356c8039fc6SAlexander Motin xpt_action((union ccb *)&cts); 357c8039fc6SAlexander Motin if (path->device->transport == XPORT_ATA) { 358c8039fc6SAlexander Motin if (cts.xport_specific.ata.valid & CTS_ATA_VALID_MODE) 359c8039fc6SAlexander Motin mode = cts.xport_specific.ata.mode; 360c8039fc6SAlexander Motin } else { 3611a6f09b8SAlexander Motin if (cts.xport_specific.sata.valid & CTS_SATA_VALID_MODE) 362c8039fc6SAlexander Motin mode = cts.xport_specific.sata.mode; 363c8039fc6SAlexander Motin } 3642121d8a5SAlexander Motin if (periph->path->device->protocol == PROTO_ATA) { 3652121d8a5SAlexander Motin if (ata_dma == 0 && (mode == 0 || mode > ATA_PIO_MAX)) 3662121d8a5SAlexander Motin mode = ATA_PIO_MAX; 3672121d8a5SAlexander Motin } else { 3682121d8a5SAlexander Motin if (atapi_dma == 0 && (mode == 0 || mode > ATA_PIO_MAX)) 3692121d8a5SAlexander Motin mode = ATA_PIO_MAX; 3702121d8a5SAlexander Motin } 371c8039fc6SAlexander Motin negotiate: 372c8039fc6SAlexander Motin /* Honor device capabilities. */ 373c8039fc6SAlexander Motin wantmode = mode = ata_max_mode(ident_buf, mode); 374c8039fc6SAlexander Motin /* Report modes to SIM. */ 375c8039fc6SAlexander Motin bzero(&cts, sizeof(cts)); 37683c5d981SAlexander Motin xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE); 377c8039fc6SAlexander Motin cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 378c8039fc6SAlexander Motin cts.type = CTS_TYPE_CURRENT_SETTINGS; 379c8039fc6SAlexander Motin if (path->device->transport == XPORT_ATA) { 380c8039fc6SAlexander Motin cts.xport_specific.ata.mode = mode; 381c8039fc6SAlexander Motin cts.xport_specific.ata.valid = CTS_ATA_VALID_MODE; 382c8039fc6SAlexander Motin } else { 383c8039fc6SAlexander Motin cts.xport_specific.sata.mode = mode; 384c8039fc6SAlexander Motin cts.xport_specific.sata.valid = CTS_SATA_VALID_MODE; 385c8039fc6SAlexander Motin } 386c8039fc6SAlexander Motin xpt_action((union ccb *)&cts); 387066f913aSAlexander Motin /* Fetch current modes from SIM. */ 388c8039fc6SAlexander Motin bzero(&cts, sizeof(cts)); 38983c5d981SAlexander Motin xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE); 390c8039fc6SAlexander Motin cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 391c8039fc6SAlexander Motin cts.type = CTS_TYPE_CURRENT_SETTINGS; 392c8039fc6SAlexander Motin xpt_action((union ccb *)&cts); 393c8039fc6SAlexander Motin if (path->device->transport == XPORT_ATA) { 394c8039fc6SAlexander Motin if (cts.xport_specific.ata.valid & CTS_ATA_VALID_MODE) 395c8039fc6SAlexander Motin mode = cts.xport_specific.ata.mode; 396c8039fc6SAlexander Motin } else { 397c8039fc6SAlexander Motin if (cts.xport_specific.ata.valid & CTS_SATA_VALID_MODE) 398c8039fc6SAlexander Motin mode = cts.xport_specific.sata.mode; 399c8039fc6SAlexander Motin } 400c8039fc6SAlexander Motin /* If SIM disagree - renegotiate. */ 401c8039fc6SAlexander Motin if (mode != wantmode) 402c8039fc6SAlexander Motin goto negotiate; 403cf2b9a5fSAlexander Motin /* Remember what transport thinks about DMA. */ 404cf2b9a5fSAlexander Motin if (mode < ATA_DMA) 405cf2b9a5fSAlexander Motin path->device->inq_flags &= ~SID_DMA; 406cf2b9a5fSAlexander Motin else 407cf2b9a5fSAlexander Motin path->device->inq_flags |= SID_DMA; 408581b2e78SAlexander Motin xpt_async(AC_GETDEV_CHANGED, path, NULL); 40952c9ce25SScott Long cam_fill_ataio(ataio, 41052c9ce25SScott Long 1, 41152c9ce25SScott Long probedone, 4125daa555dSAlexander Motin /*flags*/CAM_DIR_NONE, 4135daa555dSAlexander Motin 0, 4145daa555dSAlexander Motin /*data_ptr*/NULL, 4155daa555dSAlexander Motin /*dxfer_len*/0, 41652c9ce25SScott Long 30 * 1000); 417c8039fc6SAlexander Motin ata_28bit_cmd(ataio, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode); 41852c9ce25SScott Long break; 419c8039fc6SAlexander Motin } 420da6808c1SAlexander Motin case PROBE_SETPM: 421da6808c1SAlexander Motin cam_fill_ataio(ataio, 422da6808c1SAlexander Motin 1, 423da6808c1SAlexander Motin probedone, 424da6808c1SAlexander Motin CAM_DIR_NONE, 425da6808c1SAlexander Motin 0, 426da6808c1SAlexander Motin NULL, 427da6808c1SAlexander Motin 0, 428da6808c1SAlexander Motin 30*1000); 429da6808c1SAlexander Motin ata_28bit_cmd(ataio, ATA_SETFEATURES, 430da6808c1SAlexander Motin (softc->caps & CTS_SATA_CAPS_H_PMREQ) ? 0x10 : 0x90, 431da6808c1SAlexander Motin 0, 0x03); 432da6808c1SAlexander Motin break; 433da6808c1SAlexander Motin case PROBE_SETAPST: 434da6808c1SAlexander Motin cam_fill_ataio(ataio, 435da6808c1SAlexander Motin 1, 436da6808c1SAlexander Motin probedone, 437da6808c1SAlexander Motin CAM_DIR_NONE, 438da6808c1SAlexander Motin 0, 439da6808c1SAlexander Motin NULL, 440da6808c1SAlexander Motin 0, 441da6808c1SAlexander Motin 30*1000); 442da6808c1SAlexander Motin ata_28bit_cmd(ataio, ATA_SETFEATURES, 443da6808c1SAlexander Motin (softc->caps & CTS_SATA_CAPS_H_APST) ? 0x10 : 0x90, 444da6808c1SAlexander Motin 0, 0x07); 445da6808c1SAlexander Motin break; 446da6808c1SAlexander Motin case PROBE_SETDMAAA: 447da6808c1SAlexander Motin cam_fill_ataio(ataio, 448da6808c1SAlexander Motin 1, 449da6808c1SAlexander Motin probedone, 450da6808c1SAlexander Motin CAM_DIR_NONE, 451da6808c1SAlexander Motin 0, 452da6808c1SAlexander Motin NULL, 453da6808c1SAlexander Motin 0, 454da6808c1SAlexander Motin 30*1000); 455da6808c1SAlexander Motin ata_28bit_cmd(ataio, ATA_SETFEATURES, 456da6808c1SAlexander Motin (softc->caps & CTS_SATA_CAPS_H_DMAAA) ? 0x10 : 0x90, 457da6808c1SAlexander Motin 0, 0x02); 458da6808c1SAlexander Motin break; 4598d169381SAlexander Motin case PROBE_SETAN: 4603631c638SAlexander Motin /* Remember what transport thinks about AEN. */ 4613631c638SAlexander Motin if (softc->caps & CTS_SATA_CAPS_H_AN) 4623631c638SAlexander Motin path->device->inq_flags |= SID_AEN; 4633631c638SAlexander Motin else 4643631c638SAlexander Motin path->device->inq_flags &= ~SID_AEN; 4653631c638SAlexander Motin xpt_async(AC_GETDEV_CHANGED, path, NULL); 4668d169381SAlexander Motin cam_fill_ataio(ataio, 4678d169381SAlexander Motin 1, 4688d169381SAlexander Motin probedone, 4698d169381SAlexander Motin CAM_DIR_NONE, 4708d169381SAlexander Motin 0, 4718d169381SAlexander Motin NULL, 4728d169381SAlexander Motin 0, 4738d169381SAlexander Motin 30*1000); 4748d169381SAlexander Motin ata_28bit_cmd(ataio, ATA_SETFEATURES, 4758d169381SAlexander Motin (softc->caps & CTS_SATA_CAPS_H_AN) ? 0x10 : 0x90, 4768d169381SAlexander Motin 0, 0x05); 4778d169381SAlexander Motin break; 4781e637ba6SAlexander Motin case PROBE_SET_MULTI: 4791e637ba6SAlexander Motin { 480066f913aSAlexander Motin u_int sectors, bytecount; 4811e637ba6SAlexander Motin 482066f913aSAlexander Motin bytecount = 8192; /* SATA maximum */ 483066f913aSAlexander Motin /* Fetch user bytecount from SIM. */ 484066f913aSAlexander Motin bzero(&cts, sizeof(cts)); 48583c5d981SAlexander Motin xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE); 486066f913aSAlexander Motin cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 487066f913aSAlexander Motin cts.type = CTS_TYPE_USER_SETTINGS; 488066f913aSAlexander Motin xpt_action((union ccb *)&cts); 489066f913aSAlexander Motin if (path->device->transport == XPORT_ATA) { 490066f913aSAlexander Motin if (cts.xport_specific.ata.valid & CTS_ATA_VALID_BYTECOUNT) 491066f913aSAlexander Motin bytecount = cts.xport_specific.ata.bytecount; 492066f913aSAlexander Motin } else { 493066f913aSAlexander Motin if (cts.xport_specific.sata.valid & CTS_SATA_VALID_BYTECOUNT) 494066f913aSAlexander Motin bytecount = cts.xport_specific.sata.bytecount; 495066f913aSAlexander Motin } 496066f913aSAlexander Motin /* Honor device capabilities. */ 497066f913aSAlexander Motin sectors = max(1, min(ident_buf->sectors_intr & 0xff, 498066f913aSAlexander Motin bytecount / ata_logical_sector_size(ident_buf))); 4991e637ba6SAlexander Motin /* Report bytecount to SIM. */ 5001e637ba6SAlexander Motin bzero(&cts, sizeof(cts)); 50183c5d981SAlexander Motin xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE); 5021e637ba6SAlexander Motin cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 5031e637ba6SAlexander Motin cts.type = CTS_TYPE_CURRENT_SETTINGS; 5041e637ba6SAlexander Motin if (path->device->transport == XPORT_ATA) { 505c1bd46c2SAlexander Motin cts.xport_specific.ata.bytecount = sectors * 506c1bd46c2SAlexander Motin ata_logical_sector_size(ident_buf); 5071e637ba6SAlexander Motin cts.xport_specific.ata.valid = CTS_ATA_VALID_BYTECOUNT; 5081e637ba6SAlexander Motin } else { 509c1bd46c2SAlexander Motin cts.xport_specific.sata.bytecount = sectors * 510c1bd46c2SAlexander Motin ata_logical_sector_size(ident_buf); 5111e637ba6SAlexander Motin cts.xport_specific.sata.valid = CTS_SATA_VALID_BYTECOUNT; 5121e637ba6SAlexander Motin } 5131e637ba6SAlexander Motin xpt_action((union ccb *)&cts); 514066f913aSAlexander Motin /* Fetch current bytecount from SIM. */ 515066f913aSAlexander Motin bzero(&cts, sizeof(cts)); 51683c5d981SAlexander Motin xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE); 517066f913aSAlexander Motin cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 518066f913aSAlexander Motin cts.type = CTS_TYPE_CURRENT_SETTINGS; 519066f913aSAlexander Motin xpt_action((union ccb *)&cts); 520066f913aSAlexander Motin if (path->device->transport == XPORT_ATA) { 521066f913aSAlexander Motin if (cts.xport_specific.ata.valid & CTS_ATA_VALID_BYTECOUNT) 522066f913aSAlexander Motin bytecount = cts.xport_specific.ata.bytecount; 523066f913aSAlexander Motin } else { 524066f913aSAlexander Motin if (cts.xport_specific.sata.valid & CTS_SATA_VALID_BYTECOUNT) 525066f913aSAlexander Motin bytecount = cts.xport_specific.sata.bytecount; 526066f913aSAlexander Motin } 527066f913aSAlexander Motin sectors = bytecount / ata_logical_sector_size(ident_buf); 5281e637ba6SAlexander Motin 5291e637ba6SAlexander Motin cam_fill_ataio(ataio, 5301e637ba6SAlexander Motin 1, 5311e637ba6SAlexander Motin probedone, 5321e637ba6SAlexander Motin CAM_DIR_NONE, 5331e637ba6SAlexander Motin 0, 5341e637ba6SAlexander Motin NULL, 5351e637ba6SAlexander Motin 0, 5361e637ba6SAlexander Motin 30*1000); 5371e637ba6SAlexander Motin ata_28bit_cmd(ataio, ATA_SET_MULTI, 0, 0, sectors); 5381e637ba6SAlexander Motin break; 53952c9ce25SScott Long } 54052c9ce25SScott Long case PROBE_INQUIRY: 541066f913aSAlexander Motin { 542066f913aSAlexander Motin u_int bytecount; 543066f913aSAlexander Motin 544066f913aSAlexander Motin bytecount = 8192; /* SATA maximum */ 545066f913aSAlexander Motin /* Fetch user bytecount from SIM. */ 546066f913aSAlexander Motin bzero(&cts, sizeof(cts)); 54783c5d981SAlexander Motin xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE); 548066f913aSAlexander Motin cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 549066f913aSAlexander Motin cts.type = CTS_TYPE_USER_SETTINGS; 550066f913aSAlexander Motin xpt_action((union ccb *)&cts); 551066f913aSAlexander Motin if (path->device->transport == XPORT_ATA) { 552066f913aSAlexander Motin if (cts.xport_specific.ata.valid & CTS_ATA_VALID_BYTECOUNT) 553066f913aSAlexander Motin bytecount = cts.xport_specific.ata.bytecount; 554066f913aSAlexander Motin } else { 555066f913aSAlexander Motin if (cts.xport_specific.sata.valid & CTS_SATA_VALID_BYTECOUNT) 556066f913aSAlexander Motin bytecount = cts.xport_specific.sata.bytecount; 557066f913aSAlexander Motin } 558066f913aSAlexander Motin /* Honor device capabilities. */ 559066f913aSAlexander Motin bytecount &= ~1; 560066f913aSAlexander Motin bytecount = max(2, min(65534, bytecount)); 561066f913aSAlexander Motin if (ident_buf->satacapabilities != 0x0000 && 562066f913aSAlexander Motin ident_buf->satacapabilities != 0xffff) { 563066f913aSAlexander Motin bytecount = min(8192, bytecount); 564066f913aSAlexander Motin } 565066f913aSAlexander Motin /* Report bytecount to SIM. */ 566066f913aSAlexander Motin bzero(&cts, sizeof(cts)); 56783c5d981SAlexander Motin xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE); 568066f913aSAlexander Motin cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 569066f913aSAlexander Motin cts.type = CTS_TYPE_CURRENT_SETTINGS; 570066f913aSAlexander Motin if (path->device->transport == XPORT_ATA) { 571066f913aSAlexander Motin cts.xport_specific.ata.bytecount = bytecount; 572066f913aSAlexander Motin cts.xport_specific.ata.valid = CTS_ATA_VALID_BYTECOUNT; 573066f913aSAlexander Motin } else { 574066f913aSAlexander Motin cts.xport_specific.sata.bytecount = bytecount; 575066f913aSAlexander Motin cts.xport_specific.sata.valid = CTS_SATA_VALID_BYTECOUNT; 576066f913aSAlexander Motin } 577066f913aSAlexander Motin xpt_action((union ccb *)&cts); 578066f913aSAlexander Motin /* FALLTHROUGH */ 579066f913aSAlexander Motin } 58052c9ce25SScott Long case PROBE_FULL_INQUIRY: 58152c9ce25SScott Long { 58252c9ce25SScott Long u_int inquiry_len; 58352c9ce25SScott Long struct scsi_inquiry_data *inq_buf = 58452c9ce25SScott Long &periph->path->device->inq_data; 58552c9ce25SScott Long 58652c9ce25SScott Long if (softc->action == PROBE_INQUIRY) 58752c9ce25SScott Long inquiry_len = SHORT_INQUIRY_LENGTH; 58852c9ce25SScott Long else 58952c9ce25SScott Long inquiry_len = SID_ADDITIONAL_LENGTH(inq_buf); 59052c9ce25SScott Long /* 59152c9ce25SScott Long * Some parallel SCSI devices fail to send an 59252c9ce25SScott Long * ignore wide residue message when dealing with 59352c9ce25SScott Long * odd length inquiry requests. Round up to be 59452c9ce25SScott Long * safe. 59552c9ce25SScott Long */ 59652c9ce25SScott Long inquiry_len = roundup2(inquiry_len, 2); 59752c9ce25SScott Long scsi_inquiry(csio, 59852c9ce25SScott Long /*retries*/1, 59952c9ce25SScott Long probedone, 60052c9ce25SScott Long MSG_SIMPLE_Q_TAG, 60152c9ce25SScott Long (u_int8_t *)inq_buf, 60252c9ce25SScott Long inquiry_len, 60352c9ce25SScott Long /*evpd*/FALSE, 60452c9ce25SScott Long /*page_code*/0, 60552c9ce25SScott Long SSD_MIN_SIZE, 60652c9ce25SScott Long /*timeout*/60 * 1000); 60752c9ce25SScott Long break; 60852c9ce25SScott Long } 60952c9ce25SScott Long case PROBE_PM_PID: 61052c9ce25SScott Long cam_fill_ataio(ataio, 61152c9ce25SScott Long 1, 61252c9ce25SScott Long probedone, 61352c9ce25SScott Long /*flags*/CAM_DIR_NONE, 61465d0fb03SAlexander Motin 0, 61552c9ce25SScott Long /*data_ptr*/NULL, 61652c9ce25SScott Long /*dxfer_len*/0, 61752c9ce25SScott Long 10 * 1000); 61852c9ce25SScott Long ata_pm_read_cmd(ataio, 0, 15); 61952c9ce25SScott Long break; 62052c9ce25SScott Long case PROBE_PM_PRV: 62152c9ce25SScott Long cam_fill_ataio(ataio, 62252c9ce25SScott Long 1, 62352c9ce25SScott Long probedone, 62452c9ce25SScott Long /*flags*/CAM_DIR_NONE, 62565d0fb03SAlexander Motin 0, 62652c9ce25SScott Long /*data_ptr*/NULL, 62752c9ce25SScott Long /*dxfer_len*/0, 62852c9ce25SScott Long 10 * 1000); 62952c9ce25SScott Long ata_pm_read_cmd(ataio, 1, 15); 63052c9ce25SScott Long break; 6313089bb2eSAlexander Motin case PROBE_IDENTIFY_SES: 6323089bb2eSAlexander Motin cam_fill_ataio(ataio, 6333089bb2eSAlexander Motin 1, 6343089bb2eSAlexander Motin probedone, 6353089bb2eSAlexander Motin /*flags*/CAM_DIR_IN, 6363089bb2eSAlexander Motin 0, 6373089bb2eSAlexander Motin /*data_ptr*/(u_int8_t *)&softc->ident_data, 6383089bb2eSAlexander Motin /*dxfer_len*/sizeof(softc->ident_data), 6393089bb2eSAlexander Motin 30 * 1000); 6403089bb2eSAlexander Motin ata_28bit_cmd(ataio, ATA_SEP_ATTN, 0xEC, 0x02, 6413089bb2eSAlexander Motin sizeof(softc->ident_data) / 4); 6423089bb2eSAlexander Motin break; 6433089bb2eSAlexander Motin case PROBE_IDENTIFY_SAFTE: 6443089bb2eSAlexander Motin cam_fill_ataio(ataio, 6453089bb2eSAlexander Motin 1, 6463089bb2eSAlexander Motin probedone, 6473089bb2eSAlexander Motin /*flags*/CAM_DIR_IN, 6483089bb2eSAlexander Motin 0, 6493089bb2eSAlexander Motin /*data_ptr*/(u_int8_t *)&softc->ident_data, 6503089bb2eSAlexander Motin /*dxfer_len*/sizeof(softc->ident_data), 6513089bb2eSAlexander Motin 30 * 1000); 6523089bb2eSAlexander Motin ata_28bit_cmd(ataio, ATA_SEP_ATTN, 0xEC, 0x00, 6533089bb2eSAlexander Motin sizeof(softc->ident_data) / 4); 6543089bb2eSAlexander Motin break; 65552c9ce25SScott Long default: 656a4d953c4SAlexander Motin panic("probestart: invalid action state 0x%x\n", softc->action); 65752c9ce25SScott Long } 658cccf4220SAlexander Motin start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE; 65952c9ce25SScott Long xpt_action(start_ccb); 66052c9ce25SScott Long } 661b9c473b2SAlexander Motin 66252c9ce25SScott Long static void 66352c9ce25SScott Long proberequestdefaultnegotiation(struct cam_periph *periph) 66452c9ce25SScott Long { 66552c9ce25SScott Long struct ccb_trans_settings cts; 66652c9ce25SScott Long 66783c5d981SAlexander Motin xpt_setup_ccb(&cts.ccb_h, periph->path, CAM_PRIORITY_NONE); 66852c9ce25SScott Long cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 66952c9ce25SScott Long cts.type = CTS_TYPE_USER_SETTINGS; 67052c9ce25SScott Long xpt_action((union ccb *)&cts); 671b9c473b2SAlexander Motin if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) 67252c9ce25SScott Long return; 673b9c473b2SAlexander Motin cts.xport_specific.valid = 0; 67452c9ce25SScott Long cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 67552c9ce25SScott Long cts.type = CTS_TYPE_CURRENT_SETTINGS; 67652c9ce25SScott Long xpt_action((union ccb *)&cts); 67752c9ce25SScott Long } 67852c9ce25SScott Long 67952c9ce25SScott Long static void 68052c9ce25SScott Long probedone(struct cam_periph *periph, union ccb *done_ccb) 68152c9ce25SScott Long { 682c8039fc6SAlexander Motin struct ccb_trans_settings cts; 68352c9ce25SScott Long struct ata_params *ident_buf; 6843089bb2eSAlexander Motin struct scsi_inquiry_data *inq_buf; 68552c9ce25SScott Long probe_softc *softc; 68652c9ce25SScott Long struct cam_path *path; 68726bdaeddSAlexander Motin cam_status status; 68852c9ce25SScott Long u_int32_t priority; 689da6808c1SAlexander Motin u_int caps; 6903089bb2eSAlexander Motin int changed = 1, found = 1; 6913089bb2eSAlexander Motin static const uint8_t fake_device_id_hdr[8] = 6923089bb2eSAlexander Motin {0, SVPD_DEVICE_ID, 0, 12, 6933089bb2eSAlexander Motin SVPD_ID_CODESET_BINARY, SVPD_ID_TYPE_NAA, 0, 8}; 69452c9ce25SScott Long 69552c9ce25SScott Long CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probedone\n")); 69652c9ce25SScott Long 69752c9ce25SScott Long softc = (probe_softc *)periph->softc; 69852c9ce25SScott Long path = done_ccb->ccb_h.path; 69952c9ce25SScott Long priority = done_ccb->ccb_h.pinfo.priority; 70052c9ce25SScott Long ident_buf = &path->device->ident_data; 7013089bb2eSAlexander Motin inq_buf = &path->device->inq_data; 70252c9ce25SScott Long 7031e637ba6SAlexander Motin if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 7040191d9b3SAlexander Motin if (cam_periph_error(done_ccb, 7050191d9b3SAlexander Motin 0, softc->restart ? (SF_NO_RECOVERY | SF_NO_RETRY) : 0, 706cccf4220SAlexander Motin NULL) == ERESTART) { 707cccf4220SAlexander Motin out: 708cccf4220SAlexander Motin /* Drop freeze taken due to CAM_DEV_QFREEZE flag set. */ 709cccf4220SAlexander Motin cam_release_devq(path, 0, 0, 0, FALSE); 7101e637ba6SAlexander Motin return; 711cccf4220SAlexander Motin } 71225a519a9SAlexander Motin if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 7131e637ba6SAlexander Motin /* Don't wedge the queue */ 714cccf4220SAlexander Motin xpt_release_devq(path, /*count*/1, /*run_queue*/TRUE); 7151e637ba6SAlexander Motin } 71626bdaeddSAlexander Motin status = done_ccb->ccb_h.status & CAM_STATUS_MASK; 71725a519a9SAlexander Motin if (softc->restart) { 71825a519a9SAlexander Motin softc->faults++; 71925a519a9SAlexander Motin if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == 72025a519a9SAlexander Motin CAM_CMD_TIMEOUT) 72125a519a9SAlexander Motin softc->faults += 4; 72225a519a9SAlexander Motin if (softc->faults < 10) 72325a519a9SAlexander Motin goto done; 72425a519a9SAlexander Motin else 72525a519a9SAlexander Motin softc->restart = 0; 72626bdaeddSAlexander Motin 7271e637ba6SAlexander Motin /* Old PIO2 devices may not support mode setting. */ 72826bdaeddSAlexander Motin } else if (softc->action == PROBE_SETMODE && 72926bdaeddSAlexander Motin status == CAM_ATA_STATUS_ERROR && 7301e637ba6SAlexander Motin ata_max_pmode(ident_buf) <= ATA_PIO2 && 73126bdaeddSAlexander Motin (ident_buf->capabilities1 & ATA_SUPPORT_IORDY) == 0) { 7321e637ba6SAlexander Motin goto noerror; 73326bdaeddSAlexander Motin 73426bdaeddSAlexander Motin /* 73526bdaeddSAlexander Motin * Some old WD SATA disks report supported and enabled 73626bdaeddSAlexander Motin * device-initiated interface power management, but return 73726bdaeddSAlexander Motin * ABORT on attempt to disable it. 73826bdaeddSAlexander Motin */ 73926bdaeddSAlexander Motin } else if (softc->action == PROBE_SETPM && 74026bdaeddSAlexander Motin status == CAM_ATA_STATUS_ERROR) { 74126bdaeddSAlexander Motin goto noerror; 742025e2c12SAlexander Motin 743025e2c12SAlexander Motin /* 744025e2c12SAlexander Motin * Some HP SATA disks report supported DMA Auto-Activation, 745025e2c12SAlexander Motin * but return ABORT on attempt to enable it. 746025e2c12SAlexander Motin */ 747025e2c12SAlexander Motin } else if (softc->action == PROBE_SETDMAAA && 748025e2c12SAlexander Motin status == CAM_ATA_STATUS_ERROR) { 749025e2c12SAlexander Motin goto noerror; 7503089bb2eSAlexander Motin 7513089bb2eSAlexander Motin /* 75209dff101SAlexander Motin * Some Samsung SSDs report supported Asynchronous Notification, 75309dff101SAlexander Motin * but return ABORT on attempt to enable it. 75409dff101SAlexander Motin */ 75509dff101SAlexander Motin } else if (softc->action == PROBE_SETAN && 75609dff101SAlexander Motin status == CAM_ATA_STATUS_ERROR) { 75709dff101SAlexander Motin goto noerror; 75809dff101SAlexander Motin 75909dff101SAlexander Motin /* 7603089bb2eSAlexander Motin * SES and SAF-TE SEPs have different IDENTIFY commands, 7613089bb2eSAlexander Motin * but SATA specification doesn't tell how to identify them. 7623089bb2eSAlexander Motin * Until better way found, just try another if first fail. 7633089bb2eSAlexander Motin */ 7643089bb2eSAlexander Motin } else if (softc->action == PROBE_IDENTIFY_SES && 7653089bb2eSAlexander Motin status == CAM_ATA_STATUS_ERROR) { 7663089bb2eSAlexander Motin PROBE_SET_ACTION(softc, PROBE_IDENTIFY_SAFTE); 7673089bb2eSAlexander Motin xpt_release_ccb(done_ccb); 7683089bb2eSAlexander Motin xpt_schedule(periph, priority); 769cccf4220SAlexander Motin goto out; 77026bdaeddSAlexander Motin } 77126bdaeddSAlexander Motin 7721e637ba6SAlexander Motin /* 7731e637ba6SAlexander Motin * If we get to this point, we got an error status back 7741e637ba6SAlexander Motin * from the inquiry and the error status doesn't require 7751e637ba6SAlexander Motin * automatically retrying the command. Therefore, the 7761e637ba6SAlexander Motin * inquiry failed. If we had inquiry information before 7771e637ba6SAlexander Motin * for this device, but this latest inquiry command failed, 7781e637ba6SAlexander Motin * the device has probably gone away. If this device isn't 7791e637ba6SAlexander Motin * already marked unconfigured, notify the peripheral 7801e637ba6SAlexander Motin * drivers that this device is no more. 7811e637ba6SAlexander Motin */ 78225a519a9SAlexander Motin device_fail: if ((path->device->flags & CAM_DEV_UNCONFIGURED) == 0) 7831e637ba6SAlexander Motin xpt_async(AC_LOST_DEVICE, path, NULL); 784a4d953c4SAlexander Motin PROBE_SET_ACTION(softc, PROBE_INVALID); 7851e637ba6SAlexander Motin found = 0; 7861e637ba6SAlexander Motin goto done; 7871e637ba6SAlexander Motin } 7881e637ba6SAlexander Motin noerror: 789a9b8edb1SAlexander Motin if (softc->restart) 790a9b8edb1SAlexander Motin goto done; 79152c9ce25SScott Long switch (softc->action) { 79252c9ce25SScott Long case PROBE_RESET: 7931e637ba6SAlexander Motin { 79452c9ce25SScott Long int sign = (done_ccb->ataio.res.lba_high << 8) + 79552c9ce25SScott Long done_ccb->ataio.res.lba_mid; 796a4d953c4SAlexander Motin CAM_DEBUG(path, CAM_DEBUG_PROBE, 797a4d953c4SAlexander Motin ("SIGNATURE: %04x\n", sign)); 79852c9ce25SScott Long if (sign == 0x0000 && 79952c9ce25SScott Long done_ccb->ccb_h.target_id != 15) { 80052c9ce25SScott Long path->device->protocol = PROTO_ATA; 80152c9ce25SScott Long PROBE_SET_ACTION(softc, PROBE_IDENTIFY); 80252c9ce25SScott Long } else if (sign == 0x9669 && 80352c9ce25SScott Long done_ccb->ccb_h.target_id == 15) { 80452c9ce25SScott Long /* Report SIM that PM is present. */ 80552c9ce25SScott Long bzero(&cts, sizeof(cts)); 80683c5d981SAlexander Motin xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE); 80752c9ce25SScott Long cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 80852c9ce25SScott Long cts.type = CTS_TYPE_CURRENT_SETTINGS; 80952c9ce25SScott Long cts.xport_specific.sata.pm_present = 1; 81052c9ce25SScott Long cts.xport_specific.sata.valid = CTS_SATA_VALID_PM; 81152c9ce25SScott Long xpt_action((union ccb *)&cts); 81252c9ce25SScott Long path->device->protocol = PROTO_SATAPM; 81352c9ce25SScott Long PROBE_SET_ACTION(softc, PROBE_PM_PID); 8143089bb2eSAlexander Motin } else if (sign == 0xc33c && 8153089bb2eSAlexander Motin done_ccb->ccb_h.target_id != 15) { 8163089bb2eSAlexander Motin path->device->protocol = PROTO_SEMB; 8173089bb2eSAlexander Motin PROBE_SET_ACTION(softc, PROBE_IDENTIFY_SES); 81852c9ce25SScott Long } else if (sign == 0xeb14 && 81952c9ce25SScott Long done_ccb->ccb_h.target_id != 15) { 82052c9ce25SScott Long path->device->protocol = PROTO_SCSI; 82152c9ce25SScott Long PROBE_SET_ACTION(softc, PROBE_IDENTIFY); 82252c9ce25SScott Long } else { 82352c9ce25SScott Long if (done_ccb->ccb_h.target_id != 15) { 82452c9ce25SScott Long xpt_print(path, 82552c9ce25SScott Long "Unexpected signature 0x%04x\n", sign); 82652c9ce25SScott Long } 82765d0fb03SAlexander Motin goto device_fail; 82852c9ce25SScott Long } 82952c9ce25SScott Long xpt_release_ccb(done_ccb); 83052c9ce25SScott Long xpt_schedule(periph, priority); 831cccf4220SAlexander Motin goto out; 83252c9ce25SScott Long } 83352c9ce25SScott Long case PROBE_IDENTIFY: 83452c9ce25SScott Long { 835699f853bSAlexander Motin struct ccb_pathinq cpi; 83652c9ce25SScott Long int16_t *ptr; 83752c9ce25SScott Long 838a9b8edb1SAlexander Motin ident_buf = &softc->ident_data; 83952c9ce25SScott Long for (ptr = (int16_t *)ident_buf; 84052c9ce25SScott Long ptr < (int16_t *)ident_buf + sizeof(struct ata_params)/2; ptr++) { 84152c9ce25SScott Long *ptr = le16toh(*ptr); 84252c9ce25SScott Long } 84352c9ce25SScott Long if (strncmp(ident_buf->model, "FX", 2) && 84452c9ce25SScott Long strncmp(ident_buf->model, "NEC", 3) && 84552c9ce25SScott Long strncmp(ident_buf->model, "Pioneer", 7) && 84652c9ce25SScott Long strncmp(ident_buf->model, "SHARP", 5)) { 84752c9ce25SScott Long ata_bswap(ident_buf->model, sizeof(ident_buf->model)); 84852c9ce25SScott Long ata_bswap(ident_buf->revision, sizeof(ident_buf->revision)); 84952c9ce25SScott Long ata_bswap(ident_buf->serial, sizeof(ident_buf->serial)); 85052c9ce25SScott Long } 85152c9ce25SScott Long ata_btrim(ident_buf->model, sizeof(ident_buf->model)); 85252c9ce25SScott Long ata_bpack(ident_buf->model, ident_buf->model, sizeof(ident_buf->model)); 85352c9ce25SScott Long ata_btrim(ident_buf->revision, sizeof(ident_buf->revision)); 85452c9ce25SScott Long ata_bpack(ident_buf->revision, ident_buf->revision, sizeof(ident_buf->revision)); 85552c9ce25SScott Long ata_btrim(ident_buf->serial, sizeof(ident_buf->serial)); 85652c9ce25SScott Long ata_bpack(ident_buf->serial, ident_buf->serial, sizeof(ident_buf->serial)); 8574ef08dc5SAlexander Motin /* Device may need spin-up before IDENTIFY become valid. */ 8581254b680SAlexander Motin if ((ident_buf->specconf == 0x37c8 || 8591254b680SAlexander Motin ident_buf->specconf == 0x738c) && 8601254b680SAlexander Motin ((ident_buf->config & ATA_RESP_INCOMPLETE) || 8614ef08dc5SAlexander Motin softc->spinup == 0)) { 8624ef08dc5SAlexander Motin PROBE_SET_ACTION(softc, PROBE_SPINUP); 8634ef08dc5SAlexander Motin xpt_release_ccb(done_ccb); 8644ef08dc5SAlexander Motin xpt_schedule(periph, priority); 865cccf4220SAlexander Motin goto out; 8664ef08dc5SAlexander Motin } 867a9b8edb1SAlexander Motin ident_buf = &path->device->ident_data; 86852c9ce25SScott Long if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) == 0) { 86952c9ce25SScott Long /* Check that it is the same device. */ 870a9b8edb1SAlexander Motin if (bcmp(softc->ident_data.model, ident_buf->model, 871a9b8edb1SAlexander Motin sizeof(ident_buf->model)) || 872a9b8edb1SAlexander Motin bcmp(softc->ident_data.revision, ident_buf->revision, 873a9b8edb1SAlexander Motin sizeof(ident_buf->revision)) || 874a9b8edb1SAlexander Motin bcmp(softc->ident_data.serial, ident_buf->serial, 875a9b8edb1SAlexander Motin sizeof(ident_buf->serial))) { 87652c9ce25SScott Long /* Device changed. */ 87752c9ce25SScott Long xpt_async(AC_LOST_DEVICE, path, NULL); 8781e637ba6SAlexander Motin } else { 879a9b8edb1SAlexander Motin bcopy(&softc->ident_data, ident_buf, sizeof(struct ata_params)); 8802eb4a8dcSAlexander Motin changed = 0; 8812eb4a8dcSAlexander Motin } 8822eb4a8dcSAlexander Motin } 8832eb4a8dcSAlexander Motin if (changed) { 8842eb4a8dcSAlexander Motin bcopy(&softc->ident_data, ident_buf, sizeof(struct ata_params)); 88552c9ce25SScott Long /* Clean up from previous instance of this device */ 88652c9ce25SScott Long if (path->device->serial_num != NULL) { 88752c9ce25SScott Long free(path->device->serial_num, M_CAMXPT); 88852c9ce25SScott Long path->device->serial_num = NULL; 88952c9ce25SScott Long path->device->serial_num_len = 0; 89052c9ce25SScott Long } 8913089bb2eSAlexander Motin if (path->device->device_id != NULL) { 8923089bb2eSAlexander Motin free(path->device->device_id, M_CAMXPT); 8933089bb2eSAlexander Motin path->device->device_id = NULL; 8943089bb2eSAlexander Motin path->device->device_id_len = 0; 8953089bb2eSAlexander Motin } 89652c9ce25SScott Long path->device->serial_num = 89752c9ce25SScott Long (u_int8_t *)malloc((sizeof(ident_buf->serial) + 1), 89852c9ce25SScott Long M_CAMXPT, M_NOWAIT); 89952c9ce25SScott Long if (path->device->serial_num != NULL) { 90052c9ce25SScott Long bcopy(ident_buf->serial, 90152c9ce25SScott Long path->device->serial_num, 90252c9ce25SScott Long sizeof(ident_buf->serial)); 90352c9ce25SScott Long path->device->serial_num[sizeof(ident_buf->serial)] 90452c9ce25SScott Long = '\0'; 90552c9ce25SScott Long path->device->serial_num_len = 90652c9ce25SScott Long strlen(path->device->serial_num); 90752c9ce25SScott Long } 9083089bb2eSAlexander Motin if (ident_buf->enabled.extension & 9093089bb2eSAlexander Motin ATA_SUPPORT_64BITWWN) { 9103089bb2eSAlexander Motin path->device->device_id = 9113089bb2eSAlexander Motin malloc(16, M_CAMXPT, M_NOWAIT); 9123089bb2eSAlexander Motin if (path->device->device_id != NULL) { 9133089bb2eSAlexander Motin path->device->device_id_len = 16; 9143089bb2eSAlexander Motin bcopy(&fake_device_id_hdr, 9153089bb2eSAlexander Motin path->device->device_id, 8); 9163089bb2eSAlexander Motin bcopy(ident_buf->wwn, 9173089bb2eSAlexander Motin path->device->device_id + 8, 8); 9183089bb2eSAlexander Motin } 9193089bb2eSAlexander Motin } 92052c9ce25SScott Long 9214b997c49SAlexander Motin path->device->flags |= CAM_DEV_IDENTIFY_DATA_VALID; 922581b2e78SAlexander Motin xpt_async(AC_GETDEV_CHANGED, path, NULL); 9231e637ba6SAlexander Motin } 92430a4094fSAlexander Motin if (ident_buf->satacapabilities & ATA_SUPPORT_NCQ) { 9257dc3213dSAlexander Motin path->device->mintags = 2; 9267dc3213dSAlexander Motin path->device->maxtags = 92730a4094fSAlexander Motin ATA_QUEUE_LEN(ident_buf->queue) + 1; 92830a4094fSAlexander Motin } 92930a4094fSAlexander Motin ata_find_quirk(path->device); 930507e5811SAlexander Motin if (path->device->mintags != 0 && 931507e5811SAlexander Motin path->bus->sim->max_tagged_dev_openings != 0) { 932699f853bSAlexander Motin /* Check if the SIM does not want queued commands. */ 933699f853bSAlexander Motin bzero(&cpi, sizeof(cpi)); 934699f853bSAlexander Motin xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NONE); 935699f853bSAlexander Motin cpi.ccb_h.func_code = XPT_PATH_INQ; 936699f853bSAlexander Motin xpt_action((union ccb *)&cpi); 937699f853bSAlexander Motin if (cpi.ccb_h.status == CAM_REQ_CMP && 938699f853bSAlexander Motin (cpi.hba_inquiry & PI_TAG_ABLE)) { 939c8039fc6SAlexander Motin /* Report SIM which tags are allowed. */ 940c8039fc6SAlexander Motin bzero(&cts, sizeof(cts)); 94183c5d981SAlexander Motin xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE); 942c8039fc6SAlexander Motin cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 943c8039fc6SAlexander Motin cts.type = CTS_TYPE_CURRENT_SETTINGS; 944c8039fc6SAlexander Motin cts.xport_specific.sata.tags = path->device->maxtags; 945c8039fc6SAlexander Motin cts.xport_specific.sata.valid = CTS_SATA_VALID_TAGS; 946c8039fc6SAlexander Motin xpt_action((union ccb *)&cts); 94730a4094fSAlexander Motin } 948699f853bSAlexander Motin } 949bc1bf6e8SAlexander Motin ata_device_transport(path); 950b9c473b2SAlexander Motin if (changed) 951b9c473b2SAlexander Motin proberequestdefaultnegotiation(periph); 95252c9ce25SScott Long PROBE_SET_ACTION(softc, PROBE_SETMODE); 95352c9ce25SScott Long xpt_release_ccb(done_ccb); 95452c9ce25SScott Long xpt_schedule(periph, priority); 955cccf4220SAlexander Motin goto out; 95652c9ce25SScott Long } 9574ef08dc5SAlexander Motin case PROBE_SPINUP: 9584ef08dc5SAlexander Motin if (bootverbose) 9594ef08dc5SAlexander Motin xpt_print(path, "Spin-up done\n"); 9604ef08dc5SAlexander Motin softc->spinup = 1; 9614ef08dc5SAlexander Motin PROBE_SET_ACTION(softc, PROBE_IDENTIFY); 9624ef08dc5SAlexander Motin xpt_release_ccb(done_ccb); 9634ef08dc5SAlexander Motin xpt_schedule(periph, priority); 964cccf4220SAlexander Motin goto out; 96552c9ce25SScott Long case PROBE_SETMODE: 966da6808c1SAlexander Motin /* Set supported bits. */ 967da6808c1SAlexander Motin bzero(&cts, sizeof(cts)); 968da6808c1SAlexander Motin xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE); 969da6808c1SAlexander Motin cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 970da6808c1SAlexander Motin cts.type = CTS_TYPE_CURRENT_SETTINGS; 971da6808c1SAlexander Motin xpt_action((union ccb *)&cts); 9722e1eb332SMarius Strobl if (path->device->transport == XPORT_SATA && 9732e1eb332SMarius Strobl cts.xport_specific.sata.valid & CTS_SATA_VALID_CAPS) 974da6808c1SAlexander Motin caps = cts.xport_specific.sata.caps & CTS_SATA_CAPS_H; 9752e1eb332SMarius Strobl else if (path->device->transport == XPORT_ATA && 9762e1eb332SMarius Strobl cts.xport_specific.ata.valid & CTS_ATA_VALID_CAPS) 9772e1eb332SMarius Strobl caps = cts.xport_specific.ata.caps & CTS_ATA_CAPS_H; 978da6808c1SAlexander Motin else 979da6808c1SAlexander Motin caps = 0; 9802e1eb332SMarius Strobl if (path->device->transport == XPORT_SATA && 9812e1eb332SMarius Strobl ident_buf->satacapabilities != 0xffff) { 982da6808c1SAlexander Motin if (ident_buf->satacapabilities & ATA_SUPPORT_IFPWRMNGTRCV) 983da6808c1SAlexander Motin caps |= CTS_SATA_CAPS_D_PMREQ; 984da6808c1SAlexander Motin if (ident_buf->satacapabilities & ATA_SUPPORT_HAPST) 985da6808c1SAlexander Motin caps |= CTS_SATA_CAPS_D_APST; 986da6808c1SAlexander Motin } 987da6808c1SAlexander Motin /* Mask unwanted bits. */ 988da6808c1SAlexander Motin bzero(&cts, sizeof(cts)); 989da6808c1SAlexander Motin xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE); 990da6808c1SAlexander Motin cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 991da6808c1SAlexander Motin cts.type = CTS_TYPE_USER_SETTINGS; 992da6808c1SAlexander Motin xpt_action((union ccb *)&cts); 9932e1eb332SMarius Strobl if (path->device->transport == XPORT_SATA && 9942e1eb332SMarius Strobl cts.xport_specific.sata.valid & CTS_SATA_VALID_CAPS) 995da6808c1SAlexander Motin caps &= cts.xport_specific.sata.caps; 9962e1eb332SMarius Strobl else if (path->device->transport == XPORT_ATA && 9972e1eb332SMarius Strobl cts.xport_specific.ata.valid & CTS_ATA_VALID_CAPS) 9982e1eb332SMarius Strobl caps &= cts.xport_specific.ata.caps; 999c2b82f3eSAlexander Motin else 1000c2b82f3eSAlexander Motin caps = 0; 10012e1eb332SMarius Strobl /* 10022e1eb332SMarius Strobl * Remember what transport thinks about 48-bit DMA. If 10032e1eb332SMarius Strobl * capability information is not provided or transport is 10042e1eb332SMarius Strobl * SATA, we take support for granted. 10052e1eb332SMarius Strobl */ 10062e1eb332SMarius Strobl if (!(path->device->inq_flags & SID_DMA) || 10072e1eb332SMarius Strobl (path->device->transport == XPORT_ATA && 10082e1eb332SMarius Strobl (cts.xport_specific.ata.valid & CTS_ATA_VALID_CAPS) && 10092e1eb332SMarius Strobl !(caps & CTS_ATA_CAPS_H_DMA48))) 10102e1eb332SMarius Strobl path->device->inq_flags &= ~SID_DMA48; 10112e1eb332SMarius Strobl else 10122e1eb332SMarius Strobl path->device->inq_flags |= SID_DMA48; 1013da6808c1SAlexander Motin /* Store result to SIM. */ 1014da6808c1SAlexander Motin bzero(&cts, sizeof(cts)); 1015da6808c1SAlexander Motin xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE); 1016da6808c1SAlexander Motin cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 1017da6808c1SAlexander Motin cts.type = CTS_TYPE_CURRENT_SETTINGS; 10182e1eb332SMarius Strobl if (path->device->transport == XPORT_SATA) { 1019da6808c1SAlexander Motin cts.xport_specific.sata.caps = caps; 1020da6808c1SAlexander Motin cts.xport_specific.sata.valid = CTS_SATA_VALID_CAPS; 10212e1eb332SMarius Strobl } else { 10222e1eb332SMarius Strobl cts.xport_specific.ata.caps = caps; 10232e1eb332SMarius Strobl cts.xport_specific.ata.valid = CTS_ATA_VALID_CAPS; 10242e1eb332SMarius Strobl } 1025da6808c1SAlexander Motin xpt_action((union ccb *)&cts); 1026da6808c1SAlexander Motin softc->caps = caps; 10272e1eb332SMarius Strobl if (path->device->transport != XPORT_SATA) 10282e1eb332SMarius Strobl goto notsata; 1029958e4a69SAlexander Motin if ((ident_buf->satasupport & ATA_SUPPORT_IFPWRMNGT) && 1030958e4a69SAlexander Motin (!(softc->caps & CTS_SATA_CAPS_H_PMREQ)) != 1031958e4a69SAlexander Motin (!(ident_buf->sataenabled & ATA_SUPPORT_IFPWRMNGT))) { 1032da6808c1SAlexander Motin PROBE_SET_ACTION(softc, PROBE_SETPM); 1033da6808c1SAlexander Motin xpt_release_ccb(done_ccb); 1034da6808c1SAlexander Motin xpt_schedule(periph, priority); 1035cccf4220SAlexander Motin goto out; 1036da6808c1SAlexander Motin } 1037da6808c1SAlexander Motin /* FALLTHROUGH */ 1038da6808c1SAlexander Motin case PROBE_SETPM: 1039da6808c1SAlexander Motin if (ident_buf->satacapabilities != 0xffff && 1040958e4a69SAlexander Motin (ident_buf->satacapabilities & ATA_SUPPORT_DAPST) && 1041958e4a69SAlexander Motin (!(softc->caps & CTS_SATA_CAPS_H_APST)) != 1042958e4a69SAlexander Motin (!(ident_buf->sataenabled & ATA_ENABLED_DAPST))) { 1043da6808c1SAlexander Motin PROBE_SET_ACTION(softc, PROBE_SETAPST); 1044da6808c1SAlexander Motin xpt_release_ccb(done_ccb); 1045da6808c1SAlexander Motin xpt_schedule(periph, priority); 1046cccf4220SAlexander Motin goto out; 1047da6808c1SAlexander Motin } 1048da6808c1SAlexander Motin /* FALLTHROUGH */ 1049da6808c1SAlexander Motin case PROBE_SETAPST: 1050958e4a69SAlexander Motin if ((ident_buf->satasupport & ATA_SUPPORT_AUTOACTIVATE) && 1051958e4a69SAlexander Motin (!(softc->caps & CTS_SATA_CAPS_H_DMAAA)) != 1052958e4a69SAlexander Motin (!(ident_buf->sataenabled & ATA_SUPPORT_AUTOACTIVATE))) { 1053da6808c1SAlexander Motin PROBE_SET_ACTION(softc, PROBE_SETDMAAA); 1054da6808c1SAlexander Motin xpt_release_ccb(done_ccb); 1055da6808c1SAlexander Motin xpt_schedule(periph, priority); 1056cccf4220SAlexander Motin goto out; 1057da6808c1SAlexander Motin } 1058da6808c1SAlexander Motin /* FALLTHROUGH */ 1059da6808c1SAlexander Motin case PROBE_SETDMAAA: 10608d169381SAlexander Motin if ((ident_buf->satasupport & ATA_SUPPORT_ASYNCNOTIF) && 10618d169381SAlexander Motin (!(softc->caps & CTS_SATA_CAPS_H_AN)) != 10628d169381SAlexander Motin (!(ident_buf->sataenabled & ATA_SUPPORT_ASYNCNOTIF))) { 10638d169381SAlexander Motin PROBE_SET_ACTION(softc, PROBE_SETAN); 10648d169381SAlexander Motin xpt_release_ccb(done_ccb); 10658d169381SAlexander Motin xpt_schedule(periph, priority); 1066cccf4220SAlexander Motin goto out; 10678d169381SAlexander Motin } 10688d169381SAlexander Motin /* FALLTHROUGH */ 10698d169381SAlexander Motin case PROBE_SETAN: 1070da6808c1SAlexander Motin notsata: 10711e637ba6SAlexander Motin if (path->device->protocol == PROTO_ATA) { 10721e637ba6SAlexander Motin PROBE_SET_ACTION(softc, PROBE_SET_MULTI); 10731e637ba6SAlexander Motin } else { 10741e637ba6SAlexander Motin PROBE_SET_ACTION(softc, PROBE_INQUIRY); 10751e637ba6SAlexander Motin } 10761e637ba6SAlexander Motin xpt_release_ccb(done_ccb); 10771e637ba6SAlexander Motin xpt_schedule(periph, priority); 1078cccf4220SAlexander Motin goto out; 10791e637ba6SAlexander Motin case PROBE_SET_MULTI: 10801e637ba6SAlexander Motin if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) { 108152c9ce25SScott Long path->device->flags &= ~CAM_DEV_UNCONFIGURED; 1082f98d7a47SAlexander Motin xpt_acquire_device(path->device); 108352c9ce25SScott Long done_ccb->ccb_h.func_code = XPT_GDEV_TYPE; 108452c9ce25SScott Long xpt_action(done_ccb); 1085cccf4220SAlexander Motin xpt_async(AC_FOUND_DEVICE, path, done_ccb); 10861e637ba6SAlexander Motin } 1087a4d953c4SAlexander Motin PROBE_SET_ACTION(softc, PROBE_DONE); 108852c9ce25SScott Long break; 108952c9ce25SScott Long case PROBE_INQUIRY: 109052c9ce25SScott Long case PROBE_FULL_INQUIRY: 109152c9ce25SScott Long { 10921e637ba6SAlexander Motin u_int8_t periph_qual, len; 109352c9ce25SScott Long 109452c9ce25SScott Long path->device->flags |= CAM_DEV_INQUIRY_DATA_VALID; 109552c9ce25SScott Long 109652c9ce25SScott Long periph_qual = SID_QUAL(inq_buf); 109752c9ce25SScott Long 10981e637ba6SAlexander Motin if (periph_qual != SID_QUAL_LU_CONNECTED) 10991e637ba6SAlexander Motin break; 110052c9ce25SScott Long 110152c9ce25SScott Long /* 110252c9ce25SScott Long * We conservatively request only 110352c9ce25SScott Long * SHORT_INQUIRY_LEN bytes of inquiry 110452c9ce25SScott Long * information during our first try 110552c9ce25SScott Long * at sending an INQUIRY. If the device 110652c9ce25SScott Long * has more information to give, 110752c9ce25SScott Long * perform a second request specifying 110852c9ce25SScott Long * the amount of information the device 110952c9ce25SScott Long * is willing to give. 111052c9ce25SScott Long */ 111152c9ce25SScott Long len = inq_buf->additional_length 11121e637ba6SAlexander Motin + offsetof(struct scsi_inquiry_data, additional_length) + 1; 111352c9ce25SScott Long if (softc->action == PROBE_INQUIRY 111452c9ce25SScott Long && len > SHORT_INQUIRY_LENGTH) { 111552c9ce25SScott Long PROBE_SET_ACTION(softc, PROBE_FULL_INQUIRY); 111652c9ce25SScott Long xpt_release_ccb(done_ccb); 111752c9ce25SScott Long xpt_schedule(periph, priority); 1118cccf4220SAlexander Motin goto out; 111952c9ce25SScott Long } 112052c9ce25SScott Long 11214b997c49SAlexander Motin ata_device_transport(path); 11221e637ba6SAlexander Motin if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) { 112352c9ce25SScott Long path->device->flags &= ~CAM_DEV_UNCONFIGURED; 1124f98d7a47SAlexander Motin xpt_acquire_device(path->device); 112552c9ce25SScott Long done_ccb->ccb_h.func_code = XPT_GDEV_TYPE; 112652c9ce25SScott Long xpt_action(done_ccb); 1127cccf4220SAlexander Motin xpt_async(AC_FOUND_DEVICE, path, done_ccb); 11281e637ba6SAlexander Motin } 1129a4d953c4SAlexander Motin PROBE_SET_ACTION(softc, PROBE_DONE); 113052c9ce25SScott Long break; 113152c9ce25SScott Long } 113252c9ce25SScott Long case PROBE_PM_PID: 11334b997c49SAlexander Motin if ((path->device->flags & CAM_DEV_IDENTIFY_DATA_VALID) == 0) 113452c9ce25SScott Long bzero(ident_buf, sizeof(*ident_buf)); 113552c9ce25SScott Long softc->pm_pid = (done_ccb->ataio.res.lba_high << 24) + 113652c9ce25SScott Long (done_ccb->ataio.res.lba_mid << 16) + 113752c9ce25SScott Long (done_ccb->ataio.res.lba_low << 8) + 113852c9ce25SScott Long done_ccb->ataio.res.sector_count; 113965d0fb03SAlexander Motin ((uint32_t *)ident_buf)[0] = softc->pm_pid; 114052c9ce25SScott Long snprintf(ident_buf->model, sizeof(ident_buf->model), 114152c9ce25SScott Long "Port Multiplier %08x", softc->pm_pid); 114252c9ce25SScott Long PROBE_SET_ACTION(softc, PROBE_PM_PRV); 114352c9ce25SScott Long xpt_release_ccb(done_ccb); 114452c9ce25SScott Long xpt_schedule(periph, priority); 1145cccf4220SAlexander Motin goto out; 114652c9ce25SScott Long case PROBE_PM_PRV: 114752c9ce25SScott Long softc->pm_prv = (done_ccb->ataio.res.lba_high << 24) + 114852c9ce25SScott Long (done_ccb->ataio.res.lba_mid << 16) + 114952c9ce25SScott Long (done_ccb->ataio.res.lba_low << 8) + 115052c9ce25SScott Long done_ccb->ataio.res.sector_count; 115165d0fb03SAlexander Motin ((uint32_t *)ident_buf)[1] = softc->pm_prv; 115252c9ce25SScott Long snprintf(ident_buf->revision, sizeof(ident_buf->revision), 115352c9ce25SScott Long "%04x", softc->pm_prv); 11544b997c49SAlexander Motin path->device->flags |= CAM_DEV_IDENTIFY_DATA_VALID; 1155bc1bf6e8SAlexander Motin ata_device_transport(path); 1156bc1bf6e8SAlexander Motin if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) 1157bc1bf6e8SAlexander Motin proberequestdefaultnegotiation(periph); 1158da6808c1SAlexander Motin /* Set supported bits. */ 1159da6808c1SAlexander Motin bzero(&cts, sizeof(cts)); 1160da6808c1SAlexander Motin xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE); 1161da6808c1SAlexander Motin cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 1162da6808c1SAlexander Motin cts.type = CTS_TYPE_CURRENT_SETTINGS; 1163da6808c1SAlexander Motin xpt_action((union ccb *)&cts); 1164da6808c1SAlexander Motin if (cts.xport_specific.sata.valid & CTS_SATA_VALID_CAPS) 1165da6808c1SAlexander Motin caps = cts.xport_specific.sata.caps & CTS_SATA_CAPS_H; 1166da6808c1SAlexander Motin else 1167da6808c1SAlexander Motin caps = 0; 1168da6808c1SAlexander Motin /* All PMPs must support PM requests. */ 1169da6808c1SAlexander Motin caps |= CTS_SATA_CAPS_D_PMREQ; 1170da6808c1SAlexander Motin /* Mask unwanted bits. */ 1171da6808c1SAlexander Motin bzero(&cts, sizeof(cts)); 1172da6808c1SAlexander Motin xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE); 1173da6808c1SAlexander Motin cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 1174da6808c1SAlexander Motin cts.type = CTS_TYPE_USER_SETTINGS; 1175da6808c1SAlexander Motin xpt_action((union ccb *)&cts); 1176da6808c1SAlexander Motin if (cts.xport_specific.sata.valid & CTS_SATA_VALID_CAPS) 1177da6808c1SAlexander Motin caps &= cts.xport_specific.sata.caps; 1178c2b82f3eSAlexander Motin else 1179c2b82f3eSAlexander Motin caps = 0; 11802e1eb332SMarius Strobl /* Remember what transport thinks about AEN. */ 11812e1eb332SMarius Strobl if (caps & CTS_SATA_CAPS_H_AN) 11822e1eb332SMarius Strobl path->device->inq_flags |= SID_AEN; 11832e1eb332SMarius Strobl else 11842e1eb332SMarius Strobl path->device->inq_flags &= ~SID_AEN; 1185da6808c1SAlexander Motin /* Store result to SIM. */ 1186da6808c1SAlexander Motin bzero(&cts, sizeof(cts)); 1187da6808c1SAlexander Motin xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE); 1188da6808c1SAlexander Motin cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 1189da6808c1SAlexander Motin cts.type = CTS_TYPE_CURRENT_SETTINGS; 1190da6808c1SAlexander Motin cts.xport_specific.sata.caps = caps; 1191da6808c1SAlexander Motin cts.xport_specific.sata.valid = CTS_SATA_VALID_CAPS; 1192da6808c1SAlexander Motin xpt_action((union ccb *)&cts); 1193da6808c1SAlexander Motin softc->caps = caps; 11943631c638SAlexander Motin xpt_async(AC_GETDEV_CHANGED, path, NULL); 119565d0fb03SAlexander Motin if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) { 119652c9ce25SScott Long path->device->flags &= ~CAM_DEV_UNCONFIGURED; 1197f98d7a47SAlexander Motin xpt_acquire_device(path->device); 119852c9ce25SScott Long done_ccb->ccb_h.func_code = XPT_GDEV_TYPE; 119952c9ce25SScott Long xpt_action(done_ccb); 1200cccf4220SAlexander Motin xpt_async(AC_FOUND_DEVICE, path, done_ccb); 120165d0fb03SAlexander Motin } else { 120265d0fb03SAlexander Motin done_ccb->ccb_h.func_code = XPT_GDEV_TYPE; 120365d0fb03SAlexander Motin xpt_action(done_ccb); 1204cccf4220SAlexander Motin xpt_async(AC_SCSI_AEN, path, done_ccb); 120552c9ce25SScott Long } 1206a4d953c4SAlexander Motin PROBE_SET_ACTION(softc, PROBE_DONE); 120752c9ce25SScott Long break; 12083089bb2eSAlexander Motin case PROBE_IDENTIFY_SES: 12093089bb2eSAlexander Motin case PROBE_IDENTIFY_SAFTE: 12103089bb2eSAlexander Motin if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) == 0) { 12113089bb2eSAlexander Motin /* Check that it is the same device. */ 12123089bb2eSAlexander Motin if (bcmp(&softc->ident_data, ident_buf, 53)) { 12133089bb2eSAlexander Motin /* Device changed. */ 12143089bb2eSAlexander Motin xpt_async(AC_LOST_DEVICE, path, NULL); 12153089bb2eSAlexander Motin } else { 12163089bb2eSAlexander Motin bcopy(&softc->ident_data, ident_buf, sizeof(struct ata_params)); 12173089bb2eSAlexander Motin changed = 0; 12183089bb2eSAlexander Motin } 12193089bb2eSAlexander Motin } 12203089bb2eSAlexander Motin if (changed) { 12213089bb2eSAlexander Motin bcopy(&softc->ident_data, ident_buf, sizeof(struct ata_params)); 12223089bb2eSAlexander Motin /* Clean up from previous instance of this device */ 12233089bb2eSAlexander Motin if (path->device->device_id != NULL) { 12243089bb2eSAlexander Motin free(path->device->device_id, M_CAMXPT); 12253089bb2eSAlexander Motin path->device->device_id = NULL; 12263089bb2eSAlexander Motin path->device->device_id_len = 0; 12273089bb2eSAlexander Motin } 12283089bb2eSAlexander Motin path->device->device_id = 12293089bb2eSAlexander Motin malloc(16, M_CAMXPT, M_NOWAIT); 12303089bb2eSAlexander Motin if (path->device->device_id != NULL) { 12313089bb2eSAlexander Motin path->device->device_id_len = 16; 12323089bb2eSAlexander Motin bcopy(&fake_device_id_hdr, 12333089bb2eSAlexander Motin path->device->device_id, 8); 12343089bb2eSAlexander Motin bcopy(((uint8_t*)ident_buf) + 2, 12353089bb2eSAlexander Motin path->device->device_id + 8, 8); 12363089bb2eSAlexander Motin } 12373089bb2eSAlexander Motin 12383089bb2eSAlexander Motin path->device->flags |= CAM_DEV_IDENTIFY_DATA_VALID; 12393089bb2eSAlexander Motin } 1240bc1bf6e8SAlexander Motin ata_device_transport(path); 1241bc1bf6e8SAlexander Motin if (changed) 1242bc1bf6e8SAlexander Motin proberequestdefaultnegotiation(periph); 12433089bb2eSAlexander Motin 12443089bb2eSAlexander Motin if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) { 12453089bb2eSAlexander Motin path->device->flags &= ~CAM_DEV_UNCONFIGURED; 12463089bb2eSAlexander Motin xpt_acquire_device(path->device); 12473089bb2eSAlexander Motin done_ccb->ccb_h.func_code = XPT_GDEV_TYPE; 12483089bb2eSAlexander Motin xpt_action(done_ccb); 1249cccf4220SAlexander Motin xpt_async(AC_FOUND_DEVICE, path, done_ccb); 12503089bb2eSAlexander Motin } 1251a4d953c4SAlexander Motin PROBE_SET_ACTION(softc, PROBE_DONE); 12523089bb2eSAlexander Motin break; 125352c9ce25SScott Long default: 1254a4d953c4SAlexander Motin panic("probedone: invalid action state 0x%x\n", softc->action); 125552c9ce25SScott Long } 12561e637ba6SAlexander Motin done: 125783c5d981SAlexander Motin if (softc->restart) { 125883c5d981SAlexander Motin softc->restart = 0; 12591e637ba6SAlexander Motin xpt_release_ccb(done_ccb); 126083c5d981SAlexander Motin probeschedule(periph); 1261cccf4220SAlexander Motin goto out; 126283c5d981SAlexander Motin } 126383c5d981SAlexander Motin xpt_release_ccb(done_ccb); 1264a4d953c4SAlexander Motin CAM_DEBUG(periph->path, CAM_DEBUG_PROBE, ("Probe completed\n")); 126583c5d981SAlexander Motin while ((done_ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs))) { 126683c5d981SAlexander Motin TAILQ_REMOVE(&softc->request_ccbs, 126783c5d981SAlexander Motin &done_ccb->ccb_h, periph_links.tqe); 126883c5d981SAlexander Motin done_ccb->ccb_h.status = found ? CAM_REQ_CMP : CAM_REQ_CMP_ERR; 126952c9ce25SScott Long xpt_done(done_ccb); 127083c5d981SAlexander Motin } 1271cccf4220SAlexander Motin /* Drop freeze taken due to CAM_DEV_QFREEZE flag set. */ 1272cccf4220SAlexander Motin cam_release_devq(path, 0, 0, 0, FALSE); 12732e3f592bSAlexander Motin cam_periph_invalidate(periph); 127452c9ce25SScott Long cam_periph_release_locked(periph); 127552c9ce25SScott Long } 127652c9ce25SScott Long 127752c9ce25SScott Long static void 127852c9ce25SScott Long probecleanup(struct cam_periph *periph) 127952c9ce25SScott Long { 128052c9ce25SScott Long free(periph->softc, M_CAMXPT); 128152c9ce25SScott Long } 128252c9ce25SScott Long 128352c9ce25SScott Long static void 128430a4094fSAlexander Motin ata_find_quirk(struct cam_ed *device) 128552c9ce25SScott Long { 128630a4094fSAlexander Motin struct ata_quirk_entry *quirk; 128752c9ce25SScott Long caddr_t match; 128852c9ce25SScott Long 128930a4094fSAlexander Motin match = cam_quirkmatch((caddr_t)&device->ident_data, 129030a4094fSAlexander Motin (caddr_t)ata_quirk_table, 129130a4094fSAlexander Motin ata_quirk_table_size, 129230a4094fSAlexander Motin sizeof(*ata_quirk_table), ata_identify_match); 129352c9ce25SScott Long 129452c9ce25SScott Long if (match == NULL) 129552c9ce25SScott Long panic("xpt_find_quirk: device didn't match wildcard entry!!"); 129652c9ce25SScott Long 129730a4094fSAlexander Motin quirk = (struct ata_quirk_entry *)match; 129852c9ce25SScott Long device->quirk = quirk; 12997dc3213dSAlexander Motin if (quirk->quirks & CAM_QUIRK_MAXTAGS) { 13007dc3213dSAlexander Motin device->mintags = quirk->mintags; 13017dc3213dSAlexander Motin device->maxtags = quirk->maxtags; 13027dc3213dSAlexander Motin } 130352c9ce25SScott Long } 130452c9ce25SScott Long 130552c9ce25SScott Long typedef struct { 130652c9ce25SScott Long union ccb *request_ccb; 130752c9ce25SScott Long struct ccb_pathinq *cpi; 130852c9ce25SScott Long int counter; 130952c9ce25SScott Long } ata_scan_bus_info; 131052c9ce25SScott Long 131152c9ce25SScott Long /* 131252c9ce25SScott Long * To start a scan, request_ccb is an XPT_SCAN_BUS ccb. 131352c9ce25SScott Long * As the scan progresses, xpt_scan_bus is used as the 131452c9ce25SScott Long * callback on completion function. 131552c9ce25SScott Long */ 131652c9ce25SScott Long static void 131752c9ce25SScott Long ata_scan_bus(struct cam_periph *periph, union ccb *request_ccb) 131852c9ce25SScott Long { 131952c9ce25SScott Long struct cam_path *path; 132052c9ce25SScott Long ata_scan_bus_info *scan_info; 132183c5d981SAlexander Motin union ccb *work_ccb, *reset_ccb; 132252c9ce25SScott Long cam_status status; 132352c9ce25SScott Long 132452c9ce25SScott Long CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_TRACE, 132552c9ce25SScott Long ("xpt_scan_bus\n")); 132652c9ce25SScott Long switch (request_ccb->ccb_h.func_code) { 132752c9ce25SScott Long case XPT_SCAN_BUS: 13280e85f214SMatt Jacob case XPT_SCAN_TGT: 132952c9ce25SScott Long /* Find out the characteristics of the bus */ 133052c9ce25SScott Long work_ccb = xpt_alloc_ccb_nowait(); 133152c9ce25SScott Long if (work_ccb == NULL) { 133252c9ce25SScott Long request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 133352c9ce25SScott Long xpt_done(request_ccb); 133452c9ce25SScott Long return; 133552c9ce25SScott Long } 133652c9ce25SScott Long xpt_setup_ccb(&work_ccb->ccb_h, request_ccb->ccb_h.path, 133752c9ce25SScott Long request_ccb->ccb_h.pinfo.priority); 133852c9ce25SScott Long work_ccb->ccb_h.func_code = XPT_PATH_INQ; 133952c9ce25SScott Long xpt_action(work_ccb); 134052c9ce25SScott Long if (work_ccb->ccb_h.status != CAM_REQ_CMP) { 134152c9ce25SScott Long request_ccb->ccb_h.status = work_ccb->ccb_h.status; 134252c9ce25SScott Long xpt_free_ccb(work_ccb); 134352c9ce25SScott Long xpt_done(request_ccb); 134452c9ce25SScott Long return; 134552c9ce25SScott Long } 134652c9ce25SScott Long 134783c5d981SAlexander Motin /* We may need to reset bus first, if we haven't done it yet. */ 134883c5d981SAlexander Motin if ((work_ccb->cpi.hba_inquiry & 134983c5d981SAlexander Motin (PI_WIDE_32|PI_WIDE_16|PI_SDTR_ABLE)) && 135083c5d981SAlexander Motin !(work_ccb->cpi.hba_misc & PIM_NOBUSRESET) && 135183c5d981SAlexander Motin !timevalisset(&request_ccb->ccb_h.path->bus->last_reset)) { 135283c5d981SAlexander Motin reset_ccb = xpt_alloc_ccb_nowait(); 1353f1893540SAlexander Motin if (reset_ccb == NULL) { 1354f1893540SAlexander Motin request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 1355f1893540SAlexander Motin xpt_free_ccb(work_ccb); 1356f1893540SAlexander Motin xpt_done(request_ccb); 1357f1893540SAlexander Motin return; 1358f1893540SAlexander Motin } 135983c5d981SAlexander Motin xpt_setup_ccb(&reset_ccb->ccb_h, request_ccb->ccb_h.path, 136083c5d981SAlexander Motin CAM_PRIORITY_NONE); 136183c5d981SAlexander Motin reset_ccb->ccb_h.func_code = XPT_RESET_BUS; 136283c5d981SAlexander Motin xpt_action(reset_ccb); 136383c5d981SAlexander Motin if (reset_ccb->ccb_h.status != CAM_REQ_CMP) { 136483c5d981SAlexander Motin request_ccb->ccb_h.status = reset_ccb->ccb_h.status; 136583c5d981SAlexander Motin xpt_free_ccb(reset_ccb); 136683c5d981SAlexander Motin xpt_free_ccb(work_ccb); 136783c5d981SAlexander Motin xpt_done(request_ccb); 136883c5d981SAlexander Motin return; 136983c5d981SAlexander Motin } 137083c5d981SAlexander Motin xpt_free_ccb(reset_ccb); 137183c5d981SAlexander Motin } 137283c5d981SAlexander Motin 137352c9ce25SScott Long /* Save some state for use while we probe for devices */ 137452c9ce25SScott Long scan_info = (ata_scan_bus_info *) 137552c9ce25SScott Long malloc(sizeof(ata_scan_bus_info), M_CAMXPT, M_NOWAIT); 137652c9ce25SScott Long if (scan_info == NULL) { 137752c9ce25SScott Long request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 1378f1893540SAlexander Motin xpt_free_ccb(work_ccb); 137952c9ce25SScott Long xpt_done(request_ccb); 138052c9ce25SScott Long return; 138152c9ce25SScott Long } 138252c9ce25SScott Long scan_info->request_ccb = request_ccb; 138352c9ce25SScott Long scan_info->cpi = &work_ccb->cpi; 138452c9ce25SScott Long /* If PM supported, probe it first. */ 138552c9ce25SScott Long if (scan_info->cpi->hba_inquiry & PI_SATAPM) 13860025eb12SAlexander Motin scan_info->counter = scan_info->cpi->max_target; 13870025eb12SAlexander Motin else 13880025eb12SAlexander Motin scan_info->counter = 0; 138952c9ce25SScott Long 139052c9ce25SScott Long work_ccb = xpt_alloc_ccb_nowait(); 139152c9ce25SScott Long if (work_ccb == NULL) { 139252c9ce25SScott Long free(scan_info, M_CAMXPT); 139352c9ce25SScott Long request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 139452c9ce25SScott Long xpt_done(request_ccb); 139552c9ce25SScott Long break; 139652c9ce25SScott Long } 139752c9ce25SScott Long goto scan_next; 139852c9ce25SScott Long case XPT_SCAN_LUN: 139952c9ce25SScott Long work_ccb = request_ccb; 140052c9ce25SScott Long /* Reuse the same CCB to query if a device was really found */ 140152c9ce25SScott Long scan_info = (ata_scan_bus_info *)work_ccb->ccb_h.ppriv_ptr0; 140265d0fb03SAlexander Motin /* If there is PMP... */ 14030025eb12SAlexander Motin if ((scan_info->cpi->hba_inquiry & PI_SATAPM) && 14040025eb12SAlexander Motin (scan_info->counter == scan_info->cpi->max_target)) { 140583c5d981SAlexander Motin if (work_ccb->ccb_h.status == CAM_REQ_CMP) { 140665d0fb03SAlexander Motin /* everything else will be probed by it */ 1407e2a75189SAlexander Motin /* Free the current request path- we're done with it. */ 1408e2a75189SAlexander Motin xpt_free_path(work_ccb->ccb_h.path); 14090025eb12SAlexander Motin goto done; 141052c9ce25SScott Long } else { 141152c9ce25SScott Long struct ccb_trans_settings cts; 141252c9ce25SScott Long 141352c9ce25SScott Long /* Report SIM that PM is absent. */ 141452c9ce25SScott Long bzero(&cts, sizeof(cts)); 141552c9ce25SScott Long xpt_setup_ccb(&cts.ccb_h, 1416e2a75189SAlexander Motin work_ccb->ccb_h.path, CAM_PRIORITY_NONE); 141752c9ce25SScott Long cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 141852c9ce25SScott Long cts.type = CTS_TYPE_CURRENT_SETTINGS; 14193ccda2f3SAlexander Motin cts.xport_specific.sata.pm_present = 0; 142052c9ce25SScott Long cts.xport_specific.sata.valid = CTS_SATA_VALID_PM; 142152c9ce25SScott Long xpt_action((union ccb *)&cts); 142252c9ce25SScott Long } 142352c9ce25SScott Long } 1424e2a75189SAlexander Motin /* Free the current request path- we're done with it. */ 1425e2a75189SAlexander Motin xpt_free_path(work_ccb->ccb_h.path); 14260025eb12SAlexander Motin if (scan_info->counter == 14270025eb12SAlexander Motin ((scan_info->cpi->hba_inquiry & PI_SATAPM) ? 14280025eb12SAlexander Motin 0 : scan_info->cpi->max_target)) { 14290025eb12SAlexander Motin done: 143052c9ce25SScott Long xpt_free_ccb(work_ccb); 143152c9ce25SScott Long xpt_free_ccb((union ccb *)scan_info->cpi); 143252c9ce25SScott Long request_ccb = scan_info->request_ccb; 143352c9ce25SScott Long free(scan_info, M_CAMXPT); 143452c9ce25SScott Long request_ccb->ccb_h.status = CAM_REQ_CMP; 143552c9ce25SScott Long xpt_done(request_ccb); 143652c9ce25SScott Long break; 143752c9ce25SScott Long } 14380025eb12SAlexander Motin /* Take next device. Wrap from max (PMP) to 0. */ 14390025eb12SAlexander Motin scan_info->counter = (scan_info->counter + 1 ) % 14400025eb12SAlexander Motin (scan_info->cpi->max_target + 1); 144152c9ce25SScott Long scan_next: 1442e5dfa058SAlexander Motin status = xpt_create_path(&path, NULL, 144352c9ce25SScott Long scan_info->request_ccb->ccb_h.path_id, 144452c9ce25SScott Long scan_info->counter, 0); 144552c9ce25SScott Long if (status != CAM_REQ_CMP) { 144652c9ce25SScott Long printf("xpt_scan_bus: xpt_create_path failed" 144752c9ce25SScott Long " with status %#x, bus scan halted\n", 144852c9ce25SScott Long status); 144952c9ce25SScott Long xpt_free_ccb(work_ccb); 145052c9ce25SScott Long xpt_free_ccb((union ccb *)scan_info->cpi); 145152c9ce25SScott Long request_ccb = scan_info->request_ccb; 145252c9ce25SScott Long free(scan_info, M_CAMXPT); 145352c9ce25SScott Long request_ccb->ccb_h.status = status; 145452c9ce25SScott Long xpt_done(request_ccb); 145552c9ce25SScott Long break; 145652c9ce25SScott Long } 145752c9ce25SScott Long xpt_setup_ccb(&work_ccb->ccb_h, path, 145852c9ce25SScott Long scan_info->request_ccb->ccb_h.pinfo.priority); 145952c9ce25SScott Long work_ccb->ccb_h.func_code = XPT_SCAN_LUN; 146052c9ce25SScott Long work_ccb->ccb_h.cbfcnp = ata_scan_bus; 146152c9ce25SScott Long work_ccb->ccb_h.ppriv_ptr0 = scan_info; 146252c9ce25SScott Long work_ccb->crcn.flags = scan_info->request_ccb->crcn.flags; 146352c9ce25SScott Long xpt_action(work_ccb); 146452c9ce25SScott Long break; 146552c9ce25SScott Long default: 146652c9ce25SScott Long break; 146752c9ce25SScott Long } 146852c9ce25SScott Long } 146952c9ce25SScott Long 147052c9ce25SScott Long static void 147152c9ce25SScott Long ata_scan_lun(struct cam_periph *periph, struct cam_path *path, 147252c9ce25SScott Long cam_flags flags, union ccb *request_ccb) 147352c9ce25SScott Long { 147452c9ce25SScott Long struct ccb_pathinq cpi; 147552c9ce25SScott Long cam_status status; 147652c9ce25SScott Long struct cam_path *new_path; 147752c9ce25SScott Long struct cam_periph *old_periph; 147852c9ce25SScott Long 147983c5d981SAlexander Motin CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_scan_lun\n")); 148052c9ce25SScott Long 148183c5d981SAlexander Motin xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NONE); 148252c9ce25SScott Long cpi.ccb_h.func_code = XPT_PATH_INQ; 148352c9ce25SScott Long xpt_action((union ccb *)&cpi); 148452c9ce25SScott Long 148552c9ce25SScott Long if (cpi.ccb_h.status != CAM_REQ_CMP) { 148652c9ce25SScott Long if (request_ccb != NULL) { 148752c9ce25SScott Long request_ccb->ccb_h.status = cpi.ccb_h.status; 148852c9ce25SScott Long xpt_done(request_ccb); 148952c9ce25SScott Long } 149052c9ce25SScott Long return; 149152c9ce25SScott Long } 149252c9ce25SScott Long 149352c9ce25SScott Long if (request_ccb == NULL) { 149432aa80a6SAlexander Motin request_ccb = xpt_alloc_ccb_nowait(); 149552c9ce25SScott Long if (request_ccb == NULL) { 149652c9ce25SScott Long xpt_print(path, "xpt_scan_lun: can't allocate CCB, " 149752c9ce25SScott Long "can't continue\n"); 149852c9ce25SScott Long return; 149952c9ce25SScott Long } 1500e5dfa058SAlexander Motin status = xpt_create_path(&new_path, NULL, 150152c9ce25SScott Long path->bus->path_id, 150252c9ce25SScott Long path->target->target_id, 150352c9ce25SScott Long path->device->lun_id); 150452c9ce25SScott Long if (status != CAM_REQ_CMP) { 150532aa80a6SAlexander Motin xpt_print(path, "xpt_scan_lun: can't create path, " 150652c9ce25SScott Long "can't continue\n"); 150732aa80a6SAlexander Motin xpt_free_ccb(request_ccb); 150852c9ce25SScott Long return; 150952c9ce25SScott Long } 151083c5d981SAlexander Motin xpt_setup_ccb(&request_ccb->ccb_h, new_path, CAM_PRIORITY_XPT); 151152c9ce25SScott Long request_ccb->ccb_h.cbfcnp = xptscandone; 151252c9ce25SScott Long request_ccb->ccb_h.func_code = XPT_SCAN_LUN; 151352c9ce25SScott Long request_ccb->crcn.flags = flags; 151452c9ce25SScott Long } 151552c9ce25SScott Long 1516f09f8e3eSAlexander Motin if ((old_periph = cam_periph_find(path, "aprobe")) != NULL) { 15172e3f592bSAlexander Motin if ((old_periph->flags & CAM_PERIPH_INVALID) == 0) { 151852c9ce25SScott Long probe_softc *softc; 151952c9ce25SScott Long 152052c9ce25SScott Long softc = (probe_softc *)old_periph->softc; 15212e3f592bSAlexander Motin TAILQ_INSERT_TAIL(&softc->request_ccbs, 15222e3f592bSAlexander Motin &request_ccb->ccb_h, periph_links.tqe); 152383c5d981SAlexander Motin softc->restart = 1; 152452c9ce25SScott Long } else { 15252e3f592bSAlexander Motin request_ccb->ccb_h.status = CAM_REQ_CMP_ERR; 15262e3f592bSAlexander Motin xpt_done(request_ccb); 15272e3f592bSAlexander Motin } 15282e3f592bSAlexander Motin } else { 152952c9ce25SScott Long status = cam_periph_alloc(proberegister, NULL, probecleanup, 1530f09f8e3eSAlexander Motin probestart, "aprobe", 153152c9ce25SScott Long CAM_PERIPH_BIO, 153252c9ce25SScott Long request_ccb->ccb_h.path, NULL, 0, 153352c9ce25SScott Long request_ccb); 153452c9ce25SScott Long 153552c9ce25SScott Long if (status != CAM_REQ_CMP) { 153652c9ce25SScott Long xpt_print(path, "xpt_scan_lun: cam_alloc_periph " 153752c9ce25SScott Long "returned an error, can't continue probe\n"); 153852c9ce25SScott Long request_ccb->ccb_h.status = status; 153952c9ce25SScott Long xpt_done(request_ccb); 154052c9ce25SScott Long } 154152c9ce25SScott Long } 154252c9ce25SScott Long } 154352c9ce25SScott Long 154452c9ce25SScott Long static void 154552c9ce25SScott Long xptscandone(struct cam_periph *periph, union ccb *done_ccb) 154652c9ce25SScott Long { 154732aa80a6SAlexander Motin 154832aa80a6SAlexander Motin xpt_free_path(done_ccb->ccb_h.path); 154932aa80a6SAlexander Motin xpt_free_ccb(done_ccb); 155052c9ce25SScott Long } 155152c9ce25SScott Long 155252c9ce25SScott Long static struct cam_ed * 155352c9ce25SScott Long ata_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id) 155452c9ce25SScott Long { 155552c9ce25SScott Long struct cam_path path; 155630a4094fSAlexander Motin struct ata_quirk_entry *quirk; 155752c9ce25SScott Long struct cam_ed *device; 155852c9ce25SScott Long 155952c9ce25SScott Long device = xpt_alloc_device(bus, target, lun_id); 156052c9ce25SScott Long if (device == NULL) 156152c9ce25SScott Long return (NULL); 156252c9ce25SScott Long 156352c9ce25SScott Long /* 156452c9ce25SScott Long * Take the default quirk entry until we have inquiry 156552c9ce25SScott Long * data and can determine a better quirk to use. 156652c9ce25SScott Long */ 156730a4094fSAlexander Motin quirk = &ata_quirk_table[ata_quirk_table_size - 1]; 156852c9ce25SScott Long device->quirk = (void *)quirk; 156930a4094fSAlexander Motin device->mintags = 0; 157030a4094fSAlexander Motin device->maxtags = 0; 157152c9ce25SScott Long bzero(&device->inq_data, sizeof(device->inq_data)); 157252c9ce25SScott Long device->inq_flags = 0; 157352c9ce25SScott Long device->queue_flags = 0; 157452c9ce25SScott Long device->serial_num = NULL; 157552c9ce25SScott Long device->serial_num_len = 0; 157652c9ce25SScott Long 157752c9ce25SScott Long /* 157852c9ce25SScott Long * XXX should be limited by number of CCBs this bus can 157952c9ce25SScott Long * do. 158052c9ce25SScott Long */ 158152c9ce25SScott Long bus->sim->max_ccbs += device->ccbq.devq_openings; 158252c9ce25SScott Long if (lun_id != CAM_LUN_WILDCARD) { 158352c9ce25SScott Long xpt_compile_path(&path, 158452c9ce25SScott Long NULL, 158552c9ce25SScott Long bus->path_id, 158652c9ce25SScott Long target->target_id, 158752c9ce25SScott Long lun_id); 158852c9ce25SScott Long ata_device_transport(&path); 158952c9ce25SScott Long xpt_release_path(&path); 159052c9ce25SScott Long } 159152c9ce25SScott Long 159252c9ce25SScott Long return (device); 159352c9ce25SScott Long } 159452c9ce25SScott Long 159552c9ce25SScott Long static void 159652c9ce25SScott Long ata_device_transport(struct cam_path *path) 159752c9ce25SScott Long { 159852c9ce25SScott Long struct ccb_pathinq cpi; 15994b997c49SAlexander Motin struct ccb_trans_settings cts; 16004b997c49SAlexander Motin struct scsi_inquiry_data *inq_buf = NULL; 16014b997c49SAlexander Motin struct ata_params *ident_buf = NULL; 160252c9ce25SScott Long 160352c9ce25SScott Long /* Get transport information from the SIM */ 160483c5d981SAlexander Motin xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NONE); 160552c9ce25SScott Long cpi.ccb_h.func_code = XPT_PATH_INQ; 160652c9ce25SScott Long xpt_action((union ccb *)&cpi); 160752c9ce25SScott Long 160852c9ce25SScott Long path->device->transport = cpi.transport; 16094b997c49SAlexander Motin if ((path->device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0) 16104b997c49SAlexander Motin inq_buf = &path->device->inq_data; 16114b997c49SAlexander Motin if ((path->device->flags & CAM_DEV_IDENTIFY_DATA_VALID) != 0) 16124b997c49SAlexander Motin ident_buf = &path->device->ident_data; 16134b997c49SAlexander Motin if (path->device->protocol == PROTO_ATA) { 16144b997c49SAlexander Motin path->device->protocol_version = ident_buf ? 16154b997c49SAlexander Motin ata_version(ident_buf->version_major) : cpi.protocol_version; 16164b997c49SAlexander Motin } else if (path->device->protocol == PROTO_SCSI) { 16174b997c49SAlexander Motin path->device->protocol_version = inq_buf ? 16184b997c49SAlexander Motin SID_ANSI_REV(inq_buf) : cpi.protocol_version; 161952c9ce25SScott Long } 16204b997c49SAlexander Motin path->device->transport_version = ident_buf ? 16214b997c49SAlexander Motin ata_version(ident_buf->version_major) : cpi.transport_version; 162252c9ce25SScott Long 162352c9ce25SScott Long /* Tell the controller what we think */ 162483c5d981SAlexander Motin xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE); 162552c9ce25SScott Long cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 162652c9ce25SScott Long cts.type = CTS_TYPE_CURRENT_SETTINGS; 162752c9ce25SScott Long cts.transport = path->device->transport; 162852c9ce25SScott Long cts.transport_version = path->device->transport_version; 162952c9ce25SScott Long cts.protocol = path->device->protocol; 163052c9ce25SScott Long cts.protocol_version = path->device->protocol_version; 163152c9ce25SScott Long cts.proto_specific.valid = 0; 16324cca1530SAlexander Motin if (ident_buf) { 16334cca1530SAlexander Motin if (path->device->transport == XPORT_ATA) { 16344cca1530SAlexander Motin cts.xport_specific.ata.atapi = 16358e6cab54SAlexander Motin (ident_buf->config == ATA_PROTO_CFA) ? 0 : 16364cca1530SAlexander Motin ((ident_buf->config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_16) ? 16 : 16374cca1530SAlexander Motin ((ident_buf->config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_12) ? 12 : 0; 16384cca1530SAlexander Motin cts.xport_specific.ata.valid = CTS_ATA_VALID_ATAPI; 16394cca1530SAlexander Motin } else { 16404cca1530SAlexander Motin cts.xport_specific.sata.atapi = 16418e6cab54SAlexander Motin (ident_buf->config == ATA_PROTO_CFA) ? 0 : 16424cca1530SAlexander Motin ((ident_buf->config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_16) ? 16 : 16434cca1530SAlexander Motin ((ident_buf->config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_12) ? 12 : 0; 16444cca1530SAlexander Motin cts.xport_specific.sata.valid = CTS_SATA_VALID_ATAPI; 16454cca1530SAlexander Motin } 16464cca1530SAlexander Motin } else 164752c9ce25SScott Long cts.xport_specific.valid = 0; 164852c9ce25SScott Long xpt_action((union ccb *)&cts); 164952c9ce25SScott Long } 165052c9ce25SScott Long 165152c9ce25SScott Long static void 165214f900e2SWill Andrews ata_dev_advinfo(union ccb *start_ccb) 165314f900e2SWill Andrews { 165414f900e2SWill Andrews struct cam_ed *device; 165514f900e2SWill Andrews struct ccb_dev_advinfo *cdai; 165614f900e2SWill Andrews off_t amt; 165714f900e2SWill Andrews 165814f900e2SWill Andrews start_ccb->ccb_h.status = CAM_REQ_INVALID; 165914f900e2SWill Andrews device = start_ccb->ccb_h.path->device; 166014f900e2SWill Andrews cdai = &start_ccb->cdai; 166114f900e2SWill Andrews switch(cdai->buftype) { 16623089bb2eSAlexander Motin case CDAI_TYPE_SCSI_DEVID: 16633089bb2eSAlexander Motin if (cdai->flags & CDAI_FLAG_STORE) 16643089bb2eSAlexander Motin return; 16653089bb2eSAlexander Motin cdai->provsiz = device->device_id_len; 16663089bb2eSAlexander Motin if (device->device_id_len == 0) 16673089bb2eSAlexander Motin break; 16683089bb2eSAlexander Motin amt = device->device_id_len; 16693089bb2eSAlexander Motin if (cdai->provsiz > cdai->bufsiz) 16703089bb2eSAlexander Motin amt = cdai->bufsiz; 16713089bb2eSAlexander Motin memcpy(cdai->buf, device->device_id, amt); 16723089bb2eSAlexander Motin break; 167314f900e2SWill Andrews case CDAI_TYPE_SERIAL_NUM: 167414f900e2SWill Andrews if (cdai->flags & CDAI_FLAG_STORE) 16753089bb2eSAlexander Motin return; 167614f900e2SWill Andrews cdai->provsiz = device->serial_num_len; 167714f900e2SWill Andrews if (device->serial_num_len == 0) 167814f900e2SWill Andrews break; 167914f900e2SWill Andrews amt = device->serial_num_len; 168014f900e2SWill Andrews if (cdai->provsiz > cdai->bufsiz) 168114f900e2SWill Andrews amt = cdai->bufsiz; 168214f900e2SWill Andrews memcpy(cdai->buf, device->serial_num, amt); 168314f900e2SWill Andrews break; 16843089bb2eSAlexander Motin case CDAI_TYPE_PHYS_PATH: 16853089bb2eSAlexander Motin if (cdai->flags & CDAI_FLAG_STORE) { 16863089bb2eSAlexander Motin if (device->physpath != NULL) 16873089bb2eSAlexander Motin free(device->physpath, M_CAMXPT); 16883089bb2eSAlexander Motin device->physpath_len = cdai->bufsiz; 16893089bb2eSAlexander Motin /* Clear existing buffer if zero length */ 16903089bb2eSAlexander Motin if (cdai->bufsiz == 0) 169114f900e2SWill Andrews break; 16923089bb2eSAlexander Motin device->physpath = malloc(cdai->bufsiz, M_CAMXPT, M_NOWAIT); 16933089bb2eSAlexander Motin if (device->physpath == NULL) { 16943089bb2eSAlexander Motin start_ccb->ccb_h.status = CAM_REQ_ABORTED; 16953089bb2eSAlexander Motin return; 16963089bb2eSAlexander Motin } 16973089bb2eSAlexander Motin memcpy(device->physpath, cdai->buf, cdai->bufsiz); 16983089bb2eSAlexander Motin } else { 16993089bb2eSAlexander Motin cdai->provsiz = device->physpath_len; 17003089bb2eSAlexander Motin if (device->physpath_len == 0) 17013089bb2eSAlexander Motin break; 17023089bb2eSAlexander Motin amt = device->physpath_len; 17033089bb2eSAlexander Motin if (cdai->provsiz > cdai->bufsiz) 17043089bb2eSAlexander Motin amt = cdai->bufsiz; 17053089bb2eSAlexander Motin memcpy(cdai->buf, device->physpath, amt); 17063089bb2eSAlexander Motin } 17073089bb2eSAlexander Motin break; 17083089bb2eSAlexander Motin default: 17093089bb2eSAlexander Motin return; 17103089bb2eSAlexander Motin } 17113089bb2eSAlexander Motin start_ccb->ccb_h.status = CAM_REQ_CMP; 17123089bb2eSAlexander Motin 17133089bb2eSAlexander Motin if (cdai->flags & CDAI_FLAG_STORE) { 17143089bb2eSAlexander Motin int owned; 17153089bb2eSAlexander Motin 17163089bb2eSAlexander Motin owned = mtx_owned(start_ccb->ccb_h.path->bus->sim->mtx); 17173089bb2eSAlexander Motin if (owned == 0) 17183089bb2eSAlexander Motin mtx_lock(start_ccb->ccb_h.path->bus->sim->mtx); 17193089bb2eSAlexander Motin xpt_async(AC_ADVINFO_CHANGED, start_ccb->ccb_h.path, 17203089bb2eSAlexander Motin (void *)(uintptr_t)cdai->buftype); 17213089bb2eSAlexander Motin if (owned == 0) 17223089bb2eSAlexander Motin mtx_unlock(start_ccb->ccb_h.path->bus->sim->mtx); 172314f900e2SWill Andrews } 172414f900e2SWill Andrews } 172514f900e2SWill Andrews 172614f900e2SWill Andrews static void 172752c9ce25SScott Long ata_action(union ccb *start_ccb) 172852c9ce25SScott Long { 172952c9ce25SScott Long 173052c9ce25SScott Long switch (start_ccb->ccb_h.func_code) { 173152c9ce25SScott Long case XPT_SET_TRAN_SETTINGS: 173252c9ce25SScott Long { 173330a4094fSAlexander Motin ata_set_transfer_settings(&start_ccb->cts, 173452c9ce25SScott Long start_ccb->ccb_h.path->device, 173552c9ce25SScott Long /*async_update*/FALSE); 173652c9ce25SScott Long break; 173752c9ce25SScott Long } 173852c9ce25SScott Long case XPT_SCAN_BUS: 17390e85f214SMatt Jacob case XPT_SCAN_TGT: 174052c9ce25SScott Long ata_scan_bus(start_ccb->ccb_h.path->periph, start_ccb); 174152c9ce25SScott Long break; 174252c9ce25SScott Long case XPT_SCAN_LUN: 174352c9ce25SScott Long ata_scan_lun(start_ccb->ccb_h.path->periph, 174452c9ce25SScott Long start_ccb->ccb_h.path, start_ccb->crcn.flags, 174552c9ce25SScott Long start_ccb); 174652c9ce25SScott Long break; 174752c9ce25SScott Long case XPT_GET_TRAN_SETTINGS: 174852c9ce25SScott Long { 1749b9c473b2SAlexander Motin ata_get_transfer_settings(&start_ccb->cts); 175052c9ce25SScott Long break; 175152c9ce25SScott Long } 17524cca1530SAlexander Motin case XPT_SCSI_IO: 17534cca1530SAlexander Motin { 17544cca1530SAlexander Motin struct cam_ed *device; 17554cca1530SAlexander Motin u_int maxlen = 0; 17564cca1530SAlexander Motin 17574cca1530SAlexander Motin device = start_ccb->ccb_h.path->device; 17584cca1530SAlexander Motin if (device->protocol == PROTO_SCSI && 17594cca1530SAlexander Motin (device->flags & CAM_DEV_IDENTIFY_DATA_VALID)) { 17604cca1530SAlexander Motin uint16_t p = 17614cca1530SAlexander Motin device->ident_data.config & ATA_PROTO_MASK; 17624cca1530SAlexander Motin 17638e6cab54SAlexander Motin maxlen = 17648e6cab54SAlexander Motin (device->ident_data.config == ATA_PROTO_CFA) ? 0 : 17658e6cab54SAlexander Motin (p == ATA_PROTO_ATAPI_16) ? 16 : 17664cca1530SAlexander Motin (p == ATA_PROTO_ATAPI_12) ? 12 : 0; 17674cca1530SAlexander Motin } 17684cca1530SAlexander Motin if (start_ccb->csio.cdb_len > maxlen) { 17694cca1530SAlexander Motin start_ccb->ccb_h.status = CAM_REQ_INVALID; 17704cca1530SAlexander Motin xpt_done(start_ccb); 17714cca1530SAlexander Motin break; 17724cca1530SAlexander Motin } 1773ee2b236bSAlexander Motin xpt_action_default(start_ccb); 1774ee2b236bSAlexander Motin break; 17754cca1530SAlexander Motin } 177614f900e2SWill Andrews case XPT_DEV_ADVINFO: 177714f900e2SWill Andrews { 177814f900e2SWill Andrews ata_dev_advinfo(start_ccb); 177914f900e2SWill Andrews break; 178014f900e2SWill Andrews } 178152c9ce25SScott Long default: 178252c9ce25SScott Long xpt_action_default(start_ccb); 178352c9ce25SScott Long break; 178452c9ce25SScott Long } 178552c9ce25SScott Long } 178652c9ce25SScott Long 178752c9ce25SScott Long static void 1788b9c473b2SAlexander Motin ata_get_transfer_settings(struct ccb_trans_settings *cts) 1789b9c473b2SAlexander Motin { 1790b9c473b2SAlexander Motin struct ccb_trans_settings_ata *ata; 1791b9c473b2SAlexander Motin struct ccb_trans_settings_scsi *scsi; 1792b9c473b2SAlexander Motin struct cam_ed *device; 1793b9c473b2SAlexander Motin struct cam_sim *sim; 1794b9c473b2SAlexander Motin 1795b9c473b2SAlexander Motin device = cts->ccb_h.path->device; 1796b9c473b2SAlexander Motin sim = cts->ccb_h.path->bus->sim; 1797b9c473b2SAlexander Motin (*(sim->sim_action))(sim, (union ccb *)cts); 1798b9c473b2SAlexander Motin 1799bc1bf6e8SAlexander Motin if (cts->protocol == PROTO_UNKNOWN || 1800bc1bf6e8SAlexander Motin cts->protocol == PROTO_UNSPECIFIED) { 1801bc1bf6e8SAlexander Motin cts->protocol = device->protocol; 1802bc1bf6e8SAlexander Motin cts->protocol_version = device->protocol_version; 1803bc1bf6e8SAlexander Motin } 1804bc1bf6e8SAlexander Motin 1805b9c473b2SAlexander Motin if (cts->protocol == PROTO_ATA) { 1806b9c473b2SAlexander Motin ata = &cts->proto_specific.ata; 1807b9c473b2SAlexander Motin if ((ata->valid & CTS_ATA_VALID_TQ) == 0) { 1808b9c473b2SAlexander Motin ata->valid |= CTS_ATA_VALID_TQ; 1809b9c473b2SAlexander Motin if (cts->type == CTS_TYPE_USER_SETTINGS || 1810b9c473b2SAlexander Motin (device->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 || 1811b9c473b2SAlexander Motin (device->inq_flags & SID_CmdQue) != 0) 1812b9c473b2SAlexander Motin ata->flags |= CTS_ATA_FLAGS_TAG_ENB; 1813b9c473b2SAlexander Motin } 1814b9c473b2SAlexander Motin } 1815b9c473b2SAlexander Motin if (cts->protocol == PROTO_SCSI) { 1816b9c473b2SAlexander Motin scsi = &cts->proto_specific.scsi; 1817b9c473b2SAlexander Motin if ((scsi->valid & CTS_SCSI_VALID_TQ) == 0) { 1818b9c473b2SAlexander Motin scsi->valid |= CTS_SCSI_VALID_TQ; 1819b9c473b2SAlexander Motin if (cts->type == CTS_TYPE_USER_SETTINGS || 1820b9c473b2SAlexander Motin (device->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 || 1821b9c473b2SAlexander Motin (device->inq_flags & SID_CmdQue) != 0) 1822b9c473b2SAlexander Motin scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 1823b9c473b2SAlexander Motin } 1824b9c473b2SAlexander Motin } 1825bc1bf6e8SAlexander Motin 1826bc1bf6e8SAlexander Motin if (cts->transport == XPORT_UNKNOWN || 1827bc1bf6e8SAlexander Motin cts->transport == XPORT_UNSPECIFIED) { 1828bc1bf6e8SAlexander Motin cts->transport = device->transport; 1829bc1bf6e8SAlexander Motin cts->transport_version = device->transport_version; 1830bc1bf6e8SAlexander Motin } 1831b9c473b2SAlexander Motin } 1832b9c473b2SAlexander Motin 1833b9c473b2SAlexander Motin static void 183430a4094fSAlexander Motin ata_set_transfer_settings(struct ccb_trans_settings *cts, struct cam_ed *device, 183552c9ce25SScott Long int async_update) 183652c9ce25SScott Long { 183752c9ce25SScott Long struct ccb_pathinq cpi; 1838b9c473b2SAlexander Motin struct ccb_trans_settings_ata *ata; 183952c9ce25SScott Long struct ccb_trans_settings_scsi *scsi; 184052c9ce25SScott Long struct cam_sim *sim; 1841b9c473b2SAlexander Motin struct ata_params *ident_data; 184252c9ce25SScott Long struct scsi_inquiry_data *inq_data; 184352c9ce25SScott Long 184452c9ce25SScott Long if (device == NULL) { 184552c9ce25SScott Long cts->ccb_h.status = CAM_PATH_INVALID; 184652c9ce25SScott Long xpt_done((union ccb *)cts); 184752c9ce25SScott Long return; 184852c9ce25SScott Long } 184952c9ce25SScott Long 185052c9ce25SScott Long if (cts->protocol == PROTO_UNKNOWN 185152c9ce25SScott Long || cts->protocol == PROTO_UNSPECIFIED) { 185252c9ce25SScott Long cts->protocol = device->protocol; 185352c9ce25SScott Long cts->protocol_version = device->protocol_version; 185452c9ce25SScott Long } 185552c9ce25SScott Long 185652c9ce25SScott Long if (cts->protocol_version == PROTO_VERSION_UNKNOWN 185752c9ce25SScott Long || cts->protocol_version == PROTO_VERSION_UNSPECIFIED) 185852c9ce25SScott Long cts->protocol_version = device->protocol_version; 185952c9ce25SScott Long 186052c9ce25SScott Long if (cts->protocol != device->protocol) { 186152c9ce25SScott Long xpt_print(cts->ccb_h.path, "Uninitialized Protocol %x:%x?\n", 186252c9ce25SScott Long cts->protocol, device->protocol); 186352c9ce25SScott Long cts->protocol = device->protocol; 186452c9ce25SScott Long } 186552c9ce25SScott Long 186652c9ce25SScott Long if (cts->protocol_version > device->protocol_version) { 186752c9ce25SScott Long if (bootverbose) { 186852c9ce25SScott Long xpt_print(cts->ccb_h.path, "Down reving Protocol " 186952c9ce25SScott Long "Version from %d to %d?\n", cts->protocol_version, 187052c9ce25SScott Long device->protocol_version); 187152c9ce25SScott Long } 187252c9ce25SScott Long cts->protocol_version = device->protocol_version; 187352c9ce25SScott Long } 187452c9ce25SScott Long 187552c9ce25SScott Long if (cts->transport == XPORT_UNKNOWN 187652c9ce25SScott Long || cts->transport == XPORT_UNSPECIFIED) { 187752c9ce25SScott Long cts->transport = device->transport; 187852c9ce25SScott Long cts->transport_version = device->transport_version; 187952c9ce25SScott Long } 188052c9ce25SScott Long 188152c9ce25SScott Long if (cts->transport_version == XPORT_VERSION_UNKNOWN 188252c9ce25SScott Long || cts->transport_version == XPORT_VERSION_UNSPECIFIED) 188352c9ce25SScott Long cts->transport_version = device->transport_version; 188452c9ce25SScott Long 188552c9ce25SScott Long if (cts->transport != device->transport) { 188652c9ce25SScott Long xpt_print(cts->ccb_h.path, "Uninitialized Transport %x:%x?\n", 188752c9ce25SScott Long cts->transport, device->transport); 188852c9ce25SScott Long cts->transport = device->transport; 188952c9ce25SScott Long } 189052c9ce25SScott Long 189152c9ce25SScott Long if (cts->transport_version > device->transport_version) { 189252c9ce25SScott Long if (bootverbose) { 189352c9ce25SScott Long xpt_print(cts->ccb_h.path, "Down reving Transport " 189452c9ce25SScott Long "Version from %d to %d?\n", cts->transport_version, 189552c9ce25SScott Long device->transport_version); 189652c9ce25SScott Long } 189752c9ce25SScott Long cts->transport_version = device->transport_version; 189852c9ce25SScott Long } 189952c9ce25SScott Long 190052c9ce25SScott Long sim = cts->ccb_h.path->bus->sim; 1901b9c473b2SAlexander Motin ident_data = &device->ident_data; 190252c9ce25SScott Long inq_data = &device->inq_data; 1903b9c473b2SAlexander Motin if (cts->protocol == PROTO_ATA) 1904b9c473b2SAlexander Motin ata = &cts->proto_specific.ata; 1905b9c473b2SAlexander Motin else 1906b9c473b2SAlexander Motin ata = NULL; 1907b9c473b2SAlexander Motin if (cts->protocol == PROTO_SCSI) 190852c9ce25SScott Long scsi = &cts->proto_specific.scsi; 1909b9c473b2SAlexander Motin else 1910b9c473b2SAlexander Motin scsi = NULL; 191183c5d981SAlexander Motin xpt_setup_ccb(&cpi.ccb_h, cts->ccb_h.path, CAM_PRIORITY_NONE); 191252c9ce25SScott Long cpi.ccb_h.func_code = XPT_PATH_INQ; 191352c9ce25SScott Long xpt_action((union ccb *)&cpi); 191452c9ce25SScott Long 1915b9c473b2SAlexander Motin /* Sanity checking */ 191652c9ce25SScott Long if ((cpi.hba_inquiry & PI_TAG_ABLE) == 0 1917b9c473b2SAlexander Motin || (ata && (ident_data->satacapabilities & ATA_SUPPORT_NCQ) == 0) 1918b9c473b2SAlexander Motin || (scsi && (INQ_DATA_TQ_ENABLED(inq_data)) == 0) 191952c9ce25SScott Long || (device->queue_flags & SCP_QUEUE_DQUE) != 0 192052c9ce25SScott Long || (device->mintags == 0)) { 192152c9ce25SScott Long /* 192252c9ce25SScott Long * Can't tag on hardware that doesn't support tags, 192352c9ce25SScott Long * doesn't have it enabled, or has broken tag support. 192452c9ce25SScott Long */ 1925b9c473b2SAlexander Motin if (ata) 1926b9c473b2SAlexander Motin ata->flags &= ~CTS_ATA_FLAGS_TAG_ENB; 1927b9c473b2SAlexander Motin if (scsi) 192852c9ce25SScott Long scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 192952c9ce25SScott Long } 193052c9ce25SScott Long 1931b9c473b2SAlexander Motin /* Start/stop tags use. */ 1932b9c473b2SAlexander Motin if (cts->type == CTS_TYPE_CURRENT_SETTINGS && 1933b9c473b2SAlexander Motin ((ata && (ata->valid & CTS_ATA_VALID_TQ) != 0) || 1934b9c473b2SAlexander Motin (scsi && (scsi->valid & CTS_SCSI_VALID_TQ) != 0))) { 1935b9c473b2SAlexander Motin int nowt, newt = 0; 193652c9ce25SScott Long 1937b9c473b2SAlexander Motin nowt = ((device->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 || 1938b9c473b2SAlexander Motin (device->inq_flags & SID_CmdQue) != 0); 1939b9c473b2SAlexander Motin if (ata) 1940b9c473b2SAlexander Motin newt = (ata->flags & CTS_ATA_FLAGS_TAG_ENB) != 0; 1941b9c473b2SAlexander Motin if (scsi) 1942b9c473b2SAlexander Motin newt = (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0; 194352c9ce25SScott Long 1944b9c473b2SAlexander Motin if (newt && !nowt) { 194552c9ce25SScott Long /* 194652c9ce25SScott Long * Delay change to use tags until after a 194752c9ce25SScott Long * few commands have gone to this device so 194852c9ce25SScott Long * the controller has time to perform transfer 194952c9ce25SScott Long * negotiations without tagged messages getting 195052c9ce25SScott Long * in the way. 195152c9ce25SScott Long */ 195252c9ce25SScott Long device->tag_delay_count = CAM_TAG_DELAY_COUNT; 195352c9ce25SScott Long device->flags |= CAM_DEV_TAG_AFTER_COUNT; 1954b9c473b2SAlexander Motin } else if (nowt && !newt) 195530a4094fSAlexander Motin xpt_stop_tags(cts->ccb_h.path); 195652c9ce25SScott Long } 1957b9c473b2SAlexander Motin 195852c9ce25SScott Long if (async_update == FALSE) 195952c9ce25SScott Long (*(sim->sim_action))(sim, (union ccb *)cts); 196052c9ce25SScott Long } 196152c9ce25SScott Long 196252c9ce25SScott Long /* 196352c9ce25SScott Long * Handle any per-device event notifications that require action by the XPT. 196452c9ce25SScott Long */ 196552c9ce25SScott Long static void 196652c9ce25SScott Long ata_dev_async(u_int32_t async_code, struct cam_eb *bus, struct cam_et *target, 196752c9ce25SScott Long struct cam_ed *device, void *async_arg) 196852c9ce25SScott Long { 196952c9ce25SScott Long cam_status status; 197052c9ce25SScott Long struct cam_path newpath; 197152c9ce25SScott Long 197252c9ce25SScott Long /* 197352c9ce25SScott Long * We only need to handle events for real devices. 197452c9ce25SScott Long */ 197552c9ce25SScott Long if (target->target_id == CAM_TARGET_WILDCARD 197652c9ce25SScott Long || device->lun_id == CAM_LUN_WILDCARD) 197752c9ce25SScott Long return; 197852c9ce25SScott Long 197952c9ce25SScott Long /* 198052c9ce25SScott Long * We need our own path with wildcards expanded to 198152c9ce25SScott Long * handle certain types of events. 198252c9ce25SScott Long */ 198352c9ce25SScott Long if ((async_code == AC_SENT_BDR) 198452c9ce25SScott Long || (async_code == AC_BUS_RESET) 198552c9ce25SScott Long || (async_code == AC_INQ_CHANGED)) 198652c9ce25SScott Long status = xpt_compile_path(&newpath, NULL, 198752c9ce25SScott Long bus->path_id, 198852c9ce25SScott Long target->target_id, 198952c9ce25SScott Long device->lun_id); 199052c9ce25SScott Long else 199152c9ce25SScott Long status = CAM_REQ_CMP_ERR; 199252c9ce25SScott Long 199352c9ce25SScott Long if (status == CAM_REQ_CMP) { 199452c9ce25SScott Long if (async_code == AC_INQ_CHANGED) { 199552c9ce25SScott Long /* 199652c9ce25SScott Long * We've sent a start unit command, or 199752c9ce25SScott Long * something similar to a device that 199852c9ce25SScott Long * may have caused its inquiry data to 199952c9ce25SScott Long * change. So we re-scan the device to 200052c9ce25SScott Long * refresh the inquiry data for it. 200152c9ce25SScott Long */ 200252c9ce25SScott Long ata_scan_lun(newpath.periph, &newpath, 200352c9ce25SScott Long CAM_EXPECT_INQ_CHANGE, NULL); 200483c5d981SAlexander Motin } else { 200583c5d981SAlexander Motin /* We need to reinitialize device after reset. */ 200683c5d981SAlexander Motin ata_scan_lun(newpath.periph, &newpath, 200783c5d981SAlexander Motin 0, NULL); 200852c9ce25SScott Long } 200952c9ce25SScott Long xpt_release_path(&newpath); 2010f98d7a47SAlexander Motin } else if (async_code == AC_LOST_DEVICE && 2011f98d7a47SAlexander Motin (device->flags & CAM_DEV_UNCONFIGURED) == 0) { 201252c9ce25SScott Long device->flags |= CAM_DEV_UNCONFIGURED; 2013f98d7a47SAlexander Motin xpt_release_device(device); 201452c9ce25SScott Long } else if (async_code == AC_TRANSFER_NEG) { 201552c9ce25SScott Long struct ccb_trans_settings *settings; 201652c9ce25SScott Long 201752c9ce25SScott Long settings = (struct ccb_trans_settings *)async_arg; 201830a4094fSAlexander Motin ata_set_transfer_settings(settings, device, 201952c9ce25SScott Long /*async_update*/TRUE); 202052c9ce25SScott Long } 202152c9ce25SScott Long } 202252c9ce25SScott Long 202357079b17SAlexander Motin static void 202457079b17SAlexander Motin ata_announce_periph(struct cam_periph *periph) 202557079b17SAlexander Motin { 202657079b17SAlexander Motin struct ccb_pathinq cpi; 202757079b17SAlexander Motin struct ccb_trans_settings cts; 202857079b17SAlexander Motin struct cam_path *path = periph->path; 202957079b17SAlexander Motin u_int speed; 203057079b17SAlexander Motin u_int mb; 203157079b17SAlexander Motin 203257079b17SAlexander Motin mtx_assert(periph->sim->mtx, MA_OWNED); 203357079b17SAlexander Motin 203457079b17SAlexander Motin xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL); 203557079b17SAlexander Motin cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 203657079b17SAlexander Motin cts.type = CTS_TYPE_CURRENT_SETTINGS; 203757079b17SAlexander Motin xpt_action((union ccb*)&cts); 203857079b17SAlexander Motin if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) 203957079b17SAlexander Motin return; 204057079b17SAlexander Motin /* Ask the SIM for its base transfer speed */ 204157079b17SAlexander Motin xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NORMAL); 204257079b17SAlexander Motin cpi.ccb_h.func_code = XPT_PATH_INQ; 204357079b17SAlexander Motin xpt_action((union ccb *)&cpi); 204457079b17SAlexander Motin /* Report connection speed */ 204557079b17SAlexander Motin speed = cpi.base_transfer_speed; 204657079b17SAlexander Motin if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_ATA) { 2047b9c473b2SAlexander Motin struct ccb_trans_settings_pata *pata = 204857079b17SAlexander Motin &cts.xport_specific.ata; 204957079b17SAlexander Motin 2050b9c473b2SAlexander Motin if (pata->valid & CTS_ATA_VALID_MODE) 2051b9c473b2SAlexander Motin speed = ata_mode2speed(pata->mode); 205257079b17SAlexander Motin } 205357079b17SAlexander Motin if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_SATA) { 205457079b17SAlexander Motin struct ccb_trans_settings_sata *sata = 205557079b17SAlexander Motin &cts.xport_specific.sata; 205657079b17SAlexander Motin 205757079b17SAlexander Motin if (sata->valid & CTS_SATA_VALID_REVISION) 205857079b17SAlexander Motin speed = ata_revision2speed(sata->revision); 205957079b17SAlexander Motin } 206057079b17SAlexander Motin mb = speed / 1000; 206157079b17SAlexander Motin if (mb > 0) 206257079b17SAlexander Motin printf("%s%d: %d.%03dMB/s transfers", 206357079b17SAlexander Motin periph->periph_name, periph->unit_number, 206457079b17SAlexander Motin mb, speed % 1000); 206557079b17SAlexander Motin else 206657079b17SAlexander Motin printf("%s%d: %dKB/s transfers", periph->periph_name, 206757079b17SAlexander Motin periph->unit_number, speed); 206857079b17SAlexander Motin /* Report additional information about connection */ 206957079b17SAlexander Motin if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_ATA) { 2070b9c473b2SAlexander Motin struct ccb_trans_settings_pata *pata = 207157079b17SAlexander Motin &cts.xport_specific.ata; 207257079b17SAlexander Motin 207357079b17SAlexander Motin printf(" ("); 2074b9c473b2SAlexander Motin if (pata->valid & CTS_ATA_VALID_MODE) 2075b9c473b2SAlexander Motin printf("%s, ", ata_mode2string(pata->mode)); 2076b9c473b2SAlexander Motin if ((pata->valid & CTS_ATA_VALID_ATAPI) && pata->atapi != 0) 2077b9c473b2SAlexander Motin printf("ATAPI %dbytes, ", pata->atapi); 2078b9c473b2SAlexander Motin if (pata->valid & CTS_ATA_VALID_BYTECOUNT) 2079b9c473b2SAlexander Motin printf("PIO %dbytes", pata->bytecount); 208057079b17SAlexander Motin printf(")"); 208157079b17SAlexander Motin } 208257079b17SAlexander Motin if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_SATA) { 208357079b17SAlexander Motin struct ccb_trans_settings_sata *sata = 208457079b17SAlexander Motin &cts.xport_specific.sata; 208557079b17SAlexander Motin 208657079b17SAlexander Motin printf(" ("); 208757079b17SAlexander Motin if (sata->valid & CTS_SATA_VALID_REVISION) 208857079b17SAlexander Motin printf("SATA %d.x, ", sata->revision); 208957079b17SAlexander Motin else 209057079b17SAlexander Motin printf("SATA, "); 209157079b17SAlexander Motin if (sata->valid & CTS_SATA_VALID_MODE) 209257079b17SAlexander Motin printf("%s, ", ata_mode2string(sata->mode)); 209357079b17SAlexander Motin if ((sata->valid & CTS_ATA_VALID_ATAPI) && sata->atapi != 0) 209457079b17SAlexander Motin printf("ATAPI %dbytes, ", sata->atapi); 209557079b17SAlexander Motin if (sata->valid & CTS_SATA_VALID_BYTECOUNT) 209657079b17SAlexander Motin printf("PIO %dbytes", sata->bytecount); 209757079b17SAlexander Motin printf(")"); 209857079b17SAlexander Motin } 209957079b17SAlexander Motin printf("\n"); 210057079b17SAlexander Motin } 2101