1/*	$OpenBSD: octcf.c,v 1.36 2024/05/20 23:13:33 jsg Exp $ */
2/*	$NetBSD: wd.c,v 1.193 1999/02/28 17:15:27 explorer Exp $ */
3
4/*
5 * Copyright (c) 1998, 2001 Manuel Bouyer.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *	notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *	notice, this list of conditions and the following disclaimer in the
14 *	documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28/*-
29 * Copyright (c) 1998 The NetBSD Foundation, Inc.
30 * All rights reserved.
31 *
32 * This code is derived from software contributed to The NetBSD Foundation
33 * by Charles M. Hannum and by Onno van der Linden.
34 *
35 * Redistribution and use in source and binary forms, with or without
36 * modification, are permitted provided that the following conditions
37 * are met:
38 * 1. Redistributions of source code must retain the above copyright
39 *    notice, this list of conditions and the following disclaimer.
40 * 2. Redistributions in binary form must reproduce the above copyright
41 *    notice, this list of conditions and the following disclaimer in the
42 *    documentation and/or other materials provided with the distribution.
43 *
44 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
45 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
46 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
47 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
48 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
49 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
50 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
51 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
52 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
53 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
54 * POSSIBILITY OF SUCH DAMAGE.
55 */
56
57#include <sys/param.h>
58#include <sys/systm.h>
59#include <sys/kernel.h>
60#include <sys/conf.h>
61#include <sys/fcntl.h>
62#include <sys/stat.h>
63#include <sys/ioctl.h>
64#include <sys/mutex.h>
65#include <sys/buf.h>
66#include <sys/uio.h>
67#include <sys/malloc.h>
68#include <sys/device.h>
69#include <sys/disklabel.h>
70#include <sys/disk.h>
71#include <sys/syslog.h>
72#include <sys/proc.h>
73#include <sys/vnode.h>
74#include <sys/dkio.h>
75
76#include <machine/intr.h>
77#include <machine/bus.h>
78
79#include <dev/ata/atareg.h>
80#include <dev/ata/atavar.h>
81#include <dev/ic/wdcreg.h>
82#include <dev/ic/wdcvar.h>
83
84#include <octeon/dev/iobusvar.h>
85#include <machine/octeonreg.h>
86#include <machine/octeonvar.h>
87
88#define OCTCF_REG_SIZE	8
89#define ATAPARAMS_SIZE	512
90#define SECTOR_SIZE	512
91#define OCTCFDELAY	100 /* 100 microseconds */
92#define NR_TRIES	1000
93
94#define DEBUG_XFERS  0x02
95#define DEBUG_FUNCS  0x08
96#define DEBUG_PROBE  0x10
97
98#ifdef OCTCFDEBUG
99int octcfdebug_mask = 0xff;
100#define OCTCFDEBUG_PRINT(args, level) do {	\
101	if ((octcfdebug_mask & (level)) != 0)	\
102		printf args;			\
103} while (0)
104#else
105#define OCTCFDEBUG_PRINT(args, level)
106#endif
107
108struct octcf_softc {
109	/* General disk infos */
110	struct device sc_dev;
111	struct disk sc_dk;
112	struct bufq sc_bufq;
113	struct buf *sc_bp;
114	struct ataparams sc_params;/* drive characteristics found */
115	int sc_flags;
116#define OCTCFF_LOADED		0x10 /* parameters loaded */
117	u_int64_t sc_capacity;
118	bus_space_tag_t       sc_iot;
119	bus_space_handle_t    sc_ioh;
120};
121
122int	octcfprobe(struct device *, void *, void *);
123void	octcfattach(struct device *, struct device *, void *);
124int	octcfdetach(struct device *, int);
125int	octcfactivate(struct device *, int);
126
127const struct cfattach octcf_ca = {
128	sizeof(struct octcf_softc), octcfprobe, octcfattach,
129	octcfdetach, octcfactivate
130};
131
132struct cfdriver octcf_cd = {
133	NULL, "octcf", DV_DISK
134};
135
136void  octcfgetdefaultlabel(struct octcf_softc *, struct disklabel *);
137int   octcfgetdisklabel(dev_t dev, struct octcf_softc *, struct disklabel *, int);
138void  octcfstrategy(struct buf *);
139void  octcfstart(void *);
140void  _octcfstart(struct octcf_softc*, struct buf *);
141void  octcfdone(void *);
142
143cdev_decl(octcf);
144bdev_decl(octcf);
145
146#define octcflookup(unit) (struct octcf_softc *)disk_lookup(&octcf_cd, (unit))
147
148int	octcf_write_sectors(struct octcf_softc *, uint32_t, uint32_t, void *);
149int	octcf_read_sectors(struct octcf_softc *, uint32_t, uint32_t, void *);
150int	octcf_wait_busy(struct octcf_softc *);
151void	octcf_command(struct octcf_softc *, uint32_t, uint8_t);
152int 	octcf_get_params(struct octcf_softc *, struct ataparams *);
153
154#define OCTCF_REG_READ(wd, reg) \
155	bus_space_read_2(wd->sc_iot, wd->sc_ioh, reg & 0x6)
156#define OCTCF_REG_WRITE(wd, reg, val) \
157	bus_space_write_2(wd->sc_iot, wd->sc_ioh, reg & 0x6, val)
158
159int
160octcfprobe(struct device *parent, void *match, void *aux)
161{
162	if (octeon_boot_info->cf_common_addr == 0) {
163		OCTCFDEBUG_PRINT(("%s: No cf bus found\n", __func__), DEBUG_FUNCS | DEBUG_PROBE);
164		return 0;
165	}
166
167	return 1;
168}
169
170void
171octcfattach(struct device *parent, struct device *self, void *aux)
172{
173	struct octcf_softc *wd = (void *)self;
174	struct iobus_attach_args *aa = aux;
175	int i, blank;
176	char buf[41], c, *p, *q;
177	uint8_t status;
178	OCTCFDEBUG_PRINT(("%s\n", __func__), DEBUG_FUNCS | DEBUG_PROBE);
179
180	wd->sc_iot = aa->aa_bust;
181
182	if (bus_space_map(wd->sc_iot, aa->aa_addr,
183	    OCTCF_REG_SIZE, BUS_SPACE_MAP_KSEG0, &wd->sc_ioh)) {
184		printf(": couldn't map registers\n");
185		return;
186	}
187
188	for (i = 0; i < 8; i++) {
189		uint64_t cfg =
190		*(uint64_t *)PHYS_TO_XKPHYS(
191			OCTEON_MIO_BOOT_BASE + MIO_BOOT_REG_CFG(i), CCA_NC);
192
193		if ((cfg & BOOT_CFG_BASE_MASK) ==
194			(OCTEON_CF_BASE >> BOOT_CFG_BASE_SHIFT)) {
195			if ((cfg & BOOT_CFG_WIDTH_MASK) == 0)
196				printf(": doesn't support 8bit cards\n");
197			break;
198		}
199	}
200
201	/* Check if CF is inserted */
202	i = 0;
203	while ( (status = (OCTCF_REG_READ(wd, wdr_status)>>8)) & WDCS_BSY) {
204		if ((i++) == NR_TRIES )     {
205			printf(": card not present\n");
206			return;
207               	}
208		DELAY(OCTCFDELAY);
209	}
210
211	/* read our drive info */
212	if (octcf_get_params(wd, &wd->sc_params) != 0) {
213		printf(": IDENTIFY failed\n");
214		return;
215	}
216
217	for (blank = 0, p = wd->sc_params.atap_model, q = buf, i = 0;
218	    i < sizeof(wd->sc_params.atap_model); i++) {
219		c = *p++;
220		if (c == '\0')
221			break;
222		if (c != ' ') {
223			if (blank) {
224				*q++ = ' ';
225				blank = 0;
226			}
227			*q++ = c;
228		} else
229			blank = 1;
230		}
231	*q++ = '\0';
232
233	printf(": <%s>\n", buf);
234	printf("%s: %d-sector PIO,",
235		wd->sc_dev.dv_xname, wd->sc_params.atap_multi & 0xff);
236
237	wd->sc_capacity =
238		wd->sc_params.atap_cylinders *
239		wd->sc_params.atap_heads *
240		wd->sc_params.atap_sectors;
241	printf(" CHS, %lluMB, %d cyl, %d head, %d sec, %llu sectors\n",
242		wd->sc_capacity / (1048576 / DEV_BSIZE),
243		wd->sc_params.atap_cylinders,
244		wd->sc_params.atap_heads,
245		wd->sc_params.atap_sectors,
246		wd->sc_capacity);
247
248	OCTCFDEBUG_PRINT(
249		("%s: atap_dmatiming_mimi=%d, atap_dmatiming_recom=%d\n",
250		self->dv_xname, wd->sc_params.atap_dmatiming_mimi,
251		wd->sc_params.atap_dmatiming_recom), DEBUG_PROBE);
252
253	/*
254	 * Initialize disk structures.
255	 */
256	wd->sc_dk.dk_name = wd->sc_dev.dv_xname;
257	bufq_init(&wd->sc_bufq, BUFQ_DEFAULT);
258
259	/* Attach disk. */
260	disk_attach(&wd->sc_dev, &wd->sc_dk);
261}
262
263int
264octcfactivate(struct device *self, int act)
265{
266	return 0;
267}
268
269int
270octcfdetach(struct device *self, int flags)
271{
272	struct octcf_softc *sc = (struct octcf_softc *)self;
273
274	bufq_drain(&sc->sc_bufq);
275
276	disk_gone(octcfopen, self->dv_unit);
277
278	/* Detach disk. */
279	bufq_destroy(&sc->sc_bufq);
280	disk_detach(&sc->sc_dk);
281
282	return (0);
283}
284
285/*
286 * Read/write routine for a buffer.  Validates the arguments and schedules the
287 * transfer.  Does not wait for the transfer to complete.
288 */
289void
290octcfstrategy(struct buf *bp)
291{
292	struct octcf_softc *wd;
293	int s;
294
295	wd = octcflookup(DISKUNIT(bp->b_dev));
296	if (wd == NULL) {
297		bp->b_error = ENXIO;
298		goto bad;
299	}
300
301	OCTCFDEBUG_PRINT(("%s (%s)\n", __func__, wd->sc_dev.dv_xname),
302	    DEBUG_XFERS);
303
304	/* If device invalidated (e.g. media change, door open), error. */
305	if ((wd->sc_flags & OCTCFF_LOADED) == 0) {
306		bp->b_error = EIO;
307		goto bad;
308	}
309
310	/* Validate the request. */
311	if (bounds_check_with_label(bp, wd->sc_dk.dk_label) == -1)
312		goto done;
313
314	/* Check that the number of sectors can fit in a byte. */
315	if ((bp->b_bcount / wd->sc_dk.dk_label->d_secsize) >= (1 << NBBY)) {
316		bp->b_error = EINVAL;
317		goto bad;
318	}
319
320	/* Queue transfer on drive, activate drive and controller if idle. */
321	bufq_queue(&wd->sc_bufq, bp);
322	s = splbio();
323	octcfstart(wd);
324	splx(s);
325	device_unref(&wd->sc_dev);
326	return;
327
328 bad:
329	bp->b_flags |= B_ERROR;
330	bp->b_resid = bp->b_bcount;
331 done:
332	s = splbio();
333	biodone(bp);
334	splx(s);
335	if (wd != NULL)
336		device_unref(&wd->sc_dev);
337}
338
339/*
340 * Queue a drive for I/O.
341 */
342void
343octcfstart(void *arg)
344{
345	struct octcf_softc *wd = arg;
346	struct buf *bp;
347
348	OCTCFDEBUG_PRINT(("%s %s\n", __func__, wd->sc_dev.dv_xname),
349	    DEBUG_XFERS);
350	while ((bp = bufq_dequeue(&wd->sc_bufq)) != NULL) {
351		/* Transfer this buffer now. */
352		_octcfstart(wd, bp);
353	}
354}
355
356void
357_octcfstart(struct octcf_softc *wd, struct buf *bp)
358{
359	struct disklabel *lp;
360	u_int64_t secno;
361	u_int64_t nsecs;
362
363	lp = wd->sc_dk.dk_label;
364	secno = DL_BLKTOSEC(lp, bp->b_blkno) +
365	    DL_GETPOFFSET(&lp->d_partitions[DISKPART(bp->b_dev)]);
366	nsecs = howmany(bp->b_bcount, lp->d_secsize);
367	wd->sc_bp = bp;
368
369	/* Instrumentation. */
370	disk_busy(&wd->sc_dk);
371
372	if (bp->b_flags & B_READ)
373		bp->b_error = octcf_read_sectors(wd, nsecs, secno, bp->b_data);
374	else
375		bp->b_error = octcf_write_sectors(wd, nsecs, secno, bp->b_data);
376
377	octcfdone(wd);
378}
379
380void
381octcfdone(void *arg)
382{
383	struct octcf_softc *wd = arg;
384	struct buf *bp = wd->sc_bp;
385
386	if (bp->b_error == 0)
387		bp->b_resid = 0;
388	else
389		bp->b_flags |= B_ERROR;
390
391	disk_unbusy(&wd->sc_dk, (bp->b_bcount - bp->b_resid),
392	    bp->b_blkno, (bp->b_flags & B_READ));
393	biodone(bp);
394}
395
396int
397octcfread(dev_t dev, struct uio *uio, int flags)
398{
399
400	OCTCFDEBUG_PRINT(("%s\n", __func__), DEBUG_XFERS);
401	return (physio(octcfstrategy, dev, B_READ, minphys, uio));
402}
403
404int
405octcfwrite(dev_t dev, struct uio *uio, int flags)
406{
407
408	OCTCFDEBUG_PRINT(("%s\n", __func__), DEBUG_XFERS);
409	return (physio(octcfstrategy, dev, B_WRITE, minphys, uio));
410}
411
412int
413octcfopen(dev_t dev, int flag, int fmt, struct proc *p)
414{
415	struct octcf_softc *wd;
416	int unit, part;
417	int error;
418
419	OCTCFDEBUG_PRINT(("%s\n", __func__), DEBUG_FUNCS);
420
421	unit = DISKUNIT(dev);
422	wd = octcflookup(unit);
423	if (wd == NULL)
424		return ENXIO;
425
426	/*
427	 * If this is the first open of this device, add a reference
428	 * to the adapter.
429	 */
430	if ((error = disk_lock(&wd->sc_dk)) != 0)
431		goto bad4;
432
433	if (wd->sc_dk.dk_openmask != 0) {
434		/*
435		 * If any partition is open, but the disk has been invalidated,
436		 * disallow further opens.
437		 */
438		if ((wd->sc_flags & OCTCFF_LOADED) == 0) {
439			error = EIO;
440			goto bad3;
441		}
442	} else {
443		if ((wd->sc_flags & OCTCFF_LOADED) == 0) {
444			wd->sc_flags |= OCTCFF_LOADED;
445
446			/* Load the physical device parameters. */
447			octcf_get_params(wd, &wd->sc_params);
448
449			/* Load the partition info if not already loaded. */
450			if (octcfgetdisklabel(dev, wd,
451			    wd->sc_dk.dk_label, 0) == EIO) {
452				error = EIO;
453				goto bad;
454			}
455		}
456	}
457
458	part = DISKPART(dev);
459
460	if ((error = disk_openpart(&wd->sc_dk, part, fmt, 1)) != 0)
461		goto bad;
462
463	disk_unlock(&wd->sc_dk);
464	device_unref(&wd->sc_dev);
465	return 0;
466
467bad:
468	if (wd->sc_dk.dk_openmask == 0) {
469	}
470
471bad3:
472	disk_unlock(&wd->sc_dk);
473bad4:
474	device_unref(&wd->sc_dev);
475	return error;
476}
477
478int
479octcfclose(dev_t dev, int flag, int fmt, struct proc *p)
480{
481	struct octcf_softc *wd;
482	int part = DISKPART(dev);
483
484	wd = octcflookup(DISKUNIT(dev));
485	if (wd == NULL)
486		return ENXIO;
487
488	OCTCFDEBUG_PRINT(("%s\n", __func__), DEBUG_FUNCS);
489
490	disk_lock_nointr(&wd->sc_dk);
491
492	disk_closepart(&wd->sc_dk, part, fmt);
493
494	disk_unlock(&wd->sc_dk);
495
496	device_unref(&wd->sc_dev);
497	return (0);
498}
499
500void
501octcfgetdefaultlabel(struct octcf_softc *wd, struct disklabel *lp)
502{
503	OCTCFDEBUG_PRINT(("%s\n", __func__), DEBUG_FUNCS);
504	bzero(lp, sizeof(struct disklabel));
505
506	lp->d_secsize = DEV_BSIZE;
507	DL_SETDSIZE(lp, wd->sc_capacity);
508	lp->d_ntracks = wd->sc_params.atap_heads;
509	lp->d_nsectors = wd->sc_params.atap_sectors;
510	lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
511	lp->d_ncylinders = DL_GETDSIZE(lp) / lp->d_secpercyl;
512	lp->d_type = DTYPE_ESDI;
513	strncpy(lp->d_typename, "ESDI/IDE disk", sizeof lp->d_typename);
514
515	/* XXX - user viscopy() like sd.c */
516	strncpy(lp->d_packname, wd->sc_params.atap_model, sizeof lp->d_packname);
517	lp->d_version = 1;
518
519	lp->d_magic = DISKMAGIC;
520	lp->d_magic2 = DISKMAGIC;
521	lp->d_checksum = dkcksum(lp);
522}
523
524/*
525 * Fabricate a default disk label, and try to read the correct one.
526 */
527int
528octcfgetdisklabel(dev_t dev, struct octcf_softc *wd, struct disklabel *lp,
529    int spoofonly)
530{
531	int error;
532
533	OCTCFDEBUG_PRINT(("%s\n", __func__), DEBUG_FUNCS);
534
535	octcfgetdefaultlabel(wd, lp);
536	error = readdisklabel(DISKLABELDEV(dev), octcfstrategy, lp,
537	    spoofonly);
538	return (error);
539}
540
541int
542octcfioctl(dev_t dev, u_long xfer, caddr_t addr, int flag, struct proc *p)
543{
544	struct octcf_softc *wd;
545	struct disklabel *lp;
546	int error = 0;
547
548	OCTCFDEBUG_PRINT(("%s\n", __func__), DEBUG_FUNCS);
549
550	wd = octcflookup(DISKUNIT(dev));
551	if (wd == NULL)
552		return ENXIO;
553
554	if ((wd->sc_flags & OCTCFF_LOADED) == 0) {
555		error = EIO;
556		goto exit;
557	}
558
559	switch (xfer) {
560	case DIOCRLDINFO:
561		lp = malloc(sizeof(*lp), M_TEMP, M_WAITOK);
562		octcfgetdisklabel(dev, wd, lp, 0);
563		bcopy(lp, wd->sc_dk.dk_label, sizeof(*lp));
564		free(lp, M_TEMP, sizeof(*lp));
565		goto exit;
566
567	case DIOCGPDINFO:
568		octcfgetdisklabel(dev, wd, (struct disklabel *)addr, 1);
569		goto exit;
570
571	case DIOCGDINFO:
572		*(struct disklabel *)addr = *(wd->sc_dk.dk_label);
573		goto exit;
574
575	case DIOCGPART:
576		((struct partinfo *)addr)->disklab = wd->sc_dk.dk_label;
577		((struct partinfo *)addr)->part =
578		    &wd->sc_dk.dk_label->d_partitions[DISKPART(dev)];
579		goto exit;
580
581	case DIOCWDINFO:
582	case DIOCSDINFO:
583		if ((flag & FWRITE) == 0) {
584			error = EBADF;
585			goto exit;
586		}
587
588		if ((error = disk_lock(&wd->sc_dk)) != 0)
589			goto exit;
590
591		error = setdisklabel(wd->sc_dk.dk_label,
592		    (struct disklabel *)addr, wd->sc_dk.dk_openmask);
593		if (error == 0) {
594			if (xfer == DIOCWDINFO)
595				error = writedisklabel(DISKLABELDEV(dev),
596				    octcfstrategy, wd->sc_dk.dk_label);
597		}
598
599		disk_unlock(&wd->sc_dk);
600		goto exit;
601
602	default:
603		error = ENOTTY;
604		goto exit;
605	}
606
607#ifdef DIAGNOSTIC
608	panic("octcfioctl: impossible");
609#endif
610
611 exit:
612	device_unref(&wd->sc_dev);
613	return (error);
614}
615
616#ifdef B_FORMAT
617int
618wdformat(struct buf *bp)
619{
620	bp->b_flags |= B_FORMAT;
621	return octcfstrategy(bp);
622}
623#endif
624
625daddr_t
626octcfsize(dev_t dev)
627{
628	struct octcf_softc *wd;
629	struct disklabel *lp;
630	int part, omask;
631	daddr_t size;
632
633	OCTCFDEBUG_PRINT(("%s\n", __func__), DEBUG_FUNCS);
634
635	wd = octcflookup(DISKUNIT(dev));
636	if (wd == NULL)
637		return (-1);
638
639	part = DISKPART(dev);
640	omask = wd->sc_dk.dk_openmask & (1 << part);
641
642	if (omask == 0 && octcfopen(dev, 0, S_IFBLK, NULL) != 0) {
643		size = -1;
644		goto exit;
645	}
646
647	lp = wd->sc_dk.dk_label;
648	size = DL_SECTOBLK(lp, DL_GETPSIZE(&lp->d_partitions[part]));
649	if (omask == 0 && octcfclose(dev, 0, S_IFBLK, NULL) != 0)
650		size = -1;
651
652 exit:
653	device_unref(&wd->sc_dev);
654	return (size);
655}
656
657/*
658 * Dump core after a system crash.
659 */
660int
661octcfdump(dev_t dev, daddr_t blkno, caddr_t va, size_t size)
662{
663	return ENXIO;
664}
665
666int
667octcf_read_sectors(struct octcf_softc *wd, uint32_t nr_sectors,
668	uint32_t start_sector, void *buf)
669{
670	uint32_t count;
671	uint16_t *ptr = (uint16_t*)buf;
672	int error;
673	uint8_t status;
674
675	while (nr_sectors--) {
676		while ((status = (OCTCF_REG_READ(wd, wdr_status)>>8)) & WDCS_BSY)
677			DELAY(OCTCFDELAY);
678		octcf_command(wd, start_sector++, WDCC_READ);
679		error = octcf_wait_busy(wd);
680		if (error != 0)
681			return (error);
682
683        	volatile uint16_t dummy;
684		for (count = 0; count < SECTOR_SIZE; count+=2) {
685			uint16_t temp;
686			temp = OCTCF_REG_READ(wd, 0x0);
687			*ptr++ = swap16(temp);
688			if ((count & 0xf) == 0)
689				dummy = OCTCF_REG_READ(wd, wdr_status);
690		}
691	}
692	return (0);
693}
694
695int
696octcf_write_sectors(struct octcf_softc *wd, uint32_t nr_sectors,
697	uint32_t start_sector, void *buf)
698{
699	uint32_t count;
700	uint16_t *ptr = (uint16_t*)buf;
701	int error;
702	uint8_t status;
703
704	while (nr_sectors--) {
705		while ((status = (OCTCF_REG_READ(wd, wdr_status)>>8)) & WDCS_BSY)
706			DELAY(OCTCFDELAY);
707		octcf_command(wd, start_sector++, WDCC_WRITE);
708		if((error = octcf_wait_busy(wd)))
709			return (error);
710
711	      	volatile uint16_t dummy;
712		for (count = 0; count < SECTOR_SIZE; count+=2) {
713			uint16_t temp = *ptr++;
714			OCTCF_REG_WRITE(wd, 0x0, swap16(temp));
715			if ((count & 0xf) == 0)
716				dummy = OCTCF_REG_READ(wd, wdr_status);
717		}
718	}
719	return (0);
720}
721
722void
723octcf_command(struct octcf_softc *wd, uint32_t lba, uint8_t cmd)
724{
725	OCTCF_REG_WRITE(wd, wdr_seccnt, 1 | ((lba & 0xff) << 8));
726	OCTCF_REG_WRITE(wd, wdr_cyl_lo,
727		((lba >> 8) & 0xff) | (((lba >> 16) & 0xff) << 8));
728	OCTCF_REG_WRITE(wd, wdr_sdh,
729		(((lba >> 24) & 0xff) | 0xe0) | (cmd << 8));
730}
731
732int
733octcf_wait_busy(struct octcf_softc *wd)
734{
735	uint8_t status;
736
737	status = OCTCF_REG_READ(wd, wdr_status)>>8;
738	while ((status & WDCS_BSY) == WDCS_BSY) {
739		if ((status & WDCS_DWF) != 0)
740			return (EIO);
741		DELAY(OCTCFDELAY);
742		status = (uint8_t)(OCTCF_REG_READ(wd, wdr_status)>>8);
743	}
744
745	if ((status & WDCS_DRQ) == 0)
746		return (ENXIO);
747
748	return (0);
749}
750
751/* Get the disk's parameters */
752int
753octcf_get_params(struct octcf_softc *wd, struct ataparams *params)
754{
755	char *tb;
756	int i;
757	u_int16_t *p;
758	int count;
759	uint8_t status;
760	int error;
761
762	OCTCFDEBUG_PRINT(("%s\n", __func__), DEBUG_FUNCS);
763
764	tb = malloc(ATAPARAMS_SIZE, M_DEVBUF, M_NOWAIT | M_ZERO);
765	if (tb == NULL)
766		return CMD_AGAIN;
767
768	while ((status = (OCTCF_REG_READ(wd, wdr_status)>>8)) & WDCS_BSY)
769		DELAY(OCTCFDELAY);
770
771	OCTCF_REG_WRITE(wd, wdr_seccnt, 0);
772	OCTCF_REG_WRITE(wd, wdr_cyl_lo, 0);
773	OCTCF_REG_WRITE(wd, wdr_sdh, 0 | (WDCC_IDENTIFY<<8));
774
775	error = octcf_wait_busy(wd);
776	if (error == 0) {
777		for (count = 0; count < SECTOR_SIZE; count+=2) {
778			uint16_t temp;
779			temp = OCTCF_REG_READ(wd, 0x0);
780
781			/* endianness will be swapped below */
782			tb[count]   = (temp & 0xff);
783			tb[count+1] = (temp & 0xff00)>>8;
784		}
785	}
786
787	if (error != 0) {
788		printf("%s: identify failed: %d\n", __func__, error);
789		free(tb, M_DEVBUF, ATAPARAMS_SIZE);
790		return CMD_ERR;
791	} else {
792		/*
793		 * All the fields in the params structure are 16-bit
794		 * integers except for the ID strings which are char
795		 * strings.  The 16-bit integers are currently in
796		 * memory in little-endian, regardless of architecture.
797		 * So, they need to be swapped on big-endian architectures
798		 * before they are accessed through the ataparams structure.
799		 *
800		 * The swaps below avoid touching the char strings.
801		*/
802		swap16_multi((u_int16_t *)tb, 10);
803		swap16_multi((u_int16_t *)tb + 20, 3);
804		swap16_multi((u_int16_t *)tb + 47, ATAPARAMS_SIZE / 2 - 47);
805
806		/* Read in parameter block. */
807		bcopy(tb, params, sizeof(struct ataparams));
808
809		/*
810		 * Shuffle string byte order.
811		 * ATAPI Mitsumi and NEC drives don't need this.
812		 */
813		if ((params->atap_config & WDC_CFG_ATAPI_MASK) ==
814		    WDC_CFG_ATAPI &&
815		    ((params->atap_model[0] == 'N' &&
816			params->atap_model[1] == 'E') ||
817		     (params->atap_model[0] == 'F' &&
818			 params->atap_model[1] == 'X'))) {
819			free(tb, M_DEVBUF, ATAPARAMS_SIZE);
820			return CMD_OK;
821		}
822		for (i = 0; i < sizeof(params->atap_model); i += 2) {
823			p = (u_short *)(params->atap_model + i);
824			*p = swap16(*p);
825		}
826		for (i = 0; i < sizeof(params->atap_serial); i += 2) {
827			p = (u_short *)(params->atap_serial + i);
828			*p = swap16(*p);
829		}
830		for (i = 0; i < sizeof(params->atap_revision); i += 2) {
831			p = (u_short *)(params->atap_revision + i);
832			*p = swap16(*p);
833		}
834
835		free(tb, M_DEVBUF, ATAPARAMS_SIZE);
836		return CMD_OK;
837	}
838}
839