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