diff options
author | Alexander Motin <mav@FreeBSD.org> | 2010-02-03 10:06:03 +0000 |
---|---|---|
committer | Alexander Motin <mav@FreeBSD.org> | 2010-02-03 10:06:03 +0000 |
commit | 4ef08dc5a5420e5619caa313dfd1332110f93264 (patch) | |
tree | e0cd5fcf9ab423607f8ac7eeae819d5fa0a80a9b /sys/cam/ata/ata_xpt.c | |
parent | 6f15a274a84a93f8e2bbd4b0e62a2f57be3da0fa (diff) | |
download | src-4ef08dc5a5420e5619caa313dfd1332110f93264.tar.gz src-4ef08dc5a5420e5619caa313dfd1332110f93264.zip |
MFp4:
Add Power Up In Stand-by feature support. Device with PUIS enabled
require explicit command to do initial spin-up. Mark that command
with CAM_HIGH_POWER flag, to allow CAM manage staggered spin-up.
Notes
Notes:
svn path=/head/; revision=203421
Diffstat (limited to 'sys/cam/ata/ata_xpt.c')
-rw-r--r-- | sys/cam/ata/ata_xpt.c | 38 |
1 files changed, 36 insertions, 2 deletions
diff --git a/sys/cam/ata/ata_xpt.c b/sys/cam/ata/ata_xpt.c index 26fd85806dcd..bbd34bd9c95e 100644 --- a/sys/cam/ata/ata_xpt.c +++ b/sys/cam/ata/ata_xpt.c @@ -86,6 +86,7 @@ PERIPHDRIVER_DECLARE(aprobe, probe_driver); typedef enum { PROBE_RESET, PROBE_IDENTIFY, + PROBE_SPINUP, PROBE_SETMODE, PROBE_SET_MULTI, PROBE_INQUIRY, @@ -98,6 +99,7 @@ typedef enum { static char *probe_action_text[] = { "PROBE_RESET", "PROBE_IDENTIFY", + "PROBE_SPINUP", "PROBE_SETMODE", "PROBE_SET_MULTI", "PROBE_INQUIRY", @@ -129,6 +131,7 @@ typedef struct { uint32_t pm_pid; uint32_t pm_prv; int restart; + int spinup; struct cam_periph *periph; } probe_softc; @@ -212,7 +215,7 @@ proberegister(struct cam_periph *periph, void *arg) return(CAM_REQ_CMP_ERR); } - softc = (probe_softc *)malloc(sizeof(*softc), M_CAMXPT, M_NOWAIT); + softc = (probe_softc *)malloc(sizeof(*softc), M_CAMXPT, M_ZERO | M_NOWAIT); if (softc == NULL) { printf("proberegister: Unable to probe new device. " @@ -314,6 +317,19 @@ probestart(struct cam_periph *periph, union ccb *start_ccb) else ata_28bit_cmd(ataio, ATA_ATAPI_IDENTIFY, 0, 0, 0); break; + case PROBE_SPINUP: + if (bootverbose) + xpt_print(path, "Spinning up device\n"); + cam_fill_ataio(ataio, + 1, + probedone, + /*flags*/CAM_DIR_NONE | CAM_HIGH_POWER, + 0, + /*data_ptr*/NULL, + /*dxfer_len*/0, + 30 * 1000); + ata_28bit_cmd(ataio, ATA_SETFEATURES, ATA_SF_PUIS_SPINUP, 0, 0); + break; case PROBE_SETMODE: { int mode, wantmode; @@ -768,8 +784,18 @@ noerror: 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)); + /* Device may need spin-up before IDENTIFY become valid. */ + if ((ident_buf->config & ATA_RESP_INCOMPLETE) || + ((ident_buf->support.command2 & ATA_SUPPORT_STANDBY) && + (ident_buf->enabled.command2 & ATA_SUPPORT_STANDBY) && + (ident_buf->support.command2 & ATA_SUPPORT_SPINUP) && + softc->spinup == 0)) { + PROBE_SET_ACTION(softc, PROBE_SPINUP); + xpt_release_ccb(done_ccb); + xpt_schedule(periph, priority); + return; + } ident_buf = &path->device->ident_data; - if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) == 0) { /* Check that it is the same device. */ if (bcmp(softc->ident_data.model, ident_buf->model, @@ -829,6 +855,14 @@ noerror: xpt_schedule(periph, priority); return; } + case PROBE_SPINUP: + if (bootverbose) + xpt_print(path, "Spin-up done\n"); + softc->spinup = 1; + PROBE_SET_ACTION(softc, PROBE_IDENTIFY); + xpt_release_ccb(done_ccb); + xpt_schedule(periph, priority); + return; case PROBE_SETMODE: if (path->device->protocol == PROTO_ATA) { PROBE_SET_ACTION(softc, PROBE_SET_MULTI); |