From owner-svn-src-stable@FreeBSD.ORG Tue Nov 17 20:43:04 2009 Return-Path: Delivered-To: svn-src-stable@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 95BAD1065672; Tue, 17 Nov 2009 20:43:04 +0000 (UTC) (envelope-from mav@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 8342C8FC23; Tue, 17 Nov 2009 20:43:04 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id nAHKh4gR037131; Tue, 17 Nov 2009 20:43:04 GMT (envelope-from mav@svn.freebsd.org) Received: (from mav@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id nAHKh4Ho037126; Tue, 17 Nov 2009 20:43:04 GMT (envelope-from mav@svn.freebsd.org) Message-Id: <200911172043.nAHKh4Ho037126@svn.freebsd.org> From: Alexander Motin Date: Tue, 17 Nov 2009 20:43:04 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org X-SVN-Group: stable-8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r199431 - in stable/8/sys/cam: . ata scsi X-BeenThere: svn-src-stable@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for all the -stable branches of the src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 17 Nov 2009 20:43:05 -0000 Author: mav Date: Tue Nov 17 20:43:04 2009 New Revision: 199431 URL: http://svn.freebsd.org/changeset/base/199431 Log: MFC r198708: - Reduce code duplication in ATA XPT and PMP driver. - Move PIO size setting from ada driver to ATA XPT. It is XPT business to negotiate transfer details. ada driver is now stateless. - Report PIO size to SIM. It is required for correct PATA SIM operation. - Tune PMP scan timings. It workarounds some problems with SiI. - If reset hapens during PMP initialization - restart it. - Introduce early-initialized periph drivers, which are used during initial scan process. Use it for xpt, probe, aprobe and pmp. It gives pmp chance to finish scan before mountroot and numerate devices in right order. Modified: stable/8/sys/cam/ata/ata_da.c stable/8/sys/cam/ata/ata_pmp.c stable/8/sys/cam/ata/ata_xpt.c stable/8/sys/cam/cam.h stable/8/sys/cam/cam_ccb.h stable/8/sys/cam/cam_periph.h stable/8/sys/cam/cam_xpt.c stable/8/sys/cam/scsi/scsi_da.c stable/8/sys/cam/scsi/scsi_sg.c stable/8/sys/cam/scsi/scsi_xpt.c Directory Properties: stable/8/sys/ (props changed) stable/8/sys/amd64/include/xen/ (props changed) stable/8/sys/cddl/contrib/opensolaris/ (props changed) stable/8/sys/contrib/dev/acpica/ (props changed) stable/8/sys/contrib/pf/ (props changed) stable/8/sys/dev/xen/xenpci/ (props changed) Modified: stable/8/sys/cam/ata/ata_da.c ============================================================================== --- stable/8/sys/cam/ata/ata_da.c Tue Nov 17 20:41:15 2009 (r199430) +++ stable/8/sys/cam/ata/ata_da.c Tue Nov 17 20:43:04 2009 (r199431) @@ -63,8 +63,7 @@ __FBSDID("$FreeBSD$"); #define ATA_MAX_28BIT_LBA 268435455UL typedef enum { - ADA_STATE_NORMAL, - ADA_STATE_SET_MULTI + ADA_STATE_NORMAL } ada_state; typedef enum { @@ -84,7 +83,6 @@ typedef enum { } ada_quirks; typedef enum { - ADA_CCB_SET_MULTI = 0x01, ADA_CCB_BUFFER_IO = 0x03, ADA_CCB_WAITING = 0x04, ADA_CCB_DUMP = 0x05, @@ -112,7 +110,6 @@ struct ada_softc { ada_quirks quirks; int ordered_tag_count; int outstanding_cmds; - int secsperint; struct disk_params params; struct disk *disk; union ccb saved_ccb; @@ -550,22 +547,6 @@ adaasync(void *callback_arg, u_int32_t c "due to status 0x%x\n", status); break; } - case AC_SENT_BDR: - case AC_BUS_RESET: - { - struct ada_softc *softc = (struct ada_softc *)periph->softc; - - cam_periph_async(periph, code, path, arg); - if (softc->state != ADA_STATE_NORMAL) - break; - /* - * Restore device configuration. - */ - softc->state = ADA_STATE_SET_MULTI; - cam_periph_acquire(periph); - xpt_schedule(periph, CAM_PRIORITY_DEV); - break; - } default: cam_periph_async(periph, code, path, arg); break; @@ -644,8 +625,7 @@ adaregister(struct cam_periph *periph, v if (cgd->ident_data.satacapabilities & ATA_SUPPORT_NCQ && cgd->ident_data.queue >= 31) softc->flags |= ADA_FLAG_CAN_NCQ; - softc->secsperint = max(1, min(cgd->ident_data.sectors_intr, 16)); - softc->state = ADA_STATE_SET_MULTI; + softc->state = ADA_STATE_NORMAL; periph->softc = softc; @@ -734,18 +714,10 @@ adaregister(struct cam_periph *periph, v * them and the only alternative would be to * not attach the device on failure. */ - xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE, + xpt_register_async(AC_LOST_DEVICE, adaasync, periph, periph->path); /* - * Take an exclusive refcount on the periph while adastart is called - * to finish the probe. The reference will be dropped in adadone at - * the end of probe. - */ - cam_periph_acquire(periph); - xpt_schedule(periph, /*priority*/5); - - /* * Schedule a periodic event to occasionally send an * ordered tag to a device. */ @@ -901,21 +873,6 @@ adastart(struct cam_periph *periph, unio } break; } - case ADA_STATE_SET_MULTI: - { - cam_fill_ataio(ataio, - ada_retry_count, - adadone, - CAM_DIR_NONE, - 0, - NULL, - 0, - ada_default_timeout*1000); - - ata_28bit_cmd(ataio, ATA_SET_MULTI, 0, 0, softc->secsperint); - start_ccb->ccb_h.ccb_state = ADA_CCB_SET_MULTI; - xpt_action(start_ccb); - } } } @@ -1003,35 +960,6 @@ adadone(struct cam_periph *periph, union wakeup(&done_ccb->ccb_h.cbfcnp); return; } - case ADA_CCB_SET_MULTI: - { - if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { - } else { - int error; - - error = adaerror(done_ccb, 0, 0); - if (error == ERESTART) { - /* A retry was scheduled, so just return. */ - return; - } - } - softc->state = ADA_STATE_NORMAL; - /* - * Since our peripheral may be invalidated by an error - * above or an external event, we must release our CCB - * before releasing the probe lock on the peripheral. - * The peripheral will only go away once the last lock - * is removed, and we need it around for the CCB release - * operation. - */ - xpt_release_ccb(done_ccb); - if (bioq_first(&softc->bio_queue) != NULL) { - /* Have more work to do, so ensure we stay scheduled */ - xpt_schedule(periph, CAM_PRIORITY_NORMAL); - } - cam_periph_release_locked(periph); - return; - } case ADA_CCB_DUMP: /* No-op. We're polling */ return; Modified: stable/8/sys/cam/ata/ata_pmp.c ============================================================================== --- stable/8/sys/cam/ata/ata_pmp.c Tue Nov 17 20:41:15 2009 (r199430) +++ stable/8/sys/cam/ata/ata_pmp.c Tue Nov 17 20:43:04 2009 (r199431) @@ -93,7 +93,9 @@ struct pmp_softc { int pm_step; int pm_try; int found; + int reset; int frozen; + int restart; union ccb saved_ccb; struct task sysctl_task; struct sysctl_ctx_list sysctl_ctx; @@ -134,7 +136,8 @@ TUNABLE_INT("kern.cam.pmp.default_timeou static struct periph_driver pmpdriver = { pmpinit, "pmp", - TAILQ_HEAD_INITIALIZER(pmpdriver.units), /* generation */ 0 + TAILQ_HEAD_INITIALIZER(pmpdriver.units), /* generation */ 0, + CAM_PERIPH_DRV_EARLY }; PERIPHDRIVER_DECLARE(pmp, pmpdriver); @@ -292,14 +295,21 @@ pmpasync(void *callback_arg, u_int32_t c case AC_BUS_RESET: softc = (struct pmp_softc *)periph->softc; cam_periph_async(periph, code, path, arg); - if (softc->state != PMP_STATE_NORMAL) + if (code == AC_SCSI_AEN && softc->state != PMP_STATE_NORMAL && + softc->state != PMP_STATE_SCAN) break; - pmpfreeze(periph, softc->found); + if (softc->state != PMP_STATE_SCAN) + pmpfreeze(periph, softc->found); + else + pmpfreeze(periph, softc->found & ~(1 << softc->pm_step)); if (code == AC_SENT_BDR || code == AC_BUS_RESET) softc->found = 0; /* We have to reset everything. */ - softc->state = PMP_STATE_PORTS; - cam_periph_acquire(periph); - xpt_schedule(periph, CAM_PRIORITY_DEV); + if (softc->state == PMP_STATE_NORMAL) { + softc->state = PMP_STATE_PORTS; + cam_periph_acquire(periph); + xpt_schedule(periph, CAM_PRIORITY_BUS); + } else + softc->restart = 1; break; default: cam_periph_async(periph, code, path, arg); @@ -395,7 +405,7 @@ pmpregister(struct cam_periph *periph, v * the end of probe. */ (void)cam_periph_acquire(periph); - xpt_schedule(periph, CAM_PRIORITY_DEV); + xpt_schedule(periph, CAM_PRIORITY_BUS); return(CAM_REQ_CMP); } @@ -408,6 +418,11 @@ pmpstart(struct cam_periph *periph, unio softc = (struct pmp_softc *)periph->softc; ataio = &start_ccb->ataio; + + if (softc->restart) { + softc->restart = 0; + softc->state = PMP_STATE_PORTS; + } switch (softc->state) { case PMP_STATE_PORTS: @@ -469,6 +484,7 @@ printf("PM RESET %d%s\n", softc->pm_step ata_pm_read_cmd(ataio, 0, softc->pm_step); break; case PMP_STATE_CLEAR: + softc->reset = 0; cam_fill_ataio(ataio, pmp_retry_count, pmpdone, @@ -492,7 +508,7 @@ pmpdone(struct cam_periph *periph, union struct ccb_ataio *ataio; union ccb *work_ccb; struct cam_path *path, *dpath; - u_int32_t priority; + u_int32_t priority, res; softc = (struct pmp_softc *)periph->softc; ataio = &done_ccb->ataio; @@ -502,193 +518,158 @@ pmpdone(struct cam_periph *periph, union path = done_ccb->ccb_h.path; priority = done_ccb->ccb_h.pinfo.priority; - switch (softc->state) { - case PMP_STATE_PORTS: - if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { - softc->pm_ports = (done_ccb->ataio.res.lba_high << 24) + - (done_ccb->ataio.res.lba_mid << 16) + - (done_ccb->ataio.res.lba_low << 8) + - done_ccb->ataio.res.sector_count; - /* This PM declares 6 ports, while only 5 of them are real. - * Port 5 is enclosure management bridge port, which has implementation - * problems, causing probe faults. Hide it for now. */ - if (softc->pm_pid == 0x37261095 && softc->pm_ports == 6) - softc->pm_ports = 5; - /* This PM declares 7 ports, while only 5 of them are real. - * Port 5 is some fake "Config Disk" with 640 sectors size, - * port 6 is enclosure management bridge port. - * Both fake ports has implementation problems, causing - * probe faults. Hide them for now. */ - if (softc->pm_pid == 0x47261095 && softc->pm_ports == 7) - softc->pm_ports = 5; - printf("PM ports: %d\n", softc->pm_ports); - softc->state = PMP_STATE_CONFIG; - xpt_release_ccb(done_ccb); - xpt_schedule(periph, priority); - return; - } else if (cam_periph_error(done_ccb, 0, 0, - &softc->saved_ccb) == ERESTART) { + if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { + if (cam_periph_error(done_ccb, 0, 0, + &softc->saved_ccb) == ERESTART) { return; } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { - cam_release_devq(done_ccb->ccb_h.path, - /*relsim_flags*/0, - /*reduction*/0, - /*timeout*/0, - /*getcount_only*/0); + cam_release_devq(done_ccb->ccb_h.path, + /*relsim_flags*/0, + /*reduction*/0, + /*timeout*/0, + /*getcount_only*/0); + } + goto done; + } + + if (softc->restart) { + softc->restart = 0; + if (softc->state == PMP_STATE_SCAN) { + pmpfreeze(periph, 1 << softc->pm_step); + work_ccb = done_ccb; + done_ccb = (union ccb*)work_ccb->ccb_h.ppriv_ptr0; + /* Free the current request path- we're done with it. */ + xpt_free_path(work_ccb->ccb_h.path); + xpt_free_ccb(work_ccb); } xpt_release_ccb(done_ccb); - break; + softc->state = PMP_STATE_PORTS; + xpt_schedule(periph, priority); + return; + } + + switch (softc->state) { + case PMP_STATE_PORTS: + softc->pm_ports = (done_ccb->ataio.res.lba_high << 24) + + (done_ccb->ataio.res.lba_mid << 16) + + (done_ccb->ataio.res.lba_low << 8) + + done_ccb->ataio.res.sector_count; + /* This PM declares 6 ports, while only 5 of them are real. + * Port 5 is enclosure management bridge port, which has implementation + * problems, causing probe faults. Hide it for now. */ + if (softc->pm_pid == 0x37261095 && softc->pm_ports == 6) + softc->pm_ports = 5; + /* This PM declares 7 ports, while only 5 of them are real. + * Port 5 is some fake "Config Disk" with 640 sectors size, + * port 6 is enclosure management bridge port. + * Both fake ports has implementation problems, causing + * probe faults. Hide them for now. */ + if (softc->pm_pid == 0x47261095 && softc->pm_ports == 7) + softc->pm_ports = 5; + printf("PM ports: %d\n", softc->pm_ports); + softc->state = PMP_STATE_CONFIG; + xpt_release_ccb(done_ccb); + xpt_schedule(periph, priority); + return; case PMP_STATE_CONFIG: - if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { - softc->pm_step = 0; - softc->state = PMP_STATE_RESET; - xpt_release_ccb(done_ccb); - xpt_schedule(periph, priority); - return; - } else if (cam_periph_error(done_ccb, 0, 0, - &softc->saved_ccb) == ERESTART) { - return; - } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { - cam_release_devq(done_ccb->ccb_h.path, - /*relsim_flags*/0, - /*reduction*/0, - /*timeout*/0, - /*getcount_only*/0); - } + softc->pm_step = 0; + softc->state = PMP_STATE_RESET; + softc->reset |= ~softc->found; xpt_release_ccb(done_ccb); - break; + xpt_schedule(periph, priority); + return; case PMP_STATE_RESET: - if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { - softc->pm_step++; - if (softc->pm_step < softc->pm_ports) { - xpt_release_ccb(done_ccb); - xpt_schedule(periph, priority); - return; - } else { - softc->pm_step = 0; - DELAY(5000); - printf("PM reset done\n"); - softc->state = PMP_STATE_CONNECT; - xpt_release_ccb(done_ccb); - xpt_schedule(periph, priority); - return; - } - } else if (cam_periph_error(done_ccb, 0, 0, - &softc->saved_ccb) == ERESTART) { - return; - } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { - cam_release_devq(done_ccb->ccb_h.path, - /*relsim_flags*/0, - /*reduction*/0, - /*timeout*/0, - /*getcount_only*/0); + softc->pm_step++; + if (softc->pm_step >= softc->pm_ports) { + softc->pm_step = 0; + cam_freeze_devq(periph->path); + cam_release_devq(periph->path, + RELSIM_RELEASE_AFTER_TIMEOUT, + /*reduction*/0, + /*timeout*/5, + /*getcount_only*/0); + printf("PM reset done\n"); + softc->state = PMP_STATE_CONNECT; } xpt_release_ccb(done_ccb); - break; + xpt_schedule(periph, priority); + return; case PMP_STATE_CONNECT: - if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { - softc->pm_step++; - if (softc->pm_step < softc->pm_ports) { - xpt_release_ccb(done_ccb); - xpt_schedule(periph, priority); - return; - } else { - softc->pm_step = 0; - softc->pm_try = 0; - printf("PM connect done\n"); - softc->state = PMP_STATE_CHECK; - xpt_release_ccb(done_ccb); - xpt_schedule(periph, priority); - return; - } - } else if (cam_periph_error(done_ccb, 0, 0, - &softc->saved_ccb) == ERESTART) { - return; - } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { - cam_release_devq(done_ccb->ccb_h.path, - /*relsim_flags*/0, - /*reduction*/0, - /*timeout*/0, - /*getcount_only*/0); + softc->pm_step++; + if (softc->pm_step >= softc->pm_ports) { + softc->pm_step = 0; + softc->pm_try = 0; + cam_freeze_devq(periph->path); + cam_release_devq(periph->path, + RELSIM_RELEASE_AFTER_TIMEOUT, + /*reduction*/0, + /*timeout*/10, + /*getcount_only*/0); + printf("PM connect done\n"); + softc->state = PMP_STATE_CHECK; } xpt_release_ccb(done_ccb); - break; + xpt_schedule(periph, priority); + return; case PMP_STATE_CHECK: - if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { - int res = (done_ccb->ataio.res.lba_high << 24) + - (done_ccb->ataio.res.lba_mid << 16) + - (done_ccb->ataio.res.lba_low << 8) + - done_ccb->ataio.res.sector_count; - if ((res & 0xf0f) == 0x103 && (res & 0x0f0) != 0) { - printf("PM status: %d - %08x\n", softc->pm_step, res); - softc->found |= (1 << softc->pm_step); - softc->pm_step++; + res = (done_ccb->ataio.res.lba_high << 24) + + (done_ccb->ataio.res.lba_mid << 16) + + (done_ccb->ataio.res.lba_low << 8) + + done_ccb->ataio.res.sector_count; + if ((res & 0xf0f) == 0x103 && (res & 0x0f0) != 0) { + printf("PM status: %d - %08x\n", softc->pm_step, res); + softc->found |= (1 << softc->pm_step); + softc->pm_step++; + } else { + if (softc->pm_try < 10) { + cam_freeze_devq(periph->path); + cam_release_devq(periph->path, + RELSIM_RELEASE_AFTER_TIMEOUT, + /*reduction*/0, + /*timeout*/10, + /*getcount_only*/0); + softc->pm_try++; } else { - if (softc->pm_try < 100) { - DELAY(10000); - softc->pm_try++; - } else { - printf("PM status: %d - %08x\n", softc->pm_step, res); - softc->found &= ~(1 << softc->pm_step); - if (xpt_create_path(&dpath, periph, - done_ccb->ccb_h.path_id, - softc->pm_step, 0) == CAM_REQ_CMP) { - xpt_async(AC_LOST_DEVICE, dpath, NULL); - xpt_free_path(dpath); - } - softc->pm_step++; + printf("PM status: %d - %08x\n", softc->pm_step, res); + softc->found &= ~(1 << softc->pm_step); + if (xpt_create_path(&dpath, periph, + done_ccb->ccb_h.path_id, + softc->pm_step, 0) == CAM_REQ_CMP) { + xpt_async(AC_LOST_DEVICE, dpath, NULL); + xpt_free_path(dpath); } + softc->pm_step++; } - if (softc->pm_step < softc->pm_ports) { - xpt_release_ccb(done_ccb); - xpt_schedule(periph, priority); - return; - } else { - softc->pm_step = 0; - softc->state = PMP_STATE_CLEAR; - xpt_release_ccb(done_ccb); - xpt_schedule(periph, priority); - return; + } + if (softc->pm_step >= softc->pm_ports) { + if (softc->reset & softc->found) { + cam_freeze_devq(periph->path); + cam_release_devq(periph->path, + RELSIM_RELEASE_AFTER_TIMEOUT, + /*reduction*/0, + /*timeout*/1000, + /*getcount_only*/0); } - } else if (cam_periph_error(done_ccb, 0, 0, - &softc->saved_ccb) == ERESTART) { - return; - } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { - cam_release_devq(done_ccb->ccb_h.path, - /*relsim_flags*/0, - /*reduction*/0, - /*timeout*/0, - /*getcount_only*/0); + softc->state = PMP_STATE_CLEAR; + softc->pm_step = 0; } xpt_release_ccb(done_ccb); - break; + xpt_schedule(periph, priority); + return; case PMP_STATE_CLEAR: - if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { - softc->pm_step++; - if (softc->pm_step < softc->pm_ports) { - xpt_release_ccb(done_ccb); - xpt_schedule(periph, priority); - return; - } else if (softc->found) { - softc->pm_step = 0; - softc->state = PMP_STATE_SCAN; - work_ccb = xpt_alloc_ccb_nowait(); - if (work_ccb != NULL) - goto do_scan; - xpt_release_ccb(done_ccb); - } - break; - } else if (cam_periph_error(done_ccb, 0, 0, - &softc->saved_ccb) == ERESTART) { + softc->pm_step++; + if (softc->pm_step < softc->pm_ports) { + xpt_release_ccb(done_ccb); + xpt_schedule(periph, priority); return; - } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { - cam_release_devq(done_ccb->ccb_h.path, - /*relsim_flags*/0, - /*reduction*/0, - /*timeout*/0, - /*getcount_only*/0); + } else if (softc->found) { + softc->pm_step = 0; + softc->state = PMP_STATE_SCAN; + work_ccb = xpt_alloc_ccb_nowait(); + if (work_ccb != NULL) + goto do_scan; + xpt_release_ccb(done_ccb); } - xpt_release_ccb(done_ccb); break; case PMP_STATE_SCAN: work_ccb = done_ccb; @@ -703,7 +684,6 @@ do_scan: } if (softc->pm_step >= softc->pm_ports) { xpt_free_ccb(work_ccb); - xpt_release_ccb(done_ccb); break; } if (xpt_create_path(&dpath, periph, @@ -712,7 +692,6 @@ do_scan: printf("pmpdone: xpt_create_path failed" ", bus scan halted\n"); xpt_free_ccb(work_ccb); - xpt_release_ccb(done_ccb); break; } xpt_setup_ccb(&work_ccb->ccb_h, dpath, @@ -727,6 +706,8 @@ do_scan: default: break; } +done: + xpt_release_ccb(done_ccb); softc->state = PMP_STATE_NORMAL; pmprelease(periph, -1); cam_periph_release_locked(periph); Modified: stable/8/sys/cam/ata/ata_xpt.c ============================================================================== --- stable/8/sys/cam/ata/ata_xpt.c Tue Nov 17 20:41:15 2009 (r199430) +++ stable/8/sys/cam/ata/ata_xpt.c Tue Nov 17 20:43:04 2009 (r199431) @@ -83,7 +83,8 @@ static periph_init_t probe_periph_init; static struct periph_driver probe_driver = { probe_periph_init, "aprobe", - TAILQ_HEAD_INITIALIZER(probe_driver.units) + TAILQ_HEAD_INITIALIZER(probe_driver.units), /* generation */ 0, + CAM_PERIPH_DRV_EARLY }; PERIPHDRIVER_DECLARE(aprobe, probe_driver); @@ -92,6 +93,7 @@ typedef enum { PROBE_RESET, PROBE_IDENTIFY, PROBE_SETMODE, + PROBE_SET_MULTI, PROBE_INQUIRY, PROBE_FULL_INQUIRY, PROBE_PM_PID, @@ -103,6 +105,7 @@ static char *probe_action_text[] = { "PROBE_RESET", "PROBE_IDENTIFY", "PROBE_SETMODE", + "PROBE_SET_MULTI", "PROBE_INQUIRY", "PROBE_FULL_INQUIRY", "PROBE_PM_PID", @@ -282,12 +285,16 @@ probestart(struct cam_periph *periph, un struct ccb_ataio *ataio; struct ccb_scsiio *csio; probe_softc *softc; + struct cam_path *path; + struct ata_params *ident_buf; CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probestart\n")); softc = (probe_softc *)periph->softc; + path = start_ccb->ccb_h.path; ataio = &start_ccb->ataio; csio = &start_ccb->csio; + ident_buf = &periph->path->device->ident_data; switch (softc->action) { case PROBE_RESET: @@ -302,10 +309,6 @@ probestart(struct cam_periph *periph, un ata_reset_cmd(ataio); break; case PROBE_IDENTIFY: - { - struct ata_params *ident_buf = - &periph->path->device->ident_data; - if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) == 0) { /* Prepare check that it is the same device. */ MD5_CTX context; @@ -335,12 +338,7 @@ probestart(struct cam_periph *periph, un else ata_28bit_cmd(ataio, ATA_ATAPI_IDENTIFY, 0, 0, 0); break; - } case PROBE_SETMODE: - { - struct ata_params *ident_buf = - &periph->path->device->ident_data; - cam_fill_ataio(ataio, 1, probedone, @@ -352,6 +350,37 @@ probestart(struct cam_periph *periph, un ata_28bit_cmd(ataio, ATA_SETFEATURES, ATA_SF_SETXFER, 0, ata_max_mode(ident_buf, ATA_UDMA6, ATA_UDMA6)); break; + case PROBE_SET_MULTI: + { + struct ccb_trans_settings cts; + u_int sectors; + + sectors = max(1, min(ident_buf->sectors_intr & 0xff, 16)); + + /* Report bytecount to SIM. */ + bzero(&cts, sizeof(cts)); + xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL); + cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; + cts.type = CTS_TYPE_CURRENT_SETTINGS; + if (path->device->transport == XPORT_ATA) { + cts.xport_specific.ata.bytecount = sectors * 512; + cts.xport_specific.ata.valid = CTS_ATA_VALID_BYTECOUNT; + } else { + cts.xport_specific.sata.bytecount = sectors * 512; + cts.xport_specific.sata.valid = CTS_SATA_VALID_BYTECOUNT; + } + xpt_action((union ccb *)&cts); + + cam_fill_ataio(ataio, + 1, + probedone, + CAM_DIR_NONE, + 0, + NULL, + 0, + 30*1000); + ata_28bit_cmd(ataio, ATA_SET_MULTI, 0, 0, sectors); + break; } case PROBE_INQUIRY: case PROBE_FULL_INQUIRY: @@ -406,7 +435,7 @@ probestart(struct cam_periph *periph, un ata_pm_read_cmd(ataio, 1, 15); break; case PROBE_INVALID: - CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_INFO, + CAM_DEBUG(path, CAM_DEBUG_INFO, ("probestart: invalid action state\n")); default: break; @@ -552,101 +581,119 @@ probedone(struct cam_periph *periph, uni priority = done_ccb->ccb_h.pinfo.priority; ident_buf = &path->device->ident_data; - switch (softc->action) { - case PROBE_RESET: - if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { - int sign = (done_ccb->ataio.res.lba_high << 8) + - done_ccb->ataio.res.lba_mid; - xpt_print(path, "SIGNATURE: %04x\n", sign); - if (sign == 0x0000 && - done_ccb->ccb_h.target_id != 15) { - path->device->protocol = PROTO_ATA; - PROBE_SET_ACTION(softc, PROBE_IDENTIFY); - } else if (sign == 0x9669 && - done_ccb->ccb_h.target_id == 15) { - struct ccb_trans_settings cts; - - /* Report SIM that PM is present. */ - bzero(&cts, sizeof(cts)); - xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL); - cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; - cts.type = CTS_TYPE_CURRENT_SETTINGS; - cts.xport_specific.sata.pm_present = 1; - cts.xport_specific.sata.valid = CTS_SATA_VALID_PM; - xpt_action((union ccb *)&cts); - path->device->protocol = PROTO_SATAPM; - PROBE_SET_ACTION(softc, PROBE_PM_PID); - } else if (sign == 0xeb14 && - done_ccb->ccb_h.target_id != 15) { - path->device->protocol = PROTO_SCSI; - PROBE_SET_ACTION(softc, PROBE_IDENTIFY); - } else { - if (done_ccb->ccb_h.target_id != 15) { - xpt_print(path, - "Unexpected signature 0x%04x\n", sign); - } - goto device_fail; - } - xpt_release_ccb(done_ccb); - xpt_schedule(periph, priority); - return; - } else if (cam_periph_error(done_ccb, 0, 0, - &softc->saved_ccb) == ERESTART) { + if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { +device_fail: if (cam_periph_error(done_ccb, 0, 0, + &softc->saved_ccb) == ERESTART) { return; } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { /* Don't wedge the queue */ xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, /*run_queue*/TRUE); } - goto device_fail; - case PROBE_IDENTIFY: + /* Old PIO2 devices may not support mode setting. */ + if (softc->action == PROBE_SETMODE && + ata_max_pmode(ident_buf) <= ATA_PIO2 && + (ident_buf->capabilities1 & ATA_SUPPORT_IORDY) == 0) + goto noerror; + /* + * If we get to this point, we got an error status back + * from the inquiry and the error status doesn't require + * automatically retrying the command. Therefore, the + * inquiry failed. If we had inquiry information before + * for this device, but this latest inquiry command failed, + * the device has probably gone away. If this device isn't + * already marked unconfigured, notify the peripheral + * drivers that this device is no more. + */ + if ((path->device->flags & CAM_DEV_UNCONFIGURED) == 0) + xpt_async(AC_LOST_DEVICE, path, NULL); + found = 0; + goto done; + } +noerror: + switch (softc->action) { + case PROBE_RESET: { - if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { - int16_t *ptr; + int sign = (done_ccb->ataio.res.lba_high << 8) + + done_ccb->ataio.res.lba_mid; + xpt_print(path, "SIGNATURE: %04x\n", sign); + if (sign == 0x0000 && + done_ccb->ccb_h.target_id != 15) { + path->device->protocol = PROTO_ATA; + PROBE_SET_ACTION(softc, PROBE_IDENTIFY); + } else if (sign == 0x9669 && + done_ccb->ccb_h.target_id == 15) { + struct ccb_trans_settings cts; - for (ptr = (int16_t *)ident_buf; - ptr < (int16_t *)ident_buf + sizeof(struct ata_params)/2; ptr++) { - *ptr = le16toh(*ptr); - } - if (strncmp(ident_buf->model, "FX", 2) && - strncmp(ident_buf->model, "NEC", 3) && - strncmp(ident_buf->model, "Pioneer", 7) && - strncmp(ident_buf->model, "SHARP", 5)) { - ata_bswap(ident_buf->model, sizeof(ident_buf->model)); - ata_bswap(ident_buf->revision, sizeof(ident_buf->revision)); - ata_bswap(ident_buf->serial, sizeof(ident_buf->serial)); - } - ata_btrim(ident_buf->model, sizeof(ident_buf->model)); - ata_bpack(ident_buf->model, ident_buf->model, sizeof(ident_buf->model)); - ata_btrim(ident_buf->revision, sizeof(ident_buf->revision)); - ata_bpack(ident_buf->revision, ident_buf->revision, sizeof(ident_buf->revision)); - ata_btrim(ident_buf->serial, sizeof(ident_buf->serial)); - ata_bpack(ident_buf->serial, ident_buf->serial, sizeof(ident_buf->serial)); - - if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) == 0) { - /* Check that it is the same device. */ - MD5_CTX context; - u_int8_t digest[16]; - - MD5Init(&context); - MD5Update(&context, - (unsigned char *)ident_buf->model, - sizeof(ident_buf->model)); - MD5Update(&context, - (unsigned char *)ident_buf->revision, - sizeof(ident_buf->revision)); - MD5Update(&context, - (unsigned char *)ident_buf->serial, - sizeof(ident_buf->serial)); - MD5Final(digest, &context); - if (bcmp(digest, softc->digest, sizeof(digest))) { - /* Device changed. */ - xpt_async(AC_LOST_DEVICE, path, NULL); - } - xpt_release_ccb(done_ccb); - break; + /* Report SIM that PM is present. */ + bzero(&cts, sizeof(cts)); + xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL); + cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; + cts.type = CTS_TYPE_CURRENT_SETTINGS; + cts.xport_specific.sata.pm_present = 1; + cts.xport_specific.sata.valid = CTS_SATA_VALID_PM; + xpt_action((union ccb *)&cts); + path->device->protocol = PROTO_SATAPM; + PROBE_SET_ACTION(softc, PROBE_PM_PID); + } else if (sign == 0xeb14 && + done_ccb->ccb_h.target_id != 15) { + path->device->protocol = PROTO_SCSI; + PROBE_SET_ACTION(softc, PROBE_IDENTIFY); + } else { + if (done_ccb->ccb_h.target_id != 15) { + xpt_print(path, + "Unexpected signature 0x%04x\n", sign); } + goto device_fail; + } + xpt_release_ccb(done_ccb); + xpt_schedule(periph, priority); + return; + } + case PROBE_IDENTIFY: + { + int16_t *ptr; + + for (ptr = (int16_t *)ident_buf; + ptr < (int16_t *)ident_buf + sizeof(struct ata_params)/2; ptr++) { + *ptr = le16toh(*ptr); + } + if (strncmp(ident_buf->model, "FX", 2) && + strncmp(ident_buf->model, "NEC", 3) && + strncmp(ident_buf->model, "Pioneer", 7) && + strncmp(ident_buf->model, "SHARP", 5)) { + ata_bswap(ident_buf->model, sizeof(ident_buf->model)); + ata_bswap(ident_buf->revision, sizeof(ident_buf->revision)); + ata_bswap(ident_buf->serial, sizeof(ident_buf->serial)); + } + ata_btrim(ident_buf->model, sizeof(ident_buf->model)); + ata_bpack(ident_buf->model, ident_buf->model, sizeof(ident_buf->model)); + ata_btrim(ident_buf->revision, sizeof(ident_buf->revision)); + ata_bpack(ident_buf->revision, ident_buf->revision, sizeof(ident_buf->revision)); + ata_btrim(ident_buf->serial, sizeof(ident_buf->serial)); + ata_bpack(ident_buf->serial, ident_buf->serial, sizeof(ident_buf->serial)); + if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) == 0) { + /* Check that it is the same device. */ + MD5_CTX context; + u_int8_t digest[16]; + + MD5Init(&context); + MD5Update(&context, + (unsigned char *)ident_buf->model, + sizeof(ident_buf->model)); + MD5Update(&context, + (unsigned char *)ident_buf->revision, + sizeof(ident_buf->revision)); + MD5Update(&context, + (unsigned char *)ident_buf->serial, + sizeof(ident_buf->serial)); + MD5Final(digest, &context); + if (bcmp(digest, softc->digest, sizeof(digest))) { + /* Device changed. */ + xpt_async(AC_LOST_DEVICE, path, NULL); + } + } else { /* Clean up from previous instance of this device */ if (path->device->serial_num != NULL) { free(path->device->serial_num, M_CAMXPT); @@ -655,7 +702,7 @@ probedone(struct cam_periph *periph, uni } path->device->serial_num = (u_int8_t *)malloc((sizeof(ident_buf->serial) + 1), - M_CAMXPT, M_NOWAIT); + M_CAMXPT, M_NOWAIT); if (path->device->serial_num != NULL) { bcopy(ident_buf->serial, path->device->serial_num, @@ -667,188 +714,120 @@ probedone(struct cam_periph *periph, uni } path->device->flags |= CAM_DEV_IDENTIFY_DATA_VALID; - ata_device_transport(path); - PROBE_SET_ACTION(softc, PROBE_SETMODE); - xpt_release_ccb(done_ccb); - xpt_schedule(periph, priority); - return; - } else if (cam_periph_error(done_ccb, 0, 0, - &softc->saved_ccb) == ERESTART) { - return; - } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { - /* Don't wedge the queue */ - xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, - /*run_queue*/TRUE); } -device_fail: - /* - * If we get to this point, we got an error status back - * from the inquiry and the error status doesn't require - * automatically retrying the command. Therefore, the - * inquiry failed. If we had inquiry information before - * for this device, but this latest inquiry command failed, - * the device has probably gone away. If this device isn't - * already marked unconfigured, notify the peripheral - * drivers that this device is no more. - */ - if ((path->device->flags & CAM_DEV_UNCONFIGURED) == 0) - xpt_async(AC_LOST_DEVICE, path, NULL); - found = 0; + ata_device_transport(path); + PROBE_SET_ACTION(softc, PROBE_SETMODE); xpt_release_ccb(done_ccb); - break; + xpt_schedule(periph, priority); + return; } case PROBE_SETMODE: - { - if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { -modedone: if (path->device->protocol == PROTO_ATA) { - path->device->flags &= ~CAM_DEV_UNCONFIGURED; - done_ccb->ccb_h.func_code = XPT_GDEV_TYPE; - xpt_action(done_ccb); - xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path, - done_ccb); - xpt_release_ccb(done_ccb); - break; - } else { - PROBE_SET_ACTION(softc, PROBE_INQUIRY); - xpt_release_ccb(done_ccb); - xpt_schedule(periph, priority); - return; - } - } else if (cam_periph_error(done_ccb, 0, 0, - &softc->saved_ccb) == ERESTART) { - return; - } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { - /* Don't wedge the queue */ - xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, - /*run_queue*/TRUE); + if (path->device->protocol == PROTO_ATA) { + PROBE_SET_ACTION(softc, PROBE_SET_MULTI); + } else { + PROBE_SET_ACTION(softc, PROBE_INQUIRY); } - /* Old PIO2 devices may not support mode setting. */ - if (ata_max_pmode(ident_buf) <= ATA_PIO2 && - (ident_buf->capabilities1 & ATA_SUPPORT_IORDY) == 0) - goto modedone; - goto device_fail; - } + xpt_release_ccb(done_ccb); + xpt_schedule(periph, priority); + return; + case PROBE_SET_MULTI: + if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) { + path->device->flags &= ~CAM_DEV_UNCONFIGURED; + done_ccb->ccb_h.func_code = XPT_GDEV_TYPE; + xpt_action(done_ccb); + xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path, + done_ccb); + } + break; case PROBE_INQUIRY: case PROBE_FULL_INQUIRY: { - if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { - struct scsi_inquiry_data *inq_buf; - u_int8_t periph_qual; + struct scsi_inquiry_data *inq_buf; + u_int8_t periph_qual, len; - path->device->flags |= CAM_DEV_INQUIRY_DATA_VALID; *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***