Home | History | Annotate | Line # | Download | only in mca
ed_mca.c revision 1.3
      1 /*	$NetBSD: ed_mca.c,v 1.3 2001/04/22 11:32:49 jdolecek 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 goo for MCA ESDI controller driver.
     38  */
     39 
     40 #include "rnd.h"
     41 
     42 #include <sys/param.h>
     43 #include <sys/systm.h>
     44 #include <sys/kernel.h>
     45 #include <sys/conf.h>
     46 #include <sys/file.h>
     47 #include <sys/stat.h>
     48 #include <sys/ioctl.h>
     49 #include <sys/buf.h>
     50 #include <sys/uio.h>
     51 #include <sys/malloc.h>
     52 #include <sys/device.h>
     53 #include <sys/disklabel.h>
     54 #include <sys/disk.h>
     55 #include <sys/syslog.h>
     56 #include <sys/proc.h>
     57 #include <sys/vnode.h>
     58 #include <sys/kthread.h>
     59 #if NRND > 0
     60 #include <sys/rnd.h>
     61 #endif
     62 
     63 #include <machine/intr.h>
     64 #include <machine/bus.h>
     65 
     66 #include <dev/mca/edcreg.h>
     67 #include <dev/mca/edvar.h>
     68 #include <dev/mca/edcvar.h>
     69 
     70 /* #define WDCDEBUG */
     71 
     72 #ifdef WDCDEBUG
     73 #define WDCDEBUG_PRINT(args, level)  printf args
     74 #else
     75 #define WDCDEBUG_PRINT(args, level)
     76 #endif
     77 
     78 #define	EDLABELDEV(dev) (MAKEDISKDEV(major(dev), DISKUNIT(dev), RAW_PART))
     79 
     80 /* XXX: these should go elsewhere */
     81 cdev_decl(edmca);
     82 bdev_decl(edmca);
     83 
     84 static int     ed_mca_probe   __P((struct device *, struct cfdata *, void *));
     85 static void    ed_mca_attach  __P((struct device *, struct device *, void *));
     86 
     87 struct cfattach ed_mca_ca = {
     88 	sizeof(struct ed_softc), ed_mca_probe, ed_mca_attach
     89 };
     90 
     91 extern struct cfdriver ed_cd;
     92 
     93 static int	ed_get_params __P((struct ed_softc *));
     94 static int	ed_lock	__P((struct ed_softc *));
     95 static void	ed_unlock	__P((struct ed_softc *));
     96 static void	edgetdisklabel	__P((struct ed_softc *));
     97 static void	edgetdefaultlabel __P((struct ed_softc *, struct disklabel *));
     98 static void	ed_shutdown __P((void*));
     99 static void	__edstart __P((struct ed_softc*, struct buf *));
    100 static void	bad144intern __P((struct ed_softc *));
    101 static void	edworker __P((void *));
    102 static void	ed_spawn_worker __P((void *));
    103 static void	edmcadone __P((struct ed_softc *));
    104 
    105 static struct dkdriver eddkdriver = { edmcastrategy };
    106 
    107 /*
    108  * Just check if it's possible to identify the disk.
    109  */
    110 static int
    111 ed_mca_probe(parent, match, aux)
    112 	struct device *parent;
    113 	struct cfdata *match;
    114 	void *aux;
    115 {
    116 	u_int16_t cmd_args[2];
    117 	struct edc_mca_softc *sc = (void *) parent;
    118 	struct ed_attach_args *eda = (void *) aux;
    119 
    120 	/*
    121 	 * Get Device Configuration (09).
    122 	 */
    123 	cmd_args[0] = 6;	/* Options: 00s110, s: 0=Physical 1=Pseudo */
    124 	cmd_args[1] = 0;
    125 	if (edc_run_cmd(sc, CMD_GET_DEV_CONF, eda->sc_devno, cmd_args, 2, 0))
    126 		return (0);
    127 
    128 	return (1);
    129 }
    130 
    131 static void
    132 ed_mca_attach(parent, self, aux)
    133 	struct device *parent, *self;
    134 	void *aux;
    135 {
    136 	struct ed_softc *ed = (void *) self;
    137 	struct edc_mca_softc *sc = (void *) parent;
    138 	struct ed_attach_args *eda = (void *) aux;
    139 	char pbuf[8];
    140 	int error, nsegs;
    141 
    142 	ed->edc_softc = sc;
    143 	ed->sc_dmat = eda->sc_dmat;
    144 	ed->sc_devno = eda->sc_devno;
    145 	edc_add_disk(sc, ed, eda->sc_devno);
    146 
    147 	BUFQ_INIT(&ed->sc_q);
    148 	spinlockinit(&ed->sc_q_lock, "edbqlock", 0);
    149 	lockinit(&ed->sc_lock, PRIBIO | PCATCH, "edlck", 0, 0);
    150 
    151 	if (ed_get_params(ed)) {
    152 		printf(": IDENTIFY failed, no disk found\n");
    153 		return;
    154 	}
    155 
    156 	format_bytes(pbuf, sizeof(pbuf),
    157 		(u_int64_t) ed->sc_capacity * DEV_BSIZE);
    158 	printf(": %s, %u cyl, %u head, %u sec, 512 bytes/sect x %u sectors\n",
    159 		pbuf,
    160 		ed->cyl, ed->heads, ed->sectors,
    161 		ed->sc_capacity);
    162 
    163 	printf("%s: %u spares/cyl, %s.%s.%s.%s.%s\n",
    164 		ed->sc_dev.dv_xname, ed->spares,
    165 		(ed->drv_flags & (1 << 0)) ? "NoRetries" : "Retries",
    166 		(ed->drv_flags & (1 << 1)) ? "Removable" : "Fixed",
    167 		(ed->drv_flags & (1 << 2)) ? "SkewedFormat" : "NoSkew",
    168 		(ed->drv_flags & (1 << 3)) ? "ZeroDefect" : "Defects",
    169 		(ed->drv_flags & (1 << 4)) ? "InvalidSecondary" : "SeconOK"
    170 		);
    171 
    172 	/* Create a DMA map for mapping individual transfer bufs */
    173 	if ((error = bus_dmamap_create(ed->sc_dmat, 65536, 1,
    174 		65536, 65536, BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW,
    175 		&ed->dmamap_xfer)) != 0) {
    176 		printf("%s: unable to create xfer DMA map, error=%d\n",
    177 			ed->sc_dev.dv_xname, error);
    178 		return;
    179 	}
    180 
    181 	/*
    182 	 * Allocate DMA memory used in case where passed buf isn't
    183 	 * physically contiguous.
    184 	 */
    185 	ed->sc_dmam_sz = MAXPHYS;
    186 	if ((error = bus_dmamem_alloc(ed->sc_dmat, ed->sc_dmam_sz,
    187 		ed->sc_dmam_sz, 65536, ed->sc_dmam, 1, &nsegs,
    188 		BUS_DMA_WAITOK|BUS_DMA_STREAMING)) != 0) {
    189 		printf("%s: unable to allocate DMA memory for xfer, errno=%d\n",
    190 				ed->sc_dev.dv_xname, error);
    191 		bus_dmamap_destroy(ed->sc_dmat, ed->dmamap_xfer);
    192 		return;
    193 	}
    194 	/*
    195 	 * Map the memory.
    196 	 */
    197 	if ((error = bus_dmamem_map(ed->sc_dmat, ed->sc_dmam, 1,
    198 		ed->sc_dmam_sz, &ed->sc_dmamkva, BUS_DMA_WAITOK)) != 0) {
    199 		printf("%s: unable to map DMA memory, error=%d\n",
    200 			ed->sc_dev.dv_xname, error);
    201 		bus_dmamem_free(ed->sc_dmat, ed->sc_dmam, 1);
    202 		bus_dmamap_destroy(ed->sc_dmat, ed->dmamap_xfer);
    203 		return;
    204 	}
    205 
    206 
    207 	/*
    208 	 * Initialize and attach the disk structure.
    209 	 */
    210 	ed->sc_dk.dk_driver = &eddkdriver;
    211 	ed->sc_dk.dk_name = ed->sc_dev.dv_xname;
    212 	disk_attach(&ed->sc_dk);
    213 #if 0
    214 	wd->sc_wdc_bio.lp = wd->sc_dk.dk_label;
    215 #endif
    216 	ed->sc_sdhook = shutdownhook_establish(ed_shutdown, ed);
    217 	if (ed->sc_sdhook == NULL)
    218 		printf("%s: WARNING: unable to establish shutdown hook\n",
    219 		    ed->sc_dev.dv_xname);
    220 #if NRND > 0
    221 	rnd_attach_source(&ed->rnd_source, ed->sc_dev.dv_xname,
    222 			  RND_TYPE_DISK, 0);
    223 #endif
    224 
    225 	config_pending_incr();
    226 	kthread_create(ed_spawn_worker, (void *) ed);
    227 }
    228 
    229 void
    230 ed_spawn_worker(arg)
    231 	void *arg;
    232 {
    233 	struct ed_softc *ed = (struct ed_softc *) arg;
    234 	int error;
    235 
    236 	/* Now, everything is ready, start a kthread */
    237 	if ((error = kthread_create1(edworker, ed, &ed->sc_worker,
    238 			"%s", ed->sc_dev.dv_xname))) {
    239 		printf("%s: cannot spawn worker thread: errno=%d\n",
    240 			ed->sc_dev.dv_xname, error);
    241 		panic("ed_spawn_worker");
    242 	}
    243 }
    244 
    245 /*
    246  * Read/write routine for a buffer.  Validates the arguments and schedules the
    247  * transfer.  Does not wait for the transfer to complete.
    248  */
    249 void
    250 edmcastrategy(bp)
    251 	struct buf *bp;
    252 {
    253 	struct ed_softc *wd = device_lookup(&ed_cd, DISKUNIT(bp->b_dev));
    254 	struct disklabel *lp = wd->sc_dk.dk_label;
    255 	daddr_t blkno;
    256 	int s;
    257 
    258 	WDCDEBUG_PRINT(("edmcastrategy (%s)\n", wd->sc_dev.dv_xname),
    259 	    DEBUG_XFERS);
    260 
    261 	/* Valid request?  */
    262 	if (bp->b_blkno < 0 ||
    263 	    (bp->b_bcount % lp->d_secsize) != 0 ||
    264 	    (bp->b_bcount / lp->d_secsize) >= (1 << NBBY)) {
    265 		bp->b_error = EINVAL;
    266 		goto bad;
    267 	}
    268 
    269 	/* If device invalidated (e.g. media change, door open), error. */
    270 	if ((wd->sc_flags & WDF_LOADED) == 0) {
    271 		bp->b_error = EIO;
    272 		goto bad;
    273 	}
    274 
    275 	/* If it's a null transfer, return immediately. */
    276 	if (bp->b_bcount == 0)
    277 		goto done;
    278 
    279 	/*
    280 	 * Do bounds checking, adjust transfer. if error, process.
    281 	 * If end of partition, just return.
    282 	 */
    283 	if (DISKPART(bp->b_dev) != RAW_PART &&
    284 	    bounds_check_with_label(bp, wd->sc_dk.dk_label,
    285 	    (wd->sc_flags & (WDF_WLABEL|WDF_LABELLING)) != 0) <= 0)
    286 		goto done;
    287 
    288 	/*
    289 	 * Now convert the block number to absolute and put it in
    290 	 * terms of the device's logical block size.
    291 	 */
    292 	if (lp->d_secsize >= DEV_BSIZE)
    293 		blkno = bp->b_blkno / (lp->d_secsize / DEV_BSIZE);
    294 	else
    295 		blkno = bp->b_blkno * (DEV_BSIZE / lp->d_secsize);
    296 
    297 	if (DISKPART(bp->b_dev) != RAW_PART)
    298 		blkno += lp->d_partitions[DISKPART(bp->b_dev)].p_offset;
    299 
    300 	bp->b_rawblkno = blkno;
    301 
    302 	/* Queue transfer on drive, activate drive and controller if idle. */
    303 	s = splbio();
    304 	simple_lock(&wd->sc_q_lock);
    305 	disksort_blkno(&wd->sc_q, bp);
    306 	simple_unlock(&wd->sc_q_lock);
    307 
    308 	/* Ring the worker thread */
    309 	wd->sc_flags |= EDF_PROCESS_QUEUE;
    310 	wakeup_one(&wd->sc_q);
    311 
    312 	splx(s);
    313 	return;
    314 bad:
    315 	bp->b_flags |= B_ERROR;
    316 done:
    317 	/* Toss transfer; we're done early. */
    318 	bp->b_resid = bp->b_bcount;
    319 	biodone(bp);
    320 }
    321 
    322 static void
    323 __edstart(ed, bp)
    324 	struct ed_softc *ed;
    325 	struct buf *bp;
    326 {
    327 	u_int16_t cmd_args[4];
    328 	int error=0;
    329 	u_int16_t track;
    330 	u_int16_t cyl;
    331 	u_int8_t head;
    332 	u_int8_t sector;
    333 
    334 	WDCDEBUG_PRINT(("__edstart %s (%s): %lu %lu %u\n", ed->sc_dev.dv_xname,
    335 		(bp->b_flags & B_READ) ? "read" : "write",
    336 		bp->b_bcount, bp->b_resid, bp->b_rawblkno),
    337 	    DEBUG_XFERS);
    338 
    339 	ed->sc_bp = bp;
    340 
    341 	/* Get physical bus mapping for buf. */
    342 	if (bus_dmamap_load(ed->sc_dmat, ed->dmamap_xfer,
    343 			bp->b_data, bp->b_bcount, NULL,
    344 			BUS_DMA_WAITOK|BUS_DMA_STREAMING) != 0) {
    345 
    346 		/*
    347 		 * Use our DMA safe memory to get data to/from device.
    348 		 */
    349 		if ((error = bus_dmamap_load(ed->sc_dmat, ed->dmamap_xfer,
    350 			ed->sc_dmamkva, bp->b_bcount, NULL,
    351 			BUS_DMA_WAITOK|BUS_DMA_STREAMING)) != 0) {
    352 			printf("%s: unable to load raw data for xfer, errno=%d\n",
    353 				ed->sc_dev.dv_xname, error);
    354 			goto out;
    355 		}
    356 		ed->sc_flags |= EDF_BOUNCEBUF;
    357 
    358 		/* If data write, copy the data to our bounce buffer. */
    359 		if ((bp->b_flags & B_READ) == 0)
    360 			memcpy(ed->sc_dmamkva, bp->b_data, bp->b_bcount);
    361 	}
    362 
    363 	ed->sc_flags |= EDF_DMAMAP_LOADED;
    364 
    365 	track = bp->b_rawblkno / ed->sectors;
    366 	head = track % ed->heads;
    367 	cyl = track / ed->heads;
    368 	sector = bp->b_rawblkno % ed->sectors;
    369 
    370 	WDCDEBUG_PRINT(("__edstart %s: map: %u %u %u\n", ed->sc_dev.dv_xname,
    371 		cyl, sector, head),
    372 	    DEBUG_XFERS);
    373 
    374 	/* Instrumentation. */
    375 	disk_busy(&ed->sc_dk);
    376 	ed->sc_flags |= EDF_DK_BUSY;
    377 
    378 	/* Read or Write Data command */
    379 	cmd_args[0] = 2;	/* Options 0000010 */
    380 	cmd_args[1] = bp->b_bcount / DEV_BSIZE;
    381 	cmd_args[2] = ((cyl & 0x1f) << 11) | (head << 5) | sector;
    382 	cmd_args[3] = ((cyl & 0x3E0) >> 5);
    383 	if (edc_run_cmd(ed->edc_softc,
    384 			(bp->b_flags & B_READ) ? CMD_READ_DATA : CMD_WRITE_DATA,
    385 			ed->sc_devno, cmd_args, 4, 1)) {
    386 		printf("%s: data i/o command failed\n", ed->sc_dev.dv_xname);
    387 		error = EIO;
    388 	}
    389 
    390     out:
    391 	if (error)
    392 		ed->sc_error = error;
    393 }
    394 
    395 
    396 static void
    397 edmcadone(ed)
    398 	struct ed_softc *ed;
    399 {
    400 	struct buf *bp = ed->sc_bp;
    401 
    402 	WDCDEBUG_PRINT(("eddone %s\n", ed->sc_dev.dv_xname),
    403 	    DEBUG_XFERS);
    404 
    405 	if (ed->sc_error) {
    406 		bp->b_error = ed->sc_error;
    407 		bp->b_flags |= B_ERROR;
    408 	} else {
    409 		/* Set resid, most commonly to zero. */
    410 		bp->b_resid = ed->sc_status_block[SB_RESBLKCNT_IDX] * DEV_BSIZE;
    411 	}
    412 
    413 	/*
    414 	 * If read transfer finished without error and using a bounce
    415 	 * buffer, copy the data to buf.
    416 	 */
    417 	if ((bp->b_flags & B_ERROR) == 0 && (ed->sc_flags & EDF_BOUNCEBUF)
    418 	     && (bp->b_flags & B_READ)) {
    419 		memcpy(bp->b_data, ed->sc_dmamkva, bp->b_bcount);
    420 	}
    421 	ed->sc_flags &= ~EDF_BOUNCEBUF;
    422 
    423 	/* Unload buf from DMA map */
    424 	if (ed->sc_flags & EDF_DMAMAP_LOADED) {
    425 		bus_dmamap_unload(ed->sc_dmat, ed->dmamap_xfer);
    426 		ed->sc_flags &= ~EDF_DMAMAP_LOADED;
    427 	}
    428 
    429 	/* If disk was busied, unbusy it now */
    430 	if (ed->sc_flags & EDF_DK_BUSY) {
    431 		disk_unbusy(&ed->sc_dk, (bp->b_bcount - bp->b_resid));
    432 		ed->sc_flags &= ~EDF_DK_BUSY;
    433 	}
    434 
    435 	ed->sc_flags &= ~EDF_IODONE;
    436 
    437 #if NRND > 0
    438 	rnd_add_uint32(&ed->rnd_source, bp->b_blkno);
    439 #endif
    440 	biodone(bp);
    441 }
    442 
    443 int
    444 edmcaread(dev, uio, flags)
    445 	dev_t dev;
    446 	struct uio *uio;
    447 	int flags;
    448 {
    449 	WDCDEBUG_PRINT(("edread\n"), DEBUG_XFERS);
    450 	return (physio(edmcastrategy, NULL, dev, B_READ, minphys, uio));
    451 }
    452 
    453 int
    454 edmcawrite(dev, uio, flags)
    455 	dev_t dev;
    456 	struct uio *uio;
    457 	int flags;
    458 {
    459 	WDCDEBUG_PRINT(("edwrite\n"), DEBUG_XFERS);
    460 	return (physio(edmcastrategy, NULL, dev, B_WRITE, minphys, uio));
    461 }
    462 
    463 /*
    464  * Wait interruptibly for an exclusive lock.
    465  */
    466 static int
    467 ed_lock(ed)
    468 	struct ed_softc *ed;
    469 {
    470 	int error;
    471 	int s;
    472 
    473 	WDCDEBUG_PRINT(("ed_lock\n"), DEBUG_FUNCS);
    474 
    475 	s = splbio();
    476 	error = lockmgr(&ed->sc_lock, LK_EXCLUSIVE, NULL);
    477 	splx(s);
    478 
    479 	return (error);
    480 }
    481 
    482 /*
    483  * Unlock and wake up any waiters.
    484  */
    485 static void
    486 ed_unlock(ed)
    487 	struct ed_softc *ed;
    488 {
    489 	WDCDEBUG_PRINT(("ed_unlock\n"), DEBUG_FUNCS);
    490 
    491 	(void) lockmgr(&ed->sc_lock, LK_RELEASE, NULL);
    492 }
    493 
    494 int
    495 edmcaopen(dev, flag, fmt, p)
    496 	dev_t dev;
    497 	int flag, fmt;
    498 	struct proc *p;
    499 {
    500 	struct ed_softc *wd;
    501 	int part, error;
    502 
    503 	WDCDEBUG_PRINT(("edopen\n"), DEBUG_FUNCS);
    504 	wd = device_lookup(&ed_cd, DISKUNIT(dev));
    505 	if (wd == NULL)
    506 		return (ENXIO);
    507 
    508 	if ((error = ed_lock(wd)) != 0)
    509 		goto bad4;
    510 
    511 	if (wd->sc_dk.dk_openmask != 0) {
    512 		/*
    513 		 * If any partition is open, but the disk has been invalidated,
    514 		 * disallow further opens.
    515 		 */
    516 		if ((wd->sc_flags & WDF_LOADED) == 0) {
    517 			error = EIO;
    518 			goto bad3;
    519 		}
    520 	} else {
    521 		if ((wd->sc_flags & WDF_LOADED) == 0) {
    522 			wd->sc_flags |= WDF_LOADED;
    523 
    524 			/* Load the physical device parameters. */
    525 			ed_get_params(wd);
    526 
    527 			/* Load the partition info if not already loaded. */
    528 			edgetdisklabel(wd);
    529 		}
    530 	}
    531 
    532 	part = DISKPART(dev);
    533 
    534 	/* Check that the partition exists. */
    535 	if (part != RAW_PART &&
    536 	    (part >= wd->sc_dk.dk_label->d_npartitions ||
    537 	     wd->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) {
    538 		error = ENXIO;
    539 		goto bad;
    540 	}
    541 
    542 	/* Insure only one open at a time. */
    543 	switch (fmt) {
    544 	case S_IFCHR:
    545 		wd->sc_dk.dk_copenmask |= (1 << part);
    546 		break;
    547 	case S_IFBLK:
    548 		wd->sc_dk.dk_bopenmask |= (1 << part);
    549 		break;
    550 	}
    551 	wd->sc_dk.dk_openmask =
    552 	    wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask;
    553 
    554 	ed_unlock(wd);
    555 	return 0;
    556 
    557 bad:
    558 	if (wd->sc_dk.dk_openmask == 0) {
    559 	}
    560 
    561 bad3:
    562 	ed_unlock(wd);
    563 bad4:
    564 	return (error);
    565 }
    566 
    567 int
    568 edmcaclose(dev, flag, fmt, p)
    569 	dev_t dev;
    570 	int flag, fmt;
    571 	struct proc *p;
    572 {
    573 	struct ed_softc *wd = device_lookup(&ed_cd, DISKUNIT(dev));
    574 	int part = DISKPART(dev);
    575 	int error;
    576 
    577 	WDCDEBUG_PRINT(("edmcaclose\n"), DEBUG_FUNCS);
    578 	if ((error = ed_lock(wd)) != 0)
    579 		return error;
    580 
    581 	switch (fmt) {
    582 	case S_IFCHR:
    583 		wd->sc_dk.dk_copenmask &= ~(1 << part);
    584 		break;
    585 	case S_IFBLK:
    586 		wd->sc_dk.dk_bopenmask &= ~(1 << part);
    587 		break;
    588 	}
    589 	wd->sc_dk.dk_openmask =
    590 	    wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask;
    591 
    592 	if (wd->sc_dk.dk_openmask == 0) {
    593 #if 0
    594 		wd_flushcache(wd, AT_WAIT);
    595 #endif
    596 		/* XXXX Must wait for I/O to complete! */
    597 
    598 		if (! (wd->sc_flags & WDF_KLABEL))
    599 			wd->sc_flags &= ~WDF_LOADED;
    600 	}
    601 
    602 	ed_unlock(wd);
    603 
    604 	return 0;
    605 }
    606 
    607 static void
    608 edgetdefaultlabel(wd, lp)
    609 	struct ed_softc *wd;
    610 	struct disklabel *lp;
    611 {
    612 	WDCDEBUG_PRINT(("edgetdefaultlabel\n"), DEBUG_FUNCS);
    613 	memset(lp, 0, sizeof(struct disklabel));
    614 
    615 	lp->d_secsize = DEV_BSIZE;
    616 	lp->d_ntracks = wd->heads;
    617 	lp->d_nsectors = wd->sectors;
    618 	lp->d_ncylinders = wd->cyl;
    619 	lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
    620 
    621 	lp->d_type = DTYPE_ESDI;
    622 
    623 	strncpy(lp->d_typename, "ESDI", 16);
    624 	strncpy(lp->d_packname, "fictitious", 16);
    625 	lp->d_secperunit = wd->sc_capacity;
    626 	lp->d_rpm = 3600;
    627 	lp->d_interleave = 1;
    628 	lp->d_flags = 0;
    629 
    630 	lp->d_partitions[RAW_PART].p_offset = 0;
    631 	lp->d_partitions[RAW_PART].p_size =
    632 	lp->d_secperunit * (lp->d_secsize / DEV_BSIZE);
    633 	lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
    634 	lp->d_npartitions = RAW_PART + 1;
    635 
    636 	lp->d_magic = DISKMAGIC;
    637 	lp->d_magic2 = DISKMAGIC;
    638 	lp->d_checksum = dkcksum(lp);
    639 }
    640 
    641 /*
    642  * Fabricate a default disk label, and try to read the correct one.
    643  */
    644 static void
    645 edgetdisklabel(wd)
    646 	struct ed_softc *wd;
    647 {
    648 	struct disklabel *lp = wd->sc_dk.dk_label;
    649 	char *errstring;
    650 
    651 	WDCDEBUG_PRINT(("edgetdisklabel\n"), DEBUG_FUNCS);
    652 
    653 	memset(wd->sc_dk.dk_cpulabel, 0, sizeof(struct cpu_disklabel));
    654 
    655 	edgetdefaultlabel(wd, lp);
    656 
    657 #if 0
    658 	wd->sc_badsect[0] = -1;
    659 
    660 	if (wd->drvp->state > RECAL)
    661 		wd->drvp->drive_flags |= DRIVE_RESET;
    662 #endif
    663 	errstring = readdisklabel(MAKEDISKDEV(0, wd->sc_dev.dv_unit, RAW_PART),
    664 	    edmcastrategy, lp, wd->sc_dk.dk_cpulabel);
    665 	if (errstring) {
    666 		/*
    667 		 * This probably happened because the drive's default
    668 		 * geometry doesn't match the DOS geometry.  We
    669 		 * assume the DOS geometry is now in the label and try
    670 		 * again.  XXX This is a kluge.
    671 		 */
    672 #if 0
    673 		if (wd->drvp->state > RECAL)
    674 			wd->drvp->drive_flags |= DRIVE_RESET;
    675 #endif
    676 		errstring = readdisklabel(MAKEDISKDEV(0, wd->sc_dev.dv_unit,
    677 		    RAW_PART), edmcastrategy, lp, wd->sc_dk.dk_cpulabel);
    678 	}
    679 	if (errstring) {
    680 		printf("%s: %s\n", wd->sc_dev.dv_xname, errstring);
    681 		return;
    682 	}
    683 
    684 #if 0
    685 	if (wd->drvp->state > RECAL)
    686 		wd->drvp->drive_flags |= DRIVE_RESET;
    687 #endif
    688 #ifdef HAS_BAD144_HANDLING
    689 	if ((lp->d_flags & D_BADSECT) != 0)
    690 		bad144intern(wd);
    691 #endif
    692 }
    693 
    694 int
    695 edmcaioctl(dev, xfer, addr, flag, p)
    696 	dev_t dev;
    697 	u_long xfer;
    698 	caddr_t addr;
    699 	int flag;
    700 	struct proc *p;
    701 {
    702 	struct ed_softc *wd = device_lookup(&ed_cd, DISKUNIT(dev));
    703 	int error;
    704 #ifdef __HAVE_OLD_DISKLABEL
    705 	struct disklabel newlabel;
    706 #endif
    707 
    708 	WDCDEBUG_PRINT(("edioctl\n"), DEBUG_FUNCS);
    709 
    710 	if ((wd->sc_flags & WDF_LOADED) == 0)
    711 		return EIO;
    712 
    713 	switch (xfer) {
    714 #ifdef HAS_BAD144_HANDLING
    715 	case DIOCSBAD:
    716 		if ((flag & FWRITE) == 0)
    717 			return EBADF;
    718 		wd->sc_dk.dk_cpulabel->bad = *(struct dkbad *)addr;
    719 		wd->sc_dk.dk_label->d_flags |= D_BADSECT;
    720 		bad144intern(wd);
    721 		return 0;
    722 #endif
    723 
    724 	case DIOCGDINFO:
    725 		*(struct disklabel *)addr = *(wd->sc_dk.dk_label);
    726 		return 0;
    727 #ifdef __HAVE_OLD_DISKLABEL
    728 	case ODIOCGDINFO:
    729 		newlabel = *(wd->sc_dk.dk_label);
    730 		if (newlabel.d_npartitions > OLDMAXPARTITIONS)
    731 			return ENOTTY;
    732 		memcpy(addr, &newlabel, sizeof (struct olddisklabel));
    733 		return 0;
    734 #endif
    735 
    736 	case DIOCGPART:
    737 		((struct partinfo *)addr)->disklab = wd->sc_dk.dk_label;
    738 		((struct partinfo *)addr)->part =
    739 		    &wd->sc_dk.dk_label->d_partitions[DISKPART(dev)];
    740 		return 0;
    741 
    742 	case DIOCWDINFO:
    743 	case DIOCSDINFO:
    744 #ifdef __HAVE_OLD_DISKLABEL
    745 	case ODIOCWDINFO:
    746 	case ODIOCSDINFO:
    747 #endif
    748 	{
    749 		struct disklabel *lp;
    750 
    751 #ifdef __HAVE_OLD_DISKLABEL
    752 		if (xfer == ODIOCSDINFO || xfer == ODIOCWDINFO) {
    753 			memset(&newlabel, 0, sizeof newlabel);
    754 			memcpy(&newlabel, addr, sizeof (struct olddisklabel));
    755 			lp = &newlabel;
    756 		} else
    757 #endif
    758 		lp = (struct disklabel *)addr;
    759 
    760 		if ((flag & FWRITE) == 0)
    761 			return EBADF;
    762 
    763 		if ((error = ed_lock(wd)) != 0)
    764 			return error;
    765 		wd->sc_flags |= WDF_LABELLING;
    766 
    767 		error = setdisklabel(wd->sc_dk.dk_label,
    768 		    lp, /*wd->sc_dk.dk_openmask : */0,
    769 		    wd->sc_dk.dk_cpulabel);
    770 		if (error == 0) {
    771 #if 0
    772 			if (wd->drvp->state > RECAL)
    773 				wd->drvp->drive_flags |= DRIVE_RESET;
    774 #endif
    775 			if (xfer == DIOCWDINFO
    776 #ifdef __HAVE_OLD_DISKLABEL
    777 			    || xfer == ODIOCWDINFO
    778 #endif
    779 			    )
    780 				error = writedisklabel(EDLABELDEV(dev),
    781 				    edmcastrategy, wd->sc_dk.dk_label,
    782 				    wd->sc_dk.dk_cpulabel);
    783 		}
    784 
    785 		wd->sc_flags &= ~WDF_LABELLING;
    786 		ed_unlock(wd);
    787 		return error;
    788 	}
    789 
    790 	case DIOCKLABEL:
    791 		if (*(int *)addr)
    792 			wd->sc_flags |= WDF_KLABEL;
    793 		else
    794 			wd->sc_flags &= ~WDF_KLABEL;
    795 		return 0;
    796 
    797 	case DIOCWLABEL:
    798 		if ((flag & FWRITE) == 0)
    799 			return EBADF;
    800 		if (*(int *)addr)
    801 			wd->sc_flags |= WDF_WLABEL;
    802 		else
    803 			wd->sc_flags &= ~WDF_WLABEL;
    804 		return 0;
    805 
    806 	case DIOCGDEFLABEL:
    807 		edgetdefaultlabel(wd, (struct disklabel *)addr);
    808 		return 0;
    809 #ifdef __HAVE_OLD_DISKLABEL
    810 	case ODIOCGDEFLABEL:
    811 		edgetdefaultlabel(wd, &newlabel);
    812 		if (newlabel.d_npartitions > OLDMAXPARTITIONS)
    813 			return ENOTTY;
    814 		memcpy(addr, &newlabel, sizeof (struct olddisklabel));
    815 		return 0;
    816 #endif
    817 
    818 #ifdef notyet
    819 	case DIOCWFORMAT:
    820 		if ((flag & FWRITE) == 0)
    821 			return EBADF;
    822 		{
    823 		register struct format_op *fop;
    824 		struct iovec aiov;
    825 		struct uio auio;
    826 
    827 		fop = (struct format_op *)addr;
    828 		aiov.iov_base = fop->df_buf;
    829 		aiov.iov_len = fop->df_count;
    830 		auio.uio_iov = &aiov;
    831 		auio.uio_iovcnt = 1;
    832 		auio.uio_resid = fop->df_count;
    833 		auio.uio_segflg = 0;
    834 		auio.uio_offset =
    835 			fop->df_startblk * wd->sc_dk.dk_label->d_secsize;
    836 		auio.uio_procp = p;
    837 		error = physio(wdformat, NULL, dev, B_WRITE, minphys,
    838 		    &auio);
    839 		fop->df_count -= auio.uio_resid;
    840 		fop->df_reg[0] = wdc->sc_status;
    841 		fop->df_reg[1] = wdc->sc_error;
    842 		return error;
    843 		}
    844 #endif
    845 
    846 	default:
    847 		return ENOTTY;
    848 	}
    849 
    850 #ifdef DIAGNOSTIC
    851 	panic("edioctl: impossible");
    852 #endif
    853 }
    854 
    855 #if 0
    856 #ifdef B_FORMAT
    857 int
    858 edmcaformat(struct buf *bp)
    859 {
    860 
    861 	bp->b_flags |= B_FORMAT;
    862 	return edmcastrategy(bp);
    863 }
    864 #endif
    865 #endif
    866 
    867 int
    868 edmcasize(dev)
    869 	dev_t dev;
    870 {
    871 	struct ed_softc *wd;
    872 	int part, omask;
    873 	int size;
    874 
    875 	WDCDEBUG_PRINT(("edsize\n"), DEBUG_FUNCS);
    876 
    877 	wd = device_lookup(&ed_cd, DISKUNIT(dev));
    878 	if (wd == NULL)
    879 		return (-1);
    880 
    881 	part = DISKPART(dev);
    882 	omask = wd->sc_dk.dk_openmask & (1 << part);
    883 
    884 	if (omask == 0 && edmcaopen(dev, 0, S_IFBLK, NULL) != 0)
    885 		return (-1);
    886 	if (wd->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP)
    887 		size = -1;
    888 	else
    889 		size = wd->sc_dk.dk_label->d_partitions[part].p_size *
    890 		    (wd->sc_dk.dk_label->d_secsize / DEV_BSIZE);
    891 	if (omask == 0 && edmcaclose(dev, 0, S_IFBLK, NULL) != 0)
    892 		return (-1);
    893 	return (size);
    894 }
    895 
    896 /* #define WD_DUMP_NOT_TRUSTED if you just want to watch */
    897 static int wddoingadump = 0;
    898 static int wddumprecalibrated = 0;
    899 
    900 /*
    901  * Dump core after a system crash.
    902  */
    903 int
    904 edmcadump(dev, blkno, va, size)
    905 	dev_t dev;
    906 	daddr_t blkno;
    907 	caddr_t va;
    908 	size_t size;
    909 {
    910 	struct ed_softc *wd;	/* disk unit to do the I/O */
    911 	struct disklabel *lp;   /* disk's disklabel */
    912 	int part; // , err;
    913 	int nblks;	/* total number of sectors left to write */
    914 
    915 	/* Check if recursive dump; if so, punt. */
    916 	if (wddoingadump)
    917 		return EFAULT;
    918 	wddoingadump = 1;
    919 
    920 	wd = device_lookup(&ed_cd, DISKUNIT(dev));
    921 	if (wd == NULL)
    922 		return (ENXIO);
    923 
    924 	part = DISKPART(dev);
    925 
    926 #if 0
    927 	/* Make sure it was initialized. */
    928 	if (wd->drvp->state < READY)
    929 		return ENXIO;
    930 #endif
    931 
    932 	/* Convert to disk sectors.  Request must be a multiple of size. */
    933 	lp = wd->sc_dk.dk_label;
    934 	if ((size % lp->d_secsize) != 0)
    935 		return EFAULT;
    936 	nblks = size / lp->d_secsize;
    937 	blkno = blkno / (lp->d_secsize / DEV_BSIZE);
    938 
    939 	/* Check transfer bounds against partition size. */
    940 	if ((blkno < 0) || ((blkno + nblks) > lp->d_partitions[part].p_size))
    941 		return EINVAL;
    942 
    943 	/* Offset block number to start of partition. */
    944 	blkno += lp->d_partitions[part].p_offset;
    945 
    946 	/* Recalibrate, if first dump transfer. */
    947 	if (wddumprecalibrated == 0) {
    948 		wddumprecalibrated = 1;
    949 #if 0
    950 		wd->drvp->state = RESET;
    951 #endif
    952 	}
    953 
    954 	while (nblks > 0) {
    955 #if 0
    956 		wd->sc_wdc_bio.blkno = blkno;
    957 		wd->sc_wdc_bio.flags = ATA_POLL;
    958 		wd->sc_wdc_bio.bcount = lp->d_secsize;
    959 		wd->sc_wdc_bio.databuf = va;
    960 #ifndef WD_DUMP_NOT_TRUSTED
    961 		switch (wdc_ata_bio(wd->drvp, &wd->sc_wdc_bio)) {
    962 		case WDC_TRY_AGAIN:
    963 			panic("wddump: try again");
    964 			break;
    965 		case WDC_QUEUED:
    966 			panic("wddump: polled command has been queued");
    967 			break;
    968 		case WDC_COMPLETE:
    969 			break;
    970 		}
    971 		if (err != 0) {
    972 			printf("\n");
    973 			return err;
    974 		}
    975 #else	/* WD_DUMP_NOT_TRUSTED */
    976 		/* Let's just talk about this first... */
    977 		printf("ed%d: dump addr 0x%x, cylin %d, head %d, sector %d\n",
    978 		    unit, va, cylin, head, sector);
    979 		delay(500 * 1000);	/* half a second */
    980 #endif
    981 #endif /* 0 */
    982 
    983 		/* update block count */
    984 		nblks -= 1;
    985 		blkno += 1;
    986 		va += lp->d_secsize;
    987 	}
    988 
    989 	wddoingadump = 0;
    990 	return (ESPIPE);
    991 }
    992 
    993 #ifdef HAS_BAD144_HANDLING
    994 /*
    995  * Internalize the bad sector table.
    996  */
    997 static void
    998 bad144intern(wd)
    999 	struct ed_softc *wd;
   1000 {
   1001 	struct dkbad *bt = &wd->sc_dk.dk_cpulabel->bad;
   1002 	struct disklabel *lp = wd->sc_dk.dk_label;
   1003 	int i = 0;
   1004 
   1005 	WDCDEBUG_PRINT(("bad144intern\n"), DEBUG_XFERS);
   1006 
   1007 	for (; i < NBT_BAD; i++) {
   1008 		if (bt->bt_bad[i].bt_cyl == 0xffff)
   1009 			break;
   1010 		wd->sc_badsect[i] =
   1011 		    bt->bt_bad[i].bt_cyl * lp->d_secpercyl +
   1012 		    (bt->bt_bad[i].bt_trksec >> 8) * lp->d_nsectors +
   1013 		    (bt->bt_bad[i].bt_trksec & 0xff);
   1014 	}
   1015 	for (; i < NBT_BAD+1; i++)
   1016 		wd->sc_badsect[i] = -1;
   1017 }
   1018 #endif
   1019 
   1020 static int
   1021 ed_get_params(ed)
   1022 	struct ed_softc *ed;
   1023 {
   1024 	u_int16_t cmd_args[2];
   1025 
   1026 	/*
   1027 	 * Get Device Configuration (09).
   1028 	 */
   1029 	cmd_args[0] = 6;	/* Options: 00s110, s: 0=Physical 1=Pseudo */
   1030 	cmd_args[1] = 0;
   1031 	if (edc_run_cmd(ed->edc_softc, CMD_GET_DEV_CONF, ed->sc_devno, cmd_args, 2, 0))
   1032 		return (1);
   1033 
   1034 	ed->spares = ed->sc_status_block[1] >> 8;
   1035 	ed->drv_flags = ed->sc_status_block[1] & 0x1f;
   1036 	ed->rba = ed->sc_status_block[2] |
   1037 		(ed->sc_status_block[3] << 16);
   1038 	/* Instead of using:
   1039 		ed->cyl = ed->sc_status_block[4];
   1040 		ed->heads = ed->sc_status_block[5] & 0xff;
   1041 		ed->sectors = ed->sc_status_block[5] >> 8;
   1042 	 * we fabricate the numbers from RBA count, so that
   1043 	 * number of sectors is 32 and heads 64. This seems
   1044 	 * to be necessary for integrated ESDI controller.
   1045 	 */
   1046 	ed->sectors = 32;
   1047 	ed->heads = 64;
   1048 	ed->cyl = ed->rba / (ed->heads * ed->sectors);
   1049 	ed->sc_capacity = ed->rba;
   1050 
   1051 	return (0);
   1052 }
   1053 
   1054 /*
   1055  * Our shutdown hook. We attempt to park disk's head only.
   1056  */
   1057 void
   1058 ed_shutdown(arg)
   1059 	void *arg;
   1060 {
   1061 #if 0
   1062 	struct ed_softc *ed = arg;
   1063 	u_int16_t cmd_args[2];
   1064 
   1065 	/* Issue Park Head command */
   1066 	cmd_args[0] = 6;	/* Options: 000110 */
   1067 	cmd_args[1] = 0;
   1068 	(void) edc_run_cmd(ed->edc_softc, CMD_PARK_HEAD, ed->sc_devno,
   1069 			cmd_args, 2, 0);
   1070 #endif
   1071 }
   1072 
   1073 /*
   1074  * Main worker thread function.
   1075  */
   1076 void
   1077 edworker(arg)
   1078 	void *arg;
   1079 {
   1080 	struct ed_softc *ed = (struct ed_softc *) arg;
   1081 	struct buf *bp;
   1082 	int s;
   1083 
   1084 	config_pending_decr();
   1085 
   1086 	for(;;) {
   1087 		/* Wait until awakened */
   1088 		(void) tsleep(&ed->sc_q, PRIBIO, "edidle", 0);
   1089 
   1090 		if ((ed->sc_flags & EDF_PROCESS_QUEUE) == 0)
   1091 			panic("edworker: expecting process queue");
   1092 		ed->sc_flags &= ~EDF_PROCESS_QUEUE;
   1093 
   1094 		for(;;) {
   1095 			/* Is there a buf for us ? */
   1096 			simple_lock(&ed->sc_q_lock);
   1097 			if ((bp = BUFQ_FIRST(&ed->sc_q)) == NULL) {
   1098 				simple_unlock(&ed->sc_q_lock);
   1099 				break;
   1100 			}
   1101 			BUFQ_REMOVE(&ed->sc_q, bp);
   1102 			simple_unlock(&ed->sc_q_lock);
   1103 
   1104 			/* Schedule i/o operation */
   1105 			ed->sc_error = 0;
   1106 			s = splbio();
   1107 			__edstart(ed, bp);
   1108 			splx(s);
   1109 
   1110 			/*
   1111 			 * Wait until the command executes; edc_intr() wakes
   1112 			 * us up.
   1113 			 */
   1114 			if (ed->sc_error == 0
   1115 			    && (ed->sc_flags & EDF_IODONE) == 0) {
   1116 				(void)tsleep(&ed->edc_softc, PRIBIO, "edwrk",0);
   1117 				edc_cmd_wait(ed->edc_softc, ed->sc_devno, 5);
   1118 			}
   1119 
   1120 			/* Handle i/o results */
   1121 			s = splbio();
   1122 			edmcadone(ed);
   1123 			splx(s);
   1124 		}
   1125 	}
   1126 }
   1127