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