int ata_set_mode(struct ata_drive_datas *drvp, u_int8_t mode, u_int8_t flags) { struct wdc_command wdc_c; WDCDEBUG_PRINT(("%s: mode=0x%x, flags=0x%x\n", __func__, mode, flags), DEBUG_PROBE); bzero(&wdc_c, sizeof(struct wdc_command)); wdc_c.r_command = SET_FEATURES; wdc_c.r_st_bmask = 0; wdc_c.r_st_pmask = 0; wdc_c.r_precomp = WDSF_SET_MODE; wdc_c.r_count = mode; wdc_c.flags = flags; wdc_c.timeout = 1000; /* 1s */ if (wdc_exec_command(drvp, &wdc_c) != WDC_COMPLETE) return CMD_AGAIN; WDCDEBUG_PRINT(("%s: after wdc_exec_command() wdc_c.flags=0x%x\n", __func__, wdc_c.flags), DEBUG_PROBE); if (wdc_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) { return CMD_ERR; } return CMD_OK; }
void wd_standby(struct wd_softc *wd, int flags) { struct wdc_command wdc_c; bzero(&wdc_c, sizeof(struct wdc_command)); wdc_c.r_command = WDCC_STANDBY_IMMED; wdc_c.r_st_bmask = WDCS_DRDY; wdc_c.r_st_pmask = WDCS_DRDY; if (flags != 0) { wdc_c.flags = AT_POLL; } else { wdc_c.flags = AT_WAIT; } wdc_c.timeout = 30000; /* 30s timeout */ if (wdc_exec_command(wd->drvp, &wdc_c) != WDC_COMPLETE) { printf("%s: standby command didn't complete\n", wd->sc_dev.dv_xname); } if (wdc_c.flags & AT_TIMEOU) { printf("%s: standby command timeout\n", wd->sc_dev.dv_xname); } if (wdc_c.flags & AT_DF) { printf("%s: standby command: drive fault\n", wd->sc_dev.dv_xname); } /* * Ignore error register, it shouldn't report anything else * than COMMAND ABORTED, which means the device doesn't support * standby */ }
static int wdc_atapi_get_params(struct scsipi_channel *chan, int drive, struct ataparams *id) { struct wdc_softc *wdc = device_private(chan->chan_adapter->adapt_dev); struct atac_softc *atac = &wdc->sc_atac; struct wdc_regs *wdr = &wdc->regs[chan->chan_channel]; struct ata_channel *chp = atac->atac_channels[chan->chan_channel]; struct ata_command ata_c; memset(&ata_c, 0, sizeof(struct ata_command)); ata_c.r_command = ATAPI_SOFT_RESET; ata_c.r_st_bmask = 0; ata_c.r_st_pmask = 0; ata_c.flags = AT_WAIT | AT_POLL; ata_c.timeout = WDC_RESET_WAIT; if (wdc_exec_command(&chp->ch_drive[drive], &ata_c) != ATACMD_COMPLETE) { printf("wdc_atapi_get_params: ATAPI_SOFT_RESET failed for" " drive %s:%d:%d: driver failed\n", device_xname(atac->atac_dev), chp->ch_channel, drive); panic("wdc_atapi_get_params"); } if (ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) { ATADEBUG_PRINT(("wdc_atapi_get_params: ATAPI_SOFT_RESET " "failed for drive %s:%d:%d: error 0x%x\n", device_xname(atac->atac_dev), chp->ch_channel, drive, ata_c.r_error), DEBUG_PROBE); return -1; } chp->ch_drive[drive].state = 0; (void)bus_space_read_1(wdr->cmd_iot, wdr->cmd_iohs[wd_status], 0); /* Some ATAPI devices need a bit more time after software reset. */ delay(5000); if (ata_get_params(&chp->ch_drive[drive], AT_WAIT, id) != 0) { ATADEBUG_PRINT(("wdc_atapi_get_params: ATAPI_IDENTIFY_DEVICE " "failed for drive %s:%d:%d: error 0x%x\n", device_xname(atac->atac_dev), chp->ch_channel, drive, ata_c.r_error), DEBUG_PROBE); return -1; } return 0; }
void wd_flushcache(struct wd_softc *wd, int flags) { struct wdc_command wdc_c; if (wd->drvp->ata_vers < 4) /* WDCC_FLUSHCACHE is here since ATA-4 */ return; bzero(&wdc_c, sizeof(struct wdc_command)); wdc_c.r_command = (wd->sc_flags & WDF_LBA48 ? WDCC_FLUSHCACHE_EXT : WDCC_FLUSHCACHE); wdc_c.r_st_bmask = WDCS_DRDY; wdc_c.r_st_pmask = WDCS_DRDY; if (flags != 0) { wdc_c.flags = AT_POLL; } else { wdc_c.flags = AT_WAIT; } wdc_c.timeout = 30000; /* 30s timeout */ if (wdc_exec_command(wd->drvp, &wdc_c) != WDC_COMPLETE) { printf("%s: flush cache command didn't complete\n", wd->sc_dev.dv_xname); } if (wdc_c.flags & AT_TIMEOU) { printf("%s: flush cache command timeout\n", wd->sc_dev.dv_xname); } if (wdc_c.flags & AT_DF) { printf("%s: flush cache command: drive fault\n", wd->sc_dev.dv_xname); } /* * Ignore error register, it shouldn't report anything else * than COMMAND ABORTED, which means the device doesn't support * flush cache */ }
/* Get the disk's parameters */ int ata_get_params(struct ata_drive_datas *drvp, u_int8_t flags, struct ataparams *prms) { char tb[ATAPARAMS_SIZE]; struct wdc_command wdc_c; int i; u_int16_t *p; int ret; WDCDEBUG_PRINT(("ata_get_parms\n"), DEBUG_FUNCS); bzero(tb, sizeof(tb)); bzero(&wdc_c, sizeof(struct wdc_command)); if (drvp->drive_flags & DRIVE_ATA) { wdc_c.r_command = WDCC_IDENTIFY; wdc_c.r_st_bmask = WDCS_DRDY; wdc_c.r_st_pmask = 0; wdc_c.timeout = 3000; /* 3s */ } else if (drvp->drive_flags & DRIVE_ATAPI) { wdc_c.r_command = ATAPI_IDENTIFY_DEVICE; wdc_c.r_st_bmask = 0; wdc_c.r_st_pmask = 0; wdc_c.timeout = 10000; /* 10s */ } else { WDCDEBUG_PRINT(("wdc_ata_get_parms: no disks\n"), DEBUG_FUNCS|DEBUG_PROBE); return CMD_ERR; } wdc_c.flags = AT_READ | flags; wdc_c.data = tb; wdc_c.bcount = ATAPARAMS_SIZE; if ((ret = wdc_exec_command(drvp, &wdc_c)) != WDC_COMPLETE) { WDCDEBUG_PRINT(("%s: wdc_exec_command failed: %d\n", __func__, ret), DEBUG_PROBE); return CMD_AGAIN; } if (wdc_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) { WDCDEBUG_PRINT(("%s: IDENTIFY failed: 0x%x\n", __func__, wdc_c.flags), DEBUG_PROBE); return CMD_ERR; } else { #if BYTE_ORDER == BIG_ENDIAN /* All the fields in the params structure are 16-bit integers except for the ID strings which are char strings. The 16-bit integers are currently in memory in little-endian, regardless of architecture. So, they need to be swapped on big-endian architectures before they are accessed through the ataparams structure. The swaps below avoid touching the char strings. */ swap16_multi((u_int16_t *)tb, 10); swap16_multi((u_int16_t *)tb + 20, 3); swap16_multi((u_int16_t *)tb + 47, ATAPARAMS_SIZE / 2 - 47); #endif /* Read in parameter block. */ bcopy(tb, prms, sizeof(struct ataparams)); /* * Shuffle string byte order. * ATAPI Mitsumi and NEC drives don't need this. */ if ((prms->atap_config & WDC_CFG_ATAPI_MASK) == WDC_CFG_ATAPI && ((prms->atap_model[0] == 'N' && prms->atap_model[1] == 'E') || (prms->atap_model[0] == 'F' && prms->atap_model[1] == 'X'))) return CMD_OK; for (i = 0; i < sizeof(prms->atap_model); i += 2) { p = (u_short *)(prms->atap_model + i); *p = swap16(*p); } for (i = 0; i < sizeof(prms->atap_serial); i += 2) { p = (u_short *)(prms->atap_serial + i); *p = swap16(*p); } for (i = 0; i < sizeof(prms->atap_revision); i += 2) { p = (u_short *)(prms->atap_revision + i); *p = swap16(*p); } return CMD_OK; } }
void wdattach(struct device *parent, struct device *self, void *aux) { struct wd_softc *wd = (void *)self; struct ata_atapi_attach *aa_link= aux; struct wdc_command wdc_c; int i, blank; char buf[41], c, *p, *q; WDCDEBUG_PRINT(("wdattach\n"), DEBUG_FUNCS | DEBUG_PROBE); wd->openings = aa_link->aa_openings; wd->drvp = aa_link->aa_drv_data; strlcpy(wd->drvp->drive_name, wd->sc_dev.dv_xname, sizeof(wd->drvp->drive_name)); wd->drvp->cf_flags = wd->sc_dev.dv_cfdata->cf_flags; if ((NERRS_MAX - 2) > 0) wd->drvp->n_dmaerrs = NERRS_MAX - 2; else wd->drvp->n_dmaerrs = 0; /* read our drive info */ if (wd_get_params(wd, at_poll, &wd->sc_params) != 0) { printf("%s: IDENTIFY failed\n", wd->sc_dev.dv_xname); return; } for (blank = 0, p = wd->sc_params.atap_model, q = buf, i = 0; i < sizeof(wd->sc_params.atap_model); i++) { c = *p++; if (c == '\0') break; if (c != ' ') { if (blank) { *q++ = ' '; blank = 0; } *q++ = c; } else blank = 1; } *q++ = '\0'; printf(": <%s>\n", buf); wdc_probe_caps(wd->drvp, &wd->sc_params); wdc_print_caps(wd->drvp); if ((wd->sc_params.atap_multi & 0xff) > 1) { wd->sc_multi = wd->sc_params.atap_multi & 0xff; } else { wd->sc_multi = 1; } printf("%s: %d-sector PIO,", wd->sc_dev.dv_xname, wd->sc_multi); /* use 48-bit LBA if enabled */ /* XXX: shall we use it if drive capacity < 137Gb? */ if ((wd->sc_params.atap_cmd2_en & ATAPI_CMD2_48AD) != 0) wd->sc_flags |= WDF_LBA48; /* Prior to ATA-4, LBA was optional. */ if ((wd->sc_params.atap_capabilities1 & WDC_CAP_LBA) != 0) wd->sc_flags |= WDF_LBA; #if 0 /* ATA-4 requires LBA. */ if (wd->sc_params.atap_ataversion != 0xffff && wd->sc_params.atap_ataversion >= WDC_VER_ATA4) wd->sc_flags |= WDF_LBA; #endif if ((wd->sc_flags & WDF_LBA48) != 0) { wd->sc_capacity = (((u_int64_t)wd->sc_params.atap_max_lba[3] << 48) | ((u_int64_t)wd->sc_params.atap_max_lba[2] << 32) | ((u_int64_t)wd->sc_params.atap_max_lba[1] << 16) | (u_int64_t)wd->sc_params.atap_max_lba[0]); printf(" LBA48, %lluMB, %llu sectors\n", wd->sc_capacity / (1048576 / DEV_BSIZE), wd->sc_capacity); } else if ((wd->sc_flags & WDF_LBA) != 0) { wd->sc_capacity = (wd->sc_params.atap_capacity[1] << 16) | wd->sc_params.atap_capacity[0]; printf(" LBA, %lluMB, %llu sectors\n", wd->sc_capacity / (1048576 / DEV_BSIZE), wd->sc_capacity); } else { wd->sc_capacity = wd->sc_params.atap_cylinders * wd->sc_params.atap_heads * wd->sc_params.atap_sectors; printf(" CHS, %lluMB, %d cyl, %d head, %d sec, %llu sectors\n", wd->sc_capacity / (1048576 / DEV_BSIZE), wd->sc_params.atap_cylinders, wd->sc_params.atap_heads, wd->sc_params.atap_sectors, wd->sc_capacity); } WDCDEBUG_PRINT(("%s: atap_dmatiming_mimi=%d, atap_dmatiming_recom=%d\n", self->dv_xname, wd->sc_params.atap_dmatiming_mimi, wd->sc_params.atap_dmatiming_recom), DEBUG_PROBE); /* use read look ahead if supported */ if (wd->sc_params.atap_cmd_set1 & WDC_CMD1_AHEAD) { bzero(&wdc_c, sizeof(struct wdc_command)); wdc_c.r_command = SET_FEATURES; wdc_c.r_precomp = WDSF_READAHEAD_EN; wdc_c.timeout = 1000; wdc_c.flags = at_poll; if (wdc_exec_command(wd->drvp, &wdc_c) != WDC_COMPLETE) { printf("%s: enable look ahead command didn't " "complete\n", wd->sc_dev.dv_xname); } } /* use write cache if supported */ if (wd->sc_params.atap_cmd_set1 & WDC_CMD1_CACHE) { bzero(&wdc_c, sizeof(struct wdc_command)); wdc_c.r_command = SET_FEATURES; wdc_c.r_precomp = WDSF_EN_WR_CACHE; wdc_c.timeout = 1000; wdc_c.flags = at_poll; if (wdc_exec_command(wd->drvp, &wdc_c) != WDC_COMPLETE) { printf("%s: enable write cache command didn't " "complete\n", wd->sc_dev.dv_xname); } } /* * FREEZE LOCK the drive so malicous users can't lock it on us. * As there is no harm in issuing this to drives that don't * support the security feature set we just send it, and don't * bother checking if the drive sends a command abort to tell us it * doesn't support it. */ bzero(&wdc_c, sizeof(struct wdc_command)); wdc_c.r_command = WDCC_SEC_FREEZE_LOCK; wdc_c.timeout = 1000; wdc_c.flags = at_poll; if (wdc_exec_command(wd->drvp, &wdc_c) != WDC_COMPLETE) { printf("%s: freeze lock command didn't complete\n", wd->sc_dev.dv_xname); } /* * Initialize disk structures. */ wd->sc_dk.dk_name = wd->sc_dev.dv_xname; bufq_init(&wd->sc_bufq, BUFQ_DEFAULT); timeout_set(&wd->sc_restart_timeout, wdrestart, wd); /* Attach disk. */ disk_attach(&wd->sc_dev, &wd->sc_dk); wd->sc_wdc_bio.lp = wd->sc_dk.dk_label; }