xref: /openbsd-src/sys/arch/octeon/dev/octcf.c (revision a8b581972213782bec450017fe45a05ea431addf)
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