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