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