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