xref: /openbsd-src/sys/arch/octeon/dev/octcf.c (revision d13be5d47e4149db2549a9828e244d59dbc43f15)
1 /*	$OpenBSD: octcf.c,v 1.7 2011/07/06 04:49:35 matthew 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/file.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 <uvm/uvm_extern.h>
77 
78 #include <machine/intr.h>
79 #include <machine/bus.h>
80 
81 #include <dev/ata/atareg.h>
82 #include <dev/ata/atavar.h>
83 #include <dev/ic/wdcreg.h>
84 #include <dev/ic/wdcvar.h>
85 
86 #include <octeon/dev/iobusvar.h>
87 #include <octeon/dev/octeonreg.h>
88 
89 #define OCTCF_REG_SIZE	8
90 #define ATAPARAMS_SIZE	512
91 #define SECTOR_SIZE	512
92 #define OCTCFDELAY	100 /* 100 microseconds */
93 #define NR_TRIES	1000
94 
95 #define DEBUG_XFERS  0x02
96 #define DEBUG_FUNCS  0x08
97 #define DEBUG_PROBE  0x10
98 
99 #ifdef OCTCFDEBUG
100 int octcfdebug_mask = 0xff;
101 #define OCTCFDEBUG_PRINT(args, level) do {	\
102 	if ((octcfdebug_mask & (level)) != 0)	\
103 		printf args;			\
104 } while (0)
105 #else
106 #define OCTCFDEBUG_PRINT(args, level)
107 #endif
108 
109 struct octcf_softc {
110 	/* General disk infos */
111 	struct device sc_dev;
112 	struct disk sc_dk;
113 	struct buf sc_q;
114 	struct buf *sc_bp;
115 	struct ataparams sc_params;/* drive characteristics found */
116 	int sc_flags;
117 #define OCTCFF_LOADED		0x10 /* parameters loaded */
118 	u_int64_t sc_capacity;
119 	bus_space_tag_t       sc_iot;
120 	bus_space_handle_t    sc_ioh;
121 };
122 
123 int	octcfprobe(struct device *, void *, void *);
124 void	octcfattach(struct device *, struct device *, void *);
125 int	octcfdetach(struct device *, int);
126 int	octcfactivate(struct device *, int);
127 int	octcfprint(void *, char *);
128 
129 struct cfattach octcf_ca = {
130 	sizeof(struct octcf_softc), octcfprobe, octcfattach,
131 	octcfdetach, octcfactivate
132 };
133 
134 struct cfdriver octcf_cd = {
135 	NULL, "octcf", DV_DISK
136 };
137 
138 void  octcfgetdefaultlabel(struct octcf_softc *, struct disklabel *);
139 int   octcfgetdisklabel(dev_t dev, struct octcf_softc *, struct disklabel *, int);
140 void  octcfstrategy(struct buf *);
141 void  octcfstart(void *);
142 void  _octcfstart(struct octcf_softc*, struct buf *);
143 void  octcfdone(void *);
144 
145 cdev_decl(octcf);
146 bdev_decl(octcf);
147 
148 #define octcflookup(unit) (struct octcf_softc *)disk_lookup(&octcf_cd, (unit))
149 
150 int	octcf_write_sectors(struct octcf_softc *, uint32_t, uint32_t, void *);
151 int	octcf_read_sectors(struct octcf_softc *, uint32_t, uint32_t, void *);
152 int	octcf_wait_busy(struct octcf_softc *);
153 void	octcf_command(struct octcf_softc *, uint32_t, uint8_t);
154 int 	octcf_get_params(struct octcf_softc *, struct ataparams *);
155 
156 #define OCTCF_REG_READ(wd, reg) \
157 	bus_space_read_2(wd->sc_iot, wd->sc_ioh, reg & 0x6)
158 #define OCTCF_REG_WRITE(wd, reg, val) \
159 	bus_space_write_2(wd->sc_iot, wd->sc_ioh, reg & 0x6, val)
160 
161 int
162 octcfprobe(struct device *parent, void *match_, void *aux)
163 {
164 	return 1;
165 }
166 
167 void
168 octcfattach(struct device *parent, struct device *self, void *aux)
169 {
170 	struct octcf_softc *wd = (void *)self;
171 	struct iobus_attach_args *aa = aux;
172 	int i, blank;
173 	char buf[41], c, *p, *q;
174 	OCTCFDEBUG_PRINT(("octcfattach\n"), DEBUG_FUNCS | DEBUG_PROBE);
175 	uint8_t status;
176 
177 	wd->sc_iot = aa->aa_bust;
178 
179 	if (bus_space_map(wd->sc_iot, aa->aa_unit->addr,
180 	    OCTCF_REG_SIZE, BUS_SPACE_MAP_KSEG0, &wd->sc_ioh)) {
181 		printf(": couldn't map registers\n");
182 		return;
183 	}
184 
185 	for (i = 0; i < 8; i++) {
186 		uint64_t cfg =
187 		*(uint64_t *)PHYS_TO_XKPHYS(
188 			OCTEON_MIO_BOOT_BASE + MIO_BOOT_REG_CFG(i), CCA_NC);
189 
190 		if ((cfg & BOOT_CFG_BASE_MASK) ==
191 			(OCTEON_CF_BASE >> BOOT_CFG_BASE_SHIFT)) {
192 			if ((cfg & BOOT_CFG_WIDTH_MASK) == 0)
193 				printf(": Doesn't support 8bit card\n",
194 					wd->sc_dev.dv_xname);
195 			break;
196 		}
197 	}
198 
199 	/* Check if CF is inserted */
200 	i = 0;
201 	while ( (status = (OCTCF_REG_READ(wd, wdr_status)>>8)) & WDCS_BSY) {
202 		if ((i++) == NR_TRIES )     {
203 			printf(": card not present\n", wd->sc_dev.dv_xname);
204 			return;
205                	}
206 		DELAY(OCTCFDELAY);
207 	}
208 
209 	/* read our drive info */
210 	if (octcf_get_params(wd, &wd->sc_params) != 0) {
211 		printf(": IDENTIFY failed\n", wd->sc_dev.dv_xname);
212 		return;
213 	}
214 
215 	for (blank = 0, p = wd->sc_params.atap_model, q = buf, i = 0;
216 	    i < sizeof(wd->sc_params.atap_model); i++) {
217 		c = *p++;
218 		if (c == '\0')
219 			break;
220 		if (c != ' ') {
221 			if (blank) {
222 				*q++ = ' ';
223 				blank = 0;
224 			}
225 			*q++ = c;
226 		} else
227 			blank = 1;
228 		}
229 	*q++ = '\0';
230 
231 	printf(": <%s>\n", buf);
232 	printf("%s: %d-sector PIO,",
233 		wd->sc_dev.dv_xname, wd->sc_params.atap_multi & 0xff);
234 
235 	wd->sc_capacity =
236 		wd->sc_params.atap_cylinders *
237 		wd->sc_params.atap_heads *
238 		wd->sc_params.atap_sectors;
239 	printf(" CHS, %lluMB, %d cyl, %d head, %d sec, %llu sectors\n",
240 		wd->sc_capacity / (1048576 / DEV_BSIZE),
241 		wd->sc_params.atap_cylinders,
242 		wd->sc_params.atap_heads,
243 		wd->sc_params.atap_sectors,
244 		wd->sc_capacity);
245 
246 	OCTCFDEBUG_PRINT(
247 		("%s: atap_dmatiming_mimi=%d, atap_dmatiming_recom=%d\n",
248 		self->dv_xname, wd->sc_params.atap_dmatiming_mimi,
249 		wd->sc_params.atap_dmatiming_recom), DEBUG_PROBE);
250 
251 	/*
252 	 * Initialize disk structures.
253 	 */
254 	wd->sc_dk.dk_name = wd->sc_dev.dv_xname;
255 
256 	/* Attach disk. */
257 	disk_attach(&wd->sc_dev, &wd->sc_dk);
258 }
259 
260 int
261 octcfactivate(struct device *self, int act)
262 {
263 	return 0;
264 }
265 
266 int
267 octcfdetach(struct device *self, int flags)
268 {
269 	struct octcf_softc *sc = (struct octcf_softc *)self;
270 	int bmaj, cmaj, mn;
271 
272 	/* Locate the lowest minor number to be detached. */
273 	mn = DISKMINOR(self->dv_unit, 0);
274 
275 	for (bmaj = 0; bmaj < nblkdev; bmaj++)
276 		if (bdevsw[bmaj].d_open == octcfopen)
277 			vdevgone(bmaj, mn, mn + MAXPARTITIONS - 1, VBLK);
278 	for (cmaj = 0; cmaj < nchrdev; cmaj++)
279 		if (cdevsw[cmaj].d_open == octcfopen)
280 			vdevgone(cmaj, mn, mn + MAXPARTITIONS - 1, VCHR);
281 
282 	/* Detach disk. */
283 	disk_detach(&sc->sc_dk);
284 
285 	return (0);
286 }
287 
288 /*
289  * Read/write routine for a buffer.  Validates the arguments and schedules the
290  * transfer.  Does not wait for the transfer to complete.
291  */
292 void
293 octcfstrategy(struct buf *bp)
294 {
295 	struct octcf_softc *wd;
296 	int s;
297 
298 	wd = octcflookup(DISKUNIT(bp->b_dev));
299 	if (wd == NULL) {
300 		bp->b_error = ENXIO;
301 		goto bad;
302 	}
303 	OCTCFDEBUG_PRINT(("octcfstrategy (%s)\n", wd->sc_dev.dv_xname),
304 	    DEBUG_XFERS);
305 	/* If device invalidated (e.g. media change, door open), error. */
306 	if ((wd->sc_flags & OCTCFF_LOADED) == 0) {
307 		bp->b_error = EIO;
308 		goto bad;
309 	}
310 
311 	/* Validate the request. */
312 	if (bounds_check_with_label(bp, wd->sc_dk.dk_label) == -1)
313 		goto done;
314 
315 	/* Check that the number of sectors can fit in a byte. */
316 	if ((bp->b_bcount / wd->sc_dk.dk_label->d_secsize) >= (1 << NBBY)) {
317 		bp->b_error = EINVAL;
318 		goto bad;
319 	}
320 
321 	/* Queue transfer on drive, activate drive and controller if idle. */
322 	s = splbio();
323 	disksort(&wd->sc_q, bp);
324 	octcfstart(wd);
325 	splx(s);
326 	device_unref(&wd->sc_dev);
327 	return;
328 
329  bad:
330 	bp->b_flags |= B_ERROR;
331 	bp->b_resid = bp->b_bcount;
332  done:
333 	s = splbio();
334 	biodone(bp);
335 	splx(s);
336 	if (wd != NULL)
337 		device_unref(&wd->sc_dev);
338 }
339 
340 /*
341  * Queue a drive for I/O.
342  */
343 void
344 octcfstart(void *arg)
345 {
346 	struct octcf_softc *wd = arg;
347 	struct buf *dp, *bp;
348 
349 	OCTCFDEBUG_PRINT(("octcfstart %s\n", wd->sc_dev.dv_xname),
350 	    DEBUG_XFERS);
351 	while (1) {
352 		/* Remove the next buffer from the queue or stop. */
353 		dp = &wd->sc_q;
354 		bp = dp->b_actf;
355 		if (bp == NULL)
356 			return;
357 		dp->b_actf = bp->b_actf;
358 
359 		/* Transfer this buffer now. */
360 		_octcfstart(wd, bp);
361 	}
362 }
363 
364 void
365 _octcfstart(struct octcf_softc *wd, struct buf *bp)
366 {
367 	uint32_t blkno;
368 	uint32_t nblks;
369 
370 	blkno = bp->b_blkno +
371 	    DL_GETPOFFSET(&wd->sc_dk.dk_label->d_partitions[DISKPART(bp->b_dev)]);
372 	blkno /= (SECTOR_SIZE / DEV_BSIZE);
373 	nblks = bp->b_bcount / SECTOR_SIZE;
374 
375 	wd->sc_bp = bp;
376 
377 	/* Instrumentation. */
378 	disk_busy(&wd->sc_dk);
379 
380 	if (bp->b_flags & B_READ)
381 		bp->b_error = octcf_read_sectors(wd, nblks, blkno, bp->b_data);
382 	else
383 		bp->b_error = octcf_write_sectors(wd, nblks, blkno, bp->b_data);
384 
385 	octcfdone(wd);
386 }
387 
388 void
389 octcfdone(void *arg)
390 {
391 	struct octcf_softc *wd = arg;
392 	struct buf *bp = wd->sc_bp;
393 
394 	if (bp->b_error == 0)
395 		bp->b_resid = 0;
396 	else
397 		bp->b_flags |= B_ERROR;
398 
399 	disk_unbusy(&wd->sc_dk, (bp->b_bcount - bp->b_resid),
400 	    (bp->b_flags & B_READ));
401 	biodone(bp);
402 }
403 
404 int
405 octcfread(dev_t dev, struct uio *uio, int flags)
406 {
407 
408 	OCTCFDEBUG_PRINT(("wdread\n"), DEBUG_XFERS);
409 	return (physio(octcfstrategy, dev, B_READ, minphys, uio));
410 }
411 
412 int
413 octcfwrite(dev_t dev, struct uio *uio, int flags)
414 {
415 
416 	OCTCFDEBUG_PRINT(("octcfwrite\n"), DEBUG_XFERS);
417 	return (physio(octcfstrategy, dev, B_WRITE, minphys, uio));
418 }
419 
420 int
421 octcfopen(dev_t dev, int flag, int fmt, struct proc *p)
422 {
423 	struct octcf_softc *wd;
424 	int unit, part;
425 	int error;
426 
427 	OCTCFDEBUG_PRINT(("octcfopen\n"), DEBUG_FUNCS);
428 
429 	unit = DISKUNIT(dev);
430 	wd = octcflookup(unit);
431 	if (wd == NULL)
432 		return ENXIO;
433 
434 	/*
435 	 * If this is the first open of this device, add a reference
436 	 * to the adapter.
437 	 */
438 	if ((error = disk_lock(&wd->sc_dk)) != 0)
439 		goto bad4;
440 
441 	if (wd->sc_dk.dk_openmask != 0) {
442 		/*
443 		 * If any partition is open, but the disk has been invalidated,
444 		 * disallow further opens.
445 		 */
446 		if ((wd->sc_flags & OCTCFF_LOADED) == 0) {
447 			error = EIO;
448 			goto bad3;
449 		}
450 	} else {
451 		if ((wd->sc_flags & OCTCFF_LOADED) == 0) {
452 			wd->sc_flags |= OCTCFF_LOADED;
453 
454 			/* Load the physical device parameters. */
455 			octcf_get_params(wd, &wd->sc_params);
456 
457 			/* Load the partition info if not already loaded. */
458 			if (octcfgetdisklabel(dev, wd,
459 			    wd->sc_dk.dk_label, 0) == EIO) {
460 				error = EIO;
461 				goto bad;
462 			}
463 		}
464 	}
465 
466 	part = DISKPART(dev);
467 
468 	/* Check that the partition exists. */
469 	if (part != RAW_PART &&
470 	    (part >= wd->sc_dk.dk_label->d_npartitions ||
471 	     wd->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) {
472 		error = ENXIO;
473 		goto bad;
474 	}
475 
476 	/* Insure only one open at a time. */
477 	switch (fmt) {
478 	case S_IFCHR:
479 		wd->sc_dk.dk_copenmask |= (1 << part);
480 		break;
481 	case S_IFBLK:
482 		wd->sc_dk.dk_bopenmask |= (1 << part);
483 		break;
484 	}
485 	wd->sc_dk.dk_openmask =
486 	    wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask;
487 
488 	disk_unlock(&wd->sc_dk);
489 	device_unref(&wd->sc_dev);
490 	return 0;
491 
492 bad:
493 	if (wd->sc_dk.dk_openmask == 0) {
494 	}
495 
496 bad3:
497 	disk_unlock(&wd->sc_dk);
498 bad4:
499 	device_unref(&wd->sc_dev);
500 	return error;
501 }
502 
503 int
504 octcfclose(dev_t dev, int flag, int fmt, struct proc *p)
505 {
506 	struct octcf_softc *wd;
507 	int part = DISKPART(dev);
508 
509 	wd = octcflookup(DISKUNIT(dev));
510 	if (wd == NULL)
511 		return ENXIO;
512 
513 	OCTCFDEBUG_PRINT(("octcfclose\n"), DEBUG_FUNCS);
514 
515 	disk_lock_nointr(&wd->sc_dk);
516 
517 	switch (fmt) {
518 	case S_IFCHR:
519 		wd->sc_dk.dk_copenmask &= ~(1 << part);
520 		break;
521 	case S_IFBLK:
522 		wd->sc_dk.dk_bopenmask &= ~(1 << part);
523 		break;
524 	}
525 	wd->sc_dk.dk_openmask =
526 	    wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask;
527 
528 	disk_unlock(&wd->sc_dk);
529 
530 	device_unref(&wd->sc_dev);
531 	return (0);
532 }
533 
534 void
535 octcfgetdefaultlabel(struct octcf_softc *wd, struct disklabel *lp)
536 {
537 	OCTCFDEBUG_PRINT(("octcfgetdefaultlabel\n"), DEBUG_FUNCS);
538 	bzero(lp, sizeof(struct disklabel));
539 
540 	lp->d_secsize = DEV_BSIZE;
541 	DL_SETDSIZE(lp, wd->sc_capacity);
542 	lp->d_ntracks = wd->sc_params.atap_heads;
543 	lp->d_nsectors = wd->sc_params.atap_sectors;
544 	lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
545 	lp->d_ncylinders = DL_GETDSIZE(lp) / lp->d_secpercyl;
546  lp->d_type = DTYPE_ESDI;
547 	strncpy(lp->d_typename, "ESDI/IDE disk", sizeof lp->d_typename);
548 
549 	/* XXX - user viscopy() like sd.c */
550 	strncpy(lp->d_packname, wd->sc_params.atap_model, sizeof lp->d_packname);
551 	lp->d_flags = 0;
552 	lp->d_version = 1;
553 
554 	lp->d_magic = DISKMAGIC;
555 	lp->d_magic2 = DISKMAGIC;
556 	lp->d_checksum = dkcksum(lp);
557 }
558 
559 /*
560  * Fabricate a default disk label, and try to read the correct one.
561  */
562 int
563 octcfgetdisklabel(dev_t dev, struct octcf_softc *wd, struct disklabel *lp,
564     int spoofonly)
565 {
566 	int error;
567 
568 	OCTCFDEBUG_PRINT(("octcfgetdisklabel\n"), DEBUG_FUNCS);
569 
570 	octcfgetdefaultlabel(wd, lp);
571 	error = readdisklabel(DISKLABELDEV(dev), octcfstrategy, lp,
572 	    spoofonly);
573 	return (error);
574 }
575 
576 int
577 octcfioctl(dev_t dev, u_long xfer, caddr_t addr, int flag, struct proc *p)
578 {
579 	struct octcf_softc *wd;
580 	struct disklabel *lp;
581 	int error = 0;
582 
583 	OCTCFDEBUG_PRINT(("octcfioctl\n"), DEBUG_FUNCS);
584 
585 	wd = octcflookup(DISKUNIT(dev));
586 	if (wd == NULL)
587 		return ENXIO;
588 
589 	if ((wd->sc_flags & OCTCFF_LOADED) == 0) {
590 		error = EIO;
591 		goto exit;
592 	}
593 
594 	switch (xfer) {
595 	case DIOCRLDINFO:
596 		lp = malloc(sizeof(*lp), M_TEMP, M_WAITOK);
597 		octcfgetdisklabel(dev, wd, lp, 0);
598 		bcopy(lp, wd->sc_dk.dk_label, sizeof(*lp));
599 		free(lp, M_TEMP);
600 		goto exit;
601 
602 	case DIOCGPDINFO:
603 		octcfgetdisklabel(dev, wd, (struct disklabel *)addr, 1);
604 		goto exit;
605 
606 	case DIOCGDINFO:
607 		*(struct disklabel *)addr = *(wd->sc_dk.dk_label);
608 		goto exit;
609 
610 	case DIOCGPART:
611 		((struct partinfo *)addr)->disklab = wd->sc_dk.dk_label;
612 		((struct partinfo *)addr)->part =
613 		    &wd->sc_dk.dk_label->d_partitions[DISKPART(dev)];
614 		goto exit;
615 
616 	case DIOCWDINFO:
617 	case DIOCSDINFO:
618 		if ((flag & FWRITE) == 0) {
619 			error = EBADF;
620 			goto exit;
621 		}
622 
623 		if ((error = disk_lock(&wd->sc_dk)) != 0)
624 			goto exit;
625 
626 		error = setdisklabel(wd->sc_dk.dk_label,
627 		    (struct disklabel *)addr, /*wd->sc_dk.dk_openmask : */0);
628 		if (error == 0) {
629 			if (xfer == DIOCWDINFO)
630 				error = writedisklabel(DISKLABELDEV(dev),
631 				    octcfstrategy, wd->sc_dk.dk_label);
632 		}
633 
634 		disk_unlock(&wd->sc_dk);
635 		goto exit;
636 
637 #ifdef notyet
638 	case DIOCWFORMAT:
639 		if ((flag & FWRITE) == 0)
640 			return EBADF;
641 		{
642 		struct format_op *fop;
643 		struct iovec aiov;
644 		struct uio auio;
645 
646 		fop = (struct format_op *)addr;
647 		aiov.iov_base = fop->df_buf;
648 		aiov.iov_len = fop->df_count;
649 		auio.uio_iov = &aiov;
650 		auio.uio_iovcnt = 1;
651 		auio.uio_resid = fop->df_count;
652 		auio.uio_segflg = 0;
653 		auio.uio_offset =
654 			fop->df_startblk * wd->sc_dk.dk_label->d_secsize;
655 		auio.uio_procp = p;
656 		error = physio(wdformat, dev, B_WRITE, minphys, &auio);
657 		fop->df_count -= auio.uio_resid;
658 		fop->df_reg[0] = wdc->sc_status;
659 		fop->df_reg[1] = wdc->sc_error;
660 		goto exit;
661 		}
662 #endif
663 
664 	default:
665 		error = ENOTTY;
666 		goto exit;
667 	}
668 
669 #ifdef DIAGNOSTIC
670 	panic("octcfioctl: impossible");
671 #endif
672 
673  exit:
674 	device_unref(&wd->sc_dev);
675 	return (error);
676 }
677 
678 #ifdef B_FORMAT
679 int
680 wdformat(struct buf *bp)
681 {
682 
683 	bp->b_flags |= B_FORMAT;
684 	return octcfstrategy(bp);
685 }
686 #endif
687 
688 daddr64_t
689 octcfsize(dev_t dev)
690 {
691 	struct octcf_softc *wd;
692 	int part, omask;
693 	int64_t size;
694 
695 	OCTCFDEBUG_PRINT(("wdsize\n"), DEBUG_FUNCS);
696 
697 	wd = octcflookup(DISKUNIT(dev));
698 	if (wd == NULL)
699 		return (-1);
700 
701 	part = DISKPART(dev);
702 	omask = wd->sc_dk.dk_openmask & (1 << part);
703 
704 	if (omask == 0 && octcfopen(dev, 0, S_IFBLK, NULL) != 0) {
705 		size = -1;
706 		goto exit;
707 	}
708 
709 	size = DL_GETPSIZE(&wd->sc_dk.dk_label->d_partitions[part]) *
710 	    (wd->sc_dk.dk_label->d_secsize / DEV_BSIZE);
711 	if (omask == 0 && octcfclose(dev, 0, S_IFBLK, NULL) != 0)
712 		size = -1;
713 
714  exit:
715 	device_unref(&wd->sc_dev);
716 	return (size);
717 }
718 
719 /*
720  * Dump core after a system crash.
721  */
722 int
723 octcfdump(dev_t dev, daddr64_t blkno, caddr_t va, size_t size)
724 {
725 	return ENXIO;
726 }
727 
728 int
729 octcf_read_sectors(struct octcf_softc *wd, uint32_t nr_sectors,
730 	uint32_t start_sector, void *buf)
731 {
732 	uint32_t count;
733 	uint16_t *ptr = (uint16_t*)buf;
734 	int error;
735 	uint8_t status;
736 
737 	while (nr_sectors--) {
738 		while ((status = (OCTCF_REG_READ(wd, wdr_status)>>8)) & WDCS_BSY)
739 			DELAY(OCTCFDELAY);
740 		octcf_command(wd, start_sector++, WDCC_READ);
741 		error = octcf_wait_busy(wd);
742 		if (error != 0)
743 			return (error);
744 
745         	volatile uint16_t dummy;
746 		for (count = 0; count < SECTOR_SIZE; count+=2) {
747 			uint16_t temp;
748 			temp = OCTCF_REG_READ(wd, 0x0);
749 			*ptr++ = swap16(temp);
750 			if ((count & 0xf) == 0)
751 				dummy = OCTCF_REG_READ(wd, wdr_status);
752 		}
753 	}
754 	return (0);
755 }
756 
757 int
758 octcf_write_sectors(struct octcf_softc *wd, uint32_t nr_sectors,
759 	uint32_t start_sector, void *buf)
760 {
761 	uint32_t count;
762 	uint16_t *ptr = (uint16_t*)buf;
763 	int error;
764 	uint8_t status;
765 
766 	while (nr_sectors--) {
767 		while ((status = (OCTCF_REG_READ(wd, wdr_status)>>8)) & WDCS_BSY)
768 			DELAY(OCTCFDELAY);
769 		octcf_command(wd, start_sector++, WDCC_WRITE);
770 		if((error = octcf_wait_busy(wd)))
771 			return (error);
772 
773 	      	volatile uint16_t dummy;
774 		for (count = 0; count < SECTOR_SIZE; count+=2) {
775 			uint16_t temp = *ptr++;
776 			OCTCF_REG_WRITE(wd, 0x0, swap16(temp));
777 			if ((count & 0xf) == 0)
778 				dummy = OCTCF_REG_READ(wd, wdr_status);
779 		}
780 	}
781 	return (0);
782 }
783 
784 void
785 octcf_command(struct octcf_softc *wd, uint32_t lba, uint8_t cmd)
786 {
787 	OCTCF_REG_WRITE(wd, wdr_seccnt, 1 | ((lba & 0xff) << 8));
788 	OCTCF_REG_WRITE(wd, wdr_cyl_lo,
789 		((lba >> 8) & 0xff) | (((lba >> 16) & 0xff) << 8));
790 	OCTCF_REG_WRITE(wd, wdr_sdh,
791 		(((lba >> 24) & 0xff) | 0xe0) | (cmd << 8));
792 }
793 
794 int
795 octcf_wait_busy(struct octcf_softc *wd)
796 {
797 	uint8_t status;
798 
799 	status = OCTCF_REG_READ(wd, wdr_status)>>8;
800 	while ((status & WDCS_BSY) == WDCS_BSY) {
801 		if ((status & WDCS_DWF) != 0)
802 			return (EIO);
803 		DELAY(OCTCFDELAY);
804 		status = (uint8_t)(OCTCF_REG_READ(wd, wdr_status)>>8);
805 	}
806 
807 	if ((status & WDCS_DRQ) == 0)
808 		return (ENXIO);
809 
810 	return (0);
811 }
812 
813 /* Get the disk's parameters */
814 int
815 octcf_get_params(struct octcf_softc *wd, struct ataparams *prms)
816 {
817 	char *tb;
818 	int i;
819 	u_int16_t *p;
820 	int count;
821 	uint8_t status;
822 	int error;
823 
824 	OCTCFDEBUG_PRINT(("octcf_get_parms\n"), DEBUG_FUNCS);
825 
826 	tb = malloc(ATAPARAMS_SIZE, M_DEVBUF, M_NOWAIT | M_ZERO);
827 	if (tb == NULL)
828 		return CMD_AGAIN;
829 
830 	while ((status = (OCTCF_REG_READ(wd, wdr_status)>>8)) & WDCS_BSY)
831 		DELAY(OCTCFDELAY);
832 
833 	OCTCF_REG_WRITE(wd, wdr_seccnt, 0);
834 	OCTCF_REG_WRITE(wd, wdr_cyl_lo, 0);
835 	OCTCF_REG_WRITE(wd, wdr_sdh, 0 | (WDCC_IDENTIFY<<8));
836 
837 	error = octcf_wait_busy(wd);
838 	if (error == 0) {
839 		for (count = 0; count < SECTOR_SIZE; count+=2) {
840 			uint16_t temp;
841 			temp = OCTCF_REG_READ(wd, 0x0);
842 
843 			/* endianess will be swapped below */
844 			tb[count]   = (temp & 0xff);
845 			tb[count+1] = (temp & 0xff00)>>8;
846 		}
847 	}
848 
849 	if (error != 0) {
850 		printf("%s: identify failed: %d\n", __func__, error);
851 		free(tb, M_DEVBUF);
852 		return CMD_ERR;
853 	} else {
854 #if BYTE_ORDER == BIG_ENDIAN
855 		/* All the fields in the params structure are 16-bit
856 		   integers except for the ID strings which are char
857 		   strings.  The 16-bit integers are currently in
858 		   memory in little-endian, regardless of architecture.
859 		   So, they need to be swapped on big-endian architectures
860 		   before they are accessed through the ataparams structure.
861 
862 		   The swaps below avoid touching the char strings.
863 		*/
864 
865 		swap16_multi((u_int16_t *)tb, 10);
866 		swap16_multi((u_int16_t *)tb + 20, 3);
867 		swap16_multi((u_int16_t *)tb + 47, ATAPARAMS_SIZE / 2 - 47);
868 #endif
869 		/* Read in parameter block. */
870 		bcopy(tb, prms, sizeof(struct ataparams));
871 
872 		/*
873 		 * Shuffle string byte order.
874 		 * ATAPI Mitsumi and NEC drives don't need this.
875 		 */
876 		if ((prms->atap_config & WDC_CFG_ATAPI_MASK) ==
877 		    WDC_CFG_ATAPI &&
878 		    ((prms->atap_model[0] == 'N' &&
879 			prms->atap_model[1] == 'E') ||
880 		     (prms->atap_model[0] == 'F' &&
881 			 prms->atap_model[1] == 'X'))) {
882 			free(tb, M_DEVBUF);
883 			return CMD_OK;
884 		}
885 		for (i = 0; i < sizeof(prms->atap_model); i += 2) {
886 			p = (u_short *)(prms->atap_model + i);
887 			*p = swap16(*p);
888 		}
889 		for (i = 0; i < sizeof(prms->atap_serial); i += 2) {
890 			p = (u_short *)(prms->atap_serial + i);
891 			*p = swap16(*p);
892 		}
893 		for (i = 0; i < sizeof(prms->atap_revision); i += 2) {
894 			p = (u_short *)(prms->atap_revision + i);
895 			*p = swap16(*p);
896 		}
897 
898 		free(tb, M_DEVBUF);
899 		return CMD_OK;
900 	}
901 }
902