1*a8b58197Sjsg /* $OpenBSD: octcf.c,v 1.36 2024/05/20 23:13:33 jsg Exp $ */
215d647adSsyuu /* $NetBSD: wd.c,v 1.193 1999/02/28 17:15:27 explorer Exp $ */
315d647adSsyuu
415d647adSsyuu /*
515d647adSsyuu * Copyright (c) 1998, 2001 Manuel Bouyer. All rights reserved.
615d647adSsyuu *
715d647adSsyuu * Redistribution and use in source and binary forms, with or without
815d647adSsyuu * modification, are permitted provided that the following conditions
915d647adSsyuu * are met:
1015d647adSsyuu * 1. Redistributions of source code must retain the above copyright
1115d647adSsyuu * notice, this list of conditions and the following disclaimer.
1215d647adSsyuu * 2. Redistributions in binary form must reproduce the above copyright
1315d647adSsyuu * notice, this list of conditions and the following disclaimer in the
1415d647adSsyuu * documentation and/or other materials provided with the distribution.
1515d647adSsyuu *
1615d647adSsyuu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1715d647adSsyuu * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1815d647adSsyuu * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1915d647adSsyuu * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2015d647adSsyuu * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2115d647adSsyuu * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2215d647adSsyuu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2315d647adSsyuu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2415d647adSsyuu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2515d647adSsyuu * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2615d647adSsyuu */
2715d647adSsyuu
2815d647adSsyuu /*-
2915d647adSsyuu * Copyright (c) 1998 The NetBSD Foundation, Inc.
3015d647adSsyuu * All rights reserved.
3115d647adSsyuu *
3215d647adSsyuu * This code is derived from software contributed to The NetBSD Foundation
3315d647adSsyuu * by Charles M. Hannum and by Onno van der Linden.
3415d647adSsyuu *
3515d647adSsyuu * Redistribution and use in source and binary forms, with or without
3615d647adSsyuu * modification, are permitted provided that the following conditions
3715d647adSsyuu * are met:
3815d647adSsyuu * 1. Redistributions of source code must retain the above copyright
3915d647adSsyuu * notice, this list of conditions and the following disclaimer.
4015d647adSsyuu * 2. Redistributions in binary form must reproduce the above copyright
4115d647adSsyuu * notice, this list of conditions and the following disclaimer in the
4215d647adSsyuu * documentation and/or other materials provided with the distribution.
4315d647adSsyuu *
4415d647adSsyuu * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
4515d647adSsyuu * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
4615d647adSsyuu * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
4715d647adSsyuu * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
4815d647adSsyuu * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
4915d647adSsyuu * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
5015d647adSsyuu * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
5115d647adSsyuu * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
5215d647adSsyuu * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
5315d647adSsyuu * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
5415d647adSsyuu * POSSIBILITY OF SUCH DAMAGE.
5515d647adSsyuu */
5615d647adSsyuu
5715d647adSsyuu #include <sys/param.h>
5815d647adSsyuu #include <sys/systm.h>
5915d647adSsyuu #include <sys/kernel.h>
6015d647adSsyuu #include <sys/conf.h>
61c0cd3489Sguenther #include <sys/fcntl.h>
6215d647adSsyuu #include <sys/stat.h>
6315d647adSsyuu #include <sys/ioctl.h>
6415d647adSsyuu #include <sys/mutex.h>
6515d647adSsyuu #include <sys/buf.h>
6615d647adSsyuu #include <sys/uio.h>
6715d647adSsyuu #include <sys/malloc.h>
6815d647adSsyuu #include <sys/device.h>
6915d647adSsyuu #include <sys/disklabel.h>
7015d647adSsyuu #include <sys/disk.h>
7115d647adSsyuu #include <sys/syslog.h>
7215d647adSsyuu #include <sys/proc.h>
7315d647adSsyuu #include <sys/vnode.h>
7415d647adSsyuu #include <sys/dkio.h>
7515d647adSsyuu
7615d647adSsyuu #include <machine/intr.h>
7715d647adSsyuu #include <machine/bus.h>
7815d647adSsyuu
7915d647adSsyuu #include <dev/ata/atareg.h>
8015d647adSsyuu #include <dev/ata/atavar.h>
8115d647adSsyuu #include <dev/ic/wdcreg.h>
8215d647adSsyuu #include <dev/ic/wdcvar.h>
8315d647adSsyuu
8461e15267Ssyuu #include <octeon/dev/iobusvar.h>
85a81120d9Sjasper #include <machine/octeonreg.h>
867b0d27bbSjasper #include <machine/octeonvar.h>
8715d647adSsyuu
8815d647adSsyuu #define OCTCF_REG_SIZE 8
8915d647adSsyuu #define ATAPARAMS_SIZE 512
9015d647adSsyuu #define SECTOR_SIZE 512
9115d647adSsyuu #define OCTCFDELAY 100 /* 100 microseconds */
9215d647adSsyuu #define NR_TRIES 1000
9315d647adSsyuu
9415d647adSsyuu #define DEBUG_XFERS 0x02
9515d647adSsyuu #define DEBUG_FUNCS 0x08
9615d647adSsyuu #define DEBUG_PROBE 0x10
9715d647adSsyuu
9815d647adSsyuu #ifdef OCTCFDEBUG
9915d647adSsyuu int octcfdebug_mask = 0xff;
10015d647adSsyuu #define OCTCFDEBUG_PRINT(args, level) do { \
10115d647adSsyuu if ((octcfdebug_mask & (level)) != 0) \
10215d647adSsyuu printf args; \
10315d647adSsyuu } while (0)
10415d647adSsyuu #else
10515d647adSsyuu #define OCTCFDEBUG_PRINT(args, level)
10615d647adSsyuu #endif
10715d647adSsyuu
10815d647adSsyuu struct octcf_softc {
10915d647adSsyuu /* General disk infos */
11015d647adSsyuu struct device sc_dev;
11115d647adSsyuu struct disk sc_dk;
112e18446e2Sdlg struct bufq sc_bufq;
11315d647adSsyuu struct buf *sc_bp;
11415d647adSsyuu struct ataparams sc_params;/* drive characteristics found */
11515d647adSsyuu int sc_flags;
11615d647adSsyuu #define OCTCFF_LOADED 0x10 /* parameters loaded */
11715d647adSsyuu u_int64_t sc_capacity;
11815d647adSsyuu bus_space_tag_t sc_iot;
11915d647adSsyuu bus_space_handle_t sc_ioh;
12015d647adSsyuu };
12115d647adSsyuu
12215d647adSsyuu int octcfprobe(struct device *, void *, void *);
12315d647adSsyuu void octcfattach(struct device *, struct device *, void *);
12415d647adSsyuu int octcfdetach(struct device *, int);
12515d647adSsyuu int octcfactivate(struct device *, int);
12615d647adSsyuu
127471aeecfSnaddy const struct cfattach octcf_ca = {
12815d647adSsyuu sizeof(struct octcf_softc), octcfprobe, octcfattach,
12915d647adSsyuu octcfdetach, octcfactivate
13015d647adSsyuu };
13115d647adSsyuu
13215d647adSsyuu struct cfdriver octcf_cd = {
13315d647adSsyuu NULL, "octcf", DV_DISK
13415d647adSsyuu };
13515d647adSsyuu
13615d647adSsyuu void octcfgetdefaultlabel(struct octcf_softc *, struct disklabel *);
13715d647adSsyuu int octcfgetdisklabel(dev_t dev, struct octcf_softc *, struct disklabel *, int);
13815d647adSsyuu void octcfstrategy(struct buf *);
13915d647adSsyuu void octcfstart(void *);
14015d647adSsyuu void _octcfstart(struct octcf_softc*, struct buf *);
14115d647adSsyuu void octcfdone(void *);
14215d647adSsyuu
14315d647adSsyuu cdev_decl(octcf);
14415d647adSsyuu bdev_decl(octcf);
14515d647adSsyuu
14615d647adSsyuu #define octcflookup(unit) (struct octcf_softc *)disk_lookup(&octcf_cd, (unit))
14715d647adSsyuu
14815d647adSsyuu int octcf_write_sectors(struct octcf_softc *, uint32_t, uint32_t, void *);
14915d647adSsyuu int octcf_read_sectors(struct octcf_softc *, uint32_t, uint32_t, void *);
15015d647adSsyuu int octcf_wait_busy(struct octcf_softc *);
15115d647adSsyuu void octcf_command(struct octcf_softc *, uint32_t, uint8_t);
15215d647adSsyuu int octcf_get_params(struct octcf_softc *, struct ataparams *);
15315d647adSsyuu
15415d647adSsyuu #define OCTCF_REG_READ(wd, reg) \
15515d647adSsyuu bus_space_read_2(wd->sc_iot, wd->sc_ioh, reg & 0x6)
15615d647adSsyuu #define OCTCF_REG_WRITE(wd, reg, val) \
15715d647adSsyuu bus_space_write_2(wd->sc_iot, wd->sc_ioh, reg & 0x6, val)
15815d647adSsyuu
15915d647adSsyuu int
octcfprobe(struct device * parent,void * match,void * aux)1607b0d27bbSjasper octcfprobe(struct device *parent, void *match, void *aux)
16115d647adSsyuu {
1625a60bedeSjasper if (octeon_boot_info->cf_common_addr == 0) {
1636aa96c80Sjasper OCTCFDEBUG_PRINT(("%s: No cf bus found\n", __func__), DEBUG_FUNCS | DEBUG_PROBE);
1647b0d27bbSjasper return 0;
1657b0d27bbSjasper }
1667b0d27bbSjasper
16715d647adSsyuu return 1;
16815d647adSsyuu }
16915d647adSsyuu
17015d647adSsyuu void
octcfattach(struct device * parent,struct device * self,void * aux)17115d647adSsyuu octcfattach(struct device *parent, struct device *self, void *aux)
17215d647adSsyuu {
17315d647adSsyuu struct octcf_softc *wd = (void *)self;
17461e15267Ssyuu struct iobus_attach_args *aa = aux;
17515d647adSsyuu int i, blank;
17615d647adSsyuu char buf[41], c, *p, *q;
17715d647adSsyuu uint8_t status;
178bcdc9b57Sjasper OCTCFDEBUG_PRINT(("%s\n", __func__), DEBUG_FUNCS | DEBUG_PROBE);
17915d647adSsyuu
18061e15267Ssyuu wd->sc_iot = aa->aa_bust;
18115d647adSsyuu
18273a9bee3Sjasper if (bus_space_map(wd->sc_iot, aa->aa_addr,
18315d647adSsyuu OCTCF_REG_SIZE, BUS_SPACE_MAP_KSEG0, &wd->sc_ioh)) {
18415d647adSsyuu printf(": couldn't map registers\n");
18515d647adSsyuu return;
18615d647adSsyuu }
18715d647adSsyuu
18815d647adSsyuu for (i = 0; i < 8; i++) {
18915d647adSsyuu uint64_t cfg =
19015d647adSsyuu *(uint64_t *)PHYS_TO_XKPHYS(
19115d647adSsyuu OCTEON_MIO_BOOT_BASE + MIO_BOOT_REG_CFG(i), CCA_NC);
19215d647adSsyuu
19315d647adSsyuu if ((cfg & BOOT_CFG_BASE_MASK) ==
19415d647adSsyuu (OCTEON_CF_BASE >> BOOT_CFG_BASE_SHIFT)) {
19515d647adSsyuu if ((cfg & BOOT_CFG_WIDTH_MASK) == 0)
1962e257b1fSjasper printf(": doesn't support 8bit cards\n");
19715d647adSsyuu break;
19815d647adSsyuu }
19915d647adSsyuu }
20015d647adSsyuu
20115d647adSsyuu /* Check if CF is inserted */
20215d647adSsyuu i = 0;
20315d647adSsyuu while ( (status = (OCTCF_REG_READ(wd, wdr_status)>>8)) & WDCS_BSY) {
20415d647adSsyuu if ((i++) == NR_TRIES ) {
205f47f0c33Sjasper printf(": card not present\n");
20615d647adSsyuu return;
20715d647adSsyuu }
20815d647adSsyuu DELAY(OCTCFDELAY);
20915d647adSsyuu }
21015d647adSsyuu
21115d647adSsyuu /* read our drive info */
21215d647adSsyuu if (octcf_get_params(wd, &wd->sc_params) != 0) {
213f47f0c33Sjasper printf(": IDENTIFY failed\n");
21415d647adSsyuu return;
21515d647adSsyuu }
21615d647adSsyuu
21715d647adSsyuu for (blank = 0, p = wd->sc_params.atap_model, q = buf, i = 0;
21815d647adSsyuu i < sizeof(wd->sc_params.atap_model); i++) {
21915d647adSsyuu c = *p++;
22015d647adSsyuu if (c == '\0')
22115d647adSsyuu break;
22215d647adSsyuu if (c != ' ') {
22315d647adSsyuu if (blank) {
22415d647adSsyuu *q++ = ' ';
22515d647adSsyuu blank = 0;
22615d647adSsyuu }
22715d647adSsyuu *q++ = c;
22815d647adSsyuu } else
22915d647adSsyuu blank = 1;
23015d647adSsyuu }
23115d647adSsyuu *q++ = '\0';
23215d647adSsyuu
23315d647adSsyuu printf(": <%s>\n", buf);
23415d647adSsyuu printf("%s: %d-sector PIO,",
23515d647adSsyuu wd->sc_dev.dv_xname, wd->sc_params.atap_multi & 0xff);
23615d647adSsyuu
23715d647adSsyuu wd->sc_capacity =
23815d647adSsyuu wd->sc_params.atap_cylinders *
23915d647adSsyuu wd->sc_params.atap_heads *
24015d647adSsyuu wd->sc_params.atap_sectors;
24115d647adSsyuu printf(" CHS, %lluMB, %d cyl, %d head, %d sec, %llu sectors\n",
24215d647adSsyuu wd->sc_capacity / (1048576 / DEV_BSIZE),
24315d647adSsyuu wd->sc_params.atap_cylinders,
24415d647adSsyuu wd->sc_params.atap_heads,
24515d647adSsyuu wd->sc_params.atap_sectors,
24615d647adSsyuu wd->sc_capacity);
24715d647adSsyuu
24815d647adSsyuu OCTCFDEBUG_PRINT(
24915d647adSsyuu ("%s: atap_dmatiming_mimi=%d, atap_dmatiming_recom=%d\n",
25015d647adSsyuu self->dv_xname, wd->sc_params.atap_dmatiming_mimi,
25115d647adSsyuu wd->sc_params.atap_dmatiming_recom), DEBUG_PROBE);
25215d647adSsyuu
25315d647adSsyuu /*
25415d647adSsyuu * Initialize disk structures.
25515d647adSsyuu */
25615d647adSsyuu wd->sc_dk.dk_name = wd->sc_dev.dv_xname;
257e18446e2Sdlg bufq_init(&wd->sc_bufq, BUFQ_DEFAULT);
25815d647adSsyuu
25915d647adSsyuu /* Attach disk. */
26015d647adSsyuu disk_attach(&wd->sc_dev, &wd->sc_dk);
26115d647adSsyuu }
26215d647adSsyuu
26315d647adSsyuu int
octcfactivate(struct device * self,int act)26415d647adSsyuu octcfactivate(struct device *self, int act)
26515d647adSsyuu {
26615d647adSsyuu return 0;
26715d647adSsyuu }
26815d647adSsyuu
26915d647adSsyuu int
octcfdetach(struct device * self,int flags)27015d647adSsyuu octcfdetach(struct device *self, int flags)
27115d647adSsyuu {
27215d647adSsyuu struct octcf_softc *sc = (struct octcf_softc *)self;
27315d647adSsyuu
274f88331f5Sjasper bufq_drain(&sc->sc_bufq);
275f88331f5Sjasper
2767d3d57aeSjasper disk_gone(octcfopen, self->dv_unit);
27715d647adSsyuu
27815d647adSsyuu /* Detach disk. */
279f88331f5Sjasper bufq_destroy(&sc->sc_bufq);
28015d647adSsyuu disk_detach(&sc->sc_dk);
28115d647adSsyuu
28215d647adSsyuu return (0);
28315d647adSsyuu }
28415d647adSsyuu
28515d647adSsyuu /*
28615d647adSsyuu * Read/write routine for a buffer. Validates the arguments and schedules the
28715d647adSsyuu * transfer. Does not wait for the transfer to complete.
28815d647adSsyuu */
28915d647adSsyuu void
octcfstrategy(struct buf * bp)29015d647adSsyuu octcfstrategy(struct buf *bp)
29115d647adSsyuu {
29215d647adSsyuu struct octcf_softc *wd;
29315d647adSsyuu int s;
29415d647adSsyuu
29515d647adSsyuu wd = octcflookup(DISKUNIT(bp->b_dev));
29615d647adSsyuu if (wd == NULL) {
29715d647adSsyuu bp->b_error = ENXIO;
29815d647adSsyuu goto bad;
29915d647adSsyuu }
300bdbc4c90Sjasper
3016aa96c80Sjasper OCTCFDEBUG_PRINT(("%s (%s)\n", __func__, wd->sc_dev.dv_xname),
30215d647adSsyuu DEBUG_XFERS);
303bdbc4c90Sjasper
30415d647adSsyuu /* If device invalidated (e.g. media change, door open), error. */
30515d647adSsyuu if ((wd->sc_flags & OCTCFF_LOADED) == 0) {
30615d647adSsyuu bp->b_error = EIO;
30715d647adSsyuu goto bad;
30815d647adSsyuu }
309d1e5b14cSmatthew
310d1e5b14cSmatthew /* Validate the request. */
311d1e5b14cSmatthew if (bounds_check_with_label(bp, wd->sc_dk.dk_label) == -1)
31215d647adSsyuu goto done;
313d1e5b14cSmatthew
314d1e5b14cSmatthew /* Check that the number of sectors can fit in a byte. */
315d1e5b14cSmatthew if ((bp->b_bcount / wd->sc_dk.dk_label->d_secsize) >= (1 << NBBY)) {
316d1e5b14cSmatthew bp->b_error = EINVAL;
317d1e5b14cSmatthew goto bad;
318d1e5b14cSmatthew }
319d1e5b14cSmatthew
32015d647adSsyuu /* Queue transfer on drive, activate drive and controller if idle. */
321bdbc4c90Sjasper bufq_queue(&wd->sc_bufq, bp);
32215d647adSsyuu s = splbio();
32315d647adSsyuu octcfstart(wd);
32415d647adSsyuu splx(s);
32515d647adSsyuu device_unref(&wd->sc_dev);
32615d647adSsyuu return;
327d1e5b14cSmatthew
32815d647adSsyuu bad:
32915d647adSsyuu bp->b_flags |= B_ERROR;
33015d647adSsyuu bp->b_resid = bp->b_bcount;
331d1e5b14cSmatthew done:
33215d647adSsyuu s = splbio();
33315d647adSsyuu biodone(bp);
33415d647adSsyuu splx(s);
33515d647adSsyuu if (wd != NULL)
33615d647adSsyuu device_unref(&wd->sc_dev);
33715d647adSsyuu }
33815d647adSsyuu
33915d647adSsyuu /*
34015d647adSsyuu * Queue a drive for I/O.
34115d647adSsyuu */
34215d647adSsyuu void
octcfstart(void * arg)34315d647adSsyuu octcfstart(void *arg)
34415d647adSsyuu {
34515d647adSsyuu struct octcf_softc *wd = arg;
346e18446e2Sdlg struct buf *bp;
34715d647adSsyuu
3486aa96c80Sjasper OCTCFDEBUG_PRINT(("%s %s\n", __func__, wd->sc_dev.dv_xname),
34915d647adSsyuu DEBUG_XFERS);
350e18446e2Sdlg while ((bp = bufq_dequeue(&wd->sc_bufq)) != NULL) {
35115d647adSsyuu /* Transfer this buffer now. */
35215d647adSsyuu _octcfstart(wd, bp);
35315d647adSsyuu }
35415d647adSsyuu }
35515d647adSsyuu
35615d647adSsyuu void
_octcfstart(struct octcf_softc * wd,struct buf * bp)35715d647adSsyuu _octcfstart(struct octcf_softc *wd, struct buf *bp)
35815d647adSsyuu {
359e2c089e9Skrw struct disklabel *lp;
360e2c089e9Skrw u_int64_t secno;
361e2c089e9Skrw u_int64_t nsecs;
36215d647adSsyuu
363e2c089e9Skrw lp = wd->sc_dk.dk_label;
364e2c089e9Skrw secno = DL_BLKTOSEC(lp, bp->b_blkno) +
3652815088fSpirofti DL_GETPOFFSET(&lp->d_partitions[DISKPART(bp->b_dev)]);
366d6c3af46Skrw nsecs = howmany(bp->b_bcount, lp->d_secsize);
36715d647adSsyuu wd->sc_bp = bp;
36815d647adSsyuu
36915d647adSsyuu /* Instrumentation. */
37015d647adSsyuu disk_busy(&wd->sc_dk);
37115d647adSsyuu
37215d647adSsyuu if (bp->b_flags & B_READ)
373e2c089e9Skrw bp->b_error = octcf_read_sectors(wd, nsecs, secno, bp->b_data);
37415d647adSsyuu else
375e2c089e9Skrw bp->b_error = octcf_write_sectors(wd, nsecs, secno, bp->b_data);
37615d647adSsyuu
37715d647adSsyuu octcfdone(wd);
37815d647adSsyuu }
37915d647adSsyuu
38015d647adSsyuu void
octcfdone(void * arg)38115d647adSsyuu octcfdone(void *arg)
38215d647adSsyuu {
38315d647adSsyuu struct octcf_softc *wd = arg;
38415d647adSsyuu struct buf *bp = wd->sc_bp;
38515d647adSsyuu
38615d647adSsyuu if (bp->b_error == 0)
38715d647adSsyuu bp->b_resid = 0;
38815d647adSsyuu else
38915d647adSsyuu bp->b_flags |= B_ERROR;
39015d647adSsyuu
39115d647adSsyuu disk_unbusy(&wd->sc_dk, (bp->b_bcount - bp->b_resid),
392d40269afSderaadt bp->b_blkno, (bp->b_flags & B_READ));
39315d647adSsyuu biodone(bp);
39415d647adSsyuu }
39515d647adSsyuu
39615d647adSsyuu int
octcfread(dev_t dev,struct uio * uio,int flags)39715d647adSsyuu octcfread(dev_t dev, struct uio *uio, int flags)
39815d647adSsyuu {
39915d647adSsyuu
4006aa96c80Sjasper OCTCFDEBUG_PRINT(("%s\n", __func__), DEBUG_XFERS);
40115d647adSsyuu return (physio(octcfstrategy, dev, B_READ, minphys, uio));
40215d647adSsyuu }
40315d647adSsyuu
40415d647adSsyuu int
octcfwrite(dev_t dev,struct uio * uio,int flags)40515d647adSsyuu octcfwrite(dev_t dev, struct uio *uio, int flags)
40615d647adSsyuu {
40715d647adSsyuu
4086aa96c80Sjasper OCTCFDEBUG_PRINT(("%s\n", __func__), DEBUG_XFERS);
40915d647adSsyuu return (physio(octcfstrategy, dev, B_WRITE, minphys, uio));
41015d647adSsyuu }
41115d647adSsyuu
41215d647adSsyuu int
octcfopen(dev_t dev,int flag,int fmt,struct proc * p)41315d647adSsyuu octcfopen(dev_t dev, int flag, int fmt, struct proc *p)
41415d647adSsyuu {
41515d647adSsyuu struct octcf_softc *wd;
41615d647adSsyuu int unit, part;
41715d647adSsyuu int error;
41815d647adSsyuu
4196aa96c80Sjasper OCTCFDEBUG_PRINT(("%s\n", __func__), DEBUG_FUNCS);
42015d647adSsyuu
42115d647adSsyuu unit = DISKUNIT(dev);
42215d647adSsyuu wd = octcflookup(unit);
42315d647adSsyuu if (wd == NULL)
42415d647adSsyuu return ENXIO;
42515d647adSsyuu
42615d647adSsyuu /*
42715d647adSsyuu * If this is the first open of this device, add a reference
42815d647adSsyuu * to the adapter.
42915d647adSsyuu */
43085bbddc9Sderaadt if ((error = disk_lock(&wd->sc_dk)) != 0)
43115d647adSsyuu goto bad4;
43215d647adSsyuu
43315d647adSsyuu if (wd->sc_dk.dk_openmask != 0) {
43415d647adSsyuu /*
43515d647adSsyuu * If any partition is open, but the disk has been invalidated,
43615d647adSsyuu * disallow further opens.
43715d647adSsyuu */
43815d647adSsyuu if ((wd->sc_flags & OCTCFF_LOADED) == 0) {
43915d647adSsyuu error = EIO;
44015d647adSsyuu goto bad3;
44115d647adSsyuu }
44215d647adSsyuu } else {
44315d647adSsyuu if ((wd->sc_flags & OCTCFF_LOADED) == 0) {
44415d647adSsyuu wd->sc_flags |= OCTCFF_LOADED;
44515d647adSsyuu
44615d647adSsyuu /* Load the physical device parameters. */
44715d647adSsyuu octcf_get_params(wd, &wd->sc_params);
44815d647adSsyuu
44915d647adSsyuu /* Load the partition info if not already loaded. */
45015d647adSsyuu if (octcfgetdisklabel(dev, wd,
45115d647adSsyuu wd->sc_dk.dk_label, 0) == EIO) {
45215d647adSsyuu error = EIO;
45315d647adSsyuu goto bad;
45415d647adSsyuu }
45515d647adSsyuu }
45615d647adSsyuu }
45715d647adSsyuu
45815d647adSsyuu part = DISKPART(dev);
4592e257b1fSjasper
4607d3d57aeSjasper if ((error = disk_openpart(&wd->sc_dk, part, fmt, 1)) != 0)
46115d647adSsyuu goto bad;
46215d647adSsyuu
46385bbddc9Sderaadt disk_unlock(&wd->sc_dk);
46415d647adSsyuu device_unref(&wd->sc_dev);
46515d647adSsyuu return 0;
46615d647adSsyuu
46715d647adSsyuu bad:
46815d647adSsyuu if (wd->sc_dk.dk_openmask == 0) {
46915d647adSsyuu }
47015d647adSsyuu
47115d647adSsyuu bad3:
47285bbddc9Sderaadt disk_unlock(&wd->sc_dk);
47315d647adSsyuu bad4:
47415d647adSsyuu device_unref(&wd->sc_dev);
47515d647adSsyuu return error;
47615d647adSsyuu }
47715d647adSsyuu
47815d647adSsyuu int
octcfclose(dev_t dev,int flag,int fmt,struct proc * p)47915d647adSsyuu octcfclose(dev_t dev, int flag, int fmt, struct proc *p)
48015d647adSsyuu {
48115d647adSsyuu struct octcf_softc *wd;
48215d647adSsyuu int part = DISKPART(dev);
48315d647adSsyuu
48415d647adSsyuu wd = octcflookup(DISKUNIT(dev));
48515d647adSsyuu if (wd == NULL)
48615d647adSsyuu return ENXIO;
48715d647adSsyuu
4886aa96c80Sjasper OCTCFDEBUG_PRINT(("%s\n", __func__), DEBUG_FUNCS);
4895f30bcfcSderaadt
4905f30bcfcSderaadt disk_lock_nointr(&wd->sc_dk);
49115d647adSsyuu
4927d3d57aeSjasper disk_closepart(&wd->sc_dk, part, fmt);
49315d647adSsyuu
49485bbddc9Sderaadt disk_unlock(&wd->sc_dk);
49515d647adSsyuu
49615d647adSsyuu device_unref(&wd->sc_dev);
4975f30bcfcSderaadt return (0);
49815d647adSsyuu }
49915d647adSsyuu
50015d647adSsyuu void
octcfgetdefaultlabel(struct octcf_softc * wd,struct disklabel * lp)50115d647adSsyuu octcfgetdefaultlabel(struct octcf_softc *wd, struct disklabel *lp)
50215d647adSsyuu {
5036aa96c80Sjasper OCTCFDEBUG_PRINT(("%s\n", __func__), DEBUG_FUNCS);
50415d647adSsyuu bzero(lp, sizeof(struct disklabel));
50515d647adSsyuu
50615d647adSsyuu lp->d_secsize = DEV_BSIZE;
50715d647adSsyuu DL_SETDSIZE(lp, wd->sc_capacity);
50815d647adSsyuu lp->d_ntracks = wd->sc_params.atap_heads;
50915d647adSsyuu lp->d_nsectors = wd->sc_params.atap_sectors;
51015d647adSsyuu lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
51115d647adSsyuu lp->d_ncylinders = DL_GETDSIZE(lp) / lp->d_secpercyl;
51215d647adSsyuu lp->d_type = DTYPE_ESDI;
51315d647adSsyuu strncpy(lp->d_typename, "ESDI/IDE disk", sizeof lp->d_typename);
51415d647adSsyuu
51515d647adSsyuu /* XXX - user viscopy() like sd.c */
51615d647adSsyuu strncpy(lp->d_packname, wd->sc_params.atap_model, sizeof lp->d_packname);
51715d647adSsyuu lp->d_version = 1;
51815d647adSsyuu
51915d647adSsyuu lp->d_magic = DISKMAGIC;
52015d647adSsyuu lp->d_magic2 = DISKMAGIC;
52115d647adSsyuu lp->d_checksum = dkcksum(lp);
52215d647adSsyuu }
52315d647adSsyuu
52415d647adSsyuu /*
52515d647adSsyuu * Fabricate a default disk label, and try to read the correct one.
52615d647adSsyuu */
52715d647adSsyuu int
octcfgetdisklabel(dev_t dev,struct octcf_softc * wd,struct disklabel * lp,int spoofonly)52815d647adSsyuu octcfgetdisklabel(dev_t dev, struct octcf_softc *wd, struct disklabel *lp,
52915d647adSsyuu int spoofonly)
53015d647adSsyuu {
53115d647adSsyuu int error;
53215d647adSsyuu
5336aa96c80Sjasper OCTCFDEBUG_PRINT(("%s\n", __func__), DEBUG_FUNCS);
53415d647adSsyuu
53515d647adSsyuu octcfgetdefaultlabel(wd, lp);
53615d647adSsyuu error = readdisklabel(DISKLABELDEV(dev), octcfstrategy, lp,
53715d647adSsyuu spoofonly);
53815d647adSsyuu return (error);
53915d647adSsyuu }
54015d647adSsyuu
54115d647adSsyuu int
octcfioctl(dev_t dev,u_long xfer,caddr_t addr,int flag,struct proc * p)54215d647adSsyuu octcfioctl(dev_t dev, u_long xfer, caddr_t addr, int flag, struct proc *p)
54315d647adSsyuu {
54415d647adSsyuu struct octcf_softc *wd;
54515d647adSsyuu struct disklabel *lp;
54615d647adSsyuu int error = 0;
54715d647adSsyuu
5486aa96c80Sjasper OCTCFDEBUG_PRINT(("%s\n", __func__), DEBUG_FUNCS);
54915d647adSsyuu
55015d647adSsyuu wd = octcflookup(DISKUNIT(dev));
55115d647adSsyuu if (wd == NULL)
55215d647adSsyuu return ENXIO;
55315d647adSsyuu
55415d647adSsyuu if ((wd->sc_flags & OCTCFF_LOADED) == 0) {
55515d647adSsyuu error = EIO;
55615d647adSsyuu goto exit;
55715d647adSsyuu }
55815d647adSsyuu
55915d647adSsyuu switch (xfer) {
56015d647adSsyuu case DIOCRLDINFO:
56115d647adSsyuu lp = malloc(sizeof(*lp), M_TEMP, M_WAITOK);
56215d647adSsyuu octcfgetdisklabel(dev, wd, lp, 0);
56315d647adSsyuu bcopy(lp, wd->sc_dk.dk_label, sizeof(*lp));
5649df86521Sfcambus free(lp, M_TEMP, sizeof(*lp));
56515d647adSsyuu goto exit;
56615d647adSsyuu
56715d647adSsyuu case DIOCGPDINFO:
56815d647adSsyuu octcfgetdisklabel(dev, wd, (struct disklabel *)addr, 1);
56915d647adSsyuu goto exit;
57015d647adSsyuu
57115d647adSsyuu case DIOCGDINFO:
57215d647adSsyuu *(struct disklabel *)addr = *(wd->sc_dk.dk_label);
57315d647adSsyuu goto exit;
57415d647adSsyuu
57515d647adSsyuu case DIOCGPART:
57615d647adSsyuu ((struct partinfo *)addr)->disklab = wd->sc_dk.dk_label;
57715d647adSsyuu ((struct partinfo *)addr)->part =
57815d647adSsyuu &wd->sc_dk.dk_label->d_partitions[DISKPART(dev)];
57915d647adSsyuu goto exit;
58015d647adSsyuu
58115d647adSsyuu case DIOCWDINFO:
58215d647adSsyuu case DIOCSDINFO:
58315d647adSsyuu if ((flag & FWRITE) == 0) {
58415d647adSsyuu error = EBADF;
58515d647adSsyuu goto exit;
58615d647adSsyuu }
58715d647adSsyuu
58885bbddc9Sderaadt if ((error = disk_lock(&wd->sc_dk)) != 0)
58915d647adSsyuu goto exit;
59015d647adSsyuu
59115d647adSsyuu error = setdisklabel(wd->sc_dk.dk_label,
592bcdc9b57Sjasper (struct disklabel *)addr, wd->sc_dk.dk_openmask);
59315d647adSsyuu if (error == 0) {
59415d647adSsyuu if (xfer == DIOCWDINFO)
59515d647adSsyuu error = writedisklabel(DISKLABELDEV(dev),
59615d647adSsyuu octcfstrategy, wd->sc_dk.dk_label);
59715d647adSsyuu }
59815d647adSsyuu
59985bbddc9Sderaadt disk_unlock(&wd->sc_dk);
60015d647adSsyuu goto exit;
60115d647adSsyuu
60215d647adSsyuu default:
60315d647adSsyuu error = ENOTTY;
60415d647adSsyuu goto exit;
60515d647adSsyuu }
60615d647adSsyuu
60715d647adSsyuu #ifdef DIAGNOSTIC
60815d647adSsyuu panic("octcfioctl: impossible");
60915d647adSsyuu #endif
61015d647adSsyuu
61115d647adSsyuu exit:
61215d647adSsyuu device_unref(&wd->sc_dev);
61315d647adSsyuu return (error);
61415d647adSsyuu }
61515d647adSsyuu
61615d647adSsyuu #ifdef B_FORMAT
61715d647adSsyuu int
wdformat(struct buf * bp)61815d647adSsyuu wdformat(struct buf *bp)
61915d647adSsyuu {
62015d647adSsyuu bp->b_flags |= B_FORMAT;
62115d647adSsyuu return octcfstrategy(bp);
62215d647adSsyuu }
62315d647adSsyuu #endif
62415d647adSsyuu
6251abdbfdeSderaadt daddr_t
octcfsize(dev_t dev)62615d647adSsyuu octcfsize(dev_t dev)
62715d647adSsyuu {
62815d647adSsyuu struct octcf_softc *wd;
629b4c6ca5cSjasper struct disklabel *lp;
63015d647adSsyuu int part, omask;
631b4c6ca5cSjasper daddr_t size;
63215d647adSsyuu
6336aa96c80Sjasper OCTCFDEBUG_PRINT(("%s\n", __func__), DEBUG_FUNCS);
63415d647adSsyuu
63515d647adSsyuu wd = octcflookup(DISKUNIT(dev));
63615d647adSsyuu if (wd == NULL)
63715d647adSsyuu return (-1);
63815d647adSsyuu
63915d647adSsyuu part = DISKPART(dev);
64015d647adSsyuu omask = wd->sc_dk.dk_openmask & (1 << part);
64115d647adSsyuu
64215d647adSsyuu if (omask == 0 && octcfopen(dev, 0, S_IFBLK, NULL) != 0) {
64315d647adSsyuu size = -1;
64415d647adSsyuu goto exit;
64515d647adSsyuu }
64615d647adSsyuu
647b4c6ca5cSjasper lp = wd->sc_dk.dk_label;
648b4c6ca5cSjasper size = DL_SECTOBLK(lp, DL_GETPSIZE(&lp->d_partitions[part]));
64915d647adSsyuu if (omask == 0 && octcfclose(dev, 0, S_IFBLK, NULL) != 0)
65015d647adSsyuu size = -1;
65115d647adSsyuu
65215d647adSsyuu exit:
65315d647adSsyuu device_unref(&wd->sc_dev);
65415d647adSsyuu return (size);
65515d647adSsyuu }
65615d647adSsyuu
65715d647adSsyuu /*
65815d647adSsyuu * Dump core after a system crash.
65915d647adSsyuu */
66015d647adSsyuu int
octcfdump(dev_t dev,daddr_t blkno,caddr_t va,size_t size)6611abdbfdeSderaadt octcfdump(dev_t dev, daddr_t blkno, caddr_t va, size_t size)
66215d647adSsyuu {
66315d647adSsyuu return ENXIO;
66415d647adSsyuu }
66515d647adSsyuu
66615d647adSsyuu int
octcf_read_sectors(struct octcf_softc * wd,uint32_t nr_sectors,uint32_t start_sector,void * buf)66715d647adSsyuu octcf_read_sectors(struct octcf_softc *wd, uint32_t nr_sectors,
66815d647adSsyuu uint32_t start_sector, void *buf)
66915d647adSsyuu {
67015d647adSsyuu uint32_t count;
67115d647adSsyuu uint16_t *ptr = (uint16_t*)buf;
67215d647adSsyuu int error;
67315d647adSsyuu uint8_t status;
67415d647adSsyuu
67515d647adSsyuu while (nr_sectors--) {
67615d647adSsyuu while ((status = (OCTCF_REG_READ(wd, wdr_status)>>8)) & WDCS_BSY)
67715d647adSsyuu DELAY(OCTCFDELAY);
67815d647adSsyuu octcf_command(wd, start_sector++, WDCC_READ);
67915d647adSsyuu error = octcf_wait_busy(wd);
68015d647adSsyuu if (error != 0)
68115d647adSsyuu return (error);
68215d647adSsyuu
68315d647adSsyuu volatile uint16_t dummy;
68415d647adSsyuu for (count = 0; count < SECTOR_SIZE; count+=2) {
68515d647adSsyuu uint16_t temp;
68615d647adSsyuu temp = OCTCF_REG_READ(wd, 0x0);
68715d647adSsyuu *ptr++ = swap16(temp);
68815d647adSsyuu if ((count & 0xf) == 0)
68915d647adSsyuu dummy = OCTCF_REG_READ(wd, wdr_status);
69015d647adSsyuu }
69115d647adSsyuu }
69215d647adSsyuu return (0);
69315d647adSsyuu }
69415d647adSsyuu
69515d647adSsyuu int
octcf_write_sectors(struct octcf_softc * wd,uint32_t nr_sectors,uint32_t start_sector,void * buf)69615d647adSsyuu octcf_write_sectors(struct octcf_softc *wd, uint32_t nr_sectors,
69715d647adSsyuu uint32_t start_sector, void *buf)
69815d647adSsyuu {
69915d647adSsyuu uint32_t count;
70015d647adSsyuu uint16_t *ptr = (uint16_t*)buf;
70115d647adSsyuu int error;
70215d647adSsyuu uint8_t status;
70315d647adSsyuu
70415d647adSsyuu while (nr_sectors--) {
70515d647adSsyuu while ((status = (OCTCF_REG_READ(wd, wdr_status)>>8)) & WDCS_BSY)
70615d647adSsyuu DELAY(OCTCFDELAY);
70715d647adSsyuu octcf_command(wd, start_sector++, WDCC_WRITE);
70815d647adSsyuu if((error = octcf_wait_busy(wd)))
70915d647adSsyuu return (error);
71015d647adSsyuu
71115d647adSsyuu volatile uint16_t dummy;
71215d647adSsyuu for (count = 0; count < SECTOR_SIZE; count+=2) {
71315d647adSsyuu uint16_t temp = *ptr++;
71415d647adSsyuu OCTCF_REG_WRITE(wd, 0x0, swap16(temp));
71515d647adSsyuu if ((count & 0xf) == 0)
71615d647adSsyuu dummy = OCTCF_REG_READ(wd, wdr_status);
71715d647adSsyuu }
71815d647adSsyuu }
71915d647adSsyuu return (0);
72015d647adSsyuu }
72115d647adSsyuu
72215d647adSsyuu void
octcf_command(struct octcf_softc * wd,uint32_t lba,uint8_t cmd)72315d647adSsyuu octcf_command(struct octcf_softc *wd, uint32_t lba, uint8_t cmd)
72415d647adSsyuu {
72515d647adSsyuu OCTCF_REG_WRITE(wd, wdr_seccnt, 1 | ((lba & 0xff) << 8));
72615d647adSsyuu OCTCF_REG_WRITE(wd, wdr_cyl_lo,
72715d647adSsyuu ((lba >> 8) & 0xff) | (((lba >> 16) & 0xff) << 8));
72815d647adSsyuu OCTCF_REG_WRITE(wd, wdr_sdh,
72915d647adSsyuu (((lba >> 24) & 0xff) | 0xe0) | (cmd << 8));
73015d647adSsyuu }
73115d647adSsyuu
73215d647adSsyuu int
octcf_wait_busy(struct octcf_softc * wd)73315d647adSsyuu octcf_wait_busy(struct octcf_softc *wd)
73415d647adSsyuu {
73515d647adSsyuu uint8_t status;
73615d647adSsyuu
73715d647adSsyuu status = OCTCF_REG_READ(wd, wdr_status)>>8;
73815d647adSsyuu while ((status & WDCS_BSY) == WDCS_BSY) {
73915d647adSsyuu if ((status & WDCS_DWF) != 0)
74015d647adSsyuu return (EIO);
74115d647adSsyuu DELAY(OCTCFDELAY);
74215d647adSsyuu status = (uint8_t)(OCTCF_REG_READ(wd, wdr_status)>>8);
74315d647adSsyuu }
74415d647adSsyuu
74515d647adSsyuu if ((status & WDCS_DRQ) == 0)
74615d647adSsyuu return (ENXIO);
74715d647adSsyuu
74815d647adSsyuu return (0);
74915d647adSsyuu }
75015d647adSsyuu
75115d647adSsyuu /* Get the disk's parameters */
75215d647adSsyuu int
octcf_get_params(struct octcf_softc * wd,struct ataparams * params)753bdbc4c90Sjasper octcf_get_params(struct octcf_softc *wd, struct ataparams *params)
75415d647adSsyuu {
75515d647adSsyuu char *tb;
75615d647adSsyuu int i;
75715d647adSsyuu u_int16_t *p;
75815d647adSsyuu int count;
75915d647adSsyuu uint8_t status;
76015d647adSsyuu int error;
76115d647adSsyuu
7626aa96c80Sjasper OCTCFDEBUG_PRINT(("%s\n", __func__), DEBUG_FUNCS);
76315d647adSsyuu
76415d647adSsyuu tb = malloc(ATAPARAMS_SIZE, M_DEVBUF, M_NOWAIT | M_ZERO);
76515d647adSsyuu if (tb == NULL)
76615d647adSsyuu return CMD_AGAIN;
76715d647adSsyuu
76815d647adSsyuu while ((status = (OCTCF_REG_READ(wd, wdr_status)>>8)) & WDCS_BSY)
76915d647adSsyuu DELAY(OCTCFDELAY);
77015d647adSsyuu
77115d647adSsyuu OCTCF_REG_WRITE(wd, wdr_seccnt, 0);
77215d647adSsyuu OCTCF_REG_WRITE(wd, wdr_cyl_lo, 0);
77315d647adSsyuu OCTCF_REG_WRITE(wd, wdr_sdh, 0 | (WDCC_IDENTIFY<<8));
77415d647adSsyuu
77515d647adSsyuu error = octcf_wait_busy(wd);
77615d647adSsyuu if (error == 0) {
77715d647adSsyuu for (count = 0; count < SECTOR_SIZE; count+=2) {
77815d647adSsyuu uint16_t temp;
77915d647adSsyuu temp = OCTCF_REG_READ(wd, 0x0);
78015d647adSsyuu
78136fd90dcSjsg /* endianness will be swapped below */
78215d647adSsyuu tb[count] = (temp & 0xff);
78315d647adSsyuu tb[count+1] = (temp & 0xff00)>>8;
78415d647adSsyuu }
78515d647adSsyuu }
78615d647adSsyuu
78715d647adSsyuu if (error != 0) {
78815d647adSsyuu printf("%s: identify failed: %d\n", __func__, error);
7899df86521Sfcambus free(tb, M_DEVBUF, ATAPARAMS_SIZE);
79015d647adSsyuu return CMD_ERR;
79115d647adSsyuu } else {
792bdbc4c90Sjasper /*
793bdbc4c90Sjasper * All the fields in the params structure are 16-bit
794bdbc4c90Sjasper * integers except for the ID strings which are char
795bdbc4c90Sjasper * strings. The 16-bit integers are currently in
796bdbc4c90Sjasper * memory in little-endian, regardless of architecture.
797bdbc4c90Sjasper * So, they need to be swapped on big-endian architectures
798bdbc4c90Sjasper * before they are accessed through the ataparams structure.
799bdbc4c90Sjasper *
800bdbc4c90Sjasper * The swaps below avoid touching the char strings.
80115d647adSsyuu */
80215d647adSsyuu swap16_multi((u_int16_t *)tb, 10);
80315d647adSsyuu swap16_multi((u_int16_t *)tb + 20, 3);
80415d647adSsyuu swap16_multi((u_int16_t *)tb + 47, ATAPARAMS_SIZE / 2 - 47);
8050b0091d9Sjasper
80615d647adSsyuu /* Read in parameter block. */
807bdbc4c90Sjasper bcopy(tb, params, sizeof(struct ataparams));
80815d647adSsyuu
80915d647adSsyuu /*
81015d647adSsyuu * Shuffle string byte order.
81115d647adSsyuu * ATAPI Mitsumi and NEC drives don't need this.
81215d647adSsyuu */
813bdbc4c90Sjasper if ((params->atap_config & WDC_CFG_ATAPI_MASK) ==
81415d647adSsyuu WDC_CFG_ATAPI &&
815bdbc4c90Sjasper ((params->atap_model[0] == 'N' &&
816bdbc4c90Sjasper params->atap_model[1] == 'E') ||
817bdbc4c90Sjasper (params->atap_model[0] == 'F' &&
818bdbc4c90Sjasper params->atap_model[1] == 'X'))) {
8199df86521Sfcambus free(tb, M_DEVBUF, ATAPARAMS_SIZE);
82015d647adSsyuu return CMD_OK;
82115d647adSsyuu }
822bdbc4c90Sjasper for (i = 0; i < sizeof(params->atap_model); i += 2) {
823bdbc4c90Sjasper p = (u_short *)(params->atap_model + i);
82415d647adSsyuu *p = swap16(*p);
82515d647adSsyuu }
826bdbc4c90Sjasper for (i = 0; i < sizeof(params->atap_serial); i += 2) {
827bdbc4c90Sjasper p = (u_short *)(params->atap_serial + i);
82815d647adSsyuu *p = swap16(*p);
82915d647adSsyuu }
830bdbc4c90Sjasper for (i = 0; i < sizeof(params->atap_revision); i += 2) {
831bdbc4c90Sjasper p = (u_short *)(params->atap_revision + i);
83215d647adSsyuu *p = swap16(*p);
83315d647adSsyuu }
83415d647adSsyuu
8359df86521Sfcambus free(tb, M_DEVBUF, ATAPARAMS_SIZE);
83615d647adSsyuu return CMD_OK;
83715d647adSsyuu }
83815d647adSsyuu }
839