int wdactivate(struct device *self, int act) { struct wd_softc *wd = (void *)self; int rv = 0; switch (act) { case DVACT_SUSPEND: break; case DVACT_POWERDOWN: wd_flushcache(wd, AT_POLL); if (boothowto & RB_POWERDOWN) wd_standby(wd, AT_POLL); break; case DVACT_RESUME: /* * Do two resets separated by a small delay. The * first wakes the controller, the second resets * the channel. */ wdc_disable_intr(wd->drvp->chnl_softc); wdc_reset_channel(wd->drvp, 1); delay(10000); wdc_reset_channel(wd->drvp, 0); wdc_enable_intr(wd->drvp->chnl_softc); wd_get_params(wd, at_poll, &wd->sc_params); break; } return (rv); }
void wdprobe(void) { struct wd_softc *wd = wd_devs; u_int chan, drive, unit = 0; for (chan = 0; chan < PCIIDE_NUM_CHANNELS; chan++) { if (wdc_init(wd, chan) != 0) continue; for (drive = 0; drive < wd->sc_channel.ndrives; drive++) { wd->sc_unit = unit; wd->sc_drive = drive; if (wd_get_params(wd) != 0) continue; DPRINTF(("wd%d: channel %d drive %d\n", unit, chan, drive)); unit++; wd++; } } wd_ndevs = unit; }
/* * Open device (read drive parameters and disklabel) */ int wdopen(struct open_file *f, ...) { int error; va_list ap; u_int ctlr, unit, lunit, part; struct wd_softc *wd; va_start(ap, f); ctlr = va_arg(ap, u_int); unit = va_arg(ap, u_int); lunit = va_arg(ap, u_int); part = va_arg(ap, u_int); va_end(ap); DPRINTF(("wdopen: ide/%d/%s/%d_%d\n", ctlr, (unit == 0) ? "master" : "slave", lunit, part)); if (lunit != 0) return ENOENT; wd = alloc(sizeof(struct wd_softc)); if (wd == NULL) return ENOMEM; memset(wd, 0, sizeof(struct wd_softc)); wd->sc_part = part; wd->sc_unit = unit; wd->sc_ctlr = ctlr; if ((error = wd_get_params(wd)) != 0) return error; if ((error = wdgetdisklabel(wd)) != 0) return error; f->f_devdata = wd; return 0; }
/* * Open device (read drive parameters and disklabel) */ int wdopen(struct open_file *f, ...) { int error; va_list ap; u_int unit, part; struct wd_softc *wd; va_start(ap, f); unit = va_arg(ap, u_int); part = va_arg(ap, u_int); va_end(ap); DPRINTF(("wdopen: %d:%d\n", unit, part)); wd = alloc(sizeof(struct wd_softc)); if (wd == NULL) return ENOMEM; memset(wd, 0, sizeof(struct wd_softc)); if (wdc_init(wd, &unit) != 0) return (ENXIO); wd->sc_part = part; wd->sc_unit = unit; if ((error = wd_get_params(wd)) != 0) return error; if ((error = wdgetdisklabel(wd)) != 0) return error; f->f_devdata = wd; return 0; }
int wdopen(dev_t dev, int flag, int fmt, struct proc *p) { struct wd_softc *wd; struct channel_softc *chnl; int unit, part; int error; WDCDEBUG_PRINT(("wdopen\n"), DEBUG_FUNCS); unit = DISKUNIT(dev); wd = wdlookup(unit); if (wd == NULL) return ENXIO; chnl = (struct channel_softc *)(wd->drvp->chnl_softc); if (chnl->dying) return (ENXIO); /* * If this is the first open of this device, add a reference * to the adapter. */ if ((error = disk_lock(&wd->sc_dk)) != 0) goto bad4; if (wd->sc_dk.dk_openmask != 0) { /* * If any partition is open, but the disk has been invalidated, * disallow further opens. */ if ((wd->sc_flags & WDF_LOADED) == 0) { error = EIO; goto bad3; } } else { if ((wd->sc_flags & WDF_LOADED) == 0) { wd->sc_flags |= WDF_LOADED; /* Load the physical device parameters. */ wd_get_params(wd, AT_WAIT, &wd->sc_params); /* Load the partition info if not already loaded. */ if (wdgetdisklabel(dev, wd, wd->sc_dk.dk_label, 0) == EIO) { error = EIO; goto bad; } } } part = DISKPART(dev); if ((error = disk_openpart(&wd->sc_dk, part, fmt, 1)) != 0) goto bad; disk_unlock(&wd->sc_dk); device_unref(&wd->sc_dev); return 0; bad: if (wd->sc_dk.dk_openmask == 0) { } bad3: disk_unlock(&wd->sc_dk); bad4: device_unref(&wd->sc_dev); return error; }
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; }