xref: /openbsd/sys/arch/octeon/dev/octcf.c (revision 898184e3)
1 /*	$OpenBSD: octcf.c,v 1.10 2013/03/19 16:37:12 jasper 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 #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 buf sc_q;
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 					wd->sc_dev.dv_xname);
203 			break;
204 		}
205 	}
206 
207 	/* Check if CF is inserted */
208 	i = 0;
209 	while ( (status = (OCTCF_REG_READ(wd, wdr_status)>>8)) & WDCS_BSY) {
210 		if ((i++) == NR_TRIES )     {
211 			printf(": card not present\n", wd->sc_dev.dv_xname);
212 			return;
213                	}
214 		DELAY(OCTCFDELAY);
215 	}
216 
217 	/* read our drive info */
218 	if (octcf_get_params(wd, &wd->sc_params) != 0) {
219 		printf(": IDENTIFY failed\n", wd->sc_dev.dv_xname);
220 		return;
221 	}
222 
223 	for (blank = 0, p = wd->sc_params.atap_model, q = buf, i = 0;
224 	    i < sizeof(wd->sc_params.atap_model); i++) {
225 		c = *p++;
226 		if (c == '\0')
227 			break;
228 		if (c != ' ') {
229 			if (blank) {
230 				*q++ = ' ';
231 				blank = 0;
232 			}
233 			*q++ = c;
234 		} else
235 			blank = 1;
236 		}
237 	*q++ = '\0';
238 
239 	printf(": <%s>\n", buf);
240 	printf("%s: %d-sector PIO,",
241 		wd->sc_dev.dv_xname, wd->sc_params.atap_multi & 0xff);
242 
243 	wd->sc_capacity =
244 		wd->sc_params.atap_cylinders *
245 		wd->sc_params.atap_heads *
246 		wd->sc_params.atap_sectors;
247 	printf(" CHS, %lluMB, %d cyl, %d head, %d sec, %llu sectors\n",
248 		wd->sc_capacity / (1048576 / DEV_BSIZE),
249 		wd->sc_params.atap_cylinders,
250 		wd->sc_params.atap_heads,
251 		wd->sc_params.atap_sectors,
252 		wd->sc_capacity);
253 
254 	OCTCFDEBUG_PRINT(
255 		("%s: atap_dmatiming_mimi=%d, atap_dmatiming_recom=%d\n",
256 		self->dv_xname, wd->sc_params.atap_dmatiming_mimi,
257 		wd->sc_params.atap_dmatiming_recom), DEBUG_PROBE);
258 
259 	/*
260 	 * Initialize disk structures.
261 	 */
262 	wd->sc_dk.dk_name = wd->sc_dev.dv_xname;
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 transfer on drive, activate drive and controller if idle. */
330 	s = splbio();
331 	disksort(&wd->sc_q, bp);
332 	octcfstart(wd);
333 	splx(s);
334 	device_unref(&wd->sc_dev);
335 	return;
336 
337  bad:
338 	bp->b_flags |= B_ERROR;
339 	bp->b_resid = bp->b_bcount;
340  done:
341 	s = splbio();
342 	biodone(bp);
343 	splx(s);
344 	if (wd != NULL)
345 		device_unref(&wd->sc_dev);
346 }
347 
348 /*
349  * Queue a drive for I/O.
350  */
351 void
352 octcfstart(void *arg)
353 {
354 	struct octcf_softc *wd = arg;
355 	struct buf *dp, *bp;
356 
357 	OCTCFDEBUG_PRINT(("%s %s\n", __func__, wd->sc_dev.dv_xname),
358 	    DEBUG_XFERS);
359 	while (1) {
360 		/* Remove the next buffer from the queue or stop. */
361 		dp = &wd->sc_q;
362 		bp = dp->b_actf;
363 		if (bp == NULL)
364 			return;
365 		dp->b_actf = bp->b_actf;
366 
367 		/* Transfer this buffer now. */
368 		_octcfstart(wd, bp);
369 	}
370 }
371 
372 void
373 _octcfstart(struct octcf_softc *wd, struct buf *bp)
374 {
375 	uint32_t blkno;
376 	uint32_t nblks;
377 
378 	blkno = bp->b_blkno +
379 	    DL_GETPOFFSET(&wd->sc_dk.dk_label->d_partitions[DISKPART(bp->b_dev)]);
380 	blkno /= (SECTOR_SIZE / DEV_BSIZE);
381 	nblks = bp->b_bcount / SECTOR_SIZE;
382 
383 	wd->sc_bp = bp;
384 
385 	/* Instrumentation. */
386 	disk_busy(&wd->sc_dk);
387 
388 	if (bp->b_flags & B_READ)
389 		bp->b_error = octcf_read_sectors(wd, nblks, blkno, bp->b_data);
390 	else
391 		bp->b_error = octcf_write_sectors(wd, nblks, blkno, bp->b_data);
392 
393 	octcfdone(wd);
394 }
395 
396 void
397 octcfdone(void *arg)
398 {
399 	struct octcf_softc *wd = arg;
400 	struct buf *bp = wd->sc_bp;
401 
402 	if (bp->b_error == 0)
403 		bp->b_resid = 0;
404 	else
405 		bp->b_flags |= B_ERROR;
406 
407 	disk_unbusy(&wd->sc_dk, (bp->b_bcount - bp->b_resid),
408 	    (bp->b_flags & B_READ));
409 	biodone(bp);
410 }
411 
412 int
413 octcfread(dev_t dev, struct uio *uio, int flags)
414 {
415 
416 	OCTCFDEBUG_PRINT(("%s\n", __func__), DEBUG_XFERS);
417 	return (physio(octcfstrategy, dev, B_READ, minphys, uio));
418 }
419 
420 int
421 octcfwrite(dev_t dev, struct uio *uio, int flags)
422 {
423 
424 	OCTCFDEBUG_PRINT(("%s\n", __func__), DEBUG_XFERS);
425 	return (physio(octcfstrategy, dev, B_WRITE, minphys, uio));
426 }
427 
428 int
429 octcfopen(dev_t dev, int flag, int fmt, struct proc *p)
430 {
431 	struct octcf_softc *wd;
432 	int unit, part;
433 	int error;
434 
435 	OCTCFDEBUG_PRINT(("%s\n", __func__), DEBUG_FUNCS);
436 
437 	unit = DISKUNIT(dev);
438 	wd = octcflookup(unit);
439 	if (wd == NULL)
440 		return ENXIO;
441 
442 	/*
443 	 * If this is the first open of this device, add a reference
444 	 * to the adapter.
445 	 */
446 	if ((error = disk_lock(&wd->sc_dk)) != 0)
447 		goto bad4;
448 
449 	if (wd->sc_dk.dk_openmask != 0) {
450 		/*
451 		 * If any partition is open, but the disk has been invalidated,
452 		 * disallow further opens.
453 		 */
454 		if ((wd->sc_flags & OCTCFF_LOADED) == 0) {
455 			error = EIO;
456 			goto bad3;
457 		}
458 	} else {
459 		if ((wd->sc_flags & OCTCFF_LOADED) == 0) {
460 			wd->sc_flags |= OCTCFF_LOADED;
461 
462 			/* Load the physical device parameters. */
463 			octcf_get_params(wd, &wd->sc_params);
464 
465 			/* Load the partition info if not already loaded. */
466 			if (octcfgetdisklabel(dev, wd,
467 			    wd->sc_dk.dk_label, 0) == EIO) {
468 				error = EIO;
469 				goto bad;
470 			}
471 		}
472 	}
473 
474 	part = DISKPART(dev);
475 
476 	/* Check that the partition exists. */
477 	if (part != RAW_PART &&
478 	    (part >= wd->sc_dk.dk_label->d_npartitions ||
479 	     wd->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) {
480 		error = ENXIO;
481 		goto bad;
482 	}
483 
484 	/* Insure only one open at a time. */
485 	switch (fmt) {
486 	case S_IFCHR:
487 		wd->sc_dk.dk_copenmask |= (1 << part);
488 		break;
489 	case S_IFBLK:
490 		wd->sc_dk.dk_bopenmask |= (1 << part);
491 		break;
492 	}
493 	wd->sc_dk.dk_openmask =
494 	    wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask;
495 
496 	disk_unlock(&wd->sc_dk);
497 	device_unref(&wd->sc_dev);
498 	return 0;
499 
500 bad:
501 	if (wd->sc_dk.dk_openmask == 0) {
502 	}
503 
504 bad3:
505 	disk_unlock(&wd->sc_dk);
506 bad4:
507 	device_unref(&wd->sc_dev);
508 	return error;
509 }
510 
511 int
512 octcfclose(dev_t dev, int flag, int fmt, struct proc *p)
513 {
514 	struct octcf_softc *wd;
515 	int part = DISKPART(dev);
516 
517 	wd = octcflookup(DISKUNIT(dev));
518 	if (wd == NULL)
519 		return ENXIO;
520 
521 	OCTCFDEBUG_PRINT(("%s\n", __func__), DEBUG_FUNCS);
522 
523 	disk_lock_nointr(&wd->sc_dk);
524 
525 	switch (fmt) {
526 	case S_IFCHR:
527 		wd->sc_dk.dk_copenmask &= ~(1 << part);
528 		break;
529 	case S_IFBLK:
530 		wd->sc_dk.dk_bopenmask &= ~(1 << part);
531 		break;
532 	}
533 	wd->sc_dk.dk_openmask =
534 	    wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask;
535 
536 	disk_unlock(&wd->sc_dk);
537 
538 	device_unref(&wd->sc_dev);
539 	return (0);
540 }
541 
542 void
543 octcfgetdefaultlabel(struct octcf_softc *wd, struct disklabel *lp)
544 {
545 	OCTCFDEBUG_PRINT(("%s\n", __func__), DEBUG_FUNCS);
546 	bzero(lp, sizeof(struct disklabel));
547 
548 	lp->d_secsize = DEV_BSIZE;
549 	DL_SETDSIZE(lp, wd->sc_capacity);
550 	lp->d_ntracks = wd->sc_params.atap_heads;
551 	lp->d_nsectors = wd->sc_params.atap_sectors;
552 	lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
553 	lp->d_ncylinders = DL_GETDSIZE(lp) / lp->d_secpercyl;
554  lp->d_type = DTYPE_ESDI;
555 	strncpy(lp->d_typename, "ESDI/IDE disk", sizeof lp->d_typename);
556 
557 	/* XXX - user viscopy() like sd.c */
558 	strncpy(lp->d_packname, wd->sc_params.atap_model, sizeof lp->d_packname);
559 	lp->d_flags = 0;
560 	lp->d_version = 1;
561 
562 	lp->d_magic = DISKMAGIC;
563 	lp->d_magic2 = DISKMAGIC;
564 	lp->d_checksum = dkcksum(lp);
565 }
566 
567 /*
568  * Fabricate a default disk label, and try to read the correct one.
569  */
570 int
571 octcfgetdisklabel(dev_t dev, struct octcf_softc *wd, struct disklabel *lp,
572     int spoofonly)
573 {
574 	int error;
575 
576 	OCTCFDEBUG_PRINT(("%s\n", __func__), DEBUG_FUNCS);
577 
578 	octcfgetdefaultlabel(wd, lp);
579 	error = readdisklabel(DISKLABELDEV(dev), octcfstrategy, lp,
580 	    spoofonly);
581 	return (error);
582 }
583 
584 int
585 octcfioctl(dev_t dev, u_long xfer, caddr_t addr, int flag, struct proc *p)
586 {
587 	struct octcf_softc *wd;
588 	struct disklabel *lp;
589 	int error = 0;
590 
591 	OCTCFDEBUG_PRINT(("%s\n", __func__), DEBUG_FUNCS);
592 
593 	wd = octcflookup(DISKUNIT(dev));
594 	if (wd == NULL)
595 		return ENXIO;
596 
597 	if ((wd->sc_flags & OCTCFF_LOADED) == 0) {
598 		error = EIO;
599 		goto exit;
600 	}
601 
602 	switch (xfer) {
603 	case DIOCRLDINFO:
604 		lp = malloc(sizeof(*lp), M_TEMP, M_WAITOK);
605 		octcfgetdisklabel(dev, wd, lp, 0);
606 		bcopy(lp, wd->sc_dk.dk_label, sizeof(*lp));
607 		free(lp, M_TEMP);
608 		goto exit;
609 
610 	case DIOCGPDINFO:
611 		octcfgetdisklabel(dev, wd, (struct disklabel *)addr, 1);
612 		goto exit;
613 
614 	case DIOCGDINFO:
615 		*(struct disklabel *)addr = *(wd->sc_dk.dk_label);
616 		goto exit;
617 
618 	case DIOCGPART:
619 		((struct partinfo *)addr)->disklab = wd->sc_dk.dk_label;
620 		((struct partinfo *)addr)->part =
621 		    &wd->sc_dk.dk_label->d_partitions[DISKPART(dev)];
622 		goto exit;
623 
624 	case DIOCWDINFO:
625 	case DIOCSDINFO:
626 		if ((flag & FWRITE) == 0) {
627 			error = EBADF;
628 			goto exit;
629 		}
630 
631 		if ((error = disk_lock(&wd->sc_dk)) != 0)
632 			goto exit;
633 
634 		error = setdisklabel(wd->sc_dk.dk_label,
635 		    (struct disklabel *)addr, /*wd->sc_dk.dk_openmask : */0);
636 		if (error == 0) {
637 			if (xfer == DIOCWDINFO)
638 				error = writedisklabel(DISKLABELDEV(dev),
639 				    octcfstrategy, wd->sc_dk.dk_label);
640 		}
641 
642 		disk_unlock(&wd->sc_dk);
643 		goto exit;
644 
645 #ifdef notyet
646 	case DIOCWFORMAT:
647 		if ((flag & FWRITE) == 0)
648 			return EBADF;
649 		{
650 		struct format_op *fop;
651 		struct iovec aiov;
652 		struct uio auio;
653 
654 		fop = (struct format_op *)addr;
655 		aiov.iov_base = fop->df_buf;
656 		aiov.iov_len = fop->df_count;
657 		auio.uio_iov = &aiov;
658 		auio.uio_iovcnt = 1;
659 		auio.uio_resid = fop->df_count;
660 		auio.uio_segflg = 0;
661 		auio.uio_offset =
662 			fop->df_startblk * wd->sc_dk.dk_label->d_secsize;
663 		auio.uio_procp = p;
664 		error = physio(wdformat, dev, B_WRITE, minphys, &auio);
665 		fop->df_count -= auio.uio_resid;
666 		fop->df_reg[0] = wdc->sc_status;
667 		fop->df_reg[1] = wdc->sc_error;
668 		goto exit;
669 		}
670 #endif
671 
672 	default:
673 		error = ENOTTY;
674 		goto exit;
675 	}
676 
677 #ifdef DIAGNOSTIC
678 	panic("octcfioctl: impossible");
679 #endif
680 
681  exit:
682 	device_unref(&wd->sc_dev);
683 	return (error);
684 }
685 
686 #ifdef B_FORMAT
687 int
688 wdformat(struct buf *bp)
689 {
690 
691 	bp->b_flags |= B_FORMAT;
692 	return octcfstrategy(bp);
693 }
694 #endif
695 
696 daddr64_t
697 octcfsize(dev_t dev)
698 {
699 	struct octcf_softc *wd;
700 	int part, omask;
701 	int64_t size;
702 
703 	OCTCFDEBUG_PRINT(("%s\n", __func__), DEBUG_FUNCS);
704 
705 	wd = octcflookup(DISKUNIT(dev));
706 	if (wd == NULL)
707 		return (-1);
708 
709 	part = DISKPART(dev);
710 	omask = wd->sc_dk.dk_openmask & (1 << part);
711 
712 	if (omask == 0 && octcfopen(dev, 0, S_IFBLK, NULL) != 0) {
713 		size = -1;
714 		goto exit;
715 	}
716 
717 	size = DL_GETPSIZE(&wd->sc_dk.dk_label->d_partitions[part]) *
718 	    (wd->sc_dk.dk_label->d_secsize / DEV_BSIZE);
719 	if (omask == 0 && octcfclose(dev, 0, S_IFBLK, NULL) != 0)
720 		size = -1;
721 
722  exit:
723 	device_unref(&wd->sc_dev);
724 	return (size);
725 }
726 
727 /*
728  * Dump core after a system crash.
729  */
730 int
731 octcfdump(dev_t dev, daddr64_t blkno, caddr_t va, size_t size)
732 {
733 	return ENXIO;
734 }
735 
736 int
737 octcf_read_sectors(struct octcf_softc *wd, uint32_t nr_sectors,
738 	uint32_t start_sector, void *buf)
739 {
740 	uint32_t count;
741 	uint16_t *ptr = (uint16_t*)buf;
742 	int error;
743 	uint8_t status;
744 
745 	while (nr_sectors--) {
746 		while ((status = (OCTCF_REG_READ(wd, wdr_status)>>8)) & WDCS_BSY)
747 			DELAY(OCTCFDELAY);
748 		octcf_command(wd, start_sector++, WDCC_READ);
749 		error = octcf_wait_busy(wd);
750 		if (error != 0)
751 			return (error);
752 
753         	volatile uint16_t dummy;
754 		for (count = 0; count < SECTOR_SIZE; count+=2) {
755 			uint16_t temp;
756 			temp = OCTCF_REG_READ(wd, 0x0);
757 			*ptr++ = swap16(temp);
758 			if ((count & 0xf) == 0)
759 				dummy = OCTCF_REG_READ(wd, wdr_status);
760 		}
761 	}
762 	return (0);
763 }
764 
765 int
766 octcf_write_sectors(struct octcf_softc *wd, uint32_t nr_sectors,
767 	uint32_t start_sector, void *buf)
768 {
769 	uint32_t count;
770 	uint16_t *ptr = (uint16_t*)buf;
771 	int error;
772 	uint8_t status;
773 
774 	while (nr_sectors--) {
775 		while ((status = (OCTCF_REG_READ(wd, wdr_status)>>8)) & WDCS_BSY)
776 			DELAY(OCTCFDELAY);
777 		octcf_command(wd, start_sector++, WDCC_WRITE);
778 		if((error = octcf_wait_busy(wd)))
779 			return (error);
780 
781 	      	volatile uint16_t dummy;
782 		for (count = 0; count < SECTOR_SIZE; count+=2) {
783 			uint16_t temp = *ptr++;
784 			OCTCF_REG_WRITE(wd, 0x0, swap16(temp));
785 			if ((count & 0xf) == 0)
786 				dummy = OCTCF_REG_READ(wd, wdr_status);
787 		}
788 	}
789 	return (0);
790 }
791 
792 void
793 octcf_command(struct octcf_softc *wd, uint32_t lba, uint8_t cmd)
794 {
795 	OCTCF_REG_WRITE(wd, wdr_seccnt, 1 | ((lba & 0xff) << 8));
796 	OCTCF_REG_WRITE(wd, wdr_cyl_lo,
797 		((lba >> 8) & 0xff) | (((lba >> 16) & 0xff) << 8));
798 	OCTCF_REG_WRITE(wd, wdr_sdh,
799 		(((lba >> 24) & 0xff) | 0xe0) | (cmd << 8));
800 }
801 
802 int
803 octcf_wait_busy(struct octcf_softc *wd)
804 {
805 	uint8_t status;
806 
807 	status = OCTCF_REG_READ(wd, wdr_status)>>8;
808 	while ((status & WDCS_BSY) == WDCS_BSY) {
809 		if ((status & WDCS_DWF) != 0)
810 			return (EIO);
811 		DELAY(OCTCFDELAY);
812 		status = (uint8_t)(OCTCF_REG_READ(wd, wdr_status)>>8);
813 	}
814 
815 	if ((status & WDCS_DRQ) == 0)
816 		return (ENXIO);
817 
818 	return (0);
819 }
820 
821 /* Get the disk's parameters */
822 int
823 octcf_get_params(struct octcf_softc *wd, struct ataparams *prms)
824 {
825 	char *tb;
826 	int i;
827 	u_int16_t *p;
828 	int count;
829 	uint8_t status;
830 	int error;
831 
832 	OCTCFDEBUG_PRINT(("%s\n", __func__), DEBUG_FUNCS);
833 
834 	tb = malloc(ATAPARAMS_SIZE, M_DEVBUF, M_NOWAIT | M_ZERO);
835 	if (tb == NULL)
836 		return CMD_AGAIN;
837 
838 	while ((status = (OCTCF_REG_READ(wd, wdr_status)>>8)) & WDCS_BSY)
839 		DELAY(OCTCFDELAY);
840 
841 	OCTCF_REG_WRITE(wd, wdr_seccnt, 0);
842 	OCTCF_REG_WRITE(wd, wdr_cyl_lo, 0);
843 	OCTCF_REG_WRITE(wd, wdr_sdh, 0 | (WDCC_IDENTIFY<<8));
844 
845 	error = octcf_wait_busy(wd);
846 	if (error == 0) {
847 		for (count = 0; count < SECTOR_SIZE; count+=2) {
848 			uint16_t temp;
849 			temp = OCTCF_REG_READ(wd, 0x0);
850 
851 			/* endianess will be swapped below */
852 			tb[count]   = (temp & 0xff);
853 			tb[count+1] = (temp & 0xff00)>>8;
854 		}
855 	}
856 
857 	if (error != 0) {
858 		printf("%s: identify failed: %d\n", __func__, error);
859 		free(tb, M_DEVBUF);
860 		return CMD_ERR;
861 	} else {
862 #if BYTE_ORDER == BIG_ENDIAN
863 		/* All the fields in the params structure are 16-bit
864 		   integers except for the ID strings which are char
865 		   strings.  The 16-bit integers are currently in
866 		   memory in little-endian, regardless of architecture.
867 		   So, they need to be swapped on big-endian architectures
868 		   before they are accessed through the ataparams structure.
869 
870 		   The swaps below avoid touching the char strings.
871 		*/
872 
873 		swap16_multi((u_int16_t *)tb, 10);
874 		swap16_multi((u_int16_t *)tb + 20, 3);
875 		swap16_multi((u_int16_t *)tb + 47, ATAPARAMS_SIZE / 2 - 47);
876 #endif
877 		/* Read in parameter block. */
878 		bcopy(tb, prms, sizeof(struct ataparams));
879 
880 		/*
881 		 * Shuffle string byte order.
882 		 * ATAPI Mitsumi and NEC drives don't need this.
883 		 */
884 		if ((prms->atap_config & WDC_CFG_ATAPI_MASK) ==
885 		    WDC_CFG_ATAPI &&
886 		    ((prms->atap_model[0] == 'N' &&
887 			prms->atap_model[1] == 'E') ||
888 		     (prms->atap_model[0] == 'F' &&
889 			 prms->atap_model[1] == 'X'))) {
890 			free(tb, M_DEVBUF);
891 			return CMD_OK;
892 		}
893 		for (i = 0; i < sizeof(prms->atap_model); i += 2) {
894 			p = (u_short *)(prms->atap_model + i);
895 			*p = swap16(*p);
896 		}
897 		for (i = 0; i < sizeof(prms->atap_serial); i += 2) {
898 			p = (u_short *)(prms->atap_serial + i);
899 			*p = swap16(*p);
900 		}
901 		for (i = 0; i < sizeof(prms->atap_revision); i += 2) {
902 			p = (u_short *)(prms->atap_revision + i);
903 			*p = swap16(*p);
904 		}
905 
906 		free(tb, M_DEVBUF);
907 		return CMD_OK;
908 	}
909 }
910