xref: /netbsd-src/sys/dev/mca/ed_mca.c (revision 8b0f9554ff8762542c4defc4f70e1eb76fb508fa)
1 /*	$NetBSD: ed_mca.c,v 1.39 2007/10/19 12:00:34 ad Exp $	*/
2 
3 /*
4  * Copyright (c) 2001 The NetBSD Foundation, Inc.
5  *
6  * This code is derived from software contributed to The NetBSD Foundation
7  * by Jaromir Dolecek.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *        This product includes software developed by the NetBSD
20  *        Foundation, Inc. and its contributors.
21  * 4. The name of the author may not be used to endorse or promote products
22  *    derived from this software without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 /*
37  * Disk drive goo for MCA ESDI controller driver.
38  */
39 
40 #include <sys/cdefs.h>
41 __KERNEL_RCSID(0, "$NetBSD: ed_mca.c,v 1.39 2007/10/19 12:00:34 ad Exp $");
42 
43 #include "rnd.h"
44 
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/kernel.h>
48 #include <sys/conf.h>
49 #include <sys/file.h>
50 #include <sys/stat.h>
51 #include <sys/ioctl.h>
52 #include <sys/buf.h>
53 #include <sys/bufq.h>
54 #include <sys/uio.h>
55 #include <sys/malloc.h>
56 #include <sys/device.h>
57 #include <sys/disklabel.h>
58 #include <sys/disk.h>
59 #include <sys/syslog.h>
60 #include <sys/proc.h>
61 #include <sys/vnode.h>
62 #if NRND > 0
63 #include <sys/rnd.h>
64 #endif
65 
66 #include <sys/intr.h>
67 #include <sys/bus.h>
68 
69 #include <dev/mca/mcavar.h>
70 
71 #include <dev/mca/edcreg.h>
72 #include <dev/mca/edvar.h>
73 #include <dev/mca/edcvar.h>
74 
75 /* #define ATADEBUG */
76 
77 #ifdef ATADEBUG
78 #define ATADEBUG_PRINT(args, level)  printf args
79 #else
80 #define ATADEBUG_PRINT(args, level)
81 #endif
82 
83 #define	EDLABELDEV(dev) (MAKEDISKDEV(major(dev), DISKUNIT(dev), RAW_PART))
84 
85 static int     ed_mca_probe  (struct device *, struct cfdata *, void *);
86 static void    ed_mca_attach (struct device *, struct device *, void *);
87 
88 CFATTACH_DECL(ed_mca, sizeof(struct ed_softc),
89     ed_mca_probe, ed_mca_attach, NULL, NULL);
90 
91 extern struct cfdriver ed_cd;
92 
93 static int	ed_get_params(struct ed_softc *, int *);
94 static void	edgetdisklabel(dev_t, struct ed_softc *);
95 static void	edgetdefaultlabel(struct ed_softc *, struct disklabel *);
96 
97 dev_type_open(edmcaopen);
98 dev_type_close(edmcaclose);
99 dev_type_read(edmcaread);
100 dev_type_write(edmcawrite);
101 dev_type_ioctl(edmcaioctl);
102 dev_type_strategy(edmcastrategy);
103 dev_type_dump(edmcadump);
104 dev_type_size(edmcasize);
105 
106 const struct bdevsw ed_bdevsw = {
107 	edmcaopen, edmcaclose, edmcastrategy, edmcaioctl,
108 	edmcadump, edmcasize, D_DISK
109 };
110 
111 const struct cdevsw ed_cdevsw = {
112 	edmcaopen, edmcaclose, edmcaread, edmcawrite, edmcaioctl,
113 	nostop, notty, nopoll, nommap, nokqfilter, D_DISK
114 };
115 
116 static struct dkdriver eddkdriver = { edmcastrategy, minphys };
117 
118 /*
119  * Just check if it's possible to identify the disk.
120  */
121 static int
122 ed_mca_probe(struct device *parent, struct cfdata *cf,
123     void *aux)
124 {
125 	u_int16_t cmd_args[2];
126 	struct edc_mca_softc *sc = (void *) parent;
127 	struct ed_attach_args *eda = (struct ed_attach_args *) aux;
128 	int found = 1;
129 
130 	/*
131 	 * Get Device Configuration (09).
132 	 */
133 	cmd_args[0] = 14;	/* Options: 00s110, s: 0=Physical 1=Pseudo */
134 	cmd_args[1] = 0;
135 	if (edc_run_cmd(sc, CMD_GET_DEV_CONF, eda->edc_drive, cmd_args, 2, 1))
136 		found = 0;
137 
138 	return (found);
139 }
140 
141 static void
142 ed_mca_attach(parent, self, aux)
143 	struct device *parent, *self;
144 	void *aux;
145 {
146 	struct ed_softc *ed = device_private(self);
147 	struct edc_mca_softc *sc = device_private(parent);
148 	struct ed_attach_args *eda = (struct ed_attach_args *) aux;
149 	char pbuf[8];
150 	int drv_flags;
151 
152 	ed->edc_softc = sc;
153 	ed->sc_devno  = eda->edc_drive;
154 	edc_add_disk(sc, ed);
155 
156 	bufq_alloc(&ed->sc_q, "disksort", BUFQ_SORT_RAWBLOCK);
157 	simple_lock_init(&ed->sc_q_lock);
158 
159 	if (ed_get_params(ed, &drv_flags)) {
160 		printf(": IDENTIFY failed, no disk found\n");
161 		return;
162 	}
163 
164 	format_bytes(pbuf, sizeof(pbuf),
165 		(u_int64_t) ed->sc_capacity * DEV_BSIZE);
166 	printf(": %s, %u cyl, %u head, %u sec, 512 bytes/sect x %u sectors\n",
167 		pbuf,
168 		ed->cyl, ed->heads, ed->sectors,
169 		ed->sc_capacity);
170 
171 	printf("%s: %u spares/cyl, %s, %s, %s, %s, %s\n",
172 		ed->sc_dev.dv_xname, ed->spares,
173 		(drv_flags & (1 << 0)) ? "NoRetries" : "Retries",
174 		(drv_flags & (1 << 1)) ? "Removable" : "Fixed",
175 		(drv_flags & (1 << 2)) ? "SkewedFormat" : "NoSkew",
176 		(drv_flags & (1 << 3)) ? "ZeroDefect" : "Defects",
177 		(drv_flags & (1 << 4)) ? "InvalidSecondary" : "SecondaryOK"
178 		);
179 
180 	/*
181 	 * Initialize and attach the disk structure.
182 	 */
183 	disk_init(&ed->sc_dk, ed->sc_dev.dv_xname, &eddkdriver);
184 	disk_attach(&ed->sc_dk);
185 #if NRND > 0
186 	rnd_attach_source(&ed->rnd_source, ed->sc_dev.dv_xname,
187 			  RND_TYPE_DISK, 0);
188 #endif
189 
190 	ed->sc_flags |= EDF_INIT;
191 
192 	/*
193 	 * XXX We should try to discovery wedges here, but
194 	 * XXX that would mean being able to do I/O.  Should
195 	 * XXX use config_defer() here.
196 	 */
197 }
198 
199 /*
200  * Read/write routine for a buffer.  Validates the arguments and schedules the
201  * transfer.  Does not wait for the transfer to complete.
202  */
203 void
204 edmcastrategy(bp)
205 	struct buf *bp;
206 {
207 	struct ed_softc *ed = device_lookup(&ed_cd, DISKUNIT(bp->b_dev));
208 	struct disklabel *lp = ed->sc_dk.dk_label;
209 	daddr_t blkno;
210 
211 	ATADEBUG_PRINT(("edmcastrategy (%s)\n", ed->sc_dev.dv_xname),
212 	    DEBUG_XFERS);
213 
214 	/* Valid request?  */
215 	if (bp->b_blkno < 0 ||
216 	    (bp->b_bcount % lp->d_secsize) != 0 ||
217 	    (bp->b_bcount / lp->d_secsize) >= (1 << NBBY)) {
218 		bp->b_error = EINVAL;
219 		goto done;
220 	}
221 
222 	/* If device invalidated (e.g. media change, door open), error. */
223 	if ((ed->sc_flags & WDF_LOADED) == 0) {
224 		bp->b_error = EIO;
225 		goto done;
226 	}
227 
228 	/* If it's a null transfer, return immediately. */
229 	if (bp->b_bcount == 0)
230 		goto done;
231 
232 	/*
233 	 * Do bounds checking, adjust transfer. if error, process.
234 	 * If end of partition, just return.
235 	 */
236 	if (DISKPART(bp->b_dev) != RAW_PART &&
237 	    bounds_check_with_label(&ed->sc_dk, bp,
238 	    (ed->sc_flags & (WDF_WLABEL|WDF_LABELLING)) != 0) <= 0)
239 		goto done;
240 
241 	/*
242 	 * Now convert the block number to absolute and put it in
243 	 * terms of the device's logical block size.
244 	 */
245 	if (lp->d_secsize >= DEV_BSIZE)
246 		blkno = bp->b_blkno / (lp->d_secsize / DEV_BSIZE);
247 	else
248 		blkno = bp->b_blkno * (DEV_BSIZE / lp->d_secsize);
249 
250 	if (DISKPART(bp->b_dev) != RAW_PART)
251 		blkno += lp->d_partitions[DISKPART(bp->b_dev)].p_offset;
252 
253 	bp->b_rawblkno = blkno;
254 
255 	/* Queue transfer on drive, activate drive and controller if idle. */
256 	simple_lock(&ed->sc_q_lock);
257 	BUFQ_PUT(ed->sc_q, bp);
258 	simple_unlock(&ed->sc_q_lock);
259 
260 	/* Ring the worker thread */
261 	wakeup_one(ed->edc_softc);
262 
263 	return;
264 done:
265 	/* Toss transfer; we're done early. */
266 	bp->b_resid = bp->b_bcount;
267 	biodone(bp);
268 }
269 
270 int
271 edmcaread(dev_t dev, struct uio *uio, int flags)
272 {
273 	ATADEBUG_PRINT(("edread\n"), DEBUG_XFERS);
274 	return (physio(edmcastrategy, NULL, dev, B_READ, minphys, uio));
275 }
276 
277 int
278 edmcawrite(dev_t dev, struct uio *uio, int flags)
279 {
280 	ATADEBUG_PRINT(("edwrite\n"), DEBUG_XFERS);
281 	return (physio(edmcastrategy, NULL, dev, B_WRITE, minphys, uio));
282 }
283 
284 int
285 edmcaopen(dev_t dev, int flag, int fmt, struct lwp *l)
286 {
287 	struct ed_softc *wd;
288 	int part, error;
289 
290 	ATADEBUG_PRINT(("edopen\n"), DEBUG_FUNCS);
291 	wd = device_lookup(&ed_cd, DISKUNIT(dev));
292 	if (wd == NULL || (wd->sc_flags & EDF_INIT) == 0)
293 		return (ENXIO);
294 
295 	part = DISKPART(dev);
296 
297 	mutex_enter(&wd->sc_dk.dk_openlock);
298 
299 	/*
300 	 * If there are wedges, and this is not RAW_PART, then we
301 	 * need to fail.
302 	 */
303 	if (wd->sc_dk.dk_nwedges != 0 && part != RAW_PART) {
304 		error = EBUSY;
305 		goto bad1;
306 	}
307 
308 	if (wd->sc_dk.dk_openmask != 0) {
309 		/*
310 		 * If any partition is open, but the disk has been invalidated,
311 		 * disallow further opens.
312 		 */
313 		if ((wd->sc_flags & WDF_LOADED) == 0) {
314 			error = EIO;
315 			goto bad1;
316 		}
317 	} else {
318 		if ((wd->sc_flags & WDF_LOADED) == 0) {
319 			int s;
320 
321 			wd->sc_flags |= WDF_LOADED;
322 
323 			/* Load the physical device parameters. */
324 			s = splbio();
325 			ed_get_params(wd, NULL);
326 			splx(s);
327 
328 			/* Load the partition info if not already loaded. */
329 			edgetdisklabel(dev, wd);
330 		}
331 	}
332 
333 	/* Check that the partition exists. */
334 	if (part != RAW_PART &&
335 	    (part >= wd->sc_dk.dk_label->d_npartitions ||
336 	     wd->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) {
337 		error = ENXIO;
338 		goto bad1;
339 	}
340 
341 	/* Insure only one open at a time. */
342 	switch (fmt) {
343 	case S_IFCHR:
344 		wd->sc_dk.dk_copenmask |= (1 << part);
345 		break;
346 	case S_IFBLK:
347 		wd->sc_dk.dk_bopenmask |= (1 << part);
348 		break;
349 	}
350 	wd->sc_dk.dk_openmask =
351 	    wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask;
352 
353 	error = 0;
354  bad1:
355 	mutex_exit(&wd->sc_dk.dk_openlock);
356 	return (error);
357 }
358 
359 int
360 edmcaclose(dev_t dev, int flag, int fmt, struct lwp *l)
361 {
362 	struct ed_softc *wd = device_lookup(&ed_cd, DISKUNIT(dev));
363 	int part = DISKPART(dev);
364 
365 	ATADEBUG_PRINT(("edmcaclose\n"), DEBUG_FUNCS);
366 
367 	mutex_enter(&wd->sc_dk.dk_openlock);
368 
369 	switch (fmt) {
370 	case S_IFCHR:
371 		wd->sc_dk.dk_copenmask &= ~(1 << part);
372 		break;
373 	case S_IFBLK:
374 		wd->sc_dk.dk_bopenmask &= ~(1 << part);
375 		break;
376 	}
377 	wd->sc_dk.dk_openmask =
378 	    wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask;
379 
380 	if (wd->sc_dk.dk_openmask == 0) {
381 #if 0
382 		wd_flushcache(wd, AT_WAIT);
383 #endif
384 		/* XXXX Must wait for I/O to complete! */
385 
386 		if (! (wd->sc_flags & WDF_KLABEL))
387 			wd->sc_flags &= ~WDF_LOADED;
388 	}
389 
390 	mutex_exit(&wd->sc_dk.dk_openlock);
391 
392 	return 0;
393 }
394 
395 static void
396 edgetdefaultlabel(ed, lp)
397 	struct ed_softc *ed;
398 	struct disklabel *lp;
399 {
400 	ATADEBUG_PRINT(("edgetdefaultlabel\n"), DEBUG_FUNCS);
401 	memset(lp, 0, sizeof(struct disklabel));
402 
403 	lp->d_secsize = DEV_BSIZE;
404 	lp->d_ntracks = ed->heads;
405 	lp->d_nsectors = ed->sectors;
406 	lp->d_ncylinders = ed->cyl;
407 	lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
408 
409 	lp->d_type = DTYPE_ESDI;
410 
411 	strncpy(lp->d_typename, "ESDI", 16);
412 	strncpy(lp->d_packname, "fictitious", 16);
413 	lp->d_secperunit = ed->sc_capacity;
414 	lp->d_rpm = 3600;
415 	lp->d_interleave = 1;
416 	lp->d_flags = 0;
417 
418 	lp->d_partitions[RAW_PART].p_offset = 0;
419 	lp->d_partitions[RAW_PART].p_size =
420 	lp->d_secperunit * (lp->d_secsize / DEV_BSIZE);
421 	lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
422 	lp->d_npartitions = RAW_PART + 1;
423 
424 	lp->d_magic = DISKMAGIC;
425 	lp->d_magic2 = DISKMAGIC;
426 	lp->d_checksum = dkcksum(lp);
427 }
428 
429 /*
430  * Fabricate a default disk label, and try to read the correct one.
431  */
432 static void
433 edgetdisklabel(dev, ed)
434 	dev_t dev;
435 	struct ed_softc *ed;
436 {
437 	struct disklabel *lp = ed->sc_dk.dk_label;
438 	const char *errstring;
439 
440 	ATADEBUG_PRINT(("edgetdisklabel\n"), DEBUG_FUNCS);
441 
442 	memset(ed->sc_dk.dk_cpulabel, 0, sizeof(struct cpu_disklabel));
443 
444 	edgetdefaultlabel(ed, lp);
445 
446 	errstring = readdisklabel(
447 	    EDLABELDEV(dev), edmcastrategy, lp, ed->sc_dk.dk_cpulabel);
448 	if (errstring) {
449 		/*
450 		 * This probably happened because the drive's default
451 		 * geometry doesn't match the DOS geometry.  We
452 		 * assume the DOS geometry is now in the label and try
453 		 * again.  XXX This is a kluge.
454 		 */
455 #if 0
456 		if (wd->drvp->state > RECAL)
457 			wd->drvp->drive_flags |= DRIVE_RESET;
458 #endif
459 		errstring = readdisklabel(EDLABELDEV(dev),
460 			edmcastrategy, lp, ed->sc_dk.dk_cpulabel);
461 	}
462 	if (errstring) {
463 		printf("%s: %s\n", ed->sc_dev.dv_xname, errstring);
464 		return;
465 	}
466 }
467 
468 int
469 edmcaioctl(dev, xfer, addr, flag, l)
470 	dev_t dev;
471 	u_long xfer;
472 	void *addr;
473 	int flag;
474 	struct lwp *l;
475 {
476 	struct ed_softc *ed = device_lookup(&ed_cd, DISKUNIT(dev));
477 	int error;
478 
479 	ATADEBUG_PRINT(("edioctl\n"), DEBUG_FUNCS);
480 
481 	if ((ed->sc_flags & WDF_LOADED) == 0)
482 		return EIO;
483 
484 	switch (xfer) {
485 	case DIOCGDINFO:
486 		*(struct disklabel *)addr = *(ed->sc_dk.dk_label);
487 		return 0;
488 
489 	case DIOCGPART:
490 		((struct partinfo *)addr)->disklab = ed->sc_dk.dk_label;
491 		((struct partinfo *)addr)->part =
492 		    &ed->sc_dk.dk_label->d_partitions[DISKPART(dev)];
493 		return 0;
494 
495 	case DIOCWDINFO:
496 	case DIOCSDINFO:
497 	{
498 		struct disklabel *lp;
499 
500 		lp = (struct disklabel *)addr;
501 
502 		if ((flag & FWRITE) == 0)
503 			return EBADF;
504 
505 		mutex_enter(&ed->sc_dk.dk_openlock);
506 		ed->sc_flags |= WDF_LABELLING;
507 
508 		error = setdisklabel(ed->sc_dk.dk_label,
509 		    lp, /*wd->sc_dk.dk_openmask : */0,
510 		    ed->sc_dk.dk_cpulabel);
511 		if (error == 0) {
512 #if 0
513 			if (wd->drvp->state > RECAL)
514 				wd->drvp->drive_flags |= DRIVE_RESET;
515 #endif
516 			if (xfer == DIOCWDINFO)
517 				error = writedisklabel(EDLABELDEV(dev),
518 				    edmcastrategy, ed->sc_dk.dk_label,
519 				    ed->sc_dk.dk_cpulabel);
520 		}
521 
522 		ed->sc_flags &= ~WDF_LABELLING;
523 		mutex_exit(&ed->sc_dk.dk_openlock);
524 		return (error);
525 	}
526 
527 	case DIOCKLABEL:
528 		if (*(int *)addr)
529 			ed->sc_flags |= WDF_KLABEL;
530 		else
531 			ed->sc_flags &= ~WDF_KLABEL;
532 		return 0;
533 
534 	case DIOCWLABEL:
535 		if ((flag & FWRITE) == 0)
536 			return EBADF;
537 		if (*(int *)addr)
538 			ed->sc_flags |= WDF_WLABEL;
539 		else
540 			ed->sc_flags &= ~WDF_WLABEL;
541 		return 0;
542 
543 	case DIOCGDEFLABEL:
544 		edgetdefaultlabel(ed, (struct disklabel *)addr);
545 		return 0;
546 
547 #if 0
548 	case DIOCWFORMAT:
549 		if ((flag & FWRITE) == 0)
550 			return EBADF;
551 		{
552 		register struct format_op *fop;
553 		struct iovec aiov;
554 		struct uio auio;
555 
556 		fop = (struct format_op *)addr;
557 		aiov.iov_base = fop->df_buf;
558 		aiov.iov_len = fop->df_count;
559 		auio.uio_iov = &aiov;
560 		auio.uio_iovcnt = 1;
561 		auio.uio_resid = fop->df_count;
562 		auio.uio_segflg = 0;
563 		auio.uio_offset =
564 			fop->df_startblk * wd->sc_dk.dk_label->d_secsize;
565 		auio.uio_lwp = l;
566 		error = physio(wdformat, NULL, dev, B_WRITE, minphys,
567 		    &auio);
568 		fop->df_count -= auio.uio_resid;
569 		fop->df_reg[0] = wdc->sc_status;
570 		fop->df_reg[1] = wdc->sc_error;
571 		return error;
572 		}
573 #endif
574 
575 	case DIOCAWEDGE:
576 	    {
577 	    	struct dkwedge_info *dkw = (void *) addr;
578 
579 		if ((flag & FWRITE) == 0)
580 			return (EBADF);
581 
582 		/* If the ioctl happens here, the parent is us. */
583 		strcpy(dkw->dkw_parent, ed->sc_dev.dv_xname);
584 		return (dkwedge_add(dkw));
585 	    }
586 
587 	case DIOCDWEDGE:
588 	    {
589 	    	struct dkwedge_info *dkw = (void *) addr;
590 
591 		if ((flag & FWRITE) == 0)
592 			return (EBADF);
593 
594 		/* If the ioctl happens here, the parent is us. */
595 		strcpy(dkw->dkw_parent, ed->sc_dev.dv_xname);
596 		return (dkwedge_del(dkw));
597 	    }
598 
599 	case DIOCLWEDGES:
600 	    {
601 	    	struct dkwedge_list *dkwl = (void *) addr;
602 
603 		return (dkwedge_list(&ed->sc_dk, dkwl, l));
604 	    }
605 
606 	default:
607 		return ENOTTY;
608 	}
609 
610 #ifdef DIAGNOSTIC
611 	panic("edioctl: impossible");
612 #endif
613 }
614 
615 int
616 edmcasize(dev)
617 	dev_t dev;
618 {
619 	struct ed_softc *wd;
620 	int part, omask;
621 	int size;
622 
623 	ATADEBUG_PRINT(("edsize\n"), DEBUG_FUNCS);
624 
625 	wd = device_lookup(&ed_cd, DISKUNIT(dev));
626 	if (wd == NULL)
627 		return (-1);
628 
629 	part = DISKPART(dev);
630 	omask = wd->sc_dk.dk_openmask & (1 << part);
631 
632 	if (omask == 0 && edmcaopen(dev, 0, S_IFBLK, NULL) != 0)
633 		return (-1);
634 	if (wd->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP)
635 		size = -1;
636 	else
637 		size = wd->sc_dk.dk_label->d_partitions[part].p_size *
638 		    (wd->sc_dk.dk_label->d_secsize / DEV_BSIZE);
639 	if (omask == 0 && edmcaclose(dev, 0, S_IFBLK, NULL) != 0)
640 		return (-1);
641 	return (size);
642 }
643 
644 /* #define WD_DUMP_NOT_TRUSTED if you just want to watch */
645 static int eddoingadump = 0;
646 static int eddumprecalibrated = 0;
647 static int eddumpmulti = 1;
648 
649 /*
650  * Dump core after a system crash.
651  */
652 int
653 edmcadump(dev, blkno, va, size)
654 	dev_t dev;
655 	daddr_t blkno;
656 	void *va;
657 	size_t size;
658 {
659 	struct ed_softc *ed;	/* disk unit to do the I/O */
660 	struct disklabel *lp;   /* disk's disklabel */
661 	int part;
662 	int nblks;	/* total number of sectors left to write */
663 	int error;
664 
665 	/* Check if recursive dump; if so, punt. */
666 	if (eddoingadump)
667 		return EFAULT;
668 	eddoingadump = 1;
669 
670 	ed = device_lookup(&ed_cd, DISKUNIT(dev));
671 	if (ed == NULL)
672 		return (ENXIO);
673 
674 	part = DISKPART(dev);
675 
676 	/* Make sure it was initialized. */
677 	if ((ed->sc_flags & EDF_INIT) == 0)
678 		return ENXIO;
679 
680 	/* Convert to disk sectors.  Request must be a multiple of size. */
681 	lp = ed->sc_dk.dk_label;
682 	if ((size % lp->d_secsize) != 0)
683 		return EFAULT;
684 	nblks = size / lp->d_secsize;
685 	blkno = blkno / (lp->d_secsize / DEV_BSIZE);
686 
687 	/* Check transfer bounds against partition size. */
688 	if ((blkno < 0) || ((blkno + nblks) > lp->d_partitions[part].p_size))
689 		return EINVAL;
690 
691 	/* Offset block number to start of partition. */
692 	blkno += lp->d_partitions[part].p_offset;
693 
694 	/* Recalibrate, if first dump transfer. */
695 	if (eddumprecalibrated == 0) {
696 		eddumprecalibrated = 1;
697 		eddumpmulti = 8;
698 #if 0
699 		wd->drvp->state = RESET;
700 #endif
701 	}
702 
703 	while (nblks > 0) {
704 		error = edc_bio(ed->edc_softc, ed, va, blkno,
705 			min(nblks, eddumpmulti) * lp->d_secsize, 0, 1);
706 		if (error)
707 			return (error);
708 
709 		/* update block count */
710 		nblks -= min(nblks, eddumpmulti);
711 		blkno += min(nblks, eddumpmulti);
712 		va = (char *)va + min(nblks, eddumpmulti) * lp->d_secsize;
713 	}
714 
715 	eddoingadump = 0;
716 	return (0);
717 }
718 
719 static int
720 ed_get_params(ed, drv_flags)
721 	struct ed_softc *ed;
722 	int *drv_flags;
723 {
724 	u_int16_t cmd_args[2];
725 
726 	/*
727 	 * Get Device Configuration (09).
728 	 */
729 	cmd_args[0] = 14;	/* Options: 00s110, s: 0=Physical 1=Pseudo */
730 	cmd_args[1] = 0;
731 	if (edc_run_cmd(ed->edc_softc, CMD_GET_DEV_CONF, ed->sc_devno,
732 	    cmd_args, 2, 1))
733 		return (1);
734 
735 	ed->spares = ed->sense_data[1] >> 8;
736 	if (drv_flags)
737 		*drv_flags = ed->sense_data[1] & 0x1f;
738 	ed->rba = ed->sense_data[2] | (ed->sense_data[3] << 16);
739 	/* Instead of using:
740 		ed->cyl = ed->sense_data[4];
741 		ed->heads = ed->sense_data[5] & 0xff;
742 		ed->sectors = ed->sense_data[5] >> 8;
743 	 * we fabricate the numbers from RBA count, so that
744 	 * number of sectors is 32 and heads 64. This seems
745 	 * to be necessary for integrated ESDI controller.
746 	 */
747 	ed->sectors = 32;
748 	ed->heads = 64;
749 	ed->cyl = ed->rba / (ed->heads * ed->sectors);
750 	ed->sc_capacity = ed->rba;
751 
752 	return (0);
753 }
754