Print this page
XXXX introduce drv_sectohz
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/sun/io/fd.c
+++ new/usr/src/uts/sun/io/fd.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
23 23 */
24 24
25 25
26 26 /*
27 27 * Intel 82077 Floppy Disk Driver
28 28 */
29 29
30 30 /*
31 31 * Notes
32 32 *
33 33 * 0. The driver supports two flavors of hardware design:
34 34 * "SUNW,fdtwo" - sun4m - 82077 with sun4m style Auxio
35 35 * "fdthree" - sun4u - 82077 with DMA
36 36 * In addition it supports an apparent bug in some versions of
37 37 * the 82077 controller.
38 38 *
39 39 * 1. The driver is mostly set up for multiple controllers, multiple
40 40 * drives. However- we *do* assume the use of the AUXIO register, and
41 41 * if we ever have > 1 fdc, we'll have to see what that means. This
42 42 * is all intrinsically machine specific, but there isn't much we
43 43 * can do about it.
44 44 *
45 45 * 2. The driver also is structured to deal with one drive active at
46 46 * a time. This is because the 82072 chip (no longer supported) was
47 47 * known to be buggy with respect to overlapped seeks.
48 48 *
49 49 * 3. The high level interrupt code is in assembler, and runs in a
50 50 * sparc trap window. It acts as a pseudo-dma engine as well as
51 51 * handles a couple of other interrupts. When it gets its job done,
52 52 * it schedules a second stage interrupt (soft interrupt) which
53 53 * is then fielded here in fd_lointr. When DMA is used, the fdintr_dma
54 54 * interrupt handler is used.
55 55 *
56 56 * 4. Nearly all locking is done on a lower level MUTEX_DRIVER
57 57 * mutex. The locking is quite conservative, and is generally
58 58 * established very close to any of the entries into the driver.
59 59 * There is nearly no locking done of the high level MUTEX_DRIVER
60 60 * mutex (which generally is a SPIN mutex because the floppy usually
61 61 * interrupts above LOCK_LEVEL). The assembler high level interrupt
62 62 * handler grabs the high level mutex, but the code in the driver
63 63 * here is especially structured to not need to do this.
64 64 *
65 65 * 5. Fdrawioctl commands that pass data are not optimized for
66 66 * speed. If they need to be faster, the driver structure will
67 67 * have to be redone such that fdrawioctl calls physio after
68 68 * cons'ing up a uio structure and that fdstart will be able
69 69 * to detect that a particular buffer is a 'special' buffer.
70 70 *
71 71 * 6. Removable media support is not complete.
72 72 *
73 73 */
74 74
75 75 #include <sys/param.h>
76 76 #include <sys/buf.h>
77 77 #include <sys/ioctl.h>
78 78 #include <sys/uio.h>
79 79 #include <sys/open.h>
80 80 #include <sys/conf.h>
81 81 #include <sys/file.h>
82 82 #include <sys/cmn_err.h>
83 83 #include <sys/debug.h>
84 84 #include <sys/kmem.h>
85 85 #include <sys/stat.h>
86 86 #include <sys/autoconf.h>
87 87
88 88 #include <sys/dklabel.h>
89 89
90 90 #include <sys/vtoc.h>
91 91 #include <sys/dkio.h>
92 92 #include <sys/fdio.h>
93 93
94 94 #include <sys/ddi.h>
95 95 #include <sys/sunddi.h>
96 96 #include <sys/kstat.h>
97 97
98 98 /*
99 99 * included to check for ELC or SLC which report floppy controller that
100 100 */
101 101 #include <sys/cpu.h>
102 102
103 103 #include "sys/fdvar.h"
104 104 #include "sys/fdreg.h"
105 105 #include "sys/dma_i8237A.h"
106 106
107 107 /*
108 108 * Defines
109 109 */
110 110 #define KIOSP KSTAT_IO_PTR(un->un_iostat)
111 111 #define KIOIP KSTAT_INTR_PTR(fdc->c_intrstat)
112 112 #define MEDIUM_DENSITY 0x40
113 113 #define SEC_SIZE_CODE (fdctlr.c_csb->csb_unit]->un_chars->medium ? 3 : 2)
114 114 #define CMD_READ (MT + SK + FDRAW_RDCMD + MFM)
115 115 #define CMD_WRITE (MT + FDRAW_WRCMD + MFM)
116 116 #define C CE_CONT
117 117 #define FD_POLLABLE_PROP "pollable" /* prom property */
118 118 #define FD_MANUAL_EJECT "manual" /* prom property */
119 119 #define FD_UNIT "unit" /* prom property */
120 120
121 121 /*
122 122 * Sony MP-F17W-50D Drive Parameters
123 123 * High Capacity
124 124 * Capacity unformatted 2Mb
125 125 * Capacity formatted 1.47Mb
126 126 * Encoding method MFM
127 127 * Recording density 17434 bpi
128 128 * Track density 135 tpi
129 129 * Cylinders 80
130 130 * Heads 2
131 131 * Tracks 160
132 132 * Rotational speed 300 rpm
133 133 * Transfer rate 250/500 kbps
134 134 * Latency (average) 100 ms
135 135 * Access time
136 136 * Average 95 ms
137 137 * Track to track 3 ms
138 138 * Head settling time 15 ms
139 139 * Motor start time 500 ms
140 140 * Head load time ? ms
141 141 */
142 142
143 143 /*
144 144 * The max_fd_dma_len is used only when southbridge is present.
145 145 * It has been observed that when IFB tests are run the floppy dma could get
146 146 * starved and result in underrun errors. After experimenting it was found that
147 147 * doing dma in chunks of 2048 works OK.
148 148 * The reason for making this a global variable is that there could be
149 149 * situations under which the customer would like to get full performance
150 150 * from floppy. He may not be having IFB boards that cause underrun errors.
151 151 * Under those conditions we could set this value to a much higher value
152 152 * by editing /etc/system file.
153 153 */
154 154 int max_fd_dma_len = 2048;
155 155
156 156 static void quiesce_fd_interrupt(struct fdctlr *);
157 157
158 158 /*
159 159 * Character/block entry points function prototypes
160 160 */
161 161 static int fd_open(dev_t *, int, int, cred_t *);
162 162 static int fd_close(dev_t, int, int, cred_t *);
163 163 static int fd_strategy(struct buf *);
164 164 static int fd_read(dev_t, struct uio *, cred_t *);
165 165 static int fd_write(dev_t, struct uio *, cred_t *);
166 166 static int fd_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
167 167 static int
168 168 fd_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, int, char *, caddr_t, int *);
169 169
170 170 /*
171 171 * Device operations (dev_ops) entries function prototypes
172 172 */
173 173 static int fd_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
174 174 void **result);
175 175 static int fd_attach(dev_info_t *, ddi_attach_cmd_t);
176 176 static int fd_detach(dev_info_t *, ddi_detach_cmd_t);
177 177 static int fd_power(dev_info_t *dip, int component, int level);
178 178
179 179 /*
180 180 * Internal functions
181 181 */
182 182 static int fd_attach_check_drive(struct fdctlr *fdc);
183 183 static int fd_attach_det_ctlr(dev_info_t *dip, struct fdctlr *fdc);
184 184 static int fd_attach_map_regs(dev_info_t *dip, struct fdctlr *fdc);
185 185 static int fd_attach_register_interrupts(dev_info_t *dip, struct fdctlr *fdc,
186 186 int *hard);
187 187 static int fd_build_label_vtoc(struct fdunit *, struct vtoc *);
188 188 static void fd_build_user_vtoc(struct fdunit *, struct vtoc *);
189 189 static int fdcheckdisk(struct fdctlr *fdc, int unit);
190 190 static int fd_check_media(dev_t dev, enum dkio_state state);
191 191 static void fd_cleanup(dev_info_t *dip, struct fdctlr *fdc, int hard,
192 192 int locks);
193 193 static void fdeject(struct fdctlr *, int unit);
194 194 static int fdexec(struct fdctlr *fdc, int flags);
195 195 static void fdexec_turn_on_motor(struct fdctlr *fdc, int flags, uint_t unit);
196 196 static int fdformat(struct fdctlr *fdc, int unit, int cyl, int hd);
197 197 static caddr_t fd_getauxiova();
198 198 static struct fdctlr *fd_getctlr(dev_t);
199 199 static void fdgetcsb(struct fdctlr *);
200 200 static int fdgetlabel(struct fdctlr *fdc, int unit);
201 201 enum dkio_state fd_get_media_state(struct fdctlr *, int);
202 202 static uint_t fdintr_dma();
203 203 static int fd_isauxiodip(dev_info_t *);
204 204 static uint_t fd_lointr(caddr_t arg);
205 205 static void fd_media_watch(void *);
206 206 static void fdmotoff(void *);
207 207 static int fd_part_is_open(struct fdunit *un, int part);
208 208 static int fdrawioctl(struct fdctlr *, int, intptr_t, int);
209 209 static int fdrecalseek(struct fdctlr *fdc, int unit, int arg, int execflg);
210 210 static int fdrecover(struct fdctlr *);
211 211 static void fdretcsb(struct fdctlr *);
212 212 static int fdreset(struct fdctlr *);
213 213 static int fdrw(struct fdctlr *fdc, int, int, int, int, int, caddr_t, uint_t);
214 214 static void fdselect(struct fdctlr *fdc, int unit, int onoff);
215 215 static int fdsensedrv(struct fdctlr *fdc, int unit);
216 216 static int fdsense_chng(struct fdctlr *, int unit);
217 217 static void fdstart(struct fdctlr *);
218 218 static int fdstart_dma(register struct fdctlr *fdc, caddr_t addr, uint_t len);
219 219 static int fd_unit_is_open(struct fdunit *);
220 220 static void fdunpacklabel(struct packed_label *, struct dk_label *);
221 221 static int fd_unbind_handle(struct fdctlr *);
222 222 static void fdwatch(void *);
223 223 static void set_rotational_speed(struct fdctlr *, int);
224 224 static int fd_get_media_info(struct fdunit *un, caddr_t buf, int flag);
225 225 static int fd_pm_lower_power(struct fdctlr *fdc);
226 226 static int fd_pm_raise_power(struct fdctlr *fdc);
227 227 static void create_pm_components(dev_info_t *dip);
228 228 static void set_data_count_register(struct fdctlr *fdc, uint32_t count);
229 229 static uint32_t get_data_count_register(struct fdctlr *fdc);
230 230 static void reset_dma_controller(struct fdctlr *fdc);
231 231 static void set_data_address_register(struct fdctlr *fdc, uint32_t address);
232 232 static uint32_t get_dma_control_register(struct fdctlr *fdc);
233 233 static void set_dma_mode(struct fdctlr *fdc, int val);
234 234 static void set_dma_control_register(struct fdctlr *fdc, uint32_t val);
235 235 static void release_sb_dma(struct fdctlr *fdc);
236 236
237 237 /*
238 238 * External functions
239 239 */
240 240 extern uint_t fd_intr(caddr_t); /* defined in fd_asm.s */
241 241 extern void set_auxioreg();
242 242 extern void call_debug();
243 243
244 244
245 245
246 246 /*
247 247 * The following macro checks whether the device in a SUSPENDED state.
248 248 * As per WDD guide lines the I/O requests to a suspended device should
249 249 * be blocked until the device is resumed.
250 250 * Here we cv_wait on c_suspend_cv, and there is a cv_broadcast() in
251 251 * DDI_RESUME to wake up this thread.
252 252 *
253 253 * NOTE: This code is not tested because the kernel threads are suspended
254 254 * before the device is suspended. So there can not be any I/O requests on
255 255 * a suspended device until the cpr implementation changes..
256 256 */
257 257
258 258 #define CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc) \
259 259 {\
260 260 while (fdc->c_un->un_state == FD_STATE_SUSPENDED) {\
261 261 cv_wait(&fdc->c_suspend_cv, \
262 262 &fdc->c_lolock);\
263 263 }\
264 264 }
265 265
266 266 /*
267 267 * bss (uninitialized data)
268 268 */
269 269 struct fdctlr *fdctlrs; /* linked list of controllers */
270 270
271 271 /*
272 272 * initialized data
273 273 */
274 274
275 275 static int fd_check_media_time = 5000000; /* 5 second state check */
276 276 static int fd_pollable = 0;
277 277 static uchar_t rwretry = 10;
278 278 static uchar_t skretry = 5;
279 279 /* This variable allows the dynamic change of the burst size */
280 280 static int fd_burstsize = DCSR_BURST_0 | DCSR_BURST_1;
281 281
282 282 static struct driver_minor_data {
283 283 char *name;
284 284 int minor;
285 285 int type;
286 286 } fd_minor [] = {
287 287 { "a", 0, S_IFBLK},
288 288 { "b", 1, S_IFBLK},
289 289 { "c", 2, S_IFBLK},
290 290 { "a,raw", 0, S_IFCHR},
291 291 { "b,raw", 1, S_IFCHR},
292 292 { "c,raw", 2, S_IFCHR},
293 293 {0}
294 294 };
295 295
296 296 /*
297 297 * If the interrupt handler is invoked and no controllers expect an
298 298 * interrupt, the kernel panics. The following message is printed out.
299 299 */
300 300 char *panic_msg = "fd_intr: unexpected interrupt\n";
301 301
302 302 /*
303 303 * Specify/Configure cmd parameters
304 304 */
305 305 static uchar_t fdspec[2] = { 0xc2, 0x33 }; /* "specify" parameters */
306 306 static uchar_t fdconf[3] = { 0x64, 0x58, 0x00 }; /* "configure" parameters */
307 307
308 308 /* When DMA is used, set the ND bit to 0 */
309 309 #define SPEC_DMA_MODE 0x32
310 310
311 311 /*
312 312 * default characteristics
313 313 */
314 314 static struct fd_char fdtypes[] = {
315 315 { /* struct fd_char fdchar_1.7MB density */
316 316 0, /* medium */
317 317 500, /* transfer rate */
318 318 80, /* number of cylinders */
319 319 2, /* number of heads */
320 320 512, /* sector size */
321 321 21, /* sectors per track */
322 322 -1, /* (NA) # steps per data track */
323 323 },
324 324 { /* struct fd_char fdchar_highdens */
325 325 0, /* medium */
326 326 500, /* transfer rate */
327 327 80, /* number of cylinders */
328 328 2, /* number of heads */
329 329 512, /* sector size */
330 330 18, /* sectors per track */
331 331 -1, /* (NA) # steps per data track */
332 332 },
333 333 { /* struct fd_char fdchar_meddens */
334 334 1, /* medium */
335 335 500, /* transfer rate */
336 336 77, /* number of cylinders */
337 337 2, /* number of heads */
338 338 1024, /* sector size */
339 339 8, /* sectors per track */
340 340 -1, /* (NA) # steps per data track */
341 341 },
342 342 { /* struct fd_char fdchar_lowdens */
343 343 0, /* medium */
344 344 250, /* transfer rate */
345 345 80, /* number of cylinders */
346 346 2, /* number of heads */
347 347 512, /* sector size */
348 348 9, /* sectors per track */
349 349 -1, /* (NA) # steps per data track */
350 350 }
351 351 };
352 352
353 353
354 354 static int nfdtypes = sizeof (fdtypes) / sizeof (fdtypes[0]);
355 355
356 356
357 357 /*
358 358 * Default Label & partition maps
359 359 */
360 360
361 361 static struct packed_label fdlbl_high_21 = {
362 362 { "3.5\" floppy cyl 80 alt 0 hd 2 sec 21" },
363 363 300, /* rotations per minute */
364 364 80, /* # physical cylinders */
365 365 0, /* alternates per cylinder */
366 366 1, /* interleave factor */
367 367 80, /* # of data cylinders */
368 368 0, /* # of alternate cylinders */
369 369 2, /* # of heads in this partition */
370 370 21, /* # of 512 byte sectors per track */
371 371 {
372 372 { 0, 79 * 2 * 21 }, /* part 0 - all but last cyl */
373 373 { 79, 1 * 2 * 21 }, /* part 1 - just the last cyl */
374 374 { 0, 80 * 2 * 21 }, /* part 2 - "the whole thing" */
375 375 },
376 376 { 0, /* version */
377 377 "", /* volume label */
378 378 3, /* no. of partitions */
379 379 { 0 }, /* partition hdrs, sec 2 */
380 380 { 0 }, /* mboot info. unsupported */
381 381 VTOC_SANE, /* verify vtoc sanity */
382 382 { 0 }, /* reserved space */
383 383 0, /* timestamp */
384 384 },
385 385 };
386 386
387 387 static struct packed_label fdlbl_high_80 = {
388 388 { "3.5\" floppy cyl 80 alt 0 hd 2 sec 18" },
389 389 300, /* rotations per minute */
390 390 80, /* # physical cylinders */
391 391 0, /* alternates per cylinder */
392 392 1, /* interleave factor */
393 393 80, /* # of data cylinders */
394 394 0, /* # of alternate cylinders */
395 395 2, /* # of heads in this partition */
396 396 18, /* # of 512 byte sectors per track */
397 397 {
398 398 { 0, 79 * 2 * 18 }, /* part 0 - all but last cyl */
399 399 { 79, 1 * 2 * 18 }, /* part 1 - just the last cyl */
400 400 { 0, 80 * 2 * 18 }, /* part 2 - "the whole thing" */
401 401 },
402 402 { 0, /* version */
403 403 "", /* volume label */
404 404 3, /* no. of partitions */
405 405 { 0 }, /* partition hdrs, sec 2 */
406 406 { 0 }, /* mboot info. unsupported */
407 407 VTOC_SANE, /* verify vtoc sanity */
408 408 { 0 }, /* reserved space */
409 409 0, /* timestamp */
410 410 },
411 411 };
412 412
413 413 /*
414 414 * A medium density diskette has 1024 byte sectors. The dk_label structure
415 415 * assumes a sector is DEVBSIZE (512) bytes.
416 416 */
417 417 static struct packed_label fdlbl_medium_80 = {
418 418 { "3.5\" floppy cyl 77 alt 0 hd 2 sec 8" },
419 419 360, /* rotations per minute */
420 420 77, /* # physical cylinders */
421 421 0, /* alternates per cylinder */
422 422 1, /* interleave factor */
423 423 77, /* # of data cylinders */
424 424 0, /* # of alternate cylinders */
425 425 2, /* # of heads in this partition */
426 426 16, /* # of 512 byte sectors per track */
427 427 {
428 428 { 0, 76 * 2 * 8 * 2 }, /* part 0 - all but last cyl */
429 429 { 76, 1 * 2 * 8 * 2 }, /* part 1 - just the last cyl */
430 430 { 0, 77 * 2 * 8 * 2 }, /* part 2 - "the whole thing" */
431 431 },
432 432 { 0, /* version */
433 433 "", /* volume label */
434 434 3, /* no. of partitions */
435 435 { 0 }, /* partition hdrs, sec 2 */
436 436 { 0 }, /* mboot info. unsupported */
437 437 VTOC_SANE, /* verify vtoc sanity */
438 438 { 0 }, /* reserved space */
439 439 0, /* timestamp */
440 440 },
441 441 };
442 442
443 443 static struct packed_label fdlbl_low_80 = {
444 444 { "3.5\" floppy cyl 80 alt 0 hd 2 sec 9" },
445 445 300, /* rotations per minute */
446 446 80, /* # physical cylinders */
447 447 0, /* alternates per cylinder */
448 448 1, /* interleave factor */
449 449 80, /* # of data cylinders */
450 450 0, /* # of alternate cylinders */
451 451 2, /* # of heads in this partition */
452 452 9, /* # of 512 byte sectors per track */
453 453 {
454 454 { 0, 79 * 2 * 9 }, /* part 0 - all but last cyl */
455 455 { 79, 1 * 2 * 9 }, /* part 1 - just the last cyl */
456 456 { 0, 80 * 2 * 9 }, /* part 2 - "the whole thing" */
457 457 },
458 458 { 0, /* version */
459 459 "", /* volume label */
460 460 3, /* no. of partitions */
461 461 { 0 }, /* partition hdrs, sec 2 */
462 462 { 0 }, /* mboot info. unsupported */
463 463 VTOC_SANE, /* verify vtoc sanity */
464 464 { 0 }, /* reserved space */
465 465 0, /* timestamp */
466 466 },
467 467 };
468 468
469 469 static struct fdcmdinfo {
470 470 char *cmdname; /* command name */
471 471 uchar_t ncmdbytes; /* number of bytes of command */
472 472 uchar_t nrsltbytes; /* number of bytes in result */
473 473 uchar_t cmdtype; /* characteristics */
474 474 } fdcmds[] = {
475 475 "", 0, 0, 0, /* - */
476 476 "", 0, 0, 0, /* - */
477 477 "read_track", 9, 7, 1, /* 2 */
478 478 "specify", 3, 0, 3, /* 3 */
479 479 "sense_drv_status", 2, 1, 3, /* 4 */
480 480 "write", 9, 7, 1, /* 5 */
481 481 "read", 9, 7, 1, /* 6 */
482 482 "recalibrate", 2, 0, 2, /* 7 */
483 483 "sense_int_status", 1, 2, 3, /* 8 */
484 484 "write_del", 9, 7, 1, /* 9 */
485 485 "read_id", 2, 7, 2, /* A */
486 486 "motor_on/off", 1, 0, 4, /* B */
487 487 "read_del", 9, 7, 1, /* C */
488 488 "format_track", 10, 7, 1, /* D */
489 489 "dump_reg", 1, 10, 4, /* E */
490 490 "seek", 3, 0, 2, /* F */
491 491 "", 0, 0, 0, /* - */
492 492 "", 0, 0, 0, /* - */
493 493 "", 0, 0, 0, /* - */
494 494 "configure", 4, 0, 4, /* 13 */
495 495 /* relative seek */
496 496 };
497 497
498 498 static struct cb_ops fd_cb_ops = {
499 499 fd_open, /* open */
500 500 fd_close, /* close */
501 501 fd_strategy, /* strategy */
502 502 nodev, /* print */
503 503 nodev, /* dump */
504 504 fd_read, /* read */
505 505 fd_write, /* write */
506 506 fd_ioctl, /* ioctl */
507 507 nodev, /* devmap */
508 508 nodev, /* mmap */
509 509 nodev, /* segmap */
510 510 nochpoll, /* poll */
511 511 fd_prop_op, /* cb_prop_op */
512 512 0, /* streamtab */
513 513 D_NEW | D_MP /* Driver compatibility flag */
514 514 };
515 515
516 516 static struct dev_ops fd_ops = {
517 517 DEVO_REV, /* devo_rev, */
518 518 0, /* refcnt */
519 519 fd_info, /* info */
520 520 nulldev, /* identify */
521 521 nulldev, /* probe */
522 522 fd_attach, /* attach */
523 523 fd_detach, /* detach */
524 524 nodev, /* reset */
525 525 &fd_cb_ops, /* driver operations */
526 526 (struct bus_ops *)0, /* bus operations */
527 527 fd_power, /* power */
528 528 ddi_quiesce_not_supported, /* devo_quiesce */
529 529 };
530 530
531 531
532 532 /*
533 533 * error handling
534 534 *
535 535 * for debugging, set rwretry and skretry = 1
536 536 * set fderrlevel to 1
537 537 * set fderrmask to 224 or 100644
538 538 *
539 539 * after debug set rwretry to 10, skretry to 5, and fderrlevel to 3
540 540 * set fderrmask to FDEM_ALL
541 541 * remove the define FD_DEBUG
542 542 *
543 543 */
544 544
545 545 static unsigned int fderrmask = (unsigned int)FDEM_ALL;
546 546 static int fderrlevel = 3;
547 547
548 548 static int tosec = 16; /* long timeouts for sundiag for now */
549 549
550 550 /*
551 551 * loadable module support
552 552 */
553 553
554 554 #include <sys/modctl.h>
555 555
556 556 extern struct mod_ops mod_driverops;
557 557 static struct modldrv modldrv = {
558 558 &mod_driverops, /* Type of module. driver here */
559 559 "Floppy Driver", /* Name of the module. */
560 560 &fd_ops, /* Driver ops vector */
561 561 };
562 562
563 563 static struct modlinkage modlinkage = {
564 564 MODREV_1,
565 565 &modldrv,
566 566 NULL
567 567 };
568 568
569 569 int
570 570 _init(void)
571 571 {
572 572 return (mod_install(&modlinkage));
573 573 }
574 574
575 575 int
576 576 _info(struct modinfo *modinfop)
577 577 {
578 578 return (mod_info(&modlinkage, modinfop));
579 579 }
580 580
581 581 int
582 582 _fini(void)
583 583 {
584 584 int e;
585 585
586 586 if ((e = mod_remove(&modlinkage)) != 0)
587 587 return (e);
588 588
589 589 /* ddi_soft_state_fini() */
590 590 return (0);
591 591 }
592 592
593 593 /* ARGSUSED */
594 594 static int
595 595 fd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
596 596 {
597 597 struct fdctlr *fdc;
598 598 struct driver_minor_data *dmdp;
599 599 int instance = ddi_get_instance(dip);
600 600 int hard_intr_set = 0;
601 601
602 602 FDERRPRINT(FDEP_L1, FDEM_ATTA, (C, "fd_attach: start\n"));
603 603
604 604 switch (cmd) {
605 605 case DDI_ATTACH:
606 606 break;
607 607 case DDI_RESUME:
608 608
609 609 if (!(fdc = fd_getctlr(instance << FDINSTSHIFT))) {
610 610 return (DDI_FAILURE);
611 611 }
612 612 quiesce_fd_interrupt(fdc);
613 613 if (fdc->c_fdtype & FDCTYPE_SB)
614 614 if (ddi_add_intr(dip, 0, &fdc->c_block, 0,
615 615 fdintr_dma, (caddr_t)0) != DDI_SUCCESS) {
616 616 return (DDI_FAILURE);
617 617 }
618 618
619 619 (void) pm_raise_power(dip, 0, PM_LEVEL_ON);
620 620 mutex_enter(&fdc->c_lolock);
621 621 /*
622 622 * Wake up any thread blocked due to I/O requests
623 623 * while the device was suspended.
624 624 */
625 625 cv_broadcast(&fdc->c_suspend_cv);
626 626 mutex_exit(&fdc->c_lolock);
627 627 return (DDI_SUCCESS);
628 628
629 629 default:
630 630 return (DDI_FAILURE);
631 631 }
632 632
633 633
634 634 /*
635 635 * Check for the pollable property
636 636 * A pollable floppy drive currently only exists on the
637 637 * Sparcstation Voyager. This drive does not need to
638 638 * be turned on in order to sense whether or not a diskette
639 639 * is present.
640 640 */
641 641 if (ddi_getprop(DDI_DEV_T_ANY, dip,
642 642 DDI_PROP_DONTPASS, FD_POLLABLE_PROP, 0))
643 643 fd_pollable = 1;
644 644
645 645 fdc = kmem_zalloc(sizeof (*fdc), KM_SLEEP);
646 646 fdc->c_dip = dip;
647 647
648 648
649 649 fdc->c_next = fdctlrs;
650 650 fdctlrs = fdc;
651 651
652 652 /* Determine which type of controller is present and initialize it */
653 653 if (fd_attach_det_ctlr(dip, fdc) == DDI_FAILURE) {
654 654 fd_cleanup(dip, fdc, hard_intr_set, 0);
655 655 return (DDI_FAILURE);
656 656 }
657 657 /* Finish mapping the device registers & setting up structures */
658 658 if (fd_attach_map_regs(dip, fdc) == DDI_FAILURE) {
659 659 fd_cleanup(dip, fdc, hard_intr_set, 0);
660 660 return (DDI_FAILURE);
661 661 }
662 662
663 663 /*
664 664 * Initialize the DMA limit structures if it's being used.
665 665 */
666 666 if (fdc->c_fdtype & FDCTYPE_DMA) {
667 667 fdc->c_fd_dma_lim.dma_attr_version = DMA_ATTR_V0;
668 668 fdc->c_fd_dma_lim.dma_attr_addr_lo = 0x00000000ull;
669 669 fdc->c_fd_dma_lim.dma_attr_addr_hi = 0xfffffffeull;
670 670 fdc->c_fd_dma_lim.dma_attr_count_max = 0xffffff;
671 671 if (fdc->c_fdtype & FDCTYPE_SB) {
672 672 fdc->c_fd_dma_lim.dma_attr_align = FD_SB_DMA_ALIGN;
673 673 } else {
674 674 fdc->c_fd_dma_lim.dma_attr_align = 1;
675 675 }
676 676 fdc->c_fd_dma_lim.dma_attr_burstsizes = 0x0;
677 677 fdc->c_fd_dma_lim.dma_attr_minxfer = 1;
678 678 fdc->c_fd_dma_lim.dma_attr_maxxfer = 0xffff;
679 679 fdc->c_fd_dma_lim.dma_attr_seg = 0xffff;
680 680 fdc->c_fd_dma_lim.dma_attr_sgllen = 1;
681 681 fdc->c_fd_dma_lim.dma_attr_granular = 512;
682 682
683 683 if (ddi_dma_alloc_handle(dip, &fdc->c_fd_dma_lim,
684 684 DDI_DMA_DONTWAIT, 0, &fdc->c_dmahandle) != DDI_SUCCESS) {
685 685 fd_cleanup(dip, fdc, hard_intr_set, 0);
686 686 return (DDI_FAILURE);
687 687 }
688 688
689 689 if (fdc->c_fdtype & FDCTYPE_SB) {
690 690 ddi_device_acc_attr_t dev_attr;
691 691 size_t rlen;
692 692
693 693 dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
694 694 dev_attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
695 695 dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
696 696
697 697 if (ddi_dma_mem_alloc(fdc->c_dmahandle,
698 698 (size_t)(32*1024), &dev_attr, DDI_DMA_CONSISTENT,
699 699 DDI_DMA_SLEEP, NULL, (caddr_t *)&fdc->dma_buf,
700 700 &rlen, &fdc->c_dma_buf_handle) != DDI_SUCCESS) {
701 701 fd_cleanup(dip, fdc, hard_intr_set, 0);
702 702 return (DDI_FAILURE);
703 703 }
704 704
705 705 }
706 706 }
707 707
708 708
709 709 /* Register the interrupts */
710 710 if (fd_attach_register_interrupts(dip, fdc,
711 711 &hard_intr_set) == DDI_FAILURE) {
712 712 fd_cleanup(dip, fdc, hard_intr_set, 0);
713 713 FDERRPRINT(FDEP_L1, FDEM_ATTA,
714 714 (C, "fd_attach: registering interrupts failed\n"));
715 715 return (DDI_FAILURE);
716 716 }
717 717
718 718
719 719 /*
720 720 * set initial controller/drive/disk "characteristics/geometry"
721 721 *
722 722 * NOTE: The driver only supports one floppy drive. The hardware
723 723 * only supports one drive because there is only one auxio register
724 724 * for one drive.
725 725 */
726 726 fdc->c_un = kmem_zalloc(sizeof (struct fdunit), KM_SLEEP);
727 727 fdc->c_un->un_chars = kmem_alloc(sizeof (struct fd_char), KM_SLEEP);
728 728 fdc->c_un->un_iostat = kstat_create("fd", 0, "fd0", "disk",
729 729 KSTAT_TYPE_IO, 1, KSTAT_FLAG_PERSISTENT);
730 730 if (fdc->c_un->un_iostat) {
731 731 fdc->c_un->un_iostat->ks_lock = &fdc->c_lolock;
732 732 kstat_install(fdc->c_un->un_iostat);
733 733 }
734 734
735 735 fdc->c_un->un_drive = kmem_zalloc(sizeof (struct fd_drive), KM_SLEEP);
736 736
737 737 /* check for the manual eject property */
738 738 if (ddi_getprop(DDI_DEV_T_ANY, dip,
739 739 DDI_PROP_DONTPASS, FD_MANUAL_EJECT, 0)) {
740 740 fdc->c_un->un_drive->fdd_ejectable = 0;
741 741 } else {
742 742 /* an absence of the property indicates auto eject */
743 743 fdc->c_un->un_drive->fdd_ejectable = -1;
744 744 }
745 745
746 746 FDERRPRINT(FDEP_L1, FDEM_ATTA, (C, "fd_attach: ejectable? %d\n",
747 747 fdc->c_un->un_drive->fdd_ejectable));
748 748
749 749 /*
750 750 * Check for the drive id. If the drive id property doesn't exist
751 751 * then the drive id is set to 0
752 752 */
753 753 fdc->c_un->un_unit_no = ddi_getprop(DDI_DEV_T_ANY, dip,
754 754 DDI_PROP_DONTPASS, FD_UNIT, 0);
755 755
756 756
757 757 if (fdc->c_fdtype & FDCTYPE_SB) {
758 758 fdc->sb_dma_channel = ddi_getprop(DDI_DEV_T_ANY, dip,
759 759 DDI_PROP_DONTPASS, "dma-channel", 0);
760 760 }
761 761
762 762
763 763 FDERRPRINT(FDEP_L1, FDEM_ATTA, (C, "fd_attach: unit %d\n",
764 764 fdc->c_un->un_unit_no));
765 765
766 766 /* Initially set the characteristics to high density */
767 767 fdc->c_un->un_curfdtype = 1;
768 768 *fdc->c_un->un_chars = fdtypes[fdc->c_un->un_curfdtype];
769 769 fdunpacklabel(&fdlbl_high_80, &fdc->c_un->un_label);
770 770
771 771 /* Make sure drive is present */
772 772 if (fd_attach_check_drive(fdc) == DDI_FAILURE) {
773 773 fd_cleanup(dip, fdc, hard_intr_set, 1);
774 774 return (DDI_FAILURE);
775 775 }
776 776
777 777 for (dmdp = fd_minor; dmdp->name != NULL; dmdp++) {
778 778 if (ddi_create_minor_node(dip, dmdp->name, dmdp->type,
779 779 (instance << FDINSTSHIFT) | dmdp->minor,
780 780 DDI_NT_FD, 0) == DDI_FAILURE) {
781 781 fd_cleanup(dip, fdc, hard_intr_set, 1);
782 782 return (DDI_FAILURE);
783 783 }
784 784 }
785 785
786 786 create_pm_components(dip);
787 787
788 788 /*
789 789 * Add a zero-length attribute to tell the world we support
790 790 * kernel ioctls (for layered drivers)
791 791 */
792 792 (void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
793 793 DDI_KERNEL_IOCTL, NULL, 0);
794 794
795 795 ddi_report_dev(dip);
796 796
797 797 FDERRPRINT(FDEP_L1, FDEM_ATTA,
798 798 (C, "attached 0x%x\n", ddi_get_instance(dip)));
799 799
800 800 return (DDI_SUCCESS);
801 801 }
802 802
803 803 /*
804 804 * Finish mapping the registers and initializing structures
805 805 */
806 806 static int
807 807 fd_attach_map_regs(dev_info_t *dip, struct fdctlr *fdc)
808 808 {
809 809 ddi_device_acc_attr_t attr;
810 810
811 811 attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
812 812 attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
813 813 attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
814 814
815 815 /* Map the DMA registers of the platform supports DMA */
816 816 if (fdc->c_fdtype & FDCTYPE_SB) {
817 817 if (ddi_regs_map_setup(dip, 1, (caddr_t *)&fdc->c_dma_regs,
818 818 0, sizeof (struct sb_dma_reg), &attr,
819 819 &fdc->c_handlep_dma)) {
820 820 return (DDI_FAILURE);
821 821 }
822 822
823 823
824 824 } else if (fdc->c_fdtype & FDCTYPE_CHEERIO) {
825 825 if (ddi_regs_map_setup(dip, 1, (caddr_t *)&fdc->c_dma_regs,
826 826 0, sizeof (struct cheerio_dma_reg), &attr,
827 827 &fdc->c_handlep_dma)) {
828 828 return (DDI_FAILURE);
829 829 }
830 830 }
831 831
832 832 /* Reset the DMA engine and enable floppy interrupts */
833 833 reset_dma_controller(fdc);
834 834 set_dma_control_register(fdc, DCSR_INIT_BITS);
835 835
836 836 /* Finish initializing structures associated with the device regs */
837 837 switch (fdc->c_fdtype & FDCTYPE_CTRLMASK) {
838 838 case FDCTYPE_82077:
839 839 FDERRPRINT(FDEP_L1, FDEM_ATTA, (C, "type is 82077\n"));
840 840 /*
841 841 * Initialize addrs of key registers
842 842 */
843 843 fdc->c_control =
844 844 (uchar_t *)&fdc->c_reg->fdc_82077_reg.fdc_control;
845 845 fdc->c_fifo = (uchar_t *)&fdc->c_reg->fdc_82077_reg.fdc_fifo;
846 846 fdc->c_dor = (uchar_t *)&fdc->c_reg->fdc_82077_reg.fdc_dor;
847 847 fdc->c_dir = (uchar_t *)&fdc->c_reg->fdc_82077_reg.fdc_dir;
848 848
849 849
850 850 FDERRPRINT(FDEP_L1, FDEM_ATTA, ((int)C,
851 851 (char *)"fdattach: msr/dsr at %p\n",
852 852 (void *)fdc->c_control));
853 853
854 854 /*
855 855 * The 82077 doesn't use the first configuration parameter
856 856 * so let's adjust that while we know we're an 82077.
857 857 */
858 858 fdconf[0] = 0;
859 859
860 860 quiesce_fd_interrupt(fdc);
861 861 break;
862 862 default:
863 863 break;
864 864 }
865 865
866 866 return (0);
867 867 }
868 868
869 869 /*
870 870 * Determine which type of floppy controller is present and
871 871 * initialize the registers accordingly
872 872 */
873 873 static int
874 874 fd_attach_det_ctlr(dev_info_t *dip, struct fdctlr *fdc)
875 875 {
876 876 ddi_device_acc_attr_t attr;
877 877 attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
878 878 /* DDI_NEVERSWAP_ACC since the controller has a byte interface. */
879 879 attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
880 880 attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
881 881
882 882 FDERRPRINT(FDEP_L1, FDEM_ATTA,
883 883 (C, "fdattach_det_cltr: start \n"));
884 884
885 885 /*
886 886 * First, map in the controller's registers
887 887 * The controller has an 8-bit interface, so byte
888 888 * swapping isn't needed
889 889 */
890 890
891 891 if (ddi_regs_map_setup(dip, 0, (caddr_t *)&fdc->c_reg,
892 892 0, sizeof (union fdcreg),
893 893 &attr,
894 894 &fdc->c_handlep_cont)) {
895 895 return (DDI_FAILURE);
896 896 }
897 897
898 898 FDERRPRINT(FDEP_L1, FDEM_ATTA,
899 899 (C, "fdattach_det_cltr: mapped floppy regs\n"));
900 900
901 901
902 902 /*
903 903 * Set platform specific characteristics based on the device-tree
904 904 * node name.
905 905 */
906 906
907 907
908 908 if (strcmp(ddi_get_name(dip), "SUNW,fdtwo") == 0) {
909 909 fdc->c_fdtype |= FDCTYPE_SLAVIO;
910 910 fdc->c_fdtype |= FDCTYPE_82077;
911 911 fdc->c_auxiova = fd_getauxiova(dip);
912 912 fdc->c_auxiodata = (uchar_t)(AUX_MBO4M|AUX_TC4M);
913 913 fdc->c_auxiodata2 = (uchar_t)AUX_TC4M;
914 914 FDERRPRINT(FDEP_L1, FDEM_ATTA,
915 915 (C, "fdattach: slavio will be used!\n"));
916 916
917 917
918 918 /*
919 919 * Check the binding name to identify whether it is a South bridge based
920 920 * system or not.
921 921 */
922 922 } else if (strcmp(ddi_get_name(dip), "pnpALI,1533,0") == 0) {
923 923
924 924 fdc->c_fdtype |= FDCTYPE_SB;
925 925 fdc->c_fdtype |= FDCTYPE_82077;
926 926 fdc->c_fdtype |= FDCTYPE_DMA;
927 927
928 928 FDERRPRINT(FDEP_L1, FDEM_ATTA,
929 929 (C, "fdattach: southbridge will be used!\n"));
930 930
931 931 /*
932 932 * The driver assumes high density characteristics until
933 933 * the diskette is looked at.
934 934 */
935 935
936 936 fdc->c_fdtype |= FDCTYPE_DMA8237;
937 937 FDERRPRINT(FDEP_L1, FDEM_ATTA, (C, "fd_attach: DMA used\n"));
938 938
939 939
940 940 } else if (strcmp(ddi_get_name(dip), "fdthree") == 0) {
941 941
942 942 fdc->c_fdtype |= FDCTYPE_CHEERIO;
943 943 fdc->c_fdtype |= FDCTYPE_82077;
944 944
945 945 FDERRPRINT(FDEP_L1, FDEM_ATTA,
946 946 (C, "fdattach: cheerio will be used!\n"));
947 947 /*
948 948 * The cheerio auxio register should be memory mapped. The
949 949 * auxio register on other platforms is shared and mapped
950 950 * elsewhere in the kernel
951 951 */
952 952 if (ddi_regs_map_setup(dip, 2, (caddr_t *)&fdc->c_auxio_reg,
953 953 0, sizeof (uint_t), &attr, &fdc->c_handlep_aux)) {
954 954 return (DDI_FAILURE);
955 955 }
956 956
957 957 /*
958 958 * The driver assumes high density characteristics until
959 959 * the diskette is looked at.
960 960 */
961 961 Set_auxio(fdc, AUX_HIGH_DENSITY);
962 962 FDERRPRINT(FDEP_L1, FDEM_ATTA,
963 963 (C, "fdattach: auxio register 0x%x\n",
964 964 *fdc->c_auxio_reg));
965 965
966 966 fdc->c_fdtype |= FDCTYPE_DMA;
967 967 FDERRPRINT(FDEP_L1, FDEM_ATTA, (C, "fd_attach: DMA used\n"));
968 968
969 969 }
970 970
971 971 if (fdc->c_fdtype == 0) {
972 972 FDERRPRINT(FDEP_L1, FDEM_ATTA,
973 973 (C, "fdattach: no controller!\n"));
974 974 return (DDI_FAILURE);
975 975 } else {
976 976 return (0);
977 977 }
978 978 }
979 979
980 980
981 981 /*
982 982 * Register the floppy interrupts
983 983 */
984 984 static int
985 985 fd_attach_register_interrupts(dev_info_t *dip, struct fdctlr *fdc, int *hard)
986 986 {
987 987 ddi_iblock_cookie_t iblock_cookie_soft;
988 988 int status;
989 989
990 990 /*
991 991 * First call ddi_get_iblock_cookie() to retrieve the
992 992 * the interrupt block cookie so that the mutexes may
993 993 * be initialized before adding the interrupt. If the
994 994 * mutexes are initialized after adding the interrupt, there
995 995 * could be a race condition.
996 996 */
997 997 if (ddi_get_iblock_cookie(dip, 0, &fdc->c_block) != DDI_SUCCESS) {
998 998 FDERRPRINT(FDEP_L1, FDEM_ATTA,
999 999 (C, "fdattach: ddi_get_iblock_cookie failed\n"));
1000 1000 return (DDI_FAILURE);
1001 1001
1002 1002 }
1003 1003
1004 1004 /* Initialize high level mutex */
1005 1005 mutex_init(&fdc->c_hilock, NULL, MUTEX_DRIVER, fdc->c_block);
1006 1006
1007 1007 /*
1008 1008 * Try to register fast trap handler, if unable try standard
1009 1009 * interrupt handler, else bad
1010 1010 */
1011 1011
1012 1012 if (fdc->c_fdtype & FDCTYPE_DMA) {
1013 1013 if (ddi_add_intr(dip, 0, &fdc->c_block, 0,
1014 1014 fdintr_dma, (caddr_t)0) == DDI_SUCCESS) {
1015 1015 FDERRPRINT(FDEP_L1, FDEM_ATTA,
1016 1016 (C, "fdattach: standard intr\n"));
1017 1017
1018 1018 /*
1019 1019 * When DMA is used, the low level lock
1020 1020 * is used in the hard interrupt handler.
1021 1021 */
1022 1022 mutex_init(&fdc->c_lolock, NULL,
1023 1023 MUTEX_DRIVER, fdc->c_block);
1024 1024
1025 1025 *hard = 1;
1026 1026 } else {
1027 1027 FDERRPRINT(FDEP_L1, FDEM_ATTA,
1028 1028 (C, "fdattach: can't add dma intr\n"));
1029 1029
1030 1030 mutex_destroy(&fdc->c_hilock);
1031 1031
1032 1032 return (DDI_FAILURE);
1033 1033 }
1034 1034 } else {
1035 1035 /*
1036 1036 * Platforms that don't support DMA have both hard
1037 1037 * and soft interrupts.
1038 1038 */
1039 1039 if (ddi_add_intr(dip, 0, &fdc->c_block, 0,
1040 1040 fd_intr, (caddr_t)0) == DDI_SUCCESS) {
1041 1041 FDERRPRINT(FDEP_L1, FDEM_ATTA,
1042 1042 (C, "fdattach: standard intr\n"));
1043 1043 *hard = 1;
1044 1044
1045 1045 /* fast traps are not enabled */
1046 1046 fdc->c_fasttrap = 0;
1047 1047
1048 1048 } else {
1049 1049 FDERRPRINT(FDEP_L1, FDEM_ATTA,
1050 1050 (C, "fdattach: can't add intr\n"));
1051 1051
1052 1052 mutex_destroy(&fdc->c_hilock);
1053 1053
1054 1054 return (DDI_FAILURE);
1055 1055 }
1056 1056
1057 1057
1058 1058 /*
1059 1059 * Initialize the soft interrupt handler. First call
1060 1060 * ddi_get_soft_iblock_cookie() so that the mutex may
1061 1061 * be initialized before the handler is added.
1062 1062 */
1063 1063 status = ddi_get_soft_iblock_cookie(dip, DDI_SOFTINT_LOW,
1064 1064 &iblock_cookie_soft);
1065 1065
1066 1066
1067 1067 if (status != DDI_SUCCESS) {
1068 1068 mutex_destroy(&fdc->c_hilock);
1069 1069 return (DDI_FAILURE);
1070 1070 }
1071 1071
1072 1072 /*
1073 1073 * Initialize low level mutex which is used in the soft
1074 1074 * interrupt handler
1075 1075 */
1076 1076 mutex_init(&fdc->c_lolock, NULL, MUTEX_DRIVER,
1077 1077 iblock_cookie_soft);
1078 1078
1079 1079 if (ddi_add_softintr(dip, DDI_SOFTINT_LOW, &fdc->c_softid,
1080 1080 NULL, NULL,
1081 1081 fd_lointr,
1082 1082 (caddr_t)fdc) != DDI_SUCCESS) {
1083 1083
1084 1084 mutex_destroy(&fdc->c_hilock);
1085 1085 mutex_destroy(&fdc->c_lolock);
1086 1086
1087 1087 return (DDI_FAILURE);
1088 1088 }
1089 1089 }
1090 1090
1091 1091 fdc->c_intrstat = kstat_create("fd", 0, "fdc0", "controller",
1092 1092 KSTAT_TYPE_INTR, 1, KSTAT_FLAG_PERSISTENT);
1093 1093 if (fdc->c_intrstat) {
1094 1094 fdc->c_hiintct = &KIOIP->intrs[KSTAT_INTR_HARD];
1095 1095 kstat_install(fdc->c_intrstat);
1096 1096 }
1097 1097
1098 1098 /* condition variable to wait on while an io transaction occurs */
1099 1099 cv_init(&fdc->c_iocv, NULL, CV_DRIVER, NULL);
1100 1100
1101 1101 /* condition variable for the csb */
1102 1102 cv_init(&fdc->c_csbcv, NULL, CV_DRIVER, NULL);
1103 1103
1104 1104 /* condition variable for motor on waiting period */
1105 1105 cv_init(&fdc->c_motoncv, NULL, CV_DRIVER, NULL);
1106 1106
1107 1107 /* semaphore to serialize opens and closes */
1108 1108 sema_init(&fdc->c_ocsem, 1, NULL, SEMA_DRIVER, NULL);
1109 1109
1110 1110 /* condition variable to wait on suspended floppy controller. */
1111 1111 cv_init(&fdc->c_suspend_cv, NULL, CV_DRIVER, NULL);
1112 1112
1113 1113 return (0);
1114 1114 }
1115 1115
1116 1116 /*
1117 1117 * Make sure the drive is present
1118 1118 * - acquires the low level lock
1119 1119 */
1120 1120 static int
1121 1121 fd_attach_check_drive(struct fdctlr *fdc)
1122 1122 {
1123 1123 int tmp_fderrlevel;
1124 1124 int unit = fdc->c_un->un_unit_no;
1125 1125
1126 1126 FDERRPRINT(FDEP_L1, FDEM_ATTA,
1127 1127 (C, "fd_attach_check_drive\n"));
1128 1128
1129 1129
1130 1130 mutex_enter(&fdc->c_lolock);
1131 1131 switch (fdc->c_fdtype & FDCTYPE_CTRLMASK) {
1132 1132
1133 1133 /* insure that the eject line is reset */
1134 1134 case FDCTYPE_82077:
1135 1135
1136 1136 /*
1137 1137 * Everything but the motor enable, drive select,
1138 1138 * and reset bits are turned off. These three
1139 1139 * bits remain as they are.
1140 1140 */
1141 1141 /* LINTED */
1142 1142 Set_dor(fdc, ~((MOTEN(unit))|DRVSEL|RESET), 0);
1143 1143
1144 1144 FDERRPRINT(FDEP_L1, FDEM_ATTA,
1145 1145 (C, "fdattach: Dor 0x%x\n", Dor(fdc)));
1146 1146
1147 1147 drv_usecwait(5);
1148 1148 if (unit == 0) {
1149 1149 /* LINTED */
1150 1150 Set_dor(fdc, RESET|DRVSEL, 1);
1151 1151 } else {
1152 1152
1153 1153 /* LINTED */
1154 1154 Set_dor(fdc, DRVSEL, 0);
1155 1155 /* LINTED */
1156 1156 Set_dor(fdc, RESET, 1);
1157 1157 }
1158 1158
1159 1159 drv_usecwait(5);
1160 1160
1161 1161 FDERRPRINT(FDEP_L1, FDEM_ATTA,
1162 1162 (C, "fdattach: Dor 0x%x\n", Dor(fdc)));
1163 1163
1164 1164 if (!((fdc->c_fdtype & FDCTYPE_CHEERIO) ||
1165 1165 (fdc->c_fdtype & FDCTYPE_SB))) {
1166 1166 set_auxioreg(AUX_TC4M, 0);
1167 1167 }
1168 1168 break;
1169 1169 default:
1170 1170 break;
1171 1171 }
1172 1172
1173 1173
1174 1174 fdgetcsb(fdc);
1175 1175 if (fdreset(fdc) != 0) {
1176 1176 mutex_exit(&fdc->c_lolock);
1177 1177 return (DDI_FAILURE);
1178 1178 }
1179 1179
1180 1180
1181 1181 /* check for drive present */
1182 1182
1183 1183 tmp_fderrlevel = fderrlevel;
1184 1184
1185 1185
1186 1186 fderrlevel = FDEP_LMAX;
1187 1187
1188 1188 FDERRPRINT(FDEP_L1, FDEM_ATTA,
1189 1189 (C, "fdattach: call fdrecalseek\n"));
1190 1190
1191 1191 /* Make sure the drive is present */
1192 1192 if (fdrecalseek(fdc, unit, -1, 0) != 0) {
1193 1193 timeout_id_t timeid = fdc->c_mtimeid;
1194 1194 fderrlevel = tmp_fderrlevel;
1195 1195 fdc->c_mtimeid = 0;
1196 1196 mutex_exit(&fdc->c_lolock);
1197 1197
1198 1198
1199 1199 /* Do not hold the mutex over the call to untimeout */
1200 1200 if (timeid) {
1201 1201 (void) untimeout(timeid);
1202 1202 }
1203 1203
1204 1204 FDERRPRINT(FDEP_L2, FDEM_ATTA,
1205 1205 (C, "fd_attach: no drive?\n"));
1206 1206
1207 1207 return (DDI_FAILURE);
1208 1208 }
1209 1209
1210 1210 fderrlevel = tmp_fderrlevel;
1211 1211
1212 1212 fdselect(fdc, unit, 0); /* deselect drive zero (used in fdreset) */
1213 1213 fdretcsb(fdc);
1214 1214 mutex_exit(&fdc->c_lolock);
1215 1215
1216 1216 return (0);
1217 1217 }
1218 1218
1219 1219 /*
1220 1220 * Clean up routine used by fd_detach and fd_attach
1221 1221 *
1222 1222 * Note: if the soft id is non-zero, then ddi_add_softintr() completed
1223 1223 * successfully. I can not make the same assumption about the iblock_cookie
1224 1224 * for the high level interrupt handler. So, the hard parameter indicates
1225 1225 * whether or not a high level interrupt handler has been added.
1226 1226 *
1227 1227 * If the locks parameter is nonzero, then all mutexes, semaphores and
1228 1228 * condition variables will be destroyed.
1229 1229 *
1230 1230 * Does not assume the low level mutex is held.
1231 1231 *
1232 1232 */
1233 1233 static void
1234 1234 fd_cleanup(dev_info_t *dip, struct fdctlr *fdc, int hard, int locks)
1235 1235 {
1236 1236
1237 1237
1238 1238 FDERRPRINT(FDEP_L1, FDEM_ATTA,
1239 1239 (C, "fd_cleanup instance: %d ctlr: 0x%p\n",
1240 1240 ddi_get_instance(dip), (void *)fdc));
1241 1241
1242 1242
1243 1243 if (fdc == NULL) {
1244 1244 return;
1245 1245 }
1246 1246
1247 1247 /*
1248 1248 * Remove interrupt handlers first before anything else
1249 1249 * is deallocated.
1250 1250 */
1251 1251
1252 1252 /* Remove hard interrupt if one is registered */
1253 1253 if (hard) {
1254 1254 ddi_remove_intr(dip, (uint_t)0, fdc->c_block);
1255 1255 }
1256 1256
1257 1257 /* Remove soft interrupt if one is registered */
1258 1258 if (fdc->c_softid != NULL)
1259 1259 ddi_remove_softintr(fdc->c_softid);
1260 1260
1261 1261
1262 1262 /* Remove timers */
1263 1263 if (fdc->c_fdtype & FDCTYPE_82077) {
1264 1264 if (fdc->c_mtimeid)
1265 1265 (void) untimeout(fdc->c_mtimeid);
1266 1266 /*
1267 1267 * Need to turn off motor (includes select/LED for South Bridge
1268 1268 * chipset) just in case it was on when timer was removed
1269 1269 */
1270 1270 fdmotoff(fdc);
1271 1271 }
1272 1272 if (fdc->c_timeid)
1273 1273 (void) untimeout(fdc->c_timeid);
1274 1274
1275 1275
1276 1276 /* Remove memory handles */
1277 1277 if (fdc->c_handlep_cont)
1278 1278 ddi_regs_map_free(&fdc->c_handlep_cont);
1279 1279
1280 1280 if (fdc->c_handlep_aux)
1281 1281 ddi_regs_map_free(&fdc->c_handlep_aux);
1282 1282
1283 1283 if (fdc->c_handlep_dma)
1284 1284 ddi_regs_map_free(&fdc->c_handlep_dma);
1285 1285
1286 1286 if (fdc->c_dma_buf_handle != NULL)
1287 1287 ddi_dma_mem_free(&fdc->c_dma_buf_handle);
1288 1288
1289 1289 if (fdc->c_dmahandle != NULL)
1290 1290 ddi_dma_free_handle(&fdc->c_dmahandle);
1291 1291
1292 1292
1293 1293 /* Remove all minor nodes */
1294 1294 ddi_remove_minor_node(dip, NULL);
1295 1295
1296 1296
1297 1297
1298 1298 /* Remove unit structure if one exists */
1299 1299 if (fdc->c_un != (struct fdunit *)NULL) {
1300 1300
1301 1301 ASSERT(!mutex_owned(&fdc->c_lolock));
1302 1302
1303 1303 if (fdc->c_un->un_iostat)
1304 1304 kstat_delete(fdc->c_un->un_iostat);
1305 1305 fdc->c_un->un_iostat = NULL;
1306 1306
1307 1307 if (fdc->c_un->un_chars)
1308 1308 kmem_free(fdc->c_un->un_chars, sizeof (struct fd_char));
1309 1309
1310 1310 if (fdc->c_un->un_drive)
1311 1311 kmem_free(fdc->c_un->un_drive,
1312 1312 sizeof (struct fd_drive));
1313 1313
1314 1314 kmem_free((caddr_t)fdc->c_un, sizeof (struct fdunit));
1315 1315 }
1316 1316
1317 1317 if (fdc->c_intrstat) {
1318 1318 FDERRPRINT(FDEP_L1, FDEM_ATTA,
1319 1319 (C, "fd_cleanup: delete intrstat\n"));
1320 1320
1321 1321 kstat_delete(fdc->c_intrstat);
1322 1322 }
1323 1323
1324 1324 fdc->c_intrstat = NULL;
1325 1325
1326 1326 if (locks) {
1327 1327 cv_destroy(&fdc->c_iocv);
1328 1328 cv_destroy(&fdc->c_csbcv);
1329 1329 cv_destroy(&fdc->c_motoncv);
1330 1330 cv_destroy(&fdc->c_suspend_cv);
1331 1331 sema_destroy(&fdc->c_ocsem);
1332 1332 mutex_destroy(&fdc->c_hilock);
1333 1333 mutex_destroy(&fdc->c_lolock);
1334 1334 }
1335 1335
1336 1336
1337 1337 fdctlrs = fdc->c_next;
1338 1338 kmem_free(fdc, sizeof (*fdc));
1339 1339
1340 1340
1341 1341 }
1342 1342
1343 1343
1344 1344 static int
1345 1345 fd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
1346 1346 {
1347 1347 int instance = ddi_get_instance(dip);
1348 1348 struct fdctlr *fdc = fd_getctlr(instance << FDINSTSHIFT);
1349 1349 timeout_id_t c_mtimeid;
1350 1350
1351 1351 FDERRPRINT(FDEP_L1, FDEM_ATTA, (C, "fd_detach\n"));
1352 1352
1353 1353 switch (cmd) {
1354 1354
1355 1355 case DDI_DETACH:
1356 1356 /*
1357 1357 * The hard parameter is set to 1. If detach is called, then
1358 1358 * attach must have passed meaning that the high level
1359 1359 * interrupt handler was successfully added.
1360 1360 * Similarly, the locks parameter is also set to 1.
1361 1361 */
1362 1362 fd_cleanup(dip, fdc, 1, 1);
1363 1363
1364 1364 ddi_prop_remove_all(dip);
1365 1365
1366 1366 return (DDI_SUCCESS);
1367 1367
1368 1368 case DDI_SUSPEND:
1369 1369 if (!fdc)
1370 1370 return (DDI_FAILURE);
1371 1371
1372 1372
1373 1373 mutex_enter(&fdc->c_lolock);
1374 1374 fdgetcsb(fdc); /* Wait for I/O to finish */
1375 1375 c_mtimeid = fdc->c_mtimeid;
1376 1376 fdretcsb(fdc);
1377 1377 mutex_exit(&fdc->c_lolock);
1378 1378
1379 1379 (void) untimeout(c_mtimeid);
1380 1380 /*
1381 1381 * After suspend, the system could be powered off.
1382 1382 * When it is later powered on the southbridge floppy
1383 1383 * controller will tristate the interrupt line causing
1384 1384 * continuous dma interrupts.
1385 1385 * To avoid getting continuous fd interrupts we will remove the
1386 1386 * dma interrupt handler installed. We will re-install the
1387 1387 * handler when we RESUME.
1388 1388 */
1389 1389 if (fdc->c_fdtype & FDCTYPE_SB)
1390 1390 ddi_remove_intr(dip, 0, fdc->c_block);
1391 1391
1392 1392 fdc->c_un->un_state = FD_STATE_SUSPENDED;
1393 1393
1394 1394 return (DDI_SUCCESS);
1395 1395
1396 1396 default:
1397 1397 return (DDI_FAILURE);
1398 1398 }
1399 1399 }
1400 1400
1401 1401 /* ARGSUSED */
1402 1402 static int
1403 1403 fd_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
1404 1404 {
1405 1405 register struct fdctlr *fdc;
1406 1406 register int error;
1407 1407
1408 1408 switch (infocmd) {
1409 1409
1410 1410 case DDI_INFO_DEVT2DEVINFO:
1411 1411 if ((fdc = fd_getctlr((dev_t)arg)) == NULL) {
1412 1412 error = DDI_FAILURE;
1413 1413 } else {
1414 1414 *result = fdc->c_dip;
1415 1415 error = DDI_SUCCESS;
1416 1416 }
1417 1417 break;
1418 1418
1419 1419 case DDI_INFO_DEVT2INSTANCE:
1420 1420 *result = 0;
1421 1421 error = DDI_SUCCESS;
1422 1422 break;
1423 1423
1424 1424 default:
1425 1425 error = DDI_FAILURE;
1426 1426 }
1427 1427 return (error);
1428 1428 }
1429 1429
1430 1430 /*
1431 1431 * property operation routine. return the number of blocks for the partition
1432 1432 * in question or forward the request to the property facilities.
1433 1433 */
1434 1434 static int
1435 1435 fd_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags,
1436 1436 char *name, caddr_t valuep, int *lengthp)
1437 1437 {
1438 1438 struct fdunit *un;
1439 1439 struct fdctlr *fdc;
1440 1440 uint64_t nblocks64;
1441 1441
1442 1442 /*
1443 1443 * Our dynamic properties are all device specific and size oriented.
1444 1444 * Requests issued under conditions where size is valid are passed
1445 1445 * to ddi_prop_op_nblocks with the size information, otherwise the
1446 1446 * request is passed to ddi_prop_op.
1447 1447 */
1448 1448 if (dev == DDI_DEV_T_ANY) {
1449 1449 pass: return (ddi_prop_op(dev, dip, prop_op, mod_flags,
1450 1450 name, valuep, lengthp));
1451 1451 } else {
1452 1452 fdc = fd_getctlr(dev);
1453 1453 if (fdc == NULL)
1454 1454 goto pass;
1455 1455
1456 1456 /* we have size if diskette opened and label read */
1457 1457 un = fdc->c_un;
1458 1458 if ((un == NULL) || !fd_unit_is_open(fdc->c_un))
1459 1459 goto pass;
1460 1460
1461 1461 /* get nblocks value */
1462 1462 nblocks64 = (ulong_t)
1463 1463 un->un_label.dkl_map[FDPARTITION(dev)].dkl_nblk;
1464 1464
1465 1465 return (ddi_prop_op_nblocks(dev, dip, prop_op, mod_flags,
1466 1466 name, valuep, lengthp, nblocks64));
1467 1467 }
1468 1468 }
1469 1469
1470 1470 /* ARGSUSED3 */
1471 1471 static int
1472 1472 fd_open(dev_t *devp, int flag, int otyp, cred_t *cred_p)
1473 1473 {
1474 1474 dev_t dev;
1475 1475 int part;
1476 1476 struct fdctlr *fdc;
1477 1477 struct fdunit *un;
1478 1478 struct dk_map32 *dkm;
1479 1479 uchar_t pbit;
1480 1480 int err, part_is_open;
1481 1481 int unit;
1482 1482
1483 1483 dev = *devp;
1484 1484 fdc = fd_getctlr(dev);
1485 1485 if ((fdc == NULL) || ((un = fdc->c_un) == NULL)) {
1486 1486 return (ENXIO);
1487 1487 }
1488 1488
1489 1489 unit = fdc->c_un->un_unit_no;
1490 1490
1491 1491 /*
1492 1492 * Serialize opens/closes
1493 1493 */
1494 1494
1495 1495 sema_p(&fdc->c_ocsem);
1496 1496
1497 1497 /* check partition */
1498 1498 part = FDPARTITION(dev);
1499 1499 pbit = 1 << part;
1500 1500 dkm = &un->un_label.dkl_map[part];
1501 1501 if (dkm->dkl_nblk == 0) {
1502 1502 sema_v(&fdc->c_ocsem);
1503 1503 return (ENXIO);
1504 1504 }
1505 1505
1506 1506 FDERRPRINT(FDEP_L1, FDEM_OPEN,
1507 1507 (C, "fdopen: ctlr %d unit %d part %d\n",
1508 1508 ddi_get_instance(fdc->c_dip), unit, part));
1509 1509
1510 1510 FDERRPRINT(FDEP_L1, FDEM_OPEN,
1511 1511 (C, "fdopen: flag 0x%x", flag));
1512 1512
1513 1513
1514 1514 /*
1515 1515 * Insure that drive is present with a recalibrate on first open.
1516 1516 */
1517 1517 (void) pm_busy_component(fdc->c_dip, 0);
1518 1518
1519 1519 mutex_enter(&fdc->c_lolock);
1520 1520
1521 1521 CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc);
1522 1522
1523 1523 if (fdc->c_un->un_state == FD_STATE_STOPPED) {
1524 1524 mutex_exit(&fdc->c_lolock);
1525 1525 if ((pm_raise_power(fdc->c_dip, 0, PM_LEVEL_ON))
1526 1526 != DDI_SUCCESS) {
1527 1527 FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "Power change \
1528 1528 failed. \n"));
1529 1529
1530 1530 sema_v(&fdc->c_ocsem);
1531 1531 (void) pm_idle_component(fdc->c_dip, 0);
1532 1532 return (EIO);
1533 1533 }
1534 1534 mutex_enter(&fdc->c_lolock);
1535 1535 }
1536 1536 if (fd_unit_is_open(un) == 0) {
1537 1537 fdgetcsb(fdc);
1538 1538 /*
1539 1539 * no check changed!
1540 1540 */
1541 1541 err = fdrecalseek(fdc, unit, -1, 0);
1542 1542 fdretcsb(fdc);
1543 1543 if (err) {
1544 1544 FDERRPRINT(FDEP_L3, FDEM_OPEN,
1545 1545 (C, "fd%d: drive not ready\n", 0));
1546 1546 /* deselect drv on last close */
1547 1547 fdselect(fdc, unit, 0);
1548 1548 mutex_exit(&fdc->c_lolock);
1549 1549 sema_v(&fdc->c_ocsem);
1550 1550 (void) pm_idle_component(fdc->c_dip, 0);
1551 1551 return (EIO);
1552 1552 }
1553 1553 }
1554 1554
1555 1555 /*
1556 1556 * Check for previous exclusive open, or trying to exclusive open
1557 1557 */
1558 1558 if (otyp == OTYP_LYR) {
1559 1559 part_is_open = (un->un_lyropen[part] != 0);
1560 1560 } else {
1561 1561 part_is_open = fd_part_is_open(un, part);
1562 1562 }
1563 1563 if ((un->un_exclmask & pbit) || ((flag & FEXCL) && part_is_open)) {
1564 1564 mutex_exit(&fdc->c_lolock);
1565 1565 sema_v(&fdc->c_ocsem);
1566 1566 FDERRPRINT(FDEP_L2, FDEM_OPEN, (C, "fd:just return\n"));
1567 1567 (void) pm_idle_component(fdc->c_dip, 0);
1568 1568 return (EBUSY);
1569 1569 }
1570 1570
1571 1571 /* don't attempt access, just return successfully */
1572 1572 if (flag & (FNDELAY | FNONBLOCK)) {
1573 1573 FDERRPRINT(FDEP_L2, FDEM_OPEN,
1574 1574 (C, "fd: return busy..\n"));
1575 1575 goto out;
1576 1576 }
1577 1577
1578 1578 fdc->c_csb.csb_unit = (uchar_t)unit;
1579 1579 if (fdgetlabel(fdc, unit)) {
1580 1580 /* didn't find label (couldn't read anything) */
1581 1581 FDERRPRINT(FDEP_L3, FDEM_OPEN,
1582 1582 (C,
1583 1583 "fd%d: unformatted diskette or no diskette in the drive\n",
1584 1584 0));
1585 1585 if (fd_unit_is_open(un) == 0) {
1586 1586 /* deselect drv on last close */
1587 1587 fdselect(fdc, unit, 0);
1588 1588 }
1589 1589
1590 1590 mutex_exit(&fdc->c_lolock);
1591 1591 sema_v(&fdc->c_ocsem);
1592 1592 (void) pm_idle_component(fdc->c_dip, 0);
1593 1593 return (EIO);
1594 1594 }
1595 1595
1596 1596 /*
1597 1597 * if opening for writing, check write protect on diskette
1598 1598 */
1599 1599 if (flag & FWRITE) {
1600 1600 fdgetcsb(fdc);
1601 1601 err = fdsensedrv(fdc, unit) & WP_SR3;
1602 1602 fdretcsb(fdc);
1603 1603 if (err) {
1604 1604 if (fd_unit_is_open(un) == 0)
1605 1605 fdselect(fdc, unit, 0);
1606 1606 mutex_exit(&fdc->c_lolock);
1607 1607 sema_v(&fdc->c_ocsem);
1608 1608 (void) pm_idle_component(fdc->c_dip, 0);
1609 1609 return (EROFS);
1610 1610 }
1611 1611 }
1612 1612
1613 1613 out:
1614 1614 /*
1615 1615 * mark open as having succeeded
1616 1616 */
1617 1617 if (flag & FEXCL) {
1618 1618 un->un_exclmask |= pbit;
1619 1619 }
1620 1620 if (otyp == OTYP_LYR) {
1621 1621 un->un_lyropen[part]++;
1622 1622 } else {
1623 1623 un->un_regopen[otyp] |= pbit;
1624 1624 }
1625 1625 mutex_exit(&fdc->c_lolock);
1626 1626 sema_v(&fdc->c_ocsem);
1627 1627 (void) pm_idle_component(fdc->c_dip, 0);
1628 1628 return (0);
1629 1629 }
1630 1630 /*
1631 1631 * fd_part_is_open
1632 1632 * return 1 if the partition is open
1633 1633 * return 0 otherwise
1634 1634 */
1635 1635 static int
1636 1636 fd_part_is_open(struct fdunit *un, int part)
1637 1637 {
1638 1638 int i;
1639 1639 for (i = 0; i < OTYPCNT - 1; i++)
1640 1640 if (un->un_regopen[i] & (1 << part))
1641 1641 return (1);
1642 1642 return (0);
1643 1643 }
1644 1644
1645 1645
1646 1646 /* ARGSUSED */
1647 1647 static int
1648 1648 fd_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
1649 1649 {
1650 1650 int unit, part_is_closed, part;
1651 1651 register struct fdctlr *fdc;
1652 1652 register struct fdunit *un;
1653 1653
1654 1654 fdc = fd_getctlr(dev);
1655 1655 if (!fdc || !(un = fdc->c_un))
1656 1656 return (ENXIO);
1657 1657
1658 1658
1659 1659 unit = fdc->c_un->un_unit_no;
1660 1660 FDERRPRINT(FDEP_L1, FDEM_CLOS, (C, "fd_close\n"));
1661 1661 part = FDPARTITION(dev);
1662 1662
1663 1663 sema_p(&fdc->c_ocsem);
1664 1664 mutex_enter(&fdc->c_lolock);
1665 1665
1666 1666 if (otyp == OTYP_LYR) {
1667 1667 un->un_lyropen[part]--;
1668 1668 part_is_closed = (un->un_lyropen[part] == 0);
1669 1669 } else {
1670 1670 un->un_regopen[otyp] &= ~(1<<part);
1671 1671 part_is_closed = 1;
1672 1672 }
1673 1673 if (part_is_closed)
1674 1674 un->un_exclmask &= ~(1<<part);
1675 1675
1676 1676 if (fd_unit_is_open(un) == 0) {
1677 1677 /* deselect drive on last close */
1678 1678 fdselect(fdc, unit, 0);
1679 1679 un->un_flags &= ~FDUNIT_CHANGED;
1680 1680 }
1681 1681 mutex_exit(&fdc->c_lolock);
1682 1682 sema_v(&fdc->c_ocsem);
1683 1683
1684 1684 return (0);
1685 1685 }
1686 1686
1687 1687 /*
1688 1688 * fd_strategy
1689 1689 * checks operation, hangs buf struct off fdctlr, calls fdstart
1690 1690 * if not already busy. Note that if we call start, then the operation
1691 1691 * will already be done on return (start sleeps).
1692 1692 */
1693 1693 static int
1694 1694 fd_strategy(register struct buf *bp)
1695 1695 {
1696 1696 struct fdctlr *fdc;
1697 1697 struct fdunit *un;
1698 1698 uint_t phys_blkno;
1699 1699 struct dk_map32 *dkm;
1700 1700
1701 1701 FDERRPRINT(FDEP_L1, FDEM_STRA,
1702 1702 (C, "fd_strategy: bp = 0x%p, dev = 0x%lx\n",
1703 1703 (void *)bp, bp->b_edev));
1704 1704 FDERRPRINT(FDEP_L1, FDEM_STRA,
1705 1705 (C, "b_blkno=%x b_flags=%x b_count=%x\n",
1706 1706 (int)bp->b_blkno, bp->b_flags, (int)bp->b_bcount));
1707 1707 fdc = fd_getctlr(bp->b_edev);
1708 1708 un = fdc->c_un;
1709 1709 dkm = &un->un_label.dkl_map[FDPARTITION(bp->b_edev)];
1710 1710
1711 1711 /*
1712 1712 * If it's medium density and the block no. isn't a multiple
1713 1713 * of 1K, then return an error.
1714 1714 */
1715 1715 if (un->un_chars->fdc_medium) {
1716 1716 phys_blkno = (uint_t)bp->b_blkno >> 1;
1717 1717 if (bp->b_blkno & 1) {
1718 1718 FDERRPRINT(FDEP_L3, FDEM_STRA,
1719 1719 (C, "b_blkno=0x%lx is not 1k aligned\n",
1720 1720 (long)bp->b_blkno));
1721 1721 bp->b_error = EINVAL;
1722 1722 bp->b_resid = bp->b_bcount;
1723 1723 bp->b_flags |= B_ERROR;
1724 1724 biodone(bp);
1725 1725 return (0);
1726 1726 }
1727 1727 } else {
1728 1728 phys_blkno = (uint_t)bp->b_blkno;
1729 1729 }
1730 1730
1731 1731
1732 1732 /* If the block number is past the end, return an error */
1733 1733 if ((phys_blkno > dkm->dkl_nblk)) {
1734 1734 FDERRPRINT(FDEP_L3, FDEM_STRA,
1735 1735 (C, "fd%d: block %ld is past the end! (nblk=%d)\n",
1736 1736 0, (long)bp->b_blkno, dkm->dkl_nblk));
1737 1737 bp->b_error = ENOSPC;
1738 1738 bp->b_resid = bp->b_bcount;
1739 1739 bp->b_flags |= B_ERROR;
1740 1740 biodone(bp);
1741 1741 return (0);
1742 1742 }
1743 1743
1744 1744 /* if at end of file, skip out now */
1745 1745 if (phys_blkno == dkm->dkl_nblk) {
1746 1746 FDERRPRINT(FDEP_L1, FDEM_STRA,
1747 1747 (C, "b_blkno is at the end!\n"));
1748 1748
1749 1749 if ((bp->b_flags & B_READ) == 0) {
1750 1750 /* a write needs to get an error! */
1751 1751 bp->b_error = ENOSPC;
1752 1752 bp->b_flags |= B_ERROR;
1753 1753
1754 1754 FDERRPRINT(FDEP_L1, FDEM_STRA,
1755 1755 (C, "block is at end and this is a write\n"));
1756 1756
1757 1757 }
1758 1758
1759 1759 bp->b_resid = bp->b_bcount;
1760 1760 biodone(bp);
1761 1761 return (0);
1762 1762 }
1763 1763
1764 1764 /* if operation not a multiple of sector size, is error! */
1765 1765 if (bp->b_bcount % un->un_chars->fdc_sec_size) {
1766 1766 FDERRPRINT(FDEP_L3, FDEM_STRA,
1767 1767 (C, "fd%d: requested transfer size(0x%lx) is not"
1768 1768 " multiple of sector size(0x%x)\n", 0,
1769 1769 bp->b_bcount, un->un_chars->fdc_sec_size));
1770 1770 FDERRPRINT(FDEP_L3, FDEM_STRA,
1771 1771 (C, " b_blkno=0x%lx b_flags=0x%x\n",
1772 1772 (long)bp->b_blkno, bp->b_flags));
1773 1773 bp->b_error = EINVAL;
1774 1774 bp->b_resid = bp->b_bcount;
1775 1775 bp->b_flags |= B_ERROR;
1776 1776 biodone(bp);
1777 1777 return (0);
1778 1778
1779 1779 }
1780 1780
1781 1781 /*
1782 1782 * Put the buf request in the controller's queue, FIFO.
1783 1783 */
1784 1784 bp->av_forw = 0;
1785 1785 sema_p(&fdc->c_ocsem);
1786 1786
1787 1787 (void) pm_busy_component(fdc->c_dip, 0);
1788 1788
1789 1789 mutex_enter(&fdc->c_lolock);
1790 1790
1791 1791 CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc);
1792 1792
1793 1793 if (fdc->c_un->un_state == FD_STATE_STOPPED) {
1794 1794 mutex_exit(&fdc->c_lolock);
1795 1795 if ((pm_raise_power(fdc->c_dip, 0, PM_LEVEL_ON))
1796 1796 != DDI_SUCCESS) {
1797 1797 sema_v(&fdc->c_ocsem);
1798 1798 (void) pm_idle_component(fdc->c_dip, 0);
1799 1799 bp->b_error = EIO;
1800 1800 bp->b_resid = bp->b_bcount;
1801 1801 bp->b_flags |= B_ERROR;
1802 1802 biodone(bp);
1803 1803 return (0);
1804 1804 } else {
1805 1805 mutex_enter(&fdc->c_lolock);
1806 1806 }
1807 1807 }
1808 1808 if (un->un_iostat) {
1809 1809 kstat_waitq_enter(KIOSP);
1810 1810 }
1811 1811 if (fdc->c_actf)
1812 1812 fdc->c_actl->av_forw = bp;
1813 1813 else
1814 1814 fdc->c_actf = bp;
1815 1815 fdc->c_actl = bp;
1816 1816
1817 1817
1818 1818 /* call fdstart to start the transfer */
1819 1819 fdstart(fdc);
1820 1820
1821 1821 mutex_exit(&fdc->c_lolock);
1822 1822 sema_v(&fdc->c_ocsem);
1823 1823 (void) pm_idle_component(fdc->c_dip, 0);
1824 1824 return (0);
1825 1825 }
1826 1826
1827 1827 /* ARGSUSED2 */
1828 1828 static int
1829 1829 fd_read(dev_t dev, struct uio *uio, cred_t *cred_p)
1830 1830 {
1831 1831 FDERRPRINT(FDEP_L1, FDEM_RDWR, (C, "fd_read\n"));
1832 1832 return (physio(fd_strategy, NULL, dev, B_READ, minphys, uio));
1833 1833 }
1834 1834
1835 1835 /* ARGSUSED2 */
1836 1836 static int
1837 1837 fd_write(dev_t dev, struct uio *uio, cred_t *cred_p)
1838 1838 {
1839 1839 FDERRPRINT(FDEP_L1, FDEM_RDWR, (C, "fd_write\n"));
1840 1840 return (physio(fd_strategy, NULL, dev, B_WRITE, minphys, uio));
1841 1841 }
1842 1842
1843 1843 static void
1844 1844 fdmotoff(void *arg)
1845 1845 {
1846 1846 struct fdctlr *fdc = arg;
1847 1847 int unit = fdc->c_un->un_unit_no;
1848 1848
1849 1849 mutex_enter(&fdc->c_lolock);
1850 1850
1851 1851 /* Just return if we're about to call untimeout */
1852 1852 if (fdc->c_mtimeid == 0) {
1853 1853 mutex_exit(&fdc->c_lolock);
1854 1854 return;
1855 1855 }
1856 1856
1857 1857 FDERRPRINT(FDEP_L1, FDEM_MOFF, (C, "fdmotoff\n"));
1858 1858
1859 1859 fdc->c_mtimeid = 0;
1860 1860
1861 1861 if (!(Msr(fdc) & CB) && (Dor(fdc) & (MOTEN(unit)))) {
1862 1862 /* LINTED */
1863 1863 Set_dor(fdc, MOTEN(unit), 0);
1864 1864 }
1865 1865
1866 1866 mutex_exit(&fdc->c_lolock);
1867 1867 }
1868 1868
1869 1869 /* ARGSUSED */
1870 1870 static int
1871 1871 fd_ioctl(dev_t dev, int cmd, intptr_t arg, int flag,
1872 1872 cred_t *cred_p, int *rval_p)
1873 1873 {
1874 1874 union {
1875 1875 struct dk_cinfo dki;
1876 1876 struct dk_geom dkg;
1877 1877 struct dk_allmap32 dka;
1878 1878 struct fd_char fdchar;
1879 1879 struct fd_drive drvchar;
1880 1880 int temp;
1881 1881 } cpy;
1882 1882
1883 1883 struct vtoc vtoc;
1884 1884 struct fdunit *un;
1885 1885 struct fdctlr *fdc;
1886 1886 int unit, dkunit;
1887 1887 int err = 0;
1888 1888 uint_t sec_size;
1889 1889 enum dkio_state state;
1890 1890 int transfer_rate;
1891 1891
1892 1892 FDERRPRINT(FDEP_L1, FDEM_IOCT,
1893 1893 (C, "fd_ioctl: cmd 0x%x, arg 0x%lx\n", cmd, (long)arg));
1894 1894
1895 1895 /* The minor number should always be 0 */
1896 1896 if (FDUNIT(dev) != 0)
1897 1897 return (ENXIO);
1898 1898
1899 1899 fdc = fd_getctlr(dev);
1900 1900 unit = fdc->c_un->un_unit_no;
1901 1901 un = fdc->c_un;
1902 1902 sec_size = un->un_chars->fdc_sec_size;
1903 1903 bzero(&cpy, sizeof (cpy));
1904 1904
1905 1905 switch (cmd) {
1906 1906 case DKIOCINFO:
1907 1907 cpy.dki.dki_addr = 0;
1908 1908
1909 1909 /*
1910 1910 * The meaning of the dki_slave and dki_unit fields
1911 1911 * is unclear. The sparc floppy driver follows the same
1912 1912 * convention as sd.c in that the instance number is
1913 1913 * returned in the dki_cnum field. The dki_slave field is
1914 1914 * ignored.
1915 1915 *
1916 1916 * The dki_cnum contains the controller instance
1917 1917 * and its value can be any positive number. Even
1918 1918 * though currently Sparc platforms only support
1919 1919 * one controller, the controller instance number
1920 1920 * can be any number since it is assigned by the
1921 1921 * system depending on the device properties.
1922 1922 */
1923 1923
1924 1924 cpy.dki.dki_cnum = FDCTLR(dev);
1925 1925
1926 1926 /*
1927 1927 * Sparc platforms support only one floppy drive.
1928 1928 * The device node for the controller is the same as
1929 1929 * the device node for the drive. The x86 driver is
1930 1930 * different in that it has a node for the controller
1931 1931 * and a child node for each drive. Since Sparc supports
1932 1932 * only one drive, the unit number will always be zero.
1933 1933 */
1934 1934
1935 1935 cpy.dki.dki_unit = FDUNIT(dev);
1936 1936
1937 1937 /*
1938 1938 * The meaning of the dki_slave field is unclear.
1939 1939 * So, I will leave it set to 0.
1940 1940 */
1941 1941
1942 1942 cpy.dki.dki_slave = 0;
1943 1943
1944 1944 cpy.dki.dki_ctype = (ushort_t)-1;
1945 1945 if (fdc->c_fdtype & FDCTYPE_82077)
1946 1946 cpy.dki.dki_ctype = DKC_INTEL82077;
1947 1947 cpy.dki.dki_flags = DKI_FMTTRK;
1948 1948 cpy.dki.dki_partition = FDPARTITION(dev);
1949 1949 cpy.dki.dki_maxtransfer = maxphys / DEV_BSIZE;
1950 1950 if (ddi_copyout((caddr_t)&cpy.dki, (caddr_t)arg,
1951 1951 sizeof (cpy.dki), flag))
1952 1952 err = EFAULT;
1953 1953 break;
1954 1954 case DKIOCGGEOM:
1955 1955 cpy.dkg.dkg_ncyl = un->un_chars->fdc_ncyl;
1956 1956 cpy.dkg.dkg_nhead = un->un_chars->fdc_nhead;
1957 1957 cpy.dkg.dkg_nsect = un->un_chars->fdc_secptrack;
1958 1958 cpy.dkg.dkg_intrlv = un->un_label.dkl_intrlv;
1959 1959 cpy.dkg.dkg_rpm = un->un_label.dkl_rpm;
1960 1960 cpy.dkg.dkg_pcyl = un->un_chars->fdc_ncyl;
1961 1961 cpy.dkg.dkg_read_reinstruct =
1962 1962 (int)(cpy.dkg.dkg_nsect * cpy.dkg.dkg_rpm * 4) / 60000;
1963 1963 cpy.dkg.dkg_write_reinstruct = cpy.dkg.dkg_read_reinstruct;
1964 1964 if (ddi_copyout((caddr_t)&cpy.dkg, (caddr_t)arg,
1965 1965 sizeof (cpy.dkg), flag))
1966 1966 err = EFAULT;
1967 1967 break;
1968 1968 case DKIOCSGEOM:
1969 1969 FDERRPRINT(FDEP_L3, FDEM_IOCT,
1970 1970 (C, "fd_ioctl: DKIOCSGEOM not supported\n"));
1971 1971 err = ENOTTY;
1972 1972 break;
1973 1973
1974 1974 /*
1975 1975 * return the map of all logical partitions
1976 1976 */
1977 1977 case DKIOCGAPART:
1978 1978 /*
1979 1979 * We don't have anything to do if the application is ILP32
1980 1980 * because the label map has a 32-bit format. Otherwise
1981 1981 * convert.
1982 1982 */
1983 1983 if ((flag & DATAMODEL_MASK) == DATAMODEL_ILP32) {
1984 1984 if (ddi_copyout(&un->un_label.dkl_map,
1985 1985 (void *)arg, sizeof (struct dk_allmap32), flag))
1986 1986 err = EFAULT;
1987 1987 }
1988 1988 #ifdef _MULTI_DATAMODEL
1989 1989 else {
1990 1990 struct dk_allmap dk_allmap;
1991 1991
1992 1992 ASSERT((flag & DATAMODEL_MASK) == DATAMODEL_LP64);
1993 1993 for (dkunit = 0; dkunit < NDKMAP; dkunit++) {
1994 1994 dk_allmap.dka_map[dkunit].dkl_cylno =
1995 1995 un->un_label.dkl_map[dkunit].dkl_cylno;
1996 1996 dk_allmap.dka_map[dkunit].dkl_nblk =
1997 1997 un->un_label.dkl_map[dkunit].dkl_nblk;
1998 1998 }
1999 1999 if (ddi_copyout(&dk_allmap, (void *)arg,
2000 2000 sizeof (struct dk_allmap), flag))
2001 2001 err = EFAULT;
2002 2002 }
2003 2003 #endif /* _MULTI_DATAMODEL */
2004 2004 break;
2005 2005
2006 2006 /*
2007 2007 * Set the map of all logical partitions
2008 2008 */
2009 2009 case DKIOCSAPART:
2010 2010 if ((flag & DATAMODEL_MASK) == DATAMODEL_ILP32) {
2011 2011 if (ddi_copyin((const void *)arg, &cpy.dka,
2012 2012 sizeof (cpy.dka), flag))
2013 2013 return (EFAULT);
2014 2014 else {
2015 2015 mutex_enter(&fdc->c_lolock);
2016 2016 for (dkunit = 0; dkunit < NDKMAP; dkunit++) {
2017 2017 un->un_label.dkl_map[dkunit] =
2018 2018 cpy.dka.dka_map[dkunit];
2019 2019 }
2020 2020 mutex_exit(&fdc->c_lolock);
2021 2021 }
2022 2022 }
2023 2023 #ifdef _MULTI_DATAMODEL
2024 2024 else {
2025 2025 struct dk_allmap dk_allmap;
2026 2026
2027 2027 ASSERT((flag & DATAMODEL_MASK) == DATAMODEL_LP64);
2028 2028 if (ddi_copyin((const void *)arg, &dk_allmap,
2029 2029 sizeof (dk_allmap), flag))
2030 2030 return (EFAULT);
2031 2031 else {
2032 2032 mutex_enter(&fdc->c_lolock);
2033 2033 for (dkunit = 0; dkunit < NDKMAP; dkunit++) {
2034 2034 un->un_label.dkl_map[dkunit].dkl_cylno =
2035 2035 dk_allmap.dka_map[dkunit].dkl_cylno;
2036 2036 un->un_label.dkl_map[dkunit].dkl_nblk =
2037 2037 dk_allmap.dka_map[dkunit].dkl_nblk;
2038 2038 }
2039 2039 mutex_exit(&fdc->c_lolock);
2040 2040 }
2041 2041 }
2042 2042 #endif /* _MULTI_DATAMODEL */
2043 2043 break;
2044 2044
2045 2045 case DKIOCGVTOC:
2046 2046 mutex_enter(&fdc->c_lolock);
2047 2047
2048 2048 /*
2049 2049 * Exit if the diskette has no label.
2050 2050 * Also, get the label to make sure the
2051 2051 * correct one is being used since the diskette
2052 2052 * may have changed
2053 2053 */
2054 2054 if (fdgetlabel(fdc, unit)) {
2055 2055 mutex_exit(&fdc->c_lolock);
2056 2056 err = EINVAL;
2057 2057 break;
2058 2058 }
2059 2059
2060 2060 /* Build a vtoc from the diskette's label */
2061 2061 fd_build_user_vtoc(un, &vtoc);
2062 2062 mutex_exit(&fdc->c_lolock);
2063 2063
2064 2064 #ifdef _MULTI_DATAMODEL
2065 2065 switch (ddi_model_convert_from(flag & FMODELS)) {
2066 2066 case DDI_MODEL_ILP32: {
2067 2067 struct vtoc32 vtoc32;
2068 2068
2069 2069 vtoctovtoc32(vtoc, vtoc32);
2070 2070 if (ddi_copyout(&vtoc32, (void *)arg,
2071 2071 sizeof (struct vtoc32), flag))
2072 2072 return (EFAULT);
2073 2073 break;
2074 2074 }
2075 2075
2076 2076 case DDI_MODEL_NONE:
2077 2077 if (ddi_copyout(&vtoc, (void *)arg,
2078 2078 sizeof (vtoc), flag))
2079 2079 return (EFAULT);
2080 2080 break;
2081 2081 }
2082 2082 #else /* ! _MULTI_DATAMODEL */
2083 2083 if (ddi_copyout(&vtoc, (void *)arg, sizeof (vtoc), flag))
2084 2084 return (EFAULT);
2085 2085 #endif /* _MULTI_DATAMODEL */
2086 2086 break;
2087 2087
2088 2088 case DKIOCSVTOC:
2089 2089
2090 2090 #ifdef _MULTI_DATAMODEL
2091 2091 switch (ddi_model_convert_from(flag & FMODELS)) {
2092 2092 case DDI_MODEL_ILP32: {
2093 2093 struct vtoc32 vtoc32;
2094 2094
2095 2095 if (ddi_copyin((const void *)arg, &vtoc32,
2096 2096 sizeof (struct vtoc32), flag)) {
2097 2097 return (EFAULT);
2098 2098 }
2099 2099 vtoc32tovtoc(vtoc32, vtoc);
2100 2100 break;
2101 2101 }
2102 2102
2103 2103 case DDI_MODEL_NONE:
2104 2104 if (ddi_copyin((const void *)arg, &vtoc,
2105 2105 sizeof (vtoc), flag)) {
2106 2106 return (EFAULT);
2107 2107 }
2108 2108 break;
2109 2109 }
2110 2110 #else /* ! _MULTI_DATAMODEL */
2111 2111 if (ddi_copyin((const void *)arg, &vtoc, sizeof (vtoc), flag))
2112 2112 return (EFAULT);
2113 2113 #endif /* _MULTI_DATAMODEL */
2114 2114
2115 2115 mutex_enter(&fdc->c_lolock);
2116 2116
2117 2117 /*
2118 2118 * The characteristics structure must be filled in because
2119 2119 * it helps build the vtoc.
2120 2120 */
2121 2121 if ((un->un_chars->fdc_ncyl == 0) ||
2122 2122 (un->un_chars->fdc_nhead == 0) ||
2123 2123 (un->un_chars->fdc_secptrack == 0)) {
2124 2124 mutex_exit(&fdc->c_lolock);
2125 2125 err = EINVAL;
2126 2126 break;
2127 2127 }
2128 2128
2129 2129 if ((err = fd_build_label_vtoc(un, &vtoc)) != 0) {
2130 2130 mutex_exit(&fdc->c_lolock);
2131 2131 break;
2132 2132 }
2133 2133
2134 2134 (void) pm_busy_component(fdc->c_dip, 0);
2135 2135
2136 2136 err = fdrw(fdc, unit, FDWRITE, 0, 0, 1,
2137 2137 (caddr_t)&un->un_label, sizeof (struct dk_label));
2138 2138 mutex_exit(&fdc->c_lolock);
2139 2139 (void) pm_idle_component(fdc->c_dip, 0);
2140 2140 break;
2141 2141
2142 2142 case DKIOCSTATE:
2143 2143 if (ddi_copyin((caddr_t)arg, (caddr_t)&state,
2144 2144 sizeof (int), flag)) {
2145 2145 err = EFAULT;
2146 2146 break;
2147 2147 }
2148 2148 (void) pm_busy_component(fdc->c_dip, 0);
2149 2149
2150 2150 err = fd_check_media(dev, state);
2151 2151 (void) pm_idle_component(fdc->c_dip, 0);
2152 2152
2153 2153 if (ddi_copyout((caddr_t)&un->un_media_state,
2154 2154 (caddr_t)arg, sizeof (int), flag))
2155 2155 err = EFAULT;
2156 2156 break;
2157 2157
2158 2158 case FDIOGCHAR:
2159 2159 if (ddi_copyout((caddr_t)un->un_chars, (caddr_t)arg,
2160 2160 sizeof (struct fd_char), flag))
2161 2161 err = EFAULT;
2162 2162 break;
2163 2163
2164 2164 case FDIOSCHAR:
2165 2165 if (ddi_copyin((caddr_t)arg, (caddr_t)&cpy.fdchar,
2166 2166 sizeof (struct fd_char), flag)) {
2167 2167 err = EFAULT;
2168 2168 break;
2169 2169 }
2170 2170
2171 2171 /*
2172 2172 * Check the fields in the fdchar structure that are either
2173 2173 * driver or controller dependent.
2174 2174 */
2175 2175
2176 2176 transfer_rate = cpy.fdchar.fdc_transfer_rate;
2177 2177 if ((transfer_rate != 500) && (transfer_rate != 300) &&
2178 2178 (transfer_rate != 250) && (transfer_rate != 1000)) {
2179 2179 FDERRPRINT(FDEP_L3, FDEM_IOCT,
2180 2180 (C, "fd_ioctl: FDIOSCHAR odd transfer rate %d\n",
2181 2181 cpy.fdchar.fdc_transfer_rate));
2182 2182 err = EINVAL;
2183 2183 break;
2184 2184 }
2185 2185
2186 2186 if ((cpy.fdchar.fdc_nhead < 1) ||
2187 2187 (cpy.fdchar.fdc_nhead > 2)) {
2188 2188 FDERRPRINT(FDEP_L3, FDEM_IOCT,
2189 2189 (C, "fd_ioctl: FDIOSCHAR bad no. of heads %d\n",
2190 2190 cpy.fdchar.fdc_nhead));
2191 2191 err = EINVAL;
2192 2192 break;
2193 2193 }
2194 2194
2195 2195 /*
2196 2196 * The number of cylinders must be between 0 and 255
2197 2197 */
2198 2198 if ((cpy.fdchar.fdc_ncyl < 0) || (cpy.fdchar.fdc_ncyl > 255)) {
2199 2199 FDERRPRINT(FDEP_L3, FDEM_IOCT,
2200 2200 (C, "fd_ioctl: FDIOSCHAR bad cyl no %d\n",
2201 2201 cpy.fdchar.fdc_ncyl));
2202 2202 err = EINVAL;
2203 2203 break;
2204 2204 }
2205 2205
2206 2206 /* Copy the fdchar structure */
2207 2207
2208 2208 mutex_enter(&fdc->c_lolock);
2209 2209 *(un->un_chars) = cpy.fdchar;
2210 2210
2211 2211 un->un_curfdtype = -1;
2212 2212
2213 2213 mutex_exit(&fdc->c_lolock);
2214 2214
2215 2215 break;
2216 2216 case FDEJECT: /* eject disk */
2217 2217 case DKIOCEJECT:
2218 2218
2219 2219 /*
2220 2220 * Fail the ioctl if auto-eject isn't supported
2221 2221 */
2222 2222 if (fdc->c_un->un_drive->fdd_ejectable == 0) {
2223 2223
2224 2224 err = ENOSYS;
2225 2225
2226 2226 } else {
2227 2227 (void) pm_busy_component(fdc->c_dip, 0);
2228 2228
2229 2229 mutex_enter(&fdc->c_lolock);
2230 2230
2231 2231 CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc);
2232 2232
2233 2233 if (fdc->c_un->un_state == FD_STATE_STOPPED) {
2234 2234 mutex_exit(&fdc->c_lolock);
2235 2235 if ((pm_raise_power(fdc->c_dip, 0,
2236 2236 PM_LEVEL_ON)) != DDI_SUCCESS) {
2237 2237 (void) pm_idle_component(fdc->c_dip, 0);
2238 2238 err = EIO;
2239 2239 }
2240 2240 mutex_enter(&fdc->c_lolock);
2241 2241 }
2242 2242 }
2243 2243 if (err == 0) {
2244 2244 fdselect(fdc, unit, 1);
2245 2245 fdeject(fdc, unit);
2246 2246 mutex_exit(&fdc->c_lolock);
2247 2247 }
2248 2248
2249 2249 (void) pm_idle_component(fdc->c_dip, 0);
2250 2250
2251 2251 /*
2252 2252 * Make sure the drive is turned off
2253 2253 */
2254 2254 if (fdc->c_fdtype & FDCTYPE_82077) {
2255 2255 if (fdc->c_mtimeid == 0) {
2256 2256 fdc->c_mtimeid = timeout(fdmotoff, fdc,
2257 2257 Motoff_delay);
2258 2258 }
2259 2259 }
2260 2260
2261 2261 break;
2262 2262 case FDGETCHANGE: /* disk changed */
2263 2263
2264 2264 if (ddi_copyin((caddr_t)arg, (caddr_t)&cpy.temp,
2265 2265 sizeof (int), flag)) {
2266 2266 err = EFAULT;
2267 2267 break;
2268 2268 }
2269 2269
2270 2270 /* zero out the user's parameter */
2271 2271 cpy.temp = 0;
2272 2272
2273 2273 (void) pm_busy_component(fdc->c_dip, 0);
2274 2274
2275 2275 mutex_enter(&fdc->c_lolock);
2276 2276
2277 2277 CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc);
2278 2278
2279 2279 if (fdc->c_un->un_state == FD_STATE_STOPPED) {
2280 2280 mutex_exit(&fdc->c_lolock);
2281 2281 if ((pm_raise_power(fdc->c_dip, 0, PM_LEVEL_ON))
2282 2282 != DDI_SUCCESS) {
2283 2283 FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "Power \
2284 2284 change failed. \n"));
2285 2285 (void) pm_idle_component(fdc->c_dip, 0);
2286 2286 return (EIO);
2287 2287 }
2288 2288
2289 2289 mutex_enter(&fdc->c_lolock);
2290 2290 }
2291 2291 if (un->un_flags & FDUNIT_CHANGED)
2292 2292 cpy.temp |= FDGC_HISTORY;
2293 2293 else
2294 2294 cpy.temp &= ~FDGC_HISTORY;
2295 2295 un->un_flags &= ~FDUNIT_CHANGED;
2296 2296
2297 2297 if (fd_pollable) {
2298 2298 /*
2299 2299 * If it's a "pollable" floppy, then we don't
2300 2300 * have to do all the fdcheckdisk nastyness to
2301 2301 * figure out if the thing is still there.
2302 2302 */
2303 2303 if (fdsense_chng(fdc, unit)) {
2304 2304 cpy.temp |= FDGC_CURRENT;
2305 2305 } else {
2306 2306 cpy.temp &= ~FDGC_CURRENT;
2307 2307 }
2308 2308 } else {
2309 2309
2310 2310 if (fdsense_chng(fdc, unit)) {
2311 2311 /*
2312 2312 * check disk change signal is asserted.
2313 2313 * Now find out if the floppy is
2314 2314 * inserted
2315 2315 */
2316 2316 if (fdcheckdisk(fdc, unit)) {
2317 2317 cpy.temp |= FDGC_CURRENT;
2318 2318 } else {
2319 2319 /*
2320 2320 * Yes, the floppy was
2321 2321 * reinserted. Implies
2322 2322 * floppy change.
2323 2323 */
2324 2324 cpy.temp &= ~FDGC_CURRENT;
2325 2325 cpy.temp |= FDGC_HISTORY;
2326 2326 }
2327 2327 } else {
2328 2328 cpy.temp &= ~FDGC_CURRENT;
2329 2329 }
2330 2330 }
2331 2331
2332 2332 /*
2333 2333 * For a pollable floppy, the floppy_change signal
2334 2334 * reflects whether the floppy is in there or not.
2335 2335 * We can not detect a floppy change if we don't poll
2336 2336 * this signal when the floppy is being changed.
2337 2337 * Because as soon as the floppy is put back, the
2338 2338 * signal is reset.
2339 2339 * BUT the pollable floppies are available only on
2340 2340 * Sparcstation Voyager Voyagers (Gypsy) only and
2341 2341 * those are motorized floppies. For motorized floppies,
2342 2342 * the floppy can only (assuming the user doesn't use a
2343 2343 * pin to take out the floppy) be taken out by
2344 2344 * issuing 'eject' command which sets the
2345 2345 * un->un_ejected flag. So, if the following
2346 2346 * condition is true, we can assume there
2347 2347 * was a floppy change.
2348 2348 */
2349 2349 if (un->un_ejected && !(cpy.temp & FDGC_CURRENT)) {
2350 2350 cpy.temp |= FDGC_HISTORY;
2351 2351 }
2352 2352 un->un_ejected = 0;
2353 2353
2354 2354
2355 2355 /* return the write-protection status */
2356 2356 fdgetcsb(fdc);
2357 2357 if (fdsensedrv(fdc, unit) & WP_SR3) {
2358 2358 cpy.temp |= FDGC_CURWPROT;
2359 2359 }
2360 2360 fdretcsb(fdc);
2361 2361 mutex_exit(&fdc->c_lolock);
2362 2362
2363 2363 if (ddi_copyout((caddr_t)&cpy.temp, (caddr_t)arg,
2364 2364 sizeof (int), flag))
2365 2365 err = EFAULT;
2366 2366 (void) pm_idle_component(fdc->c_dip, 0);
2367 2367 break;
2368 2368
2369 2369 case FDGETDRIVECHAR:
2370 2370
2371 2371 if (ddi_copyin((caddr_t)arg, (caddr_t)&cpy.drvchar,
2372 2372 sizeof (struct fd_drive), flag)) {
2373 2373 err = EFAULT;
2374 2374 break;
2375 2375 }
2376 2376
2377 2377 /*
2378 2378 * Return the ejectable value based on the FD_MANUAL_EJECT
2379 2379 * property
2380 2380 */
2381 2381 cpy.drvchar.fdd_ejectable = fdc->c_un->un_drive->fdd_ejectable;
2382 2382 cpy.drvchar.fdd_maxsearch = nfdtypes; /* 3 - hi m lo density */
2383 2383 if (fd_pollable) /* pollable device */
2384 2384 cpy.drvchar.fdd_flags |= FDD_POLLABLE;
2385 2385
2386 2386 /* the rest of the fd_drive struct is meaningless to us */
2387 2387
2388 2388 if (ddi_copyout((caddr_t)&cpy.drvchar, (caddr_t)arg,
2389 2389 sizeof (struct fd_drive), flag))
2390 2390 err = EFAULT;
2391 2391 break;
2392 2392
2393 2393 case FDSETDRIVECHAR:
2394 2394 FDERRPRINT(FDEP_L3, FDEM_IOCT,
2395 2395 (C, "fd_ioctl: FDSETDRIVECHAR not supportedn\n"));
2396 2396 err = ENOTTY;
2397 2397 break;
2398 2398
2399 2399 case DKIOCREMOVABLE: {
2400 2400 int i = 1;
2401 2401
2402 2402 /* no brainer: floppies are always removable */
2403 2403 if (ddi_copyout((caddr_t)&i, (caddr_t)arg, sizeof (int),
2404 2404 flag)) {
2405 2405 err = EFAULT;
2406 2406 }
2407 2407 break;
2408 2408 }
2409 2409 case DKIOCGMEDIAINFO:
2410 2410 err = fd_get_media_info(un, (caddr_t)arg, flag);
2411 2411 break;
2412 2412
2413 2413
2414 2414 case FDIOCMD:
2415 2415 {
2416 2416 struct fd_cmd fc;
2417 2417 int cyl, hd, spc, spt;
2418 2418 int nblks; /* total no. of blocks */
2419 2419
2420 2420 #ifdef _MULTI_DATAMODEL
2421 2421 switch (ddi_model_convert_from(flag & FMODELS)) {
2422 2422 case DDI_MODEL_ILP32: {
2423 2423 struct fd_cmd32 fc32;
2424 2424
2425 2425 if (ddi_copyin((const void *)arg, &fc32,
2426 2426 sizeof (fc32), flag)) {
2427 2427 return (EFAULT);
2428 2428 }
2429 2429 fc.fdc_cmd = fc32.fdc_cmd;
2430 2430 fc.fdc_flags = fc32.fdc_flags;
2431 2431 fc.fdc_blkno = (daddr_t)fc32.fdc_blkno;
2432 2432 fc.fdc_secnt = fc32.fdc_secnt;
2433 2433 fc.fdc_bufaddr = (caddr_t)(uintptr_t)fc32.fdc_bufaddr;
2434 2434 fc.fdc_buflen = fc32.fdc_buflen;
2435 2435 fc.fdc_cmd = fc32.fdc_cmd;
2436 2436
2437 2437 break;
2438 2438 }
2439 2439
2440 2440 case DDI_MODEL_NONE:
2441 2441 if (ddi_copyin((const void *)arg, &fc,
2442 2442 sizeof (fc), flag)) {
2443 2443 return (EFAULT);
2444 2444 }
2445 2445 break;
2446 2446 }
2447 2447 #else /* ! _MULTI_DATAMODEL */
2448 2448 if (ddi_copyin((const void *)arg, &fc, sizeof (fc), flag)) {
2449 2449 return (EFAULT);
2450 2450 }
2451 2451 #endif /* _MULTI_DATAMODEL */
2452 2452
2453 2453 if (fc.fdc_cmd == FDCMD_READ || fc.fdc_cmd == FDCMD_WRITE) {
2454 2454 auto struct iovec aiov;
2455 2455 auto struct uio auio;
2456 2456 struct uio *uio = &auio;
2457 2457
2458 2458 spc = (fc.fdc_cmd == FDCMD_READ)? B_READ: B_WRITE;
2459 2459
2460 2460 bzero(&auio, sizeof (struct uio));
2461 2461 bzero(&aiov, sizeof (struct iovec));
2462 2462 aiov.iov_base = fc.fdc_bufaddr;
2463 2463 aiov.iov_len = (uint_t)fc.fdc_secnt * sec_size;
2464 2464 uio->uio_iov = &aiov;
2465 2465
2466 2466 uio->uio_iovcnt = 1;
2467 2467 uio->uio_resid = aiov.iov_len;
2468 2468 uio->uio_segflg = UIO_USERSPACE;
2469 2469 FDERRPRINT(FDEP_L2, FDEM_IOCT,
2470 2470 (C, "fd_ioctl: call physio\n"));
2471 2471 err = physio(fd_strategy, NULL, dev,
2472 2472 spc, minphys, uio);
2473 2473 break;
2474 2474 } else if (fc.fdc_cmd != FDCMD_FORMAT_TRACK) {
2475 2475
2476 2476 /*
2477 2477 * The manpage states that only the FDCMD_WRITE,
2478 2478 * FDCMD_READ, and the FDCMD_FORMAT_TR are available.
2479 2479 */
2480 2480 FDERRPRINT(FDEP_L1, FDEM_IOCT,
2481 2481 (C, "fd_ioctl: FDIOCMD invalid command\n"));
2482 2482 err = EINVAL;
2483 2483 break;
2484 2484 }
2485 2485
2486 2486 /* The command is FDCMD_FORMAT_TRACK */
2487 2487
2488 2488 spt = un->un_chars->fdc_secptrack; /* sec/trk */
2489 2489 spc = un->un_chars->fdc_nhead * spt; /* sec/cyl */
2490 2490 cyl = fc.fdc_blkno / spc;
2491 2491 hd = (fc.fdc_blkno % spc) / spt;
2492 2492
2493 2493 /*
2494 2494 * Make sure the specified block number is in the correct
2495 2495 * range. (block numbers start at 0)
2496 2496 */
2497 2497 nblks = spc * un->un_chars->fdc_ncyl;
2498 2498
2499 2499 if (fc.fdc_blkno < 0 || fc.fdc_blkno > (nblks - 1)) {
2500 2500 err = EINVAL;
2501 2501 break;
2502 2502 }
2503 2503
2504 2504 (void) pm_busy_component(fdc->c_dip, 0);
2505 2505
2506 2506 mutex_enter(&fdc->c_lolock);
2507 2507 CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc);
2508 2508 if (fdc->c_un->un_state == FD_STATE_STOPPED) {
2509 2509 mutex_exit(&fdc->c_lolock);
2510 2510 if ((pm_raise_power(fdc->c_dip, 0, PM_LEVEL_ON))
2511 2511 != DDI_SUCCESS) {
2512 2512 FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "Power \
2513 2513 change failed. \n"));
2514 2514 (void) pm_idle_component(fdc->c_dip, 0);
2515 2515 return (EIO);
2516 2516 }
2517 2517
2518 2518 mutex_enter(&fdc->c_lolock);
2519 2519 }
2520 2520
2521 2521 if (fdformat(fdc, unit, cyl, hd))
2522 2522 err = EIO;
2523 2523
2524 2524 mutex_exit(&fdc->c_lolock);
2525 2525 (void) pm_idle_component(fdc->c_dip, 0);
2526 2526
2527 2527 break;
2528 2528 }
2529 2529
2530 2530 case FDRAW:
2531 2531
2532 2532 (void) pm_busy_component(fdc->c_dip, 0);
2533 2533 err = fdrawioctl(fdc, unit, arg, flag);
2534 2534
2535 2535 (void) pm_idle_component(fdc->c_dip, 0);
2536 2536
2537 2537 break;
2538 2538 #ifdef FD_DEBUG
2539 2539 case IOCTL_DEBUG:
2540 2540 fderrlevel--;
2541 2541 if (fderrlevel < 0)
2542 2542 fderrlevel = 3;
2543 2543 cmn_err(C, "fdioctl: CHANGING debug to %d", fderrlevel);
2544 2544 return (0);
2545 2545 #endif /* FD_DEBUG */
2546 2546 default:
2547 2547 FDERRPRINT(FDEP_L2, FDEM_IOCT,
2548 2548 (C, "fd_ioctl: invalid ioctl 0x%x\n", cmd));
2549 2549 err = ENOTTY;
2550 2550 break;
2551 2551 }
2552 2552
2553 2553 return (err);
2554 2554 }
2555 2555
2556 2556 /*
2557 2557 * fdrawioctl
2558 2558 *
2559 2559 * - acquires the low level lock
2560 2560 */
2561 2561
2562 2562 static int
2563 2563 fdrawioctl(struct fdctlr *fdc, int unit, intptr_t arg, int mode)
2564 2564 {
2565 2565 struct fd_raw fdr;
2566 2566 #ifdef _MULTI_DATAMODEL
2567 2567 struct fd_raw32 fdr32;
2568 2568 #endif
2569 2569 struct fdcsb *csb;
2570 2570 int i, err, flag;
2571 2571 caddr_t fa;
2572 2572 uint_t fc;
2573 2573 size_t real_length;
2574 2574 int res;
2575 2575 ddi_device_acc_attr_t attr;
2576 2576 ddi_acc_handle_t mem_handle;
2577 2577
2578 2578 attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
2579 2579 attr.devacc_attr_endian_flags = DDI_STRUCTURE_BE_ACC;
2580 2580 attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
2581 2581
2582 2582 ASSERT(fdc->c_un->un_unit_no == unit);
2583 2583
2584 2584 flag = B_READ;
2585 2585 err = 0;
2586 2586 fa = NULL;
2587 2587 fc = (uint_t)0;
2588 2588
2589 2589 /* Copy in the arguments */
2590 2590 switch (ddi_model_convert_from(mode)) {
2591 2591 #ifdef _MULTI_DATAMODEL
2592 2592 case DDI_MODEL_ILP32:
2593 2593 if (ddi_copyin((caddr_t)arg, (caddr_t)&fdr32,
2594 2594 sizeof (fdr32), mode)) {
2595 2595 FDERRPRINT(FDEP_L1, FDEM_RAWI,
2596 2596 (C, "fdrawioctl: copyin error, args32\n"));
2597 2597 return (EFAULT);
2598 2598 }
2599 2599 bcopy(fdr32.fdr_cmd, fdr.fdr_cmd, sizeof (fdr.fdr_cmd));
2600 2600 fdr.fdr_cnum = fdr32.fdr_cnum;
2601 2601 bcopy(fdr32.fdr_result, fdr.fdr_result,
2602 2602 sizeof (fdr.fdr_result));
2603 2603 fdr.fdr_nbytes = fdr32.fdr_nbytes;
2604 2604 fdr.fdr_addr = (caddr_t)(uintptr_t)fdr32.fdr_addr;
2605 2605 break;
2606 2606 #endif
2607 2607 default:
2608 2608 case DDI_MODEL_NONE:
2609 2609 if (ddi_copyin((caddr_t)arg, (caddr_t)&fdr,
2610 2610 sizeof (fdr), mode)) {
2611 2611 FDERRPRINT(FDEP_L1, FDEM_RAWI,
2612 2612 (C, "fdrawioctl: copyin error, args\n"));
2613 2613 return (EFAULT);
2614 2614 }
2615 2615 break;
2616 2616 }
2617 2617
2618 2618 FDERRPRINT(FDEP_L1, FDEM_RAWI,
2619 2619 (C, "fdrawioctl: cmd[0]=0x%x\n", fdr.fdr_cmd[0]));
2620 2620
2621 2621 mutex_enter(&fdc->c_lolock);
2622 2622
2623 2623 CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc);
2624 2624
2625 2625 if (fdc->c_un->un_state == FD_STATE_STOPPED) {
2626 2626 mutex_exit(&fdc->c_lolock);
2627 2627 if ((pm_raise_power(fdc->c_dip, 0, PM_LEVEL_ON))
2628 2628 != DDI_SUCCESS) {
2629 2629 FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "Power change \
2630 2630 failed. \n"));
2631 2631
2632 2632 (void) pm_idle_component(fdc->c_dip, 0);
2633 2633 return (EIO);
2634 2634 }
2635 2635 mutex_enter(&fdc->c_lolock);
2636 2636 }
2637 2637
2638 2638 fdgetcsb(fdc);
2639 2639 csb = &fdc->c_csb;
2640 2640 csb->csb_unit = (uchar_t)unit;
2641 2641
2642 2642 /* copy cmd bytes into csb */
2643 2643 for (i = 0; i <= fdr.fdr_cnum; i++)
2644 2644 csb->csb_cmds[i] = fdr.fdr_cmd[i];
2645 2645 csb->csb_ncmds = (uchar_t)fdr.fdr_cnum;
2646 2646
2647 2647 csb->csb_maxretry = 0; /* let the application deal with errors */
2648 2648 csb->csb_retrys = 0;
2649 2649
2650 2650 switch (fdr.fdr_cmd[0] & 0x0f) {
2651 2651
2652 2652 case FDRAW_SPECIFY:
2653 2653 /*
2654 2654 * Ensure that the right DMA mode is selected. There is
2655 2655 * currently no way for the user to tell if DMA is
2656 2656 * happening so set the value for the user.
2657 2657 */
2658 2658
2659 2659 if (fdc->c_fdtype & FDCTYPE_DMA)
2660 2660 csb->csb_cmds[2] = csb->csb_cmds[2] & 0xFE;
2661 2661 else
2662 2662 csb->csb_cmds[2] = csb->csb_cmds[2] | 0x1;
2663 2663
2664 2664 csb->csb_opflags = CSB_OFNORESULTS;
2665 2665 csb->csb_nrslts = 0;
2666 2666 break;
2667 2667
2668 2668 case FDRAW_SENSE_DRV:
2669 2669 /* Insert the appropriate drive number */
2670 2670 csb->csb_cmds[1] = csb->csb_cmds[1] | (unit & DRV_MASK);
2671 2671 csb->csb_opflags = CSB_OFIMMEDIATE;
2672 2672 csb->csb_nrslts = 1;
2673 2673 break;
2674 2674
2675 2675 case FDRAW_REZERO:
2676 2676 case FDRAW_SEEK:
2677 2677 /* Insert the appropriate drive number */
2678 2678 csb->csb_cmds[1] = csb->csb_cmds[1] | (unit & DRV_MASK);
2679 2679 csb->csb_opflags = CSB_OFSEEKOPS + CSB_OFTIMEIT;
2680 2680 csb->csb_nrslts = 2;
2681 2681 break;
2682 2682
2683 2683 case FDRAW_FORMAT:
2684 2684 FDERRPRINT(FDEP_L1, FDEM_RAWI,
2685 2685 (C, "fdrawioctl: cmd is fdfraw format\n"));
2686 2686
2687 2687 /* Insert the appropriate drive number */
2688 2688 csb->csb_cmds[1] = csb->csb_cmds[1] | (unit & DRV_MASK);
2689 2689 csb->csb_opflags = CSB_OFXFEROPS + CSB_OFTIMEIT;
2690 2690 csb->csb_nrslts = NRBRW;
2691 2691 flag = B_WRITE;
2692 2692
2693 2693 /*
2694 2694 * Allocate memory for the command.
2695 2695 * If PIO is being used, then add an extra 16 bytes
2696 2696 */
2697 2697 if (fdc->c_fdtype & FDCTYPE_DMA) {
2698 2698
2699 2699 fc = (uint_t)(fdr.fdr_nbytes);
2700 2700 mutex_enter(&fdc->c_hilock);
2701 2701
2702 2702 res = ddi_dma_mem_alloc(fdc->c_dmahandle, fc,
2703 2703 &attr, DDI_DMA_STREAMING,
2704 2704 DDI_DMA_DONTWAIT, 0, &fa, &real_length,
2705 2705 &mem_handle);
2706 2706
2707 2707 if (res != DDI_SUCCESS) {
2708 2708 fdretcsb(fdc);
2709 2709 mutex_exit(&fdc->c_lolock);
2710 2710 mutex_exit(&fdc->c_hilock);
2711 2711 return (EIO);
2712 2712 }
2713 2713
2714 2714 fdc->c_csb.csb_read = CSB_WRITE;
2715 2715 if (fdstart_dma(fdc, fa, fc) != 0) {
2716 2716 ddi_dma_mem_free(&mem_handle);
2717 2717 fdretcsb(fdc);
2718 2718 mutex_exit(&fdc->c_lolock);
2719 2719 mutex_exit(&fdc->c_hilock);
2720 2720 return (EIO);
2721 2721 }
2722 2722 mutex_exit(&fdc->c_hilock);
2723 2723
2724 2724 } else {
2725 2725 fc = (uint_t)(fdr.fdr_nbytes + 16);
2726 2726 fa = kmem_zalloc(fc, KM_SLEEP);
2727 2727 }
2728 2728
2729 2729 /* copy in the user's command bytes */
2730 2730 if (ddi_copyin(fdr.fdr_addr, fa,
2731 2731 (uint_t)fdr.fdr_nbytes, mode)) {
2732 2732 fdretcsb(fdc);
2733 2733 mutex_exit(&fdc->c_lolock);
2734 2734
2735 2735 if (fdc->c_fdtype & FDCTYPE_DMA) {
2736 2736 ddi_dma_mem_free(&mem_handle);
2737 2737 FDERRPRINT(FDEP_L1, FDEM_RAWI,
2738 2738 (C, "fdrawioctl: (err)free dma memory\n"));
2739 2739 } else {
2740 2740 kmem_free(fa, fc);
2741 2741 }
2742 2742
2743 2743 FDERRPRINT(FDEP_L1, FDEM_RAWI,
2744 2744 (C, "fdrawioctl: ddi_copyin error\n"));
2745 2745 return (EFAULT);
2746 2746 }
2747 2747
2748 2748 break;
2749 2749 case FDRAW_WRCMD:
2750 2750 case FDRAW_WRITEDEL:
2751 2751 flag = B_WRITE;
2752 2752 /* FALLTHROUGH */
2753 2753 case FDRAW_RDCMD:
2754 2754 case FDRAW_READDEL:
2755 2755 case FDRAW_READTRACK:
2756 2756 /* Insert the appropriate drive number */
2757 2757 csb->csb_cmds[1] = csb->csb_cmds[1] | (unit & DRV_MASK);
2758 2758 if (fdc->c_fdtype & FDCTYPE_SB)
2759 2759 csb->csb_cmds[1] |= IPS;
2760 2760 csb->csb_opflags = CSB_OFXFEROPS + CSB_OFTIMEIT;
2761 2761 csb->csb_nrslts = NRBRW;
2762 2762 break;
2763 2763
2764 2764 default:
2765 2765 fdretcsb(fdc);
2766 2766 mutex_exit(&fdc->c_lolock);
2767 2767 return (EINVAL);
2768 2768 }
2769 2769
2770 2770 if ((csb->csb_opflags & CSB_OFXFEROPS) && (fdr.fdr_nbytes == 0)) {
2771 2771 fdretcsb(fdc);
2772 2772 mutex_exit(&fdc->c_lolock);
2773 2773 return (EINVAL);
2774 2774 }
2775 2775 csb->csb_opflags |= CSB_OFRAWIOCTL;
2776 2776
2777 2777 FDERRPRINT(FDEP_L1, FDEM_RAWI,
2778 2778 (C, "fdrawioctl: nbytes = %u\n", fdr.fdr_nbytes));
2779 2779
2780 2780 if ((fdr.fdr_cmd[0] & 0x0f) != FDRAW_FORMAT) {
2781 2781 if ((fc = (uint_t)fdr.fdr_nbytes) > 0) {
2782 2782 /*
2783 2783 * In SunOS 4.X, we used to as_fault things in.
2784 2784 * We really cannot do this in 5.0/SVr4. Unless
2785 2785 * someone really believes that speed is of the
2786 2786 * essence here, it is just much simpler to do
2787 2787 * this in kernel space and use copyin/copyout.
2788 2788 */
2789 2789 if (fdc->c_fdtype & FDCTYPE_DMA) {
2790 2790 mutex_enter(&fdc->c_hilock);
2791 2791 res = ddi_dma_mem_alloc(fdc->c_dmahandle, fc,
2792 2792 &attr, DDI_DMA_STREAMING,
2793 2793 DDI_DMA_DONTWAIT, 0, &fa, &real_length,
2794 2794 &mem_handle);
2795 2795
2796 2796 if (res != DDI_SUCCESS) {
2797 2797 fdretcsb(fdc);
2798 2798 mutex_exit(&fdc->c_lolock);
2799 2799 mutex_exit(&fdc->c_hilock);
2800 2800 return (EIO);
2801 2801 }
2802 2802
2803 2803 if (flag == B_WRITE)
2804 2804 fdc->c_csb.csb_read = CSB_WRITE;
2805 2805 else
2806 2806 fdc->c_csb.csb_read = CSB_READ;
2807 2807
2808 2808 if (fdstart_dma(fdc, fa, fc) != 0) {
2809 2809 ddi_dma_mem_free(&mem_handle);
2810 2810 fdretcsb(fdc);
2811 2811 mutex_exit(&fdc->c_lolock);
2812 2812 mutex_exit(&fdc->c_hilock);
2813 2813 return (EIO);
2814 2814 }
2815 2815 mutex_exit(&fdc->c_hilock);
2816 2816
2817 2817 } else {
2818 2818 fa = kmem_zalloc(fc, KM_SLEEP);
2819 2819 }
2820 2820
2821 2821 if (flag == B_WRITE) {
2822 2822 if (ddi_copyin(fdr.fdr_addr, fa, fc, mode)) {
2823 2823 if (fdc->c_fdtype & FDCTYPE_DMA)
2824 2824 ddi_dma_mem_free(&mem_handle);
2825 2825 else
2826 2826 kmem_free(fa, fc);
2827 2827 fdretcsb(fdc);
2828 2828 mutex_exit(&fdc->c_lolock);
2829 2829 FDERRPRINT(FDEP_L1, FDEM_RAWI, (C,
2830 2830 "fdrawioctl: can't copy data\n"));
2831 2831
2832 2832 return (EFAULT);
2833 2833 }
2834 2834 }
2835 2835 csb->csb_addr = fa;
2836 2836 csb->csb_len = fc;
2837 2837 } else {
2838 2838 csb->csb_addr = 0;
2839 2839 csb->csb_len = 0;
2840 2840 }
2841 2841 } else {
2842 2842 csb->csb_addr = fa;
2843 2843 csb->csb_len = fc;
2844 2844 }
2845 2845
2846 2846 FDERRPRINT(FDEP_L1, FDEM_RAWI,
2847 2847 (C, "cmd: %x %x %x %x %x %x %x %x %x %x\n", csb->csb_cmds[0],
2848 2848 csb->csb_cmds[1], csb->csb_cmds[2], csb->csb_cmds[3],
2849 2849 csb->csb_cmds[4], csb->csb_cmds[5], csb->csb_cmds[6],
2850 2850 csb->csb_cmds[7], csb->csb_cmds[8], csb->csb_cmds[9]));
2851 2851 FDERRPRINT(FDEP_L1, FDEM_RAWI,
2852 2852 (C, "nbytes: %x, opflags: %x, addr: %p, len: %x\n",
2853 2853 csb->csb_ncmds, csb->csb_opflags, (void *)csb->csb_addr,
2854 2854 csb->csb_len));
2855 2855
2856 2856
2857 2857 /*
2858 2858 * Note that we ignore any error return s from fdexec.
2859 2859 * This is the way the driver has been, and it may be
2860 2860 * that the raw ioctl senders simply don't want to
2861 2861 * see any errors returned in this fashion.
2862 2862 */
2863 2863
2864 2864 if ((csb->csb_opflags & CSB_OFNORESULTS) ||
2865 2865 (csb->csb_opflags & CSB_OFIMMEDIATE)) {
2866 2866 (void) fdexec(fdc, 0); /* don't sleep, don't check change */
2867 2867 } else {
2868 2868 (void) fdexec(fdc, FDXC_SLEEP | FDXC_CHECKCHG);
2869 2869 }
2870 2870
2871 2871
2872 2872 FDERRPRINT(FDEP_L1, FDEM_RAWI,
2873 2873 (C, "rslt: %x %x %x %x %x %x %x %x %x %x\n", csb->csb_rslt[0],
2874 2874 csb->csb_rslt[1], csb->csb_rslt[2], csb->csb_rslt[3],
2875 2875 csb->csb_rslt[4], csb->csb_rslt[5], csb->csb_rslt[6],
2876 2876 csb->csb_rslt[7], csb->csb_rslt[8], csb->csb_rslt[9]));
2877 2877
2878 2878 if ((fdr.fdr_cmd[0] & 0x0f) != FDRAW_FORMAT && fc &&
2879 2879 flag == B_READ && err == 0) {
2880 2880 if (ddi_copyout(fa, fdr.fdr_addr, fc, mode)) {
2881 2881 FDERRPRINT(FDEP_L1, FDEM_RAWI,
2882 2882 (C, "fdrawioctl: can't copy read data\n"));
2883 2883
2884 2884 err = EFAULT;
2885 2885 }
2886 2886 }
2887 2887
2888 2888
2889 2889 if (fc) {
2890 2890 if (fdc->c_fdtype & FDCTYPE_DMA) {
2891 2891 ddi_dma_mem_free(&mem_handle);
2892 2892 FDERRPRINT(FDEP_L1, FDEM_RAWI,
2893 2893 (C, "fdrawioctl: free dma memory\n"));
2894 2894 } else {
2895 2895 kmem_free(fa, fc);
2896 2896 }
2897 2897 }
2898 2898
2899 2899
2900 2900 /* copy cmd results into fdr */
2901 2901 for (i = 0; (int)i <= (int)csb->csb_nrslts; i++)
2902 2902 fdr.fdr_result[i] = csb->csb_rslt[i];
2903 2903 fdr.fdr_nbytes = fdc->c_csb.csb_rlen; /* return resid */
2904 2904
2905 2905 switch (ddi_model_convert_from(mode)) {
2906 2906 #ifdef _MULTI_DATAMODEL
2907 2907 case DDI_MODEL_ILP32:
2908 2908 bcopy(fdr.fdr_cmd, fdr32.fdr_cmd, sizeof (fdr32.fdr_cmd));
2909 2909 fdr32.fdr_cnum = fdr.fdr_cnum;
2910 2910 bcopy(fdr.fdr_result, fdr32.fdr_result,
2911 2911 sizeof (fdr32.fdr_result));
2912 2912 fdr32.fdr_nbytes = fdr.fdr_nbytes;
2913 2913 fdr32.fdr_addr = (caddr32_t)(uintptr_t)fdr.fdr_addr;
2914 2914 if (ddi_copyout(&fdr32, (caddr_t)arg, sizeof (fdr32), mode)) {
2915 2915 FDERRPRINT(FDEP_L1, FDEM_RAWI,
2916 2916 (C, "fdrawioctl: can't copy results32\n"));
2917 2917 err = EFAULT;
2918 2918 }
2919 2919 break;
2920 2920 #endif
2921 2921 case DDI_MODEL_NONE:
2922 2922 default:
2923 2923 if (ddi_copyout(&fdr, (caddr_t)arg, sizeof (fdr), mode)) {
2924 2924 FDERRPRINT(FDEP_L1, FDEM_RAWI,
2925 2925 (C, "fdrawioctl: can't copy results\n"));
2926 2926 err = EFAULT;
2927 2927 }
2928 2928 break;
2929 2929 }
2930 2930
2931 2931 fdretcsb(fdc);
2932 2932 mutex_exit(&fdc->c_lolock);
2933 2933 return (0);
2934 2934 }
2935 2935
2936 2936 /*
2937 2937 * fdformat
2938 2938 * format a track
2939 2939 * For PIO, builds a table of sector data values with 16 bytes
2940 2940 * (sizeof fdc's fifo) of dummy on end. This is so than when fdc->c_len
2941 2941 * goes to 0 and fd_intr sends a TC that all the real formatting will
2942 2942 * have already been done.
2943 2943 *
2944 2944 * - called with the low level lock held
2945 2945 */
2946 2946 static int
2947 2947 fdformat(struct fdctlr *fdc, int unit, int cyl, int hd)
2948 2948 {
2949 2949 struct fdcsb *csb;
2950 2950 struct fdunit *un;
2951 2951 struct fd_char *ch;
2952 2952 int cmdresult;
2953 2953 uchar_t *fmthdrs;
2954 2954 caddr_t fd;
2955 2955 int i;
2956 2956 size_t real_length;
2957 2957 ddi_device_acc_attr_t attr;
2958 2958 ddi_acc_handle_t mem_handle;
2959 2959
2960 2960 FDERRPRINT(FDEP_L1, FDEM_FORM,
2961 2961 (C, "fdformat cyl %d, hd %d\n", cyl, hd));
2962 2962 fdgetcsb(fdc);
2963 2963
2964 2964 ASSERT(fdc->c_un->un_unit_no == unit);
2965 2965
2966 2966 csb = &fdc->c_csb;
2967 2967 un = fdc->c_un;
2968 2968 ch = un->un_chars;
2969 2969
2970 2970 /* setup common things in csb */
2971 2971 csb->csb_unit = (uchar_t)unit;
2972 2972
2973 2973 /*
2974 2974 * The controller needs to do a seek before
2975 2975 * each format to get to right cylinder.
2976 2976 */
2977 2977 if (fdrecalseek(fdc, unit, cyl, FDXC_CHECKCHG)) {
2978 2978 fdretcsb(fdc);
2979 2979 return (EIO);
2980 2980 }
2981 2981
2982 2982 /*
2983 2983 * now do the format itself
2984 2984 */
2985 2985 csb->csb_nrslts = NRBRW;
2986 2986 csb->csb_opflags = CSB_OFXFEROPS | CSB_OFTIMEIT;
2987 2987
2988 2988 csb->csb_cmds[0] = FDRAW_FORMAT;
2989 2989 /* always or in MFM bit */
2990 2990 csb->csb_cmds[0] |= MFM;
2991 2991 csb->csb_cmds[1] = (hd << 2) | (unit & 0x03);
2992 2992 csb->csb_cmds[2] = ch->fdc_medium ? 3 : 2;
2993 2993 csb->csb_cmds[3] = ch->fdc_secptrack;
2994 2994 csb->csb_cmds[4] = GPLF;
2995 2995 csb->csb_cmds[5] = FDATA;
2996 2996 csb->csb_ncmds = 6;
2997 2997 csb->csb_maxretry = rwretry;
2998 2998 csb->csb_retrys = 0;
2999 2999
3000 3000 /*
3001 3001 * NOTE: have to add size of fifo also - for dummy format action
3002 3002 * if PIO is being used.
3003 3003 */
3004 3004
3005 3005
3006 3006 if (fdc->c_fdtype & FDCTYPE_DMA) {
3007 3007
3008 3008 csb->csb_len = (uint_t)4 * ch->fdc_secptrack;
3009 3009
3010 3010 attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
3011 3011 attr.devacc_attr_endian_flags = DDI_STRUCTURE_BE_ACC;
3012 3012 attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
3013 3013
3014 3014 mutex_enter(&fdc->c_hilock);
3015 3015
3016 3016 cmdresult = ddi_dma_mem_alloc(fdc->c_dmahandle, csb->csb_len,
3017 3017 &attr, DDI_DMA_STREAMING,
3018 3018 DDI_DMA_DONTWAIT, 0, &fd, &real_length,
3019 3019 &mem_handle);
3020 3020
3021 3021 if (cmdresult != DDI_SUCCESS) {
3022 3022 mutex_exit(&fdc->c_hilock);
3023 3023 return (cmdresult);
3024 3024 }
3025 3025
3026 3026 fdc->c_csb.csb_read = CSB_WRITE;
3027 3027 if (fdstart_dma(fdc, fd, csb->csb_len) != 0) {
3028 3028 ddi_dma_mem_free(&mem_handle);
3029 3029 mutex_exit(&fdc->c_hilock);
3030 3030 return (-1);
3031 3031 }
3032 3032 mutex_exit(&fdc->c_hilock);
3033 3033
3034 3034
3035 3035 } else {
3036 3036 csb->csb_len = (uint_t)4 * ch->fdc_secptrack + 16;
3037 3037 fd = kmem_zalloc(csb->csb_len, KM_SLEEP);
3038 3038 fmthdrs = (uchar_t *)fd;
3039 3039 }
3040 3040
3041 3041 csb->csb_addr = (caddr_t)fd;
3042 3042
3043 3043 for (i = 1; i <= ch->fdc_secptrack; i++) {
3044 3044 *fd++ = (uchar_t)cyl; /* cylinder */
3045 3045 *fd++ = (uchar_t)hd; /* head */
3046 3046 *fd++ = (uchar_t)i; /* sector number */
3047 3047 *fd++ = ch->fdc_medium ? 3 : 2; /* sec_size code */
3048 3048 }
3049 3049
3050 3050 if ((cmdresult = fdexec(fdc, FDXC_SLEEP | FDXC_CHECKCHG)) == 0) {
3051 3051 if (csb->csb_cmdstat)
3052 3052 cmdresult = EIO; /* XXX TBD NYD for now */
3053 3053 }
3054 3054
3055 3055 if (fdc->c_fdtype & FDCTYPE_DMA) {
3056 3056 ddi_dma_mem_free(&mem_handle);
3057 3057 } else {
3058 3058 kmem_free((caddr_t)fmthdrs, csb->csb_len);
3059 3059 }
3060 3060
3061 3061 fdretcsb(fdc);
3062 3062
3063 3063 return (cmdresult);
3064 3064 }
3065 3065
3066 3066 /*
3067 3067 * fdstart
3068 3068 * called from fd_strategy() or from fdXXXX() to setup and
3069 3069 * start operations of read or write only (using buf structs).
3070 3070 * Because the chip doesn't handle crossing cylinder boundaries on
3071 3071 * the fly, this takes care of those boundary conditions. Note that
3072 3072 * it sleeps until the operation is done *within fdstart* - so that
3073 3073 * when fdstart returns, the operation is already done.
3074 3074 *
3075 3075 * - called with the low level lock held
3076 3076 *
3077 3077 */
3078 3078
3079 3079 static int slavio_index_pulse_work_around = 0;
3080 3080
3081 3081 static void
3082 3082 fdstart(struct fdctlr *fdc)
3083 3083 {
3084 3084 struct buf *bp;
3085 3085 struct fdcsb *csb;
3086 3086 struct fdunit *un;
3087 3087 struct fd_char *ch;
3088 3088 struct dk_map32 *dkm;
3089 3089 uint_t part; /* partition number for the transfer */
3090 3090 uint_t start_part; /* starting block of the partition */
3091 3091 uint_t last_part; /* last block of the partition */
3092 3092 uint_t blk; /* starting block of transfer on diskette */
3093 3093 uint_t sect; /* starting block's offset into track */
3094 3094 uint_t cyl; /* starting cylinder of the transfer */
3095 3095 uint_t bincyl; /* starting blocks's offset into cylinder */
3096 3096 uint_t secpcyl; /* number of sectors per cylinder */
3097 3097 uint_t phys_blkno; /* no. of blocks on the diskette */
3098 3098 uint_t head; /* one of two diskette heads */
3099 3099 uint_t unit;
3100 3100 uint_t len, tlen;
3101 3101 caddr_t addr;
3102 3102 caddr_t temp_addr;
3103 3103 uint_t partial_read = 0;
3104 3104 int sb_temp_buf_used = 0;
3105 3105
3106 3106 bp = fdc->c_actf;
3107 3107
3108 3108 while (bp != NULL) {
3109 3109
3110 3110 fdc->c_actf = bp->av_forw;
3111 3111 fdc->c_current = bp;
3112 3112
3113 3113 /*
3114 3114 * Initialize the buf structure. The residual count is
3115 3115 * initially the number of bytes to be read or written
3116 3116 */
3117 3117 bp->b_flags &= ~B_ERROR;
3118 3118 bp->b_error = 0;
3119 3119 bp->b_resid = bp->b_bcount;
3120 3120 bp_mapin(bp); /* map in buffers */
3121 3121
3122 3122 addr = bp->b_un.b_addr; /* assign buffer address */
3123 3123
3124 3124 /*
3125 3125 * Find the unit and partition numbers.
3126 3126 */
3127 3127 unit = fdc->c_un->un_unit_no;
3128 3128 un = fdc->c_un;
3129 3129 ch = un->un_chars;
3130 3130 part = FDPARTITION(bp->b_edev);
3131 3131 dkm = &un->un_label.dkl_map[part];
3132 3132
3133 3133 if (un->un_chars->fdc_medium) {
3134 3134 phys_blkno = bp->b_blkno >> 1;
3135 3135 } else {
3136 3136 phys_blkno = bp->b_blkno;
3137 3137 }
3138 3138
3139 3139 if (un->un_iostat) {
3140 3140 kstat_waitq_to_runq(KIOSP);
3141 3141 }
3142 3142
3143 3143 FDERRPRINT(FDEP_L1, FDEM_STRT,
3144 3144 (C, "fdstart: bp=0x%p blkno=0x%x bcount=0x%x\n",
3145 3145 (void *)bp, (int)bp->b_blkno, (int)bp->b_bcount));
3146 3146
3147 3147 /*
3148 3148 * Get the csb and initialize the values that are the same
3149 3149 * for DMA and PIO.
3150 3150 */
3151 3151 fdgetcsb(fdc); /* get csb (maybe wait for it) */
3152 3152 csb = &fdc->c_csb;
3153 3153 csb->csb_unit = unit; /* floppy unit number */
3154 3154
3155 3155
3156 3156 /*
3157 3157 * bugID:4133425 : If the controller is SLAVIO, and
3158 3158 * the read does not reach end of track, then modify
3159 3159 * the tlen to read until the end of track to a temp
3160 3160 * buffer and disable MT. After the read is over,
3161 3161 * copy the useful portion of the data to 'addr'.
3162 3162 * Enable this feature only when
3163 3163 * slavio_index_pulse_work_aound variable is
3164 3164 * set in /etc/system.
3165 3165 */
3166 3166
3167 3167
3168 3168 if (bp->b_flags & B_READ) {
3169 3169 if (((fdc->c_fdtype & FDCTYPE_SLAVIO) &&
3170 3170 slavio_index_pulse_work_around) ||
3171 3171 (fdc->c_fdtype & FDCTYPE_TCBUG))
3172 3172 csb->csb_cmds[0] = SK | FDRAW_RDCMD | MFM;
3173 3173 else
3174 3174 csb->csb_cmds[0] = MT | SK | FDRAW_RDCMD | MFM;
3175 3175 } else {
3176 3176 if (fdc->c_fdtype & FDCTYPE_TCBUG)
3177 3177 csb->csb_cmds[0] = FDRAW_WRCMD | MFM;
3178 3178 else
3179 3179 csb->csb_cmds[0] = MT | FDRAW_WRCMD | MFM;
3180 3180 }
3181 3181
3182 3182
3183 3183 if (bp->b_flags & B_READ)
3184 3184 fdc->c_csb.csb_read = CSB_READ;
3185 3185 else
3186 3186 fdc->c_csb.csb_read = CSB_WRITE;
3187 3187
3188 3188
3189 3189 csb->csb_cmds[5] = ch->fdc_medium ? 3 : 2; /* sector size */
3190 3190 csb->csb_cmds[6] = ch->fdc_secptrack; /* EOT-# of sectors/trk */
3191 3191 csb->csb_cmds[7] = GPLN; /* GPL - gap 3 size code */
3192 3192 csb->csb_cmds[8] = SSSDTL; /* DTL - be 0xFF if N != 0 */
3193 3193
3194 3194 csb->csb_ncmds = NCBRW; /* number of command bytes */
3195 3195 csb->csb_nrslts = NRBRW; /* number of result bytes */
3196 3196
3197 3197
3198 3198 /*
3199 3199 * opflags for interrupt handler, et.al.
3200 3200 */
3201 3201 csb->csb_opflags = CSB_OFXFEROPS | CSB_OFTIMEIT;
3202 3202
3203 3203
3204 3204 /*
3205 3205 * Make sure the transfer does not go off the end
3206 3206 * of the partition. Limit the actual amount transferred
3207 3207 * to fit the partition.
3208 3208 */
3209 3209
3210 3210 blk = phys_blkno;
3211 3211 start_part = (dkm->dkl_cylno * ch->fdc_secptrack
3212 3212 * ch->fdc_nhead);
3213 3213 blk = blk + start_part;
3214 3214 last_part = start_part + dkm->dkl_nblk;
3215 3215
3216 3216 if ((blk + (bp->b_bcount / ch->fdc_sec_size)) > last_part)
3217 3217 len = (last_part - blk) * ch->fdc_sec_size;
3218 3218 else
3219 3219 len = (uint_t)bp->b_bcount;
3220 3220
3221 3221 /*
3222 3222 * now we have the real start blk,
3223 3223 * addr and len for xfer op
3224 3224 * sectors per cylinder
3225 3225 */
3226 3226 secpcyl = ch->fdc_nhead * ch->fdc_secptrack;
3227 3227
3228 3228 /*
3229 3229 * The controller can transfer up to a cylinder at a time.
3230 3230 * Early revs of the 82077 have a bug that causes the chip to
3231 3231 * fail to respond to the Terminal Count signal. Due to this
3232 3232 * bug, controllers with type FDCTYPE_TCBUG, only transfer up
3233 3233 * to a track at a time.
3234 3234 * See earlier comment for bugID:4133425 for index pulse
3235 3235 * work around.
3236 3236 */
3237 3237
3238 3238 while (len != 0) {
3239 3239
3240 3240 cyl = blk / secpcyl; /* cylinder of transfer */
3241 3241 bincyl = blk % secpcyl; /* blk within cylinder */
3242 3242 head = bincyl / ch->fdc_secptrack;
3243 3243 sect = (bincyl % ch->fdc_secptrack) + 1;
3244 3244 /* sect w/in track */
3245 3245
3246 3246 /*
3247 3247 * If the desired block and length will go beyond the
3248 3248 * cylinder end, limit it to the cylinder end.
3249 3249 */
3250 3250
3251 3251 if ((fdc->c_fdtype & FDCTYPE_SLAVIO) &&
3252 3252 slavio_index_pulse_work_around &&
3253 3253 (fdc->c_csb.csb_read == CSB_READ)) {
3254 3254
3255 3255 tlen = (ch->fdc_secptrack - sect + 1) *
3256 3256 ch->fdc_sec_size;
3257 3257 if (len < tlen) {
3258 3258 partial_read = 1;
3259 3259 temp_addr = (caddr_t)kmem_alloc(tlen,
3260 3260 KM_SLEEP);
3261 3261 }
3262 3262
3263 3263 } else if (fdc->c_fdtype & FDCTYPE_TCBUG) {
3264 3264 tlen = len;
3265 3265 if (len > ((ch->fdc_secptrack - sect + 1) *
3266 3266 ch->fdc_sec_size))
3267 3267 tlen = (ch->fdc_secptrack - sect + 1)
3268 3268 * ch->fdc_sec_size;
3269 3269 } else {
3270 3270 if (len > ((secpcyl - bincyl)
3271 3271 * ch->fdc_sec_size))
3272 3272 tlen = (secpcyl - bincyl)
3273 3273 * ch->fdc_sec_size;
3274 3274
3275 3275 else
3276 3276 tlen = len;
3277 3277 }
3278 3278 if (fdc->c_fdtype & FDCTYPE_SB) {
3279 3279 /*
3280 3280 * To avoid underrun errors during IFB activity.
3281 3281 */
3282 3282 if (tlen > max_fd_dma_len)
3283 3283 tlen = max_fd_dma_len;
3284 3284 }
3285 3285
3286 3286 FDERRPRINT(FDEP_L1, FDEM_STRT,
3287 3287 (C, " blk 0x%x, addr 0x%p, len 0x%x\n",
3288 3288 blk, (void *)addr, len));
3289 3289 FDERRPRINT(FDEP_L1, FDEM_STRT,
3290 3290 (C, "cyl:%x, head:%x, sec:%x\n",
3291 3291 cyl, head, sect));
3292 3292
3293 3293 FDERRPRINT(FDEP_L1, FDEM_STRT,
3294 3294 (C, " resid 0x%lx, tlen %d\n",
3295 3295 bp->b_resid, tlen));
3296 3296
3297 3297 /*
3298 3298 * Finish programming the command
3299 3299 */
3300 3300 csb->csb_cmds[1] = (head << 2) | unit;
3301 3301 if (fdc->c_fdtype & FDCTYPE_SB)
3302 3302 csb->csb_cmds[1] |= IPS;
3303 3303
3304 3304 csb->csb_cmds[2] = cyl; /* C - cylinder address */
3305 3305 csb->csb_cmds[3] = head; /* H - head number */
3306 3306 csb->csb_cmds[4] = sect; /* R - sector number */
3307 3307 if (fdc->c_fdtype & FDCTYPE_TCBUG)
3308 3308 csb->csb_cmds[6] = sect +
3309 3309 (tlen / ch->fdc_sec_size) - 1;
3310 3310
3311 3311 csb->csb_len = tlen;
3312 3312 if (partial_read)
3313 3313 csb->csb_addr = temp_addr;
3314 3314 else
3315 3315 csb->csb_addr = addr;
3316 3316
3317 3317 /* retry this many times max */
3318 3318 csb->csb_maxretry = rwretry;
3319 3319 csb->csb_retrys = 0;
3320 3320
3321 3321 /* If platform supports DMA, set up DMA resources */
3322 3322 if (fdc->c_fdtype & FDCTYPE_DMA) {
3323 3323 if ((fdc->c_fdtype & FDCTYPE_SB) &&
3324 3324 (((uint32_t)(uintptr_t)addr & 0xFFFF0000) !=
3325 3325 (((uint32_t)(uintptr_t)addr + tlen) &
3326 3326 0xFFFF0000))) {
3327 3327 csb->csb_addr = fdc->dma_buf;
3328 3328 sb_temp_buf_used = 1;
3329 3329 if (csb->csb_read != CSB_READ) {
3330 3330 bcopy(addr, fdc->dma_buf, tlen);
3331 3331 }
3332 3332 }
3333 3333 mutex_enter(&fdc->c_hilock);
3334 3334
3335 3335 if (fdstart_dma(fdc, csb->csb_addr,
3336 3336 tlen) != 0) {
3337 3337
3338 3338 bp->b_flags |= B_ERROR;
3339 3339 bp->b_error = EAGAIN;
3340 3340
3341 3341 mutex_exit(&fdc->c_hilock);
3342 3342 FDERRPRINT(FDEP_L1, FDEM_STRT,
3343 3343 (C, "fdstart: no dma resources\n"));
3344 3344
3345 3345 break;
3346 3346 }
3347 3347 mutex_exit(&fdc->c_hilock);
3348 3348
3349 3349 }
3350 3350
3351 3351 bp->b_error = fdexec(fdc, FDXC_SLEEP|FDXC_CHECKCHG);
3352 3352 if (bp->b_error != 0) {
3353 3353 /*
3354 3354 * error in fdexec
3355 3355 */
3356 3356 FDERRPRINT(FDEP_L1, FDEM_STRT, (C,
3357 3357 "fdstart: bad exec of bp: 0x%p, err %d\n",
3358 3358 (void *)bp, bp->b_error));
3359 3359
3360 3360 bp->b_flags |= B_ERROR;
3361 3361 if (partial_read) {
3362 3362 partial_read = 0;
3363 3363 kmem_free(temp_addr, tlen);
3364 3364 }
3365 3365 break;
3366 3366 }
3367 3367
3368 3368 /*
3369 3369 * If it was a partial read, copy the useful
3370 3370 * portion of data to 'addr'.
3371 3371 */
3372 3372 if (partial_read) {
3373 3373 partial_read = 0;
3374 3374 bcopy(temp_addr, addr, len);
3375 3375 kmem_free(temp_addr, tlen);
3376 3376 tlen = len;
3377 3377 }
3378 3378 if ((fdc->c_fdtype & FDCTYPE_SB) &&
3379 3379 (csb->csb_read == CSB_READ)) {
3380 3380 if (sb_temp_buf_used) {
3381 3381 bcopy(fdc->dma_buf, addr, tlen);
3382 3382 sb_temp_buf_used = 0;
3383 3383 }
3384 3384 }
3385 3385
3386 3386 blk += tlen / ch->fdc_sec_size;
3387 3387 len -= tlen;
3388 3388 addr += tlen;
3389 3389 bp->b_resid -= tlen;
3390 3390
3391 3391 }
3392 3392
3393 3393 FDERRPRINT(FDEP_L1, FDEM_STRT,
3394 3394 (C, "fdstart done: b_resid %lu, b_count %lu, csb_rlen %d\n",
3395 3395 bp->b_resid, bp->b_bcount, fdc->c_csb.csb_rlen));
3396 3396
3397 3397 fdc->c_current = 0;
3398 3398 fdretcsb(fdc);
3399 3399 if (un->un_iostat) {
3400 3400 if (bp->b_flags & B_READ) {
3401 3401 KIOSP->reads++;
3402 3402 KIOSP->nread +=
3403 3403 (bp->b_bcount - bp->b_resid);
3404 3404 } else {
3405 3405 KIOSP->writes++;
3406 3406 KIOSP->nwritten += (bp->b_bcount - bp->b_resid);
3407 3407 }
3408 3408 kstat_runq_exit(KIOSP);
3409 3409 }
3410 3410 biodone(bp);
3411 3411
3412 3412 /*
3413 3413 * Look at the next buffer
3414 3414 */
3415 3415 bp = fdc->c_actf;
3416 3416
3417 3417 }
3418 3418 }
3419 3419
3420 3420 /*
3421 3421 * Set up DMA resources
3422 3422 * The DMA handle was initialized in fd_attach()
3423 3423 * Assumes the handle has already been allocated by fd_attach()
3424 3424 */
3425 3425 static int
3426 3426 fdstart_dma(struct fdctlr *fdc, caddr_t addr, uint_t len)
3427 3427 {
3428 3428 int flags; /* flags for setting up resources */
3429 3429 int res;
3430 3430
3431 3431 FDERRPRINT(FDEP_L1, FDEM_SDMA, (C, "fdstart_dma: start\n"));
3432 3432
3433 3433 if (fdc->c_csb.csb_read == CSB_READ) {
3434 3434 flags = DDI_DMA_READ;
3435 3435 } else {
3436 3436 flags = DDI_DMA_WRITE;
3437 3437 }
3438 3438
3439 3439
3440 3440 /* allow partial mapping to maximize the portability of the driver */
3441 3441 flags = flags | DDI_DMA_PARTIAL;
3442 3442
3443 3443 FDERRPRINT(FDEP_L1, FDEM_SDMA, (C, "fdstart_dma: amt. asked for %d\n",
3444 3444 len));
3445 3445
3446 3446 /*
3447 3447 * Zero out the current cookie. This is done to ensure that
3448 3448 * the previous transfers cookie information can in no way be
3449 3449 * used.
3450 3450 */
3451 3451 bzero((char *)&fdc->c_csb.csb_dmacookie,
3452 3452 sizeof (fdc->c_csb.csb_dmacookie));
3453 3453 fdc->c_csb.csb_nwin = 0;
3454 3454 fdc->c_csb.csb_windex = 0;
3455 3455 fdc->c_csb.csb_ccount = 0;
3456 3456
3457 3457 res = ddi_dma_addr_bind_handle(fdc->c_dmahandle, NULL, addr, len,
3458 3458 flags, DDI_DMA_DONTWAIT, 0, &fdc->c_csb.csb_dmacookie,
3459 3459 &fdc->c_csb.csb_ccount);
3460 3460
3461 3461 switch (res) {
3462 3462 case DDI_DMA_MAPPED:
3463 3463 /*
3464 3464 * There is one window. csb_windex is the index
3465 3465 * into the array of windows. If there are n
3466 3466 * windows then, (0 <= windex <= n-1). csb_windex
3467 3467 * represents the index of the next window
3468 3468 * to be processed.
3469 3469 */
3470 3470 fdc->c_csb.csb_nwin = 1;
3471 3471 fdc->c_csb.csb_windex = 1;
3472 3472
3473 3473
3474 3474 FDERRPRINT(FDEP_L1, FDEM_SDMA,
3475 3475 (C, "fdstart_dma: DDI_DMA_MAPPED\n"));
3476 3476
3477 3477 break;
3478 3478 case DDI_DMA_PARTIAL_MAP:
3479 3479
3480 3480 /*
3481 3481 * obtain the number of DMA windows
3482 3482 */
3483 3483 if (ddi_dma_numwin(fdc->c_dmahandle,
3484 3484 &fdc->c_csb.csb_nwin) != DDI_SUCCESS) {
3485 3485 return (-1);
3486 3486 }
3487 3487
3488 3488
3489 3489 FDERRPRINT(FDEP_L1, FDEM_SDMA,
3490 3490 (C, "fdstart_dma: partially mapped %d windows\n",
3491 3491 fdc->c_csb.csb_nwin));
3492 3492
3493 3493 /*
3494 3494 * The DMA window currently in use is window number
3495 3495 * one.
3496 3496 */
3497 3497 fdc->c_csb.csb_windex = 1;
3498 3498
3499 3499 break;
3500 3500 case DDI_DMA_NORESOURCES:
3501 3501 FDERRPRINT(FDEP_L1, FDEM_SDMA,
3502 3502 (C, "fdstart_dma: no resources\n"));
3503 3503 return (-1);
3504 3504 case DDI_DMA_NOMAPPING:
3505 3505 FDERRPRINT(FDEP_L1, FDEM_SDMA,
3506 3506 (C, "fdstart_dma: no mapping\n"));
3507 3507 return (-1);
3508 3508 case DDI_DMA_TOOBIG:
3509 3509 FDERRPRINT(FDEP_L1, FDEM_SDMA,
3510 3510 (C, "fdstart_dma: too big\n"));
3511 3511 return (-1);
3512 3512
3513 3513 case DDI_DMA_INUSE:
3514 3514 FDERRPRINT(FDEP_L1, FDEM_SDMA,
3515 3515 (C, "fdstart_dma: dma inuse\n"));
3516 3516 return (-1);
3517 3517 default:
3518 3518 FDERRPRINT(FDEP_L1, FDEM_SDMA,
3519 3519 (C, "fdstart_dma: result is 0x%x\n", res));
3520 3520 return (-1);
3521 3521
3522 3522 };
3523 3523
3524 3524 FDERRPRINT(FDEP_L1, FDEM_SDMA,
3525 3525 (C, "fdstart_dma: bound the handle\n"));
3526 3526
3527 3527 ASSERT(fdc->c_csb.csb_dmacookie.dmac_size);
3528 3528
3529 3529 FDERRPRINT(FDEP_L1, FDEM_SDMA, (C, "fdstart_dma: done\n"));
3530 3530 return (0);
3531 3531 }
3532 3532
3533 3533
3534 3534 /*
3535 3535 * fd_unbind_handle: unbind a dma handle if one exists
3536 3536 * return EIO if unbind failes
3537 3537 */
3538 3538 static int
3539 3539 fd_unbind_handle(struct fdctlr *fdc)
3540 3540 {
3541 3541 if ((fdc->c_fdtype & FDCTYPE_DMA) &&
3542 3542 ((fdc->c_csb.csb_read == CSB_READ) ||
3543 3543 (fdc->c_csb.csb_read == CSB_WRITE))) {
3544 3544 mutex_enter(&fdc->c_hilock);
3545 3545
3546 3546 if (fdc->c_fdtype & FDCTYPE_SB) {
3547 3547 if (fdc->sb_dma_lock) {
3548 3548 release_sb_dma(fdc);
3549 3549 }
3550 3550 }
3551 3551
3552 3552 /*
3553 3553 * If the byte count isn't zero, then the DMA engine is
3554 3554 * still doing a transfer. If the byte count is nonzero,
3555 3555 * reset the DMA engine to cause it to drain.
3556 3556 */
3557 3557
3558 3558 if (get_data_count_register(fdc) != 0) {
3559 3559 FDERRPRINT(FDEP_L1, FDEM_EXEC,
3560 3560 (C, "unbind & byte count isn't zero\n"));
3561 3561
3562 3562 reset_dma_controller(fdc);
3563 3563 set_dma_control_register(fdc, DCSR_INIT_BITS);
3564 3564 }
3565 3565
3566 3566 if (ddi_dma_unbind_handle(fdc->c_dmahandle) != DDI_SUCCESS) {
3567 3567 FDERRPRINT(FDEP_L1, FDEM_EXEC,
3568 3568 (C, "problem unbinding the handle\n"));
3569 3569 mutex_exit(&fdc->c_hilock);
3570 3570 return (EIO);
3571 3571 }
3572 3572 mutex_exit(&fdc->c_hilock);
3573 3573 }
3574 3574 return (0);
3575 3575 }
3576 3576
3577 3577 /*
3578 3578 * fdexec
3579 3579 * all commands go through here. Assumes the command block
3580 3580 * fdctlr.c_csb is filled in. The bytes are sent to the
3581 3581 * controller and then we do whatever else the csb says -
3582 3582 * like wait for immediate results, etc.
3583 3583 *
3584 3584 * All waiting for operations done is in here - to allow retrys
3585 3585 * and checking for disk changed - so we don't have to worry
3586 3586 * about sleeping at interrupt level.
3587 3587 *
3588 3588 * RETURNS: 0 if all ok,
3589 3589 * ENXIO - diskette not in drive
3590 3590 * EBUSY - if chip is locked or busy
3591 3591 * EIO - for timeout during sending cmds to chip
3592 3592 *
3593 3593 * to sleep: set FDXC_SLEEP, to check for disk
3594 3594 * changed: set FDXC_CHECKCHG
3595 3595 *
3596 3596 * - called with the lock held
3597 3597 */
3598 3598 static int
3599 3599 fdexec(struct fdctlr *fdc, int flags)
3600 3600 {
3601 3601 struct fdcsb *csb;
3602 3602 int i;
3603 3603 int to, unit;
3604 3604 uchar_t tmp;
3605 3605 caddr_t a = (caddr_t)fdc;
3606 3606
3607 3607 FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "fdexec: flags:%x\n", flags));
3608 3608
3609 3609 ASSERT(mutex_owned(&fdc->c_lolock));
3610 3610
3611 3611 csb = &fdc->c_csb;
3612 3612 unit = csb->csb_unit;
3613 3613
3614 3614
3615 3615 ASSERT(unit == fdc->c_un->un_unit_no);
3616 3616
3617 3617 retry:
3618 3618 FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "fdexec: cmd is %s\n",
3619 3619 fdcmds[csb->csb_cmds[0] & 0x1f].cmdname));
3620 3620 FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "fdexec: transfer rate = %d\n",
3621 3621 fdc->c_un->un_chars->fdc_transfer_rate));
3622 3622 FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "fdexec: sec size = %d\n",
3623 3623 fdc->c_un->un_chars->fdc_sec_size));
3624 3624 FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "fdexec: nblocks (512) = %d\n",
3625 3625 fdc->c_un->un_label.dkl_map[2].dkl_nblk));
3626 3626
3627 3627 if ((fdc->c_fdtype & FDCTYPE_CTRLMASK) == FDCTYPE_82077) {
3628 3628 fdexec_turn_on_motor(fdc, flags, unit);
3629 3629 }
3630 3630
3631 3631
3632 3632 fdselect(fdc, unit, 1); /* select drive */
3633 3633
3634 3634 /*
3635 3635 * select data rate for this unit/command
3636 3636 */
3637 3637 switch (fdc->c_un->un_chars->fdc_transfer_rate) {
3638 3638 case 500:
3639 3639 Dsr(fdc, 0);
3640 3640 break;
3641 3641 case 300:
3642 3642 Dsr(fdc, 1);
3643 3643 break;
3644 3644 case 250:
3645 3645 Dsr(fdc, 2);
3646 3646 break;
3647 3647 }
3648 3648 drv_usecwait(2);
3649 3649
3650 3650
3651 3651 /*
3652 3652 * If checking for changed is enabled (i.e., not seeking in checkdisk),
3653 3653 * we sample the DSKCHG line to see if the diskette has wandered away.
3654 3654 */
3655 3655 if ((flags & FDXC_CHECKCHG) && fdsense_chng(fdc, unit)) {
3656 3656 FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "diskette changed\n"));
3657 3657 fdc->c_un->un_flags |= FDUNIT_CHANGED;
3658 3658
3659 3659 if (fdcheckdisk(fdc, unit)) {
3660 3660
3661 3661 (void) fd_unbind_handle(fdc);
3662 3662 return (ENXIO);
3663 3663
3664 3664 }
3665 3665 }
3666 3666
3667 3667 /*
3668 3668 * gather some statistics
3669 3669 */
3670 3670 switch (csb->csb_cmds[0] & 0x1f) {
3671 3671 case FDRAW_RDCMD:
3672 3672 fdc->fdstats.rd++;
3673 3673 break;
3674 3674 case FDRAW_WRCMD:
3675 3675 fdc->fdstats.wr++;
3676 3676 break;
3677 3677 case FDRAW_REZERO:
3678 3678 fdc->fdstats.recal++;
3679 3679 break;
3680 3680 case FDRAW_FORMAT:
3681 3681 fdc->fdstats.form++;
3682 3682 break;
3683 3683 default:
3684 3684 fdc->fdstats.other++;
3685 3685 break;
3686 3686 }
3687 3687
3688 3688 /*
3689 3689 * Always set the opmode *prior* to poking the chip.
3690 3690 * This way we don't have to do any locking at high level.
3691 3691 */
3692 3692 csb->csb_raddr = 0;
3693 3693 csb->csb_rlen = 0;
3694 3694 if (csb->csb_opflags & CSB_OFSEEKOPS) {
3695 3695 csb->csb_opmode = 2;
3696 3696 } else if (csb->csb_opflags & CSB_OFIMMEDIATE) {
3697 3697 csb->csb_opmode = 0;
3698 3698 } else {
3699 3699 csb->csb_opmode = 1; /* normal data xfer commands */
3700 3700 csb->csb_raddr = csb->csb_addr;
3701 3701 csb->csb_rlen = csb->csb_len;
3702 3702 }
3703 3703
3704 3704 bzero((caddr_t)csb->csb_rslt, 10);
3705 3705 csb->csb_status = 0;
3706 3706 csb->csb_cmdstat = 0;
3707 3707
3708 3708
3709 3709 /*
3710 3710 * Program the DMA engine with the length and address of the transfer
3711 3711 * (DMA is only used on a read or a write)
3712 3712 */
3713 3713 if ((fdc->c_fdtype & FDCTYPE_DMA) &&
3714 3714 ((fdc->c_csb.csb_read == CSB_READ) ||
3715 3715 (fdc->c_csb.csb_read == CSB_WRITE))) {
3716 3716 mutex_enter(&fdc->c_hilock);
3717 3717
3718 3718 /* Reset the dcsr to clear it of all errors */
3719 3719
3720 3720 reset_dma_controller(fdc);
3721 3721
3722 3722 FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "cookie addr 0x%p\n",
3723 3723 (void *)fdc->c_csb.csb_dmacookie.dmac_laddress));
3724 3724
3725 3725 FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "cookie length %ld\n",
3726 3726 fdc->c_csb.csb_dmacookie.dmac_size));
3727 3727 ASSERT(fdc->c_csb.csb_dmacookie.dmac_size);
3728 3728
3729 3729 set_data_count_register(fdc,
3730 3730 fdc->c_csb.csb_dmacookie.dmac_size);
3731 3731 set_data_address_register(fdc,
3732 3732 fdc->c_csb.csb_dmacookie.dmac_laddress);
3733 3733
3734 3734 /* Program the DCSR */
3735 3735
3736 3736 if (fdc->c_csb.csb_read == CSB_READ)
3737 3737 set_dma_mode(fdc, CSB_READ);
3738 3738 else
3739 3739 set_dma_mode(fdc, CSB_WRITE);
3740 3740 mutex_exit(&fdc->c_hilock);
3741 3741 }
3742 3742
3743 3743 /*
3744 3744 * I saw this (chip unexpectedly busy) happen when i shoved the
3745 3745 * floppy into the drive while
3746 3746 * running a dd if= /dev/rfd0c. so it *is* possible for this to happen.
3747 3747 * we need to do a ctlr reset ...
3748 3748 */
3749 3749
3750 3750 if (Msr(fdc) & CB) {
3751 3751 /* tried to give command to chip when it is busy! */
3752 3752 FDERRPRINT(FDEP_L3, FDEM_EXEC,
3753 3753 (C, "fdc: unexpectedly busy-stat 0x%x\n", Msr(fdc)));
3754 3754 csb->csb_cmdstat = 1; /* XXX TBD ERRS NYD for now */
3755 3755
3756 3756 (void) fd_unbind_handle(fdc);
3757 3757 return (EBUSY);
3758 3758 }
3759 3759
3760 3760 /* Give command to the controller */
3761 3761 for (i = 0; i < (int)csb->csb_ncmds; i++) {
3762 3762
3763 3763 /* Test the readiness of the controller to receive the cmd */
3764 3764 for (to = FD_CRETRY; to; to--) {
3765 3765 if ((Msr(fdc) & (DIO|RQM)) == RQM)
3766 3766 break;
3767 3767 }
3768 3768 if (to == 0) {
3769 3769 FDERRPRINT(FDEP_L2, FDEM_EXEC,
3770 3770 (C, "fdc: no RQM - stat 0x%x\n", Msr(fdc)));
3771 3771 csb->csb_cmdstat = 1;
3772 3772
3773 3773 (void) fd_unbind_handle(fdc);
3774 3774 return (EIO);
3775 3775 }
3776 3776
3777 3777 Set_Fifo(fdc, csb->csb_cmds[i]);
3778 3778
3779 3779 FDERRPRINT(FDEP_L1, FDEM_EXEC,
3780 3780 (C, "fdexec: sent 0x%x, Msr 0x%x\n", csb->csb_cmds[i],
3781 3781 Msr(fdc)));
↓ open down ↓ |
3781 lines elided |
↑ open up ↑ |
3782 3782
3783 3783 }
3784 3784
3785 3785
3786 3786 /*
3787 3787 * Start watchdog timer on data transfer type commands - required
3788 3788 * in case a diskette is not present or is unformatted
3789 3789 */
3790 3790 if (csb->csb_opflags & CSB_OFTIMEIT) {
3791 3791 fdc->c_timeid = timeout(fdwatch, a,
3792 - tosec * drv_usectohz(1000000));
3792 + drv_sectohz(tosec));
3793 3793 }
3794 3794
3795 3795 FDERRPRINT(FDEP_L1, FDEM_EXEC,
3796 3796 (C, "fdexec: cmd sent, Msr 0x%x\n", Msr(fdc)));
3797 3797
3798 3798 /* If the operation has no results - then just return */
3799 3799 if (csb->csb_opflags & CSB_OFNORESULTS) {
3800 3800 if (fdc->c_fdtype & FDCTYPE_82077) {
3801 3801 if (fdc->c_mtimeid == 0) {
3802 3802 fdc->c_mtimeid = timeout(fdmotoff, a,
3803 3803 Motoff_delay);
3804 3804 }
3805 3805 }
3806 3806 FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "fdexec: O K ..\n"));
3807 3807
3808 3808 /*
3809 3809 * Make sure the last byte is received well by the
3810 3810 * controller. On faster CPU, it may still be busy
3811 3811 * by the time another command comes here.
3812 3812 */
3813 3813 for (to = FD_CRETRY; to; to--) {
3814 3814 if ((Msr(fdc) & (DIO|RQM)) == RQM)
3815 3815 break;
3816 3816 }
3817 3817 if (to == 0) {
3818 3818 csb->csb_cmdstat = 1;
3819 3819 return (EIO);
3820 3820 }
3821 3821
3822 3822 /*
3823 3823 * An operation that has no results isn't doing DMA so,
3824 3824 * there is no reason to try to unbind a handle
3825 3825 */
3826 3826 return (0);
3827 3827 }
3828 3828
3829 3829 /*
3830 3830 * If this operation has no interrupt AND an immediate result
3831 3831 * then we just busy wait for the results and stuff them into
3832 3832 * the csb
3833 3833 */
3834 3834 if (csb->csb_opflags & CSB_OFIMMEDIATE) {
3835 3835 to = FD_RRETRY;
3836 3836 csb->csb_nrslts = 0;
3837 3837 /*
3838 3838 * Wait while this command is still going on.
3839 3839 */
3840 3840 while ((tmp = Msr(fdc)) & CB) {
3841 3841 /*
3842 3842 * If RQM + DIO, then a result byte is at hand.
3843 3843 */
3844 3844 if ((tmp & (RQM|DIO|CB)) == (RQM|DIO|CB)) {
3845 3845 csb->csb_rslt[csb->csb_nrslts++] =
3846 3846 Fifo(fdc);
3847 3847 /*
3848 3848 * FDERRPRINT(FDEP_L4, FDEM_EXEC,
3849 3849 * (C, "fdexec: got result 0x%x\n",
3850 3850 * csb->csb_nrslts));
3851 3851 */
3852 3852 } else if (--to == 0) {
3853 3853 FDERRPRINT(FDEP_L4, FDEM_EXEC,
3854 3854 (C, "fdexec: timeout, Msr%x, nr%x\n",
3855 3855 Msr(fdc), csb->csb_nrslts));
3856 3856
3857 3857 csb->csb_status = 2;
3858 3858 if (fdc->c_fdtype & FDCTYPE_82077) {
3859 3859 if (fdc->c_mtimeid == 0) {
3860 3860 fdc->c_mtimeid = timeout(
3861 3861 fdmotoff, a, Motoff_delay);
3862 3862 }
3863 3863 }
3864 3864 /*
3865 3865 * There is no DMA happening. No need to
3866 3866 * try freeing a handle.
3867 3867 */
3868 3868
3869 3869 return (EIO);
3870 3870 }
3871 3871 }
3872 3872 }
3873 3873
3874 3874 /*
3875 3875 * If told to sleep here, well then sleep!
3876 3876 */
3877 3877
3878 3878 if (flags & FDXC_SLEEP) {
3879 3879 fdc->c_flags |= FDCFLG_WAITING;
3880 3880 while (fdc->c_flags & FDCFLG_WAITING) {
3881 3881 cv_wait(&fdc->c_iocv, &fdc->c_lolock);
3882 3882 }
3883 3883 }
3884 3884
3885 3885 /*
3886 3886 * kludge for end-of-cylinder error which must be ignored!!!
3887 3887 */
3888 3888
3889 3889 if ((fdc->c_fdtype & FDCTYPE_TCBUG) &&
3890 3890 ((csb->csb_rslt[0] & IC_SR0) == 0x40) &&
3891 3891 (csb->csb_rslt[1] & EN_SR1))
3892 3892 csb->csb_rslt[0] &= ~IC_SR0;
3893 3893
3894 3894 /*
3895 3895 * See if there was an error detected, if so, fdrecover()
3896 3896 * will check it out and say what to do.
3897 3897 *
3898 3898 * Don't do this, though, if this was the Sense Drive Status
3899 3899 * or the Dump Registers command.
3900 3900 */
3901 3901 if (((csb->csb_rslt[0] & IC_SR0) || (fdc->c_csb.csb_dcsr_rslt) ||
3902 3902 (csb->csb_status)) &&
3903 3903 ((csb->csb_cmds[0] != FDRAW_SENSE_DRV) &&
3904 3904 (csb->csb_cmds[0] != DUMPREG))) {
3905 3905 /* if it can restarted OK, then do so, else return error */
3906 3906 if (fdrecover(fdc) != 0) {
3907 3907 if (fdc->c_fdtype & FDCTYPE_82077) {
3908 3908 if (fdc->c_mtimeid == 0) {
3909 3909 fdc->c_mtimeid = timeout(fdmotoff,
3910 3910 a, Motoff_delay);
3911 3911 }
3912 3912 }
3913 3913
3914 3914 /*
3915 3915 * If this was a dma transfer, unbind the handle so
3916 3916 * that other transfers may use it.
3917 3917 */
3918 3918
3919 3919 (void) fd_unbind_handle(fdc);
3920 3920 return (EIO);
3921 3921 } else {
3922 3922 /* ASSUMES that cmd is still intact in csb */
3923 3923 goto retry;
3924 3924 }
3925 3925 }
3926 3926
3927 3927 /* things went ok */
3928 3928 if (fdc->c_fdtype & FDCTYPE_82077) {
3929 3929 if (fdc->c_mtimeid == 0) {
3930 3930 fdc->c_mtimeid = timeout(fdmotoff, a, Motoff_delay);
3931 3931 }
3932 3932 }
3933 3933 FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "fdexec: O K ..........\n"));
3934 3934
3935 3935 if (fd_unbind_handle(fdc))
3936 3936 return (EIO);
3937 3937
3938 3938 return (0);
3939 3939 }
3940 3940
3941 3941 /*
3942 3942 * Turn on the drive's motor
3943 3943 *
3944 3944 * - called with the low level lock held
3945 3945 */
3946 3946 static void
3947 3947 fdexec_turn_on_motor(struct fdctlr *fdc, int flags, uint_t unit)
3948 3948 {
3949 3949 clock_t local_lbolt;
3950 3950 timeout_id_t timeid;
3951 3951
3952 3952 /*
3953 3953 * The low level mutex may not be held over the call to
3954 3954 * untimeout(). See the manpage for details.
3955 3955 */
3956 3956 timeid = fdc->c_mtimeid;
3957 3957 fdc->c_mtimeid = 0;
3958 3958 if (timeid) {
3959 3959 mutex_exit(&fdc->c_lolock);
3960 3960 (void) untimeout(timeid);
3961 3961 mutex_enter(&fdc->c_lolock);
3962 3962 }
3963 3963
3964 3964 ASSERT(fdc->c_un->un_unit_no == unit);
3965 3965
3966 3966
3967 3967 set_rotational_speed(fdc, unit);
3968 3968
3969 3969 if (!(Dor(fdc) & (MOTEN(unit)))) {
3970 3970 /*
3971 3971 * Turn on the motor
3972 3972 */
3973 3973 FDERRPRINT(FDEP_L1, FDEM_EXEC,
3974 3974 (C, "fdexec: turning on motor\n"));
3975 3975
3976 3976 /* LINTED */
3977 3977 Set_dor(fdc, (MOTEN(unit)), 1);
3978 3978
3979 3979 if (flags & FDXC_SLEEP) {
3980 3980 local_lbolt = ddi_get_lbolt();
3981 3981 (void) cv_timedwait(&fdc->c_motoncv,
3982 3982 &fdc->c_lolock, local_lbolt + Moton_delay);
3983 3983 } else {
3984 3984 drv_usecwait(1000000);
3985 3985 }
3986 3986 }
3987 3987
3988 3988 }
3989 3989
3990 3990 /*
3991 3991 * fdrecover
3992 3992 * see if possible to retry an operation.
3993 3993 * All we can do is restart the operation. If we are out of allowed
3994 3994 * retries - return non-zero so that the higher levels will be notified.
3995 3995 *
3996 3996 * RETURNS: 0 if ok to restart, !0 if can't or out of retries
3997 3997 * - called with the low level lock held
3998 3998 */
3999 3999 static int
4000 4000 fdrecover(struct fdctlr *fdc)
4001 4001 {
4002 4002 struct fdcsb *csb;
4003 4003
4004 4004 FDERRPRINT(FDEP_L1, FDEM_RECO, (C, "fdrecover\n"));
4005 4005 csb = &fdc->c_csb;
4006 4006
4007 4007 if (fdc->c_flags & FDCFLG_TIMEDOUT) {
4008 4008 struct fdcsb savecsb;
4009 4009
4010 4010 fdc->c_flags ^= FDCFLG_TIMEDOUT;
4011 4011 csb->csb_rslt[1] |= TO_SR1;
4012 4012 FDERRPRINT(FDEP_L1, FDEM_RECO,
4013 4013 (C, "fd%d: %s timed out\n", csb->csb_unit,
4014 4014 fdcmds[csb->csb_cmds[0] & 0x1f].cmdname));
4015 4015
4016 4016 /* use private csb */
4017 4017 savecsb = fdc->c_csb;
4018 4018 bzero(&fdc->c_csb, sizeof (struct fdcsb));
4019 4019 FDERRPRINT(FDEP_L1, FDEM_RECO, (C, "fdc: resetting\n"));
4020 4020
4021 4021 (void) fdreset(fdc);
4022 4022
4023 4023 if (fdc->c_fdtype & FDCTYPE_DMA) {
4024 4024 mutex_enter(&fdc->c_hilock);
4025 4025 /* Reset the DMA engine as well */
4026 4026 reset_dma_controller(fdc);
4027 4027 set_dma_control_register(fdc, DCSR_INIT_BITS);
4028 4028 mutex_exit(&fdc->c_hilock);
4029 4029 }
4030 4030
4031 4031
4032 4032 /* check change first?? */
4033 4033 /* don't ckchg in fdexec, too convoluted */
4034 4034 (void) fdrecalseek(fdc, savecsb.csb_unit, -1, 0);
4035 4035 fdc->c_csb = savecsb; /* restore original csb */
4036 4036 }
4037 4037
4038 4038 /*
4039 4039 * gather statistics on errors
4040 4040 */
4041 4041 if (csb->csb_rslt[1] & DE_SR1) {
4042 4042 fdc->fdstats.de++;
4043 4043 }
4044 4044 if (csb->csb_rslt[1] & OR_SR1) {
4045 4045 fdc->fdstats.run++;
4046 4046 }
4047 4047 if (csb->csb_rslt[1] & (ND_SR1+MA_SR1)) {
4048 4048 fdc->fdstats.bfmt++;
4049 4049 }
4050 4050 if (csb->csb_rslt[1] & TO_SR1) {
4051 4051 fdc->fdstats.to++;
4052 4052 }
4053 4053
4054 4054 /*
4055 4055 * If raw ioctl don't examine results just pass status
4056 4056 * back via fdraw. Raw commands are timed too, so put this
4057 4057 * after the above check.
4058 4058 */
4059 4059 if (csb->csb_opflags & CSB_OFRAWIOCTL) {
4060 4060 return (1);
4061 4061 }
4062 4062
4063 4063
4064 4064 /*
4065 4065 * if there was a pci bus error, do not retry
4066 4066 */
4067 4067
4068 4068 if (csb->csb_dcsr_rslt == 1) {
4069 4069 FDERRPRINT(FDEP_L3, FDEM_RECO,
4070 4070 (C, "fd%d: host bus error\n", 0));
4071 4071 return (1);
4072 4072 }
4073 4073
4074 4074 /*
4075 4075 * If there was an error with the DMA functions, do not retry
4076 4076 */
4077 4077 if (csb->csb_dma_rslt == 1) {
4078 4078 FDERRPRINT(FDEP_L1, FDEM_RECO,
4079 4079 (C, "fd%d: DMA interface error\n", csb->csb_unit));
4080 4080 return (1);
4081 4081 }
4082 4082
4083 4083
4084 4084 /*
4085 4085 * if we have run out of retries, return an error
4086 4086 * XXX need better status interp
4087 4087 */
4088 4088
4089 4089 csb->csb_retrys++;
4090 4090 if (csb->csb_retrys > csb->csb_maxretry) {
4091 4091 FDERRPRINT(FDEP_L3, FDEM_RECO,
4092 4092 (C, "fd%d: %s failed (%x %x %x)\n",
4093 4093 0, fdcmds[csb->csb_cmds[0] & 0x1f].cmdname,
4094 4094 csb->csb_rslt[0], csb->csb_rslt[1], csb->csb_rslt[2]));
4095 4095 if (csb->csb_rslt[1] & NW_SR1) {
4096 4096 FDERRPRINT(FDEP_L3, FDEM_RECO,
4097 4097 (C, "fd%d: not writable\n", 0));
4098 4098 }
4099 4099 if (csb->csb_rslt[1] & DE_SR1) {
4100 4100 FDERRPRINT(FDEP_L3, FDEM_RECO,
4101 4101 (C, "fd%d: crc error blk %d\n", 0,
4102 4102 (int)fdc->c_current->b_blkno));
4103 4103 }
4104 4104 if (csb->csb_rslt[1] & OR_SR1) {
4105 4105 if (fdc->c_fdtype & FDCTYPE_SB) {
4106 4106 /*
4107 4107 * When using southbridge chip we need to
4108 4108 * retry atleast 10 times to shake off the
4109 4109 * underrun err.
4110 4110 */
4111 4111 if (csb->csb_retrys <= rwretry)
4112 4112 return (0);
4113 4113 }
4114 4114 FDERRPRINT(FDEP_L3, FDEM_RECO,
4115 4115 (C, "fd%d: over/underrun\n", 0));
4116 4116 }
4117 4117
4118 4118 if (csb->csb_rslt[1] & (ND_SR1+MA_SR1)) {
4119 4119 FDERRPRINT(FDEP_L3, FDEM_RECO,
4120 4120 (C, "fd%d: bad format\n", 0));
4121 4121 }
4122 4122
4123 4123 if (csb->csb_rslt[1] & TO_SR1) {
4124 4124 FDERRPRINT(FDEP_L3, FDEM_RECO,
4125 4125 (C, "fd%d: timeout\n", 0));
4126 4126 }
4127 4127
4128 4128 csb->csb_cmdstat = 1; /* failed - give up */
4129 4129 return (1);
4130 4130 }
4131 4131
4132 4132 if (csb->csb_opflags & CSB_OFSEEKOPS) {
4133 4133 /* seek, recal type commands - just look at st0 */
4134 4134 FDERRPRINT(FDEP_L2, FDEM_RECO,
4135 4135 (C, "fd%d: %s error : st0 0x%x\n", csb->csb_unit,
4136 4136 fdcmds[csb->csb_cmds[0] & 0x1f].cmdname,
4137 4137 csb->csb_rslt[0]));
4138 4138 }
4139 4139 if (csb->csb_opflags & CSB_OFXFEROPS) {
4140 4140 /* rd, wr, fmt type commands - look at st0, st1, st2 */
4141 4141 FDERRPRINT(FDEP_L2, FDEM_RECO,
4142 4142 (C, "fd%d: %s error : st0=0x%x st1=0x%x st2=0x%x\n",
4143 4143 csb->csb_unit, fdcmds[csb->csb_cmds[0] & 0x1f].cmdname,
4144 4144 csb->csb_rslt[0], csb->csb_rslt[1], csb->csb_rslt[2]));
4145 4145 }
4146 4146
4147 4147 return (0); /* tell fdexec to retry */
4148 4148 }
4149 4149
4150 4150 /*
4151 4151 * Interrupt handle for DMA
4152 4152 */
4153 4153
4154 4154 static uint_t
4155 4155 fdintr_dma()
4156 4156 {
4157 4157 struct fdctlr *fdc;
4158 4158 off_t off;
4159 4159 size_t len;
4160 4160 uint_t ccount;
4161 4161 uint_t windex;
4162 4162 uint_t done = 0;
4163 4163 int tmp_dcsr;
4164 4164 int to;
4165 4165 uchar_t tmp;
4166 4166 int i = 0;
4167 4167 int res = DDI_INTR_UNCLAIMED;
4168 4168 int not_cheerio = 1;
4169 4169
4170 4170 /* search for a controller that's expecting an interrupt */
4171 4171 fdc = fdctlrs;
4172 4172
4173 4173 if (fdc->c_fdtype & FDCTYPE_CHEERIO) {
4174 4174 tmp_dcsr = get_dma_control_register(fdc);
4175 4175 if (!(tmp_dcsr & DCSR_INT_PEND) && !(DCSR_ERR_PEND & tmp_dcsr))
4176 4176 return (res);
4177 4177 not_cheerio = 0;
4178 4178 }
4179 4179
4180 4180 mutex_enter(&fdc->c_hilock);
4181 4181
4182 4182 if (fdc->c_csb.csb_opmode == 0x0) {
4183 4183 fdc->c_csb.csb_opmode = 2;
4184 4184 }
4185 4185 if (fdc->sb_dma_lock) {
4186 4186 release_sb_dma(fdc);
4187 4187 }
4188 4188
4189 4189 /*
4190 4190 * An interrupt can come from either the floppy controller or
4191 4191 * or the DMA engine. The DMA engine will only issue an
4192 4192 * interrupt if there was an error.
4193 4193 */
4194 4194
4195 4195 switch (fdc->c_csb.csb_opmode) {
4196 4196 case 0x1:
4197 4197 /* read/write/format data-xfer case */
4198 4198
4199 4199 FDERRPRINT(FDEP_L1, FDEM_INTR,
4200 4200 (C, "fdintr_dma: opmode 1\n"));
4201 4201
4202 4202 /*
4203 4203 * See if the interrupt is from the floppy
4204 4204 * controller. If there is, take out the status bytes.
4205 4205 */
4206 4206
4207 4207 if (not_cheerio || (tmp_dcsr & DCSR_INT_PEND)) {
4208 4208
4209 4209 FDERRPRINT(FDEP_L1, FDEM_INTR,
4210 4210 (C, "fdintr_dma: INT_PEND \n"));
4211 4211
4212 4212 res = DDI_INTR_CLAIMED;
4213 4213
4214 4214 to = FD_RRETRY;
4215 4215 fdc->c_csb.csb_nrslts = 0;
4216 4216
4217 4217 /* check status */
4218 4218 i = 0;
4219 4219
4220 4220 /*
4221 4221 * CB turns off once all the result bytes are
4222 4222 * read.
4223 4223 *
4224 4224 * NOTE: the counters are there so that the
4225 4225 * handler will never get stuck in a loop.
4226 4226 * If the counters do reach their maximum
4227 4227 * values, then a catastrophic error has
4228 4228 * occurred. This should never be the case.
4229 4229 * The counters only came into play during
4230 4230 * development.
4231 4231 */
4232 4232 while (((tmp = Msr(fdc)) & CB) &&
4233 4233 (i < 1000001)) {
4234 4234
4235 4235 /*
4236 4236 * If RQM + DIO, then a result byte
4237 4237 * is at hand.
4238 4238 */
4239 4239 if ((tmp & (RQM|DIO|CB)) ==
4240 4240 (RQM|DIO|CB)) {
4241 4241 fdc->c_csb.csb_rslt
4242 4242 [fdc->c_csb.csb_nrslts++]
4243 4243 = Fifo(fdc);
4244 4244
4245 4245 FDERRPRINT(FDEP_L1, FDEM_INTR,
4246 4246 (C,
4247 4247 "fdintr_dma: res 0x%x\n",
4248 4248 fdc->c_csb.csb_rslt
4249 4249 [fdc->c_csb.csb_nrslts
4250 4250 - 1]));
4251 4251
4252 4252 } else if (--to == 0) {
4253 4253 /*
4254 4254 * controller was never
4255 4255 * ready to give results
4256 4256 */
4257 4257 fdc->c_csb.csb_status = 2;
4258 4258 break;
4259 4259 }
4260 4260 i++;
4261 4261 }
4262 4262 if (i == 10000) {
4263 4263 FDERRPRINT(FDEP_L1, FDEM_INTR,
4264 4264 (C, "First loop overran\n"));
4265 4265 }
4266 4266 }
4267 4267
4268 4268 /*
4269 4269 * See if the interrupt is from the DMA engine,
4270 4270 * which will only interrupt on an error
4271 4271 */
4272 4272 if ((!not_cheerio) && (tmp_dcsr & DCSR_ERR_PEND)) {
4273 4273
4274 4274 res = DDI_INTR_CLAIMED;
4275 4275
4276 4276 done = 1;
4277 4277 fdc->c_csb.csb_dcsr_rslt = 1;
4278 4278 FDERRPRINT(FDEP_L1, FDEM_INTR,
4279 4279 (C, "fdintr_dma: Error pending\n"));
4280 4280 reset_dma_controller(fdc);
4281 4281 set_dma_control_register(fdc, DCSR_INIT_BITS);
4282 4282 break;
4283 4283 }
4284 4284
4285 4285 /* TCBUG kludge */
4286 4286 if ((fdc->c_fdtype & FDCTYPE_TCBUG) &&
4287 4287 ((fdc->c_csb.csb_rslt[0] & IC_SR0) == 0x40) &&
4288 4288 (fdc->c_csb.csb_rslt[1] & EN_SR1)) {
4289 4289
4290 4290 fdc->c_csb.csb_rslt[0] &= ~IC_SR0;
4291 4291
4292 4292 fdc->c_csb.csb_rslt[1] &= ~EN_SR1;
4293 4293
4294 4294
4295 4295 }
4296 4296
4297 4297
4298 4298 /* Exit if there were errors in the DMA */
4299 4299 if (((fdc->c_csb.csb_rslt[0] & IC_SR0) != 0) ||
4300 4300 (fdc->c_csb.csb_rslt[1] != 0) ||
4301 4301 (fdc->c_csb.csb_rslt[2] != 0)) {
4302 4302 done = 1;
4303 4303 FDERRPRINT(FDEP_L1, FDEM_INTR,
4304 4304 (C, "fdintr_dma: errors in command\n"));
4305 4305
4306 4306
4307 4307 break;
4308 4308 }
4309 4309
4310 4310
4311 4311 FDERRPRINT(FDEP_L1, FDEM_INTR,
4312 4312 (C, "fdintr_dma: dbcr 0x%x\n",
4313 4313 get_data_count_register(fdc)));
4314 4314 /*
4315 4315 * The csb_ccount is the number of cookies that still
4316 4316 * need to be processed. A cookie was just processed
4317 4317 * so decrement the cookie counter.
4318 4318 */
4319 4319 if (fdc->c_csb.csb_ccount == 0) {
4320 4320 done = 1;
4321 4321 break;
4322 4322 }
4323 4323 fdc->c_csb.csb_ccount--;
4324 4324 ccount = fdc->c_csb.csb_ccount;
4325 4325
4326 4326 windex = fdc->c_csb.csb_windex;
4327 4327
4328 4328 /*
4329 4329 * If there are no more cookies and all the windows
4330 4330 * have been DMA'd, then DMA is done.
4331 4331 *
4332 4332 */
4333 4333 if ((ccount == 0) && (windex == fdc->c_csb.csb_nwin)) {
4334 4334
4335 4335 done = 1;
4336 4336
4337 4337 /*
4338 4338 * The handle is unbound in fdexec
4339 4339 */
4340 4340
4341 4341 break;
4342 4342 }
4343 4343
4344 4344 if (ccount != 0) {
4345 4345 /* process the next cookie */
4346 4346 ddi_dma_nextcookie(fdc->c_dmahandle,
4347 4347 &fdc->c_csb.csb_dmacookie);
4348 4348
4349 4349 FDERRPRINT(FDEP_L1, FDEM_INTR,
4350 4350 (C, "cookie addr 0x%" PRIx64 "\n",
4351 4351 fdc->c_csb.csb_dmacookie.dmac_laddress));
4352 4352
4353 4353 FDERRPRINT(FDEP_L1, FDEM_INTR,
4354 4354 (C, "cookie length %lu\n",
4355 4355 fdc->c_csb.csb_dmacookie.dmac_size));
4356 4356
4357 4357 } else {
4358 4358
4359 4359 (void) ddi_dma_getwin(fdc->c_dmahandle,
4360 4360 fdc->c_csb.csb_windex,
4361 4361 &off, &len,
4362 4362 &fdc->c_csb.csb_dmacookie,
4363 4363 &fdc->c_csb.csb_ccount);
4364 4364 fdc->c_csb.csb_windex++;
4365 4365
4366 4366 FDERRPRINT(FDEP_L1, FDEM_INTR,
4367 4367 (C, "fdintr_dma: process %d window\n",
4368 4368 fdc->c_csb.csb_windex));
4369 4369
4370 4370 FDERRPRINT(FDEP_L1, FDEM_INTR,
4371 4371 (C, "fdintr_dma: process no. cookies %d\n",
4372 4372 fdc->c_csb.csb_ccount));
4373 4373
4374 4374 FDERRPRINT(FDEP_L1, FDEM_INTR,
4375 4375 (C, "cookie addr 0x%" PRIx64 "\n",
4376 4376 fdc->c_csb.csb_dmacookie.dmac_laddress));
4377 4377
4378 4378 FDERRPRINT(FDEP_L1, FDEM_INTR,
4379 4379 (C, "cookie length %lu\n",
4380 4380 fdc->c_csb.csb_dmacookie.dmac_size));
4381 4381 }
4382 4382
4383 4383 /*
4384 4384 * Program the DMA engine with the length and
4385 4385 * the address of the transfer
4386 4386 */
4387 4387
4388 4388 ASSERT(fdc->c_csb.csb_dmacookie.dmac_size);
4389 4389
4390 4390 set_data_count_register(fdc,
4391 4391 fdc->c_csb.csb_dmacookie.dmac_size);
4392 4392 set_data_address_register(fdc,
4393 4393 fdc->c_csb.csb_dmacookie.dmac_laddress);
4394 4394
4395 4395 FDERRPRINT(FDEP_L1, FDEM_INTR, (C,
4396 4396 "fdintr_dma: size 0x%lx\n",
4397 4397 fdc->c_csb.csb_dmacookie.dmac_size));
4398 4398
4399 4399
4400 4400 /* reprogram the controller */
4401 4401 fdc->c_csb.csb_cmds[2] = fdc->c_csb.csb_rslt[3];
4402 4402 fdc->c_csb.csb_cmds[3] = fdc->c_csb.csb_rslt[4];
4403 4403 fdc->c_csb.csb_cmds[4] = fdc->c_csb.csb_rslt[5];
4404 4404 fdc->c_csb.csb_cmds[1] = (fdc->c_csb.csb_cmds[1]
4405 4405 & ~0x04) | (fdc->c_csb.csb_rslt[4] << 2);
4406 4406
4407 4407 for (i = 0; i < (int)fdc->c_csb.csb_ncmds; i++) {
4408 4408
4409 4409 /*
4410 4410 * Test the readiness of the controller
4411 4411 * to receive the cmd
4412 4412 */
4413 4413 for (to = FD_CRETRY; to; to--) {
4414 4414 if ((Msr(fdc) & (DIO|RQM)) == RQM)
4415 4415 break;
4416 4416 }
4417 4417 if (to == 0) {
4418 4418 FDERRPRINT(FDEP_L2, FDEM_EXEC,
4419 4419 (C,
4420 4420 "fdc: no RQM - stat 0x%x\n",
4421 4421 Msr(fdc)));
4422 4422 /* stop the DMA from happening */
4423 4423 fdc->c_csb.csb_status = 2;
4424 4424 done = 1;
4425 4425 break;
4426 4426 }
4427 4427
4428 4428 Set_Fifo(fdc, fdc->c_csb.csb_cmds[i]);
4429 4429
4430 4430 FDERRPRINT(FDEP_L1, FDEM_INTR,
4431 4431 (C,
4432 4432 "fdintr_dma: sent 0x%x, Msr 0x%x\n",
4433 4433 fdc->c_csb.csb_cmds[i], Msr(fdc)));
4434 4434 }
4435 4435
4436 4436 /* reenable DMA */
4437 4437 if ((!not_cheerio) && (!done))
4438 4438 set_dma_control_register(fdc, tmp_dcsr |
4439 4439 DCSR_EN_DMA);
4440 4440 break;
4441 4441
4442 4442 case 0x2:
4443 4443 /* seek/recal type cmd */
4444 4444 FDERRPRINT(FDEP_L1, FDEM_INTR,
4445 4445 (C, "fintr_dma: opmode 2\n"));
4446 4446
4447 4447 /*
4448 4448 * See if the interrupt is from the DMA engine,
4449 4449 * which will only interrupt if there was an error.
4450 4450 */
4451 4451 if ((!not_cheerio) && (tmp_dcsr & DCSR_ERR_PEND)) {
4452 4452 res = DDI_INTR_CLAIMED;
4453 4453 done = 1;
4454 4454 fdc->c_csb.csb_dcsr_rslt = 1;
4455 4455 reset_dma_controller(fdc);
4456 4456 set_dma_control_register(fdc, DCSR_INIT_BITS);
4457 4457
4458 4458 break;
4459 4459 }
4460 4460
4461 4461
4462 4462 /* See if the interrupt is from the floppy controller */
4463 4463 if (not_cheerio || (tmp_dcsr & DCSR_INT_PEND)) {
4464 4464
4465 4465 res = DDI_INTR_CLAIMED;
4466 4466
4467 4467
4468 4468 /*
4469 4469 * Wait until there's no longer a command
4470 4470 * in progress
4471 4471 */
4472 4472
4473 4473 FDERRPRINT(FDEP_L1, FDEM_INTR,
4474 4474 (C, "fdintr_dma: interrupt pending\n"));
4475 4475 i = 0;
4476 4476 while (((Msr(fdc) & CB)) && (i < 10000)) {
4477 4477 i++;
4478 4478 }
4479 4479
4480 4480 if (i == 10000)
4481 4481 FDERRPRINT(FDEP_L1, FDEM_INTR,
4482 4482 (C, "2nd loop overran !!!\n"));
4483 4483
4484 4484 /*
4485 4485 * Check the RQM bit to see if the controller is
4486 4486 * ready to transfer status of the command.
4487 4487 */
4488 4488 i = 0;
4489 4489 while ((!(Msr(fdc) & RQM)) && (i < 10000)) {
4490 4490 i++;
4491 4491 }
4492 4492
4493 4493 if (i == 10000)
4494 4494 FDERRPRINT(FDEP_L1, FDEM_INTR,
4495 4495 (C, "3rd loop overran !!!\n"));
4496 4496
4497 4497 /*
4498 4498 * Issue the Sense Interrupt Status Command
4499 4499 */
4500 4500 Set_Fifo(fdc, SNSISTAT);
4501 4501
4502 4502 i = 0;
4503 4503 while ((!(Msr(fdc) & RQM)) && (i < 10000)) {
4504 4504 i++;
4505 4505 }
4506 4506 if (i == 10000)
4507 4507 FDERRPRINT(FDEP_L1, FDEM_INTR,
4508 4508 (C, "4th loop overran !!!\n"));
4509 4509
4510 4510 /* Store the first result byte */
4511 4511 fdc->c_csb.csb_rslt[0] = Fifo(fdc);
4512 4512
4513 4513 i = 0;
4514 4514 while ((!(Msr(fdc) & RQM)) && (i < 10000)) {
4515 4515 i++;
4516 4516 }
4517 4517 if (i == 10000)
4518 4518 FDERRPRINT(FDEP_L1, FDEM_INTR,
4519 4519 (C, "5th loop overran !!!\n"));
4520 4520
4521 4521 /* Store the second result byte */
4522 4522 fdc->c_csb.csb_rslt[1] = Fifo(fdc);
4523 4523
4524 4524 done = 1;
4525 4525 }
4526 4526
4527 4527 }
4528 4528
4529 4529 /*
4530 4530 * We are done with the actual interrupt handling here.
4531 4531 * The portion below should be actually be done by fd_lointr().
4532 4532 * We should be triggering the fd_lointr here and exiting.
4533 4533 * However for want of time this will be done in the next FIX.
4534 4534 *
4535 4535 * Hence for now we will release hilock only and keep the remaining
4536 4536 * code as it is.
4537 4537 * Releasing of hilock ensures that we don't hold on to the
4538 4538 * lolock and hilock at the same time.
4539 4539 * hilock is acquired each time dma related registers are accessed.
4540 4540 */
4541 4541 mutex_exit(&fdc->c_hilock);
4542 4542 /* Make signal and get out of interrupt handler */
4543 4543 if (done) {
4544 4544 mutex_enter(&fdc->c_lolock);
4545 4545
4546 4546 fdc->c_csb.csb_opmode = 0;
4547 4547
4548 4548 /* reset watchdog timer if armed and not already triggered */
4549 4549
4550 4550
4551 4551 if (fdc->c_timeid) {
4552 4552 timeout_id_t timeid = fdc->c_timeid;
4553 4553 fdc->c_timeid = 0;
4554 4554 mutex_exit(&fdc->c_lolock);
4555 4555 (void) untimeout(timeid);
4556 4556 mutex_enter(&fdc->c_lolock);
4557 4557 }
4558 4558
4559 4559
4560 4560 if (fdc->c_flags & FDCFLG_WAITING) {
4561 4561 /*
4562 4562 * somebody's waiting on finish of fdctlr/csb,
4563 4563 * wake them
4564 4564 */
4565 4565
4566 4566 FDERRPRINT(FDEP_L1, FDEM_INTR,
4567 4567 (C, "fdintr_dma: signal the waiter\n"));
4568 4568
4569 4569 fdc->c_flags ^= FDCFLG_WAITING;
4570 4570 cv_signal(&fdc->c_iocv);
4571 4571
4572 4572 /*
4573 4573 * FDCFLG_BUSY is NOT cleared, NOR is the csb given
4574 4574 * back; the operation just finished can look at the csb
4575 4575 */
4576 4576 } else {
4577 4577 FDERRPRINT(FDEP_L1, FDEM_INTR,
4578 4578 (C, "fdintr_dma: nobody sleeping (%x %x %x)\n",
4579 4579 fdc->c_csb.csb_rslt[0], fdc->c_csb.csb_rslt[1],
4580 4580 fdc->c_csb.csb_rslt[2]));
4581 4581 }
4582 4582 mutex_exit(&fdc->c_lolock);
4583 4583 }
4584 4584 /* update high level interrupt counter */
4585 4585 if (fdc->c_intrstat)
4586 4586 KIOIP->intrs[KSTAT_INTR_HARD]++;
4587 4587
4588 4588
4589 4589 FDERRPRINT(FDEP_L1, FDEM_INTR, (C, "fdintr_dma: done\n"));
4590 4590 return (res);
4591 4591 }
4592 4592
4593 4593 /*
4594 4594 * fd_lointr
4595 4595 * This is the low level SW interrupt handler triggered by the high
4596 4596 * level interrupt handler (or by fdwatch).
4597 4597 */
4598 4598 static uint_t
4599 4599 fd_lointr(caddr_t arg)
4600 4600 {
4601 4601 struct fdctlr *fdc = (struct fdctlr *)arg;
4602 4602 struct fdcsb *csb;
4603 4603
4604 4604 csb = &fdc->c_csb;
4605 4605 FDERRPRINT(FDEP_L1, FDEM_INTR, (C, "fdintr: opmode %d\n",
4606 4606 csb->csb_opmode));
4607 4607 /*
4608 4608 * Check that lowlevel interrupt really meant to trigger us.
4609 4609 */
4610 4610 if (csb->csb_opmode != 4) {
4611 4611 /*
4612 4612 * This should probably be protected, but, what the
4613 4613 * heck...the cost isn't worth the accuracy for this
4614 4614 * statistic.
4615 4615 */
4616 4616 if (fdc->c_intrstat)
4617 4617 KIOIP->intrs[KSTAT_INTR_SPURIOUS]++;
4618 4618 return (DDI_INTR_UNCLAIMED);
4619 4619 }
4620 4620
4621 4621 mutex_enter(&fdc->c_lolock);
4622 4622 csb->csb_opmode = 0;
4623 4623
4624 4624 /* reset watchdog timer if armed and not already triggered */
4625 4625 if (fdc->c_timeid) {
4626 4626 timeout_id_t timeid = fdc->c_timeid;
4627 4627 fdc->c_timeid = 0;
4628 4628 mutex_exit(&fdc->c_lolock);
4629 4629 (void) untimeout(timeid);
4630 4630 mutex_enter(&fdc->c_lolock);
4631 4631
4632 4632 }
4633 4633
4634 4634 if (fdc->c_flags & FDCFLG_WAITING) {
4635 4635 /*
4636 4636 * somebody's waiting on finish of fdctlr/csb, wake them
4637 4637 */
4638 4638 fdc->c_flags ^= FDCFLG_WAITING;
4639 4639 cv_signal(&fdc->c_iocv);
4640 4640
4641 4641 /*
4642 4642 * FDCFLG_BUSY is NOT cleared, NOR is the csb given back; so
4643 4643 * the operation just finished can look at the csb
4644 4644 */
4645 4645 } else {
4646 4646 FDERRPRINT(FDEP_L3, FDEM_INTR,
4647 4647 (C, "fdintr: nobody sleeping (%x %x %x)\n",
4648 4648 csb->csb_rslt[0], csb->csb_rslt[1], csb->csb_rslt[2]));
4649 4649 }
4650 4650 if (fdc->c_intrstat)
4651 4651 KIOIP->intrs[KSTAT_INTR_SOFT]++;
4652 4652 mutex_exit(&fdc->c_lolock);
4653 4653 return (DDI_INTR_CLAIMED);
4654 4654 }
4655 4655
4656 4656 /*
4657 4657 * fdwatch
4658 4658 * is called from timein() when a floppy operation has expired.
4659 4659 */
4660 4660 static void
4661 4661 fdwatch(void *arg)
4662 4662 {
4663 4663 struct fdctlr *fdc = arg;
4664 4664 int old_opmode;
4665 4665 struct fdcsb *csb;
4666 4666
4667 4667 FDERRPRINT(FDEP_L1, FDEM_WATC, (C, "fdwatch\n"));
4668 4668
4669 4669 mutex_enter(&fdc->c_lolock);
4670 4670 if (fdc->c_timeid == 0) {
4671 4671 /*
4672 4672 * fdintr got here first, ergo, no timeout condition..
4673 4673 */
4674 4674
4675 4675 FDERRPRINT(FDEP_L1, FDEM_WATC,
4676 4676 (C, "fdwatch: no timeout\n"));
4677 4677
4678 4678 mutex_exit(&fdc->c_lolock);
4679 4679 return;
4680 4680 }
4681 4681 fdc->c_timeid = 0;
4682 4682 csb = &fdc->c_csb;
4683 4683
4684 4684 mutex_enter(&fdc->c_hilock);
4685 4685 /*
4686 4686 * XXXX: We should probably reset the bloody chip
4687 4687 */
4688 4688 old_opmode = csb->csb_opmode;
4689 4689
4690 4690 FDERRPRINT(FDEP_L1, FDEM_WATC,
4691 4691 (C, "fd%d: timeout, opmode:%d\n", csb->csb_unit, old_opmode));
4692 4692
4693 4693 csb->csb_opmode = 4;
4694 4694 mutex_exit(&fdc->c_hilock);
4695 4695
4696 4696 FDERRPRINT(FDEP_L1, FDEM_WATC, (C, "fdwatch: cmd %s timed out\n",
4697 4697 fdcmds[csb->csb_cmds[0] & 0x1f].cmdname));
4698 4698 fdc->c_flags |= FDCFLG_TIMEDOUT;
4699 4699 csb->csb_status = CSB_CMDTO;
4700 4700
4701 4701 if ((fdc->c_fdtype & FDCTYPE_DMA) == 0) {
4702 4702 ddi_trigger_softintr(fdc->c_softid);
4703 4703 KIOIP->intrs[KSTAT_INTR_WATCHDOG]++;
4704 4704 mutex_exit(&fdc->c_lolock);
4705 4705 } else {
4706 4706 mutex_exit(&fdc->c_lolock);
4707 4707 (void) fd_lointr((caddr_t)fdctlrs);
4708 4708 }
4709 4709 }
4710 4710
4711 4711 /*
4712 4712 * fdgetcsb
4713 4713 * wait until the csb is free
4714 4714 */
4715 4715 static void
4716 4716 fdgetcsb(struct fdctlr *fdc)
4717 4717 {
4718 4718 FDERRPRINT(FDEP_L1, FDEM_GETC, (C, "fdgetcsb\n"));
4719 4719 ASSERT(mutex_owned(&fdc->c_lolock));
4720 4720 while (fdc->c_flags & FDCFLG_BUSY) {
4721 4721 fdc->c_flags |= FDCFLG_WANT;
4722 4722 cv_wait(&fdc->c_csbcv, &fdc->c_lolock);
4723 4723 }
4724 4724 fdc->c_flags |= FDCFLG_BUSY; /* got it! */
4725 4725 }
4726 4726
4727 4727 /*
4728 4728 * fdretcsb
4729 4729 * return csb
4730 4730 */
4731 4731 static void
4732 4732 fdretcsb(struct fdctlr *fdc)
4733 4733 {
4734 4734
4735 4735 ASSERT(mutex_owned(&fdc->c_lolock));
4736 4736 FDERRPRINT(FDEP_L1, FDEM_RETC, (C, "fdretcsb\n"));
4737 4737 fdc->c_flags &= ~FDCFLG_BUSY; /* let go */
4738 4738
4739 4739 fdc->c_csb.csb_read = 0;
4740 4740
4741 4741 if (fdc->c_flags & FDCFLG_WANT) {
4742 4742 fdc->c_flags ^= FDCFLG_WANT;
4743 4743 /*
4744 4744 * broadcast the signal. One thread will wake up and
4745 4745 * set the flags to FDCFLG_BUSY. If more than one thread is
4746 4746 * waiting then each thread will wake up in turn. The first
4747 4747 * thread to wake-up will set the FDCFLG_BUSY flag and the
4748 4748 * subsequent threads will will wake-up, but reset the
4749 4749 * flag to FDCFLG_WANT because the FDCFLG_BUSY bit is set.
4750 4750 */
4751 4751 cv_broadcast(&fdc->c_csbcv);
4752 4752 }
4753 4753 }
4754 4754
4755 4755
4756 4756 /*
4757 4757 * fdreset
4758 4758 * reset THE controller, and configure it to be
4759 4759 * the way it ought to be
4760 4760 * ASSUMES: that it already owns the csb/fdctlr!
4761 4761 *
4762 4762 * - called with the low level lock held
4763 4763 */
4764 4764 static int
4765 4765 fdreset(struct fdctlr *fdc)
4766 4766 {
4767 4767 struct fdcsb *csb;
4768 4768 clock_t local_lbolt = 0;
4769 4769 timeout_id_t timeid;
4770 4770
4771 4771 FDERRPRINT(FDEP_L1, FDEM_RESE, (C, "fdreset\n"));
4772 4772
4773 4773 ASSERT(mutex_owned(&fdc->c_lolock));
4774 4774
4775 4775 /* count resets */
4776 4776 fdc->fdstats.reset++;
4777 4777
4778 4778 /*
4779 4779 * On the 82077, the DSR will clear itself after a reset. Upon exiting
4780 4780 * the reset, a polling interrupt will be generated. If the floppy
4781 4781 * interrupt is enabled, it's possible for cv_signal() to be called
4782 4782 * before cv_wait(). This will cause the system to hang. Turn off
4783 4783 * the floppy interrupt to avoid this race condition
4784 4784 */
4785 4785 if ((fdc->c_fdtype & FDCTYPE_CTRLMASK) == FDCTYPE_82077) {
4786 4786 /*
4787 4787 * We need to perform any timeouts before we Reset the
4788 4788 * controller. We cannot afford to drop the c_lolock mutex after
4789 4789 * Resetting the controller. The reason is that we get a spate
4790 4790 * of interrupts until we take the controller out of reset.
4791 4791 * The way we avoid this spate of continuous interrupts is by
4792 4792 * holding on to the c_lolock and forcing the fdintr_dma routine
4793 4793 * to go to sleep waiting for this mutex.
4794 4794 */
4795 4795 /* Do not hold the mutex across the untimeout call */
4796 4796 timeid = fdc->c_mtimeid;
4797 4797 fdc->c_mtimeid = 0;
4798 4798 if (timeid) {
4799 4799 mutex_exit(&fdc->c_lolock);
4800 4800 (void) untimeout(timeid);
4801 4801 mutex_enter(&fdc->c_lolock);
4802 4802 }
4803 4803 /* LINTED */
4804 4804 Set_dor(fdc, DMAGATE, 0);
4805 4805 FDERRPRINT(FDEP_L1, FDEM_RESE, (C, "fdreset: set dor\n"));
4806 4806 }
4807 4807
4808 4808 /* toggle software reset */
4809 4809 Dsr(fdc, SWR);
4810 4810
4811 4811 drv_usecwait(5);
4812 4812
4813 4813 FDERRPRINT(FDEP_L1, FDEM_RESE,
4814 4814 (C, "fdreset: toggled software reset\n"));
4815 4815
4816 4816 /*
4817 4817 * This sets the data rate to 500Kbps (for high density)
4818 4818 * XXX should use current characteristics instead XXX
4819 4819 */
4820 4820 Dsr(fdc, 0);
4821 4821 drv_usecwait(5);
4822 4822 switch (fdc->c_fdtype & FDCTYPE_CTRLMASK) {
4823 4823 case FDCTYPE_82077:
4824 4824 /*
4825 4825 * when we bring the controller out of reset it will generate
4826 4826 * a polling interrupt. fdintr() will field it and schedule
4827 4827 * fd_lointr(). There will be no one sleeping but we are
4828 4828 * expecting an interrupt so....
4829 4829 */
4830 4830 fdc->c_flags |= FDCFLG_WAITING;
4831 4831
4832 4832 /*
4833 4833 * The reset bit must be cleared to take the 077 out of
4834 4834 * reset state and the DMAGATE bit must be high to enable
↓ open down ↓ |
1032 lines elided |
↑ open up ↑ |
4835 4835 * interrupts.
4836 4836 */
4837 4837 /* LINTED */
4838 4838 Set_dor(fdc, DMAGATE|RESET, 1);
4839 4839
4840 4840 FDERRPRINT(FDEP_L1, FDEM_ATTA,
4841 4841 (C, "fdattach: Dor 0x%x\n", Dor(fdc)));
4842 4842
4843 4843 local_lbolt = ddi_get_lbolt();
4844 4844 if (cv_timedwait(&fdc->c_iocv, &fdc->c_lolock,
4845 - local_lbolt + drv_usectohz(1000000)) == -1) {
4845 + local_lbolt + drv_sectohz(1)) == -1) {
4846 4846 return (-1);
4847 4847 }
4848 4848 break;
4849 4849
4850 4850 default:
4851 4851 fdc->c_flags |= FDCFLG_WAITING;
4852 4852
4853 4853 /*
4854 4854 * A timed wait is not used because it's possible for the timer
4855 4855 * to go off before the controller has a chance to interrupt.
4856 4856 */
4857 4857 cv_wait(&fdc->c_iocv, &fdc->c_lolock);
4858 4858 break;
4859 4859 }
4860 4860 csb = &fdc->c_csb;
4861 4861
4862 4862 /* setup common things in csb */
4863 4863 csb->csb_unit = fdc->c_un->un_unit_no;
4864 4864 csb->csb_nrslts = 0;
4865 4865 csb->csb_opflags = CSB_OFNORESULTS;
4866 4866 csb->csb_maxretry = 0;
4867 4867 csb->csb_retrys = 0;
4868 4868
4869 4869 csb->csb_read = CSB_NULL;
4870 4870
4871 4871 /* send SPECIFY command to fdc */
4872 4872 /* csb->unit is don't care */
4873 4873 csb->csb_cmds[0] = FDRAW_SPECIFY;
4874 4874 csb->csb_cmds[1] = fdspec[0]; /* step rate, head unload time */
4875 4875 if (fdc->c_fdtype & FDCTYPE_DMA)
4876 4876 csb->csb_cmds[2] = SPEC_DMA_MODE;
4877 4877 else
4878 4878 csb->csb_cmds[2] = fdspec[1]; /* head load time, DMA mode */
4879 4879
4880 4880 csb->csb_ncmds = 3;
4881 4881
4882 4882 /* XXX for now ignore errors, they "CAN'T HAPPEN" */
4883 4883 (void) fdexec(fdc, 0); /* no FDXC_CHECKCHG, ... */
4884 4884 /* no results */
4885 4885
4886 4886 /* send CONFIGURE command to fdc */
4887 4887 /* csb->unit is don't care */
4888 4888 csb->csb_cmds[0] = CONFIGURE;
4889 4889 csb->csb_cmds[1] = fdconf[0]; /* motor info, motor delays */
4890 4890 csb->csb_cmds[2] = fdconf[1]; /* enaimplsk, disapoll, fifothru */
4891 4891 csb->csb_cmds[3] = fdconf[2]; /* track precomp */
4892 4892 csb->csb_ncmds = 4;
4893 4893
4894 4894 csb->csb_read = CSB_NULL;
4895 4895
4896 4896 csb->csb_retrys = 0;
4897 4897
4898 4898 /* XXX for now ignore errors, they "CAN'T HAPPEN" */
4899 4899 (void) fdexec(fdc, 0); /* no FDXC_CHECKCHG, ... */
4900 4900 return (0);
4901 4901 }
4902 4902
4903 4903 /*
4904 4904 * fdrecalseek
4905 4905 * performs recalibrates or seeks if the "arg" is -1 does a
4906 4906 * recalibrate on a drive, else it seeks to the cylinder of
4907 4907 * the drive. The recalibrate is also used to find a drive,
4908 4908 * ie if the drive is not there, the controller says "error"
4909 4909 * on the operation
4910 4910 * NOTE: that there is special handling of this operation in the hardware
4911 4911 * interrupt routine - it causes the operation to appear to have results;
4912 4912 * ie the results of the SENSE INTERRUPT STATUS that the hardware interrupt
4913 4913 * function did for us.
4914 4914 * NOTE: because it uses sleep/wakeup it must be protected in a critical
4915 4915 * section so create one before calling it!
4916 4916 *
4917 4917 * RETURNS: 0 for ok,
4918 4918 * else errno from fdexec,
4919 4919 * or ENODEV if error (infers hardware type error)
4920 4920 *
4921 4921 * - called with the low level lock held
4922 4922 */
4923 4923 static int
4924 4924 fdrecalseek(struct fdctlr *fdc, int unit, int arg, int execflg)
4925 4925 {
4926 4926 struct fdcsb *csb;
4927 4927 int result;
4928 4928
4929 4929 ASSERT(fdc->c_un->un_unit_no == unit);
4930 4930
4931 4931 FDERRPRINT(FDEP_L1, FDEM_RECA, (C, "fdrecalseek to %d\n", arg));
4932 4932
4933 4933 /* XXX TODO: check see argument for <= num cyls OR < 256 */
4934 4934
4935 4935 csb = &fdc->c_csb;
4936 4936 csb->csb_unit = (uchar_t)unit;
4937 4937 csb->csb_cmds[1] = unit & 0x03;
4938 4938
4939 4939 if (arg == -1) { /* is recal... */
4940 4940 csb->csb_cmds[0] = FDRAW_REZERO;
4941 4941 csb->csb_ncmds = 2;
4942 4942 } else {
4943 4943 csb->csb_cmds[0] = FDRAW_SEEK;
4944 4944 csb->csb_cmds[2] = (uchar_t)arg;
4945 4945 csb->csb_ncmds = 3;
4946 4946 }
4947 4947 csb->csb_nrslts = 2; /* 2 for SENSE INTERRUPTS */
4948 4948 csb->csb_opflags = CSB_OFSEEKOPS | CSB_OFTIMEIT;
4949 4949 /*
4950 4950 * MAYBE NYD need to set retries to different values? - depending on
4951 4951 * drive characteristics - if we get to high capacity drives
4952 4952 */
4953 4953 csb->csb_maxretry = skretry;
4954 4954 csb->csb_retrys = 0;
4955 4955
4956 4956 /* send cmd off to fdexec */
4957 4957 if (result = fdexec(fdc, FDXC_SLEEP | execflg)) {
4958 4958 goto out;
4959 4959 }
4960 4960
4961 4961 /*
4962 4962 * if recal, test for equipment check error
4963 4963 * ASSUMES result = 0 from above call
4964 4964 */
4965 4965 if (arg == -1) {
4966 4966 result = 0;
4967 4967 } else {
4968 4968 /* for seeks, any old error will do */
4969 4969 if ((csb->csb_rslt[0] & IC_SR0) || csb->csb_cmdstat)
4970 4970 result = ENODEV;
4971 4971 }
4972 4972
4973 4973 out:
4974 4974 return (result);
4975 4975 }
4976 4976
4977 4977 /*
4978 4978 * fdsensedrv
4979 4979 * do a sense_drive command. used by fdopen and fdcheckdisk.
4980 4980 *
4981 4981 * - called with the lock held
4982 4982 */
4983 4983 static int
4984 4984 fdsensedrv(struct fdctlr *fdc, int unit)
4985 4985 {
4986 4986 struct fdcsb *csb;
4987 4987
4988 4988 ASSERT(fdc->c_un->un_unit_no == unit);
4989 4989
4990 4990 csb = &fdc->c_csb;
4991 4991
4992 4992 /* setup common things in csb */
4993 4993 csb->csb_unit = (uchar_t)unit;
4994 4994 csb->csb_opflags = CSB_OFIMMEDIATE;
4995 4995 csb->csb_cmds[0] = FDRAW_SENSE_DRV;
4996 4996 /* MOT bit set means don't delay */
4997 4997 csb->csb_cmds[1] = MOT | (unit & 0x03);
4998 4998 csb->csb_ncmds = 2;
4999 4999 csb->csb_nrslts = 1;
5000 5000 csb->csb_maxretry = skretry;
5001 5001 csb->csb_retrys = 0;
5002 5002
5003 5003 /* XXX for now ignore errors, they "CAN'T HAPPEN" */
5004 5004 (void) fdexec(fdc, 0); /* DON't check changed!, no sleep */
5005 5005
5006 5006 FDERRPRINT(FDEP_L1, FDEM_CHEK,
5007 5007 (C, "fdsensedrv: result 0x%x", csb->csb_rslt[0]));
5008 5008
5009 5009 return (csb->csb_rslt[0]); /* return status byte 3 */
5010 5010 }
5011 5011
5012 5012 /*
5013 5013 * fdcheckdisk
5014 5014 * check to see if the disk is still there - do a recalibrate,
5015 5015 * then see if DSKCHG line went away, if so, diskette is in; else
5016 5016 * it's (still) out.
5017 5017 */
5018 5018
5019 5019 static int
5020 5020 fdcheckdisk(struct fdctlr *fdc, int unit)
5021 5021 {
5022 5022 auto struct fdcsb savecsb;
5023 5023 struct fdcsb *csb;
5024 5024 int err, st3;
5025 5025 int seekto; /* where to seek for reset of DSKCHG */
5026 5026
5027 5027 FDERRPRINT(FDEP_L1, FDEM_CHEK,
5028 5028 (C, "fdcheckdisk, unit %d\n", unit));
5029 5029
5030 5030 ASSERT(fdc->c_un->un_unit_no == unit);
5031 5031
5032 5032 /*
5033 5033 * save old csb
5034 5034 */
5035 5035
5036 5036 csb = &fdc->c_csb;
5037 5037 savecsb = fdc->c_csb;
5038 5038 bzero((caddr_t)csb, sizeof (*csb));
5039 5039
5040 5040 /*
5041 5041 * Read drive status to see if at TRK0, if so, seek to cyl 1,
5042 5042 * else seek to cyl 0. We do this because the controller is
5043 5043 * "smart" enough to not send any step pulses (which are how
5044 5044 * the DSKCHG line gets reset) if it sees TRK0 'cause it
5045 5045 * knows the drive is already recalibrated.
5046 5046 */
5047 5047 st3 = fdsensedrv(fdc, unit);
5048 5048
5049 5049 /* check TRK0 bit in status */
5050 5050 if (st3 & T0_SR3)
5051 5051 seekto = 1; /* at TRK0, seek out */
5052 5052 else
5053 5053 seekto = 0;
5054 5054
5055 5055 /*
5056 5056 * DON'T recurse check changed
5057 5057 */
5058 5058 err = fdrecalseek(fdc, unit, seekto, 0);
5059 5059
5060 5060 /* "restore" old csb, check change state */
5061 5061 fdc->c_csb = savecsb;
5062 5062
5063 5063 /* any recal/seek errors are too serious to attend to */
5064 5064 if (err) {
5065 5065 FDERRPRINT(FDEP_L2, FDEM_CHEK,
5066 5066 (C, "fdcheckdisk err %d\n", err));
5067 5067 return (err);
5068 5068 }
5069 5069
5070 5070 /*
5071 5071 * if disk change still asserted, no diskette in drive!
5072 5072 */
5073 5073 if (fdsense_chng(fdc, csb->csb_unit)) {
5074 5074 FDERRPRINT(FDEP_L2, FDEM_CHEK,
5075 5075 (C, "fdcheckdisk no disk\n"));
5076 5076 return (1);
5077 5077 }
5078 5078 return (0);
5079 5079 }
5080 5080
5081 5081 /*
5082 5082 * fdselect() - select drive, needed for external to chip select logic
5083 5083 * fdeject() - ejects drive, must be previously selected
5084 5084 * fdsense_chng() - sense disk changed line from previously selected drive
5085 5085 * return s 1 is signal asserted, else 0
5086 5086 */
5087 5087 /* ARGSUSED */
5088 5088 static void
5089 5089 fdselect(struct fdctlr *fdc, int unit, int on)
5090 5090 {
5091 5091
5092 5092 ASSERT(fdc->c_un->un_unit_no == unit);
5093 5093
5094 5094 FDERRPRINT(FDEP_L1, FDEM_DSEL,
5095 5095 (C, "fdselect, unit %d, on = %d\n", unit, on));
5096 5096
5097 5097 switch (fdc->c_fdtype & FDCTYPE_AUXIOMASK) {
5098 5098 case FDCTYPE_MACHIO:
5099 5099 set_auxioreg(AUX_DRVSELECT, on);
5100 5100 break;
5101 5101
5102 5102 case FDCTYPE_SLAVIO:
5103 5103 case FDCTYPE_CHEERIO:
5104 5104 FDERRPRINT(FDEP_L1, FDEM_ATTA,
5105 5105 (C, "fdselect: (before) Dor 0x%x\n", Dor(fdc)));
5106 5106
5107 5107 if (unit == 0) {
5108 5108 Set_dor(fdc, DRVSEL, !on);
5109 5109 } else {
5110 5110 Set_dor(fdc, DRVSEL, on);
5111 5111 }
5112 5112
5113 5113 FDERRPRINT(FDEP_L1, FDEM_ATTA,
5114 5114 (C, "fdselect: Dor 0x%x\n", Dor(fdc)));
5115 5115
5116 5116 break;
5117 5117
5118 5118 default:
5119 5119 break;
5120 5120 }
5121 5121 }
5122 5122
5123 5123 /* ARGSUSED */
5124 5124 static void
5125 5125 fdeject(struct fdctlr *fdc, int unit)
5126 5126 {
5127 5127 struct fdunit *un;
5128 5128
5129 5129 ASSERT(fdc->c_un->un_unit_no == unit);
5130 5130
5131 5131 un = fdc->c_un;
5132 5132
5133 5133 FDERRPRINT(FDEP_L1, FDEM_EJEC, (C, "fdeject\n"));
5134 5134 /*
5135 5135 * assume delay of function calling sufficient settling time
5136 5136 * eject line is NOT driven by inverter so it is true low
5137 5137 */
5138 5138 switch (fdc->c_fdtype & FDCTYPE_AUXIOMASK) {
5139 5139 case FDCTYPE_MACHIO:
5140 5140 set_auxioreg(AUX_EJECT, 0);
5141 5141 drv_usecwait(2);
5142 5142 set_auxioreg(AUX_EJECT, 1);
5143 5143 break;
5144 5144
5145 5145 case FDCTYPE_SLAVIO:
5146 5146 if (!(Dor(fdc) & MOTEN(unit))) {
5147 5147 /* LINTED */
5148 5148 Set_dor(fdc, MOTEN(unit), 1);
5149 5149 }
5150 5150 drv_usecwait(2); /* just to settle */
5151 5151 /* LINTED */
5152 5152 Set_dor(fdc, EJECT, 1);
5153 5153 drv_usecwait(2);
5154 5154 /* LINTED */
5155 5155 Set_dor(fdc, EJECT, 0);
5156 5156 break;
5157 5157 case FDCTYPE_CHEERIO:
5158 5158 if (!(Dor(fdc) & MOTEN(unit))) {
5159 5159 /* LINTED */
5160 5160 Set_dor(fdc, MOTEN(unit), 1);
5161 5161 }
5162 5162 drv_usecwait(2); /* just to settle */
5163 5163 /* LINTED */
5164 5164 Set_dor(fdc, EJECT_DMA, 1);
5165 5165 drv_usecwait(2);
5166 5166 /* LINTED */
5167 5167 Set_dor(fdc, EJECT_DMA, 0);
5168 5168 break;
5169 5169 }
5170 5170 /*
5171 5171 * XXX set ejected state?
5172 5172 */
5173 5173 un->un_ejected = 1;
5174 5174 }
5175 5175
5176 5176 /* ARGSUSED */
5177 5177 static int
5178 5178 fdsense_chng(struct fdctlr *fdc, int unit)
5179 5179 {
5180 5180 int changed = 0;
5181 5181
5182 5182 FDERRPRINT(FDEP_L1, FDEM_SCHG, (C, "fdsense_chng:start\n"));
5183 5183
5184 5184 ASSERT(fdc->c_un->un_unit_no == unit);
5185 5185
5186 5186 /*
5187 5187 * Do not turn on the motor of a pollable drive
5188 5188 */
5189 5189 if (fd_pollable) {
5190 5190 FDERRPRINT(FDEP_L1, FDEM_SCHG, (C, "pollable: don't turn on motor\n"));
5191 5191 /*
5192 5192 * Invert the sense of the DSKCHG for pollable drives
5193 5193 */
5194 5194 if (Dir(fdc) & DSKCHG)
5195 5195 changed = 0;
5196 5196 else
5197 5197 changed = 1;
5198 5198
5199 5199 return (changed);
5200 5200 }
5201 5201
5202 5202 switch (fdc->c_fdtype & FDCTYPE_AUXIOMASK) {
5203 5203 case FDCTYPE_MACHIO:
5204 5204 if (*fdc->c_auxiova & AUX_DISKCHG)
5205 5205 changed = 1;
5206 5206 break;
5207 5207
5208 5208 case FDCTYPE_SB:
5209 5209 case FDCTYPE_SLAVIO:
5210 5210 case FDCTYPE_CHEERIO:
5211 5211 if (!(Dor(fdc) & MOTEN(unit))) {
5212 5212 /* LINTED */
5213 5213 Set_dor(fdc, MOTEN(unit), 1);
5214 5214 }
5215 5215 drv_usecwait(2); /* just to settle */
5216 5216 if (Dir(fdc) & DSKCHG)
5217 5217 changed = 1;
5218 5218 break;
5219 5219 }
5220 5220
5221 5221 FDERRPRINT(FDEP_L1, FDEM_SCHG, (C, "fdsense_chng:end\n"));
5222 5222
5223 5223 return (changed);
5224 5224 }
5225 5225
5226 5226 /*
5227 5227 * if it can read a valid label it does so, else it will use a
5228 5228 * default. If it can`t read the diskette - that is an error.
5229 5229 *
5230 5230 * RETURNS: 0 for ok - meaning that it could at least read the device,
5231 5231 * !0 for error XXX TBD NYD error codes
5232 5232 *
5233 5233 * - called with the low level lock held
5234 5234 */
5235 5235 static int
5236 5236 fdgetlabel(struct fdctlr *fdc, int unit)
5237 5237 {
5238 5238 struct dk_label *label = NULL;
5239 5239 struct fdunit *un;
5240 5240 short *sp;
5241 5241 short count;
5242 5242 short xsum; /* checksum */
5243 5243 int i, tries;
5244 5244 int err = 0;
5245 5245 short oldlvl;
5246 5246
5247 5247 FDERRPRINT(FDEP_L1, FDEM_GETL,
5248 5248 (C, "fdgetlabel: unit %d\n", unit));
5249 5249
5250 5250 un = fdc->c_un;
5251 5251 un->un_flags &= ~(FDUNIT_UNLABELED);
5252 5252
5253 5253 ASSERT(fdc->c_un->un_unit_no == unit);
5254 5254
5255 5255 /* Do not print errors since this is a private cmd */
5256 5256
5257 5257 oldlvl = fderrlevel;
5258 5258
5259 5259
5260 5260 fderrlevel = FDEP_L4;
5261 5261
5262 5262 label = (struct dk_label *)
5263 5263 kmem_zalloc(sizeof (struct dk_label), KM_SLEEP);
5264 5264
5265 5265 /*
5266 5266 * try different characteristics (ie densities) by attempting to read
5267 5267 * from the diskette. The diskette may not be present or
5268 5268 * is unformatted.
5269 5269 *
5270 5270 * First, the last sector of the first track is read. If this
5271 5271 * passes, attempt to read the last sector + 1 of the first track.
5272 5272 * For example, for a high density diskette, sector 18 is read. If
5273 5273 * the diskette is high density, this will pass. Next, try to
5274 5274 * read sector 19 of the first track. This should fail. If it
5275 5275 * passes, this is not a high density diskette. Finally, read
5276 5276 * the first sector which should contain a label.
5277 5277 *
5278 5278 * if un->un_curfdtype is -1 then the current characteristics
5279 5279 * were set by FDIOSCHAR and need to try it as well as everything
5280 5280 * in the table
5281 5281 */
5282 5282 if (un->un_curfdtype == -1) {
5283 5283 tries = nfdtypes+1;
5284 5284 FDERRPRINT(FDEP_L1, FDEM_GETL,
5285 5285 (C, "fdgetl: un_curfdtype is -1\n"));
5286 5286
5287 5287 } else {
5288 5288 tries = nfdtypes;
5289 5289
5290 5290 /* Always start with the highest density (1.7MB) */
5291 5291 un->un_curfdtype = 0;
5292 5292 *(un->un_chars) = fdtypes[un->un_curfdtype];
5293 5293 }
5294 5294
5295 5295 FDERRPRINT(FDEP_L1, FDEM_GETL,
5296 5296 (C, "fdgetl: no. of tries %d\n", tries));
5297 5297 FDERRPRINT(FDEP_L1, FDEM_GETL,
5298 5298 (C, "fdgetl: no. of curfdtype %d\n", un->un_curfdtype));
5299 5299
5300 5300 for (i = 0; i < tries; i++) {
5301 5301 FDERRPRINT(FDEP_L1, FDEM_GETL,
5302 5302 (C, "fdgetl: trying %d\n", i));
5303 5303
5304 5304 if (!(err = fdrw(fdc, unit, FDREAD, 0, 0,
5305 5305 un->un_chars->fdc_secptrack, (caddr_t)label,
5306 5306 sizeof (struct dk_label))) &&
5307 5307
5308 5308 fdrw(fdc, unit, FDREAD, 0, 0,
5309 5309 un->un_chars->fdc_secptrack + 1,
5310 5310 (caddr_t)label, sizeof (struct dk_label)) &&
5311 5311
5312 5312 !(err = fdrw(fdc, unit, FDREAD, 0, 0, 1, (caddr_t)label,
5313 5313 sizeof (struct dk_label)))) {
5314 5314
5315 5315 FDERRPRINT(FDEP_L1, FDEM_GETL,
5316 5316 (C, "fdgetl: succeeded\n"));
5317 5317
5318 5318 break;
5319 5319 }
5320 5320
5321 5321 /*
5322 5322 * try the next entry in the characteristics tbl
5323 5323 * If curfdtype is -1, the nxt entry in tbl is 0 (the first).
5324 5324 */
5325 5325
5326 5326 un->un_curfdtype = (un->un_curfdtype + 1) % nfdtypes;
5327 5327 *(un->un_chars) = fdtypes[un->un_curfdtype];
5328 5328
5329 5329
5330 5330 }
5331 5331
5332 5332 /* print errors again */
5333 5333 fderrlevel = oldlvl;
5334 5334
5335 5335 /* Couldn't read anything */
5336 5336 if (err) {
5337 5337
5338 5338 /* The default characteristics are high density (1.4MB) */
5339 5339 un->un_curfdtype = 1;
5340 5340 *(un->un_chars) = fdtypes[un->un_curfdtype];
5341 5341
5342 5342 fdunpacklabel(&fdlbl_high_80, &un->un_label);
5343 5343
5344 5344 FDERRPRINT(FDEP_L1, FDEM_GETL,
5345 5345 (C, "fdgetl: Can't autosense diskette\n"));
5346 5346
5347 5347 goto out;
5348 5348 }
5349 5349
5350 5350 FDERRPRINT(FDEP_L1, FDEM_GETL,
5351 5351 (C, "fdgetl: fdtype=%d !!!\n", un->un_curfdtype));
5352 5352 FDERRPRINT(FDEP_L1, FDEM_GETL,
5353 5353 (C, "fdgetl: rate=%d ssize=%d !!!\n",
5354 5354 un->un_chars->fdc_transfer_rate, un->un_chars->fdc_sec_size));
5355 5355
5356 5356 /*
5357 5357 * _something_ was read - look for unixtype label
5358 5358 */
5359 5359 if (label->dkl_magic != DKL_MAGIC) {
5360 5360
5361 5361 /*
5362 5362 * The label isn't a unix label. However, the diskette
5363 5363 * is formatted because we were able to read the first
5364 5364 * cylinder.
5365 5365 */
5366 5366
5367 5367 FDERRPRINT(FDEP_L1, FDEM_GETL,
5368 5368 (C, "fdgetl: not unix label\n"));
5369 5369
5370 5370 goto nolabel;
5371 5371 }
5372 5372
5373 5373 /*
5374 5374 * Checksum the label
5375 5375 */
5376 5376 count = sizeof (struct dk_label)/sizeof (short);
5377 5377 sp = (short *)label;
5378 5378 xsum = 0;
5379 5379 while (count--)
5380 5380 xsum ^= *sp++; /* should add up to 0 */
5381 5381 if (xsum) {
5382 5382
5383 5383 /*
5384 5384 * The checksum fails. However, the diskette is formatted
5385 5385 * because we were able to read the first cylinder
5386 5386 */
5387 5387
5388 5388 FDERRPRINT(FDEP_L1, FDEM_GETL,
5389 5389 (C, "fdgetl: bad cksum\n"));
5390 5390
5391 5391 goto nolabel;
5392 5392 }
5393 5393
5394 5394 /*
5395 5395 * The diskette has a unix label with a correct checksum.
5396 5396 * Copy the label into the unit structure
5397 5397 */
5398 5398 un->un_label = *label;
5399 5399
5400 5400 goto out;
5401 5401
5402 5402 nolabel:
5403 5403 /*
5404 5404 * The diskette doesn't have a correct unix label, but it is formatted.
5405 5405 * Use a default label according to the diskette's density
5406 5406 * (mark default used)
5407 5407 */
5408 5408 FDERRPRINT(FDEP_L1, FDEM_GETL,
5409 5409 (C, "fdgetlabel: unit %d\n", unit));
5410 5410 un->un_flags |= FDUNIT_UNLABELED;
5411 5411 switch (un->un_chars->fdc_secptrack) {
5412 5412 case 9:
5413 5413 fdunpacklabel(&fdlbl_low_80, &un->un_label);
5414 5414 break;
5415 5415 case 8:
5416 5416 fdunpacklabel(&fdlbl_medium_80, &un->un_label);
5417 5417 break;
5418 5418 case 18:
5419 5419 fdunpacklabel(&fdlbl_high_80, &un->un_label);
5420 5420 break;
5421 5421 case 21:
5422 5422 fdunpacklabel(&fdlbl_high_21, &un->un_label);
5423 5423 break;
5424 5424 default:
5425 5425 fdunpacklabel(&fdlbl_high_80, &un->un_label);
5426 5426 break;
5427 5427 }
5428 5428
5429 5429 out:
5430 5430 if (label != NULL)
5431 5431 kmem_free((caddr_t)label, sizeof (struct dk_label));
5432 5432 return (err);
5433 5433 }
5434 5434
5435 5435 /*
5436 5436 * fdrw- used only for reading labels and for DKIOCSVTOC ioctl
5437 5437 * which reads the 1 sector.
5438 5438 */
5439 5439 static int
5440 5440 fdrw(struct fdctlr *fdc, int unit, int rw, int cyl, int head,
5441 5441 int sector, caddr_t bufp, uint_t len)
5442 5442 {
5443 5443 struct fdcsb *csb;
5444 5444 struct fd_char *ch;
5445 5445 int cmdresult = 0;
5446 5446 caddr_t dma_addr;
5447 5447 size_t real_length;
5448 5448 int res;
5449 5449 ddi_device_acc_attr_t attr;
5450 5450 ddi_acc_handle_t mem_handle = NULL;
5451 5451
5452 5452 FDERRPRINT(FDEP_L1, FDEM_RW, (C, "fdrw\n"));
5453 5453
5454 5454 ASSERT(fdc->c_un->un_unit_no == unit);
5455 5455
5456 5456 CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc);
5457 5457
5458 5458 if (fdc->c_un->un_state == FD_STATE_STOPPED) {
5459 5459 mutex_exit(&fdc->c_lolock);
5460 5460 if ((pm_raise_power(fdc->c_dip, 0, PM_LEVEL_ON))
5461 5461 != DDI_SUCCESS) {
5462 5462 FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "Power change \
5463 5463 failed. \n"));
5464 5464 mutex_enter(&fdc->c_lolock);
5465 5465 return (EIO);
5466 5466 }
5467 5467
5468 5468 mutex_enter(&fdc->c_lolock);
5469 5469 }
5470 5470
5471 5471 fdgetcsb(fdc);
5472 5472 csb = &fdc->c_csb;
5473 5473 ch = fdc->c_un->un_chars;
5474 5474 if (rw == FDREAD) {
5475 5475 if (fdc->c_fdtype & FDCTYPE_TCBUG) {
5476 5476 /*
5477 5477 * kludge for lack of Multitrack functionality
5478 5478 */
5479 5479 csb->csb_cmds[0] = SK + FDRAW_RDCMD;
5480 5480 } else
5481 5481 csb->csb_cmds[0] = MT + SK + FDRAW_RDCMD;
5482 5482 } else { /* write */
5483 5483 if (fdc->c_fdtype & FDCTYPE_TCBUG) {
5484 5484 /*
5485 5485 * kludge for lack of Multitrack functionality
5486 5486 */
5487 5487 csb->csb_cmds[0] = FDRAW_WRCMD;
5488 5488 } else
5489 5489 csb->csb_cmds[0] = MT + FDRAW_WRCMD;
5490 5490 }
5491 5491
5492 5492 if (rw == FDREAD)
5493 5493 fdc->c_csb.csb_read = CSB_READ;
5494 5494 else
5495 5495 fdc->c_csb.csb_read = CSB_WRITE;
5496 5496
5497 5497 /* always or in MFM bit */
5498 5498 csb->csb_cmds[0] |= MFM;
5499 5499 csb->csb_cmds[1] = (uchar_t)(unit | ((head & 0x1) << 2));
5500 5500 if (fdc->c_fdtype & FDCTYPE_SB)
5501 5501 csb->csb_cmds[1] |= IPS;
5502 5502 csb->csb_cmds[2] = (uchar_t)cyl;
5503 5503 csb->csb_cmds[3] = (uchar_t)head;
5504 5504 csb->csb_cmds[4] = (uchar_t)sector;
5505 5505 csb->csb_cmds[5] = ch->fdc_medium ? 3 : 2; /* sector size code */
5506 5506 /*
5507 5507 * kludge for end-of-cylinder error.
5508 5508 */
5509 5509 if (fdc->c_fdtype & FDCTYPE_TCBUG)
5510 5510 csb->csb_cmds[6] = sector + (len / ch->fdc_sec_size) - 1;
5511 5511 else
5512 5512 csb->csb_cmds[6] =
5513 5513 (uchar_t)max(fdc->c_un->un_chars->fdc_secptrack, sector);
5514 5514 csb->csb_len = len;
5515 5515 csb->csb_cmds[7] = GPLN;
5516 5516 csb->csb_cmds[8] = SSSDTL;
5517 5517 csb->csb_ncmds = NCBRW;
5518 5518 csb->csb_len = len;
5519 5519 csb->csb_maxretry = 2;
5520 5520 csb->csb_retrys = 0;
5521 5521 bzero(csb->csb_rslt, NRBRW);
5522 5522 csb->csb_nrslts = NRBRW;
5523 5523 csb->csb_opflags = CSB_OFXFEROPS | CSB_OFTIMEIT;
5524 5524
5525 5525 /* If platform supports DMA, set up DMA resources */
5526 5526 if (fdc->c_fdtype & FDCTYPE_DMA) {
5527 5527
5528 5528 mutex_enter(&fdc->c_hilock);
5529 5529
5530 5530 attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
5531 5531 attr.devacc_attr_endian_flags = DDI_STRUCTURE_BE_ACC;
5532 5532 attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
5533 5533
5534 5534 res = ddi_dma_mem_alloc(fdc->c_dmahandle, len,
5535 5535 &attr, DDI_DMA_STREAMING,
5536 5536 DDI_DMA_DONTWAIT, 0, &dma_addr, &real_length,
5537 5537 &mem_handle);
5538 5538
5539 5539 if (res != DDI_SUCCESS) {
5540 5540 FDERRPRINT(FDEP_L1, FDEM_RW,
5541 5541 (C, "fdrw: dma mem alloc failed\n"));
5542 5542
5543 5543 fdretcsb(fdc);
5544 5544 mutex_exit(&fdc->c_hilock);
5545 5545 return (EIO);
5546 5546 }
5547 5547
5548 5548 FDERRPRINT(FDEP_L1, FDEM_RW, (C, "fdrw: allocated memory"));
5549 5549
5550 5550 if (fdstart_dma(fdc, dma_addr, len) != 0) {
5551 5551 fdretcsb(fdc);
5552 5552 ddi_dma_mem_free(&mem_handle);
5553 5553 mutex_exit(&fdc->c_hilock);
5554 5554 return (-1);
5555 5555
5556 5556 }
5557 5557
5558 5558 /*
5559 5559 * If the command is a write, copy the data to be written to
5560 5560 * dma_addr.
5561 5561 */
5562 5562
5563 5563 if (fdc->c_csb.csb_read == CSB_WRITE) {
5564 5564 bcopy((char *)bufp, (char *)dma_addr, len);
5565 5565 }
5566 5566
5567 5567 csb->csb_addr = dma_addr;
5568 5568 mutex_exit(&fdc->c_hilock);
5569 5569 } else {
5570 5570 csb->csb_addr = bufp;
5571 5571 }
5572 5572
5573 5573
5574 5574 FDERRPRINT(FDEP_L1, FDEM_RW, (C, "fdrw: call fdexec\n"));
5575 5575
5576 5576 if (fdexec(fdc, FDXC_SLEEP | FDXC_CHECKCHG) != 0) {
5577 5577 fdretcsb(fdc);
5578 5578
5579 5579 if (mem_handle)
5580 5580 ddi_dma_mem_free(&mem_handle);
5581 5581
5582 5582 return (EIO);
5583 5583
5584 5584 }
5585 5585
5586 5586 FDERRPRINT(FDEP_L1, FDEM_RW, (C, "fdrw: fdexec returned\n"));
5587 5587
5588 5588 /*
5589 5589 * if DMA was used and the command was a read
5590 5590 * copy the results into bufp
5591 5591 */
5592 5592 if (fdc->c_fdtype & FDCTYPE_DMA) {
5593 5593 if (fdc->c_csb.csb_read == CSB_READ) {
5594 5594 bcopy((char *)dma_addr, (char *)bufp, len);
5595 5595 }
5596 5596 ddi_dma_mem_free(&mem_handle);
5597 5597 }
5598 5598
5599 5599 if (csb->csb_cmdstat)
5600 5600 cmdresult = EIO; /* XXX TBD NYD for now */
5601 5601
5602 5602 fdretcsb(fdc);
5603 5603 return (cmdresult);
5604 5604 }
5605 5605
5606 5606 /*
5607 5607 * fdunpacklabel
5608 5608 * this unpacks a (packed) struct dk_label into a standard dk_label.
5609 5609 */
5610 5610 static void
5611 5611 fdunpacklabel(struct packed_label *from, struct dk_label *to)
5612 5612 {
5613 5613 FDERRPRINT(FDEP_L1, FDEM_PACK, (C, "fdpacklabel\n"));
5614 5614 bzero((caddr_t)to, sizeof (*to));
5615 5615 bcopy((caddr_t)&from->dkl_vname, (caddr_t)to->dkl_asciilabel,
5616 5616 sizeof (to->dkl_asciilabel));
5617 5617 to->dkl_rpm = from->dkl_rpm; /* rotations per minute */
5618 5618 to->dkl_pcyl = from->dkl_pcyl; /* # physical cylinders */
5619 5619 to->dkl_apc = from->dkl_apc; /* alternates per cylinder */
5620 5620 to->dkl_intrlv = from->dkl_intrlv; /* interleave factor */
5621 5621 to->dkl_ncyl = from->dkl_ncyl; /* # of data cylinders */
5622 5622 to->dkl_acyl = from->dkl_acyl; /* # of alternate cylinders */
5623 5623 to->dkl_nhead = from->dkl_nhead; /* # of heads in this partition */
5624 5624 to->dkl_nsect = from->dkl_nsect; /* # of 512 byte sectors per track */
5625 5625 /* logical partitions */
5626 5626 bcopy((caddr_t)from->dkl_map, (caddr_t)to->dkl_map,
5627 5627 sizeof (struct dk_map32) * NDKMAP);
5628 5628 to->dkl_vtoc = from->dkl_vtoc;
5629 5629 }
5630 5630
5631 5631 static struct fdctlr *
5632 5632 fd_getctlr(dev_t dev)
5633 5633 {
5634 5634
5635 5635 struct fdctlr *fdc = fdctlrs;
5636 5636 int ctlr = FDCTLR(dev);
5637 5637
5638 5638 while (fdc) {
5639 5639 if (ddi_get_instance(fdc->c_dip) == ctlr)
5640 5640 return (fdc);
5641 5641 fdc = fdc->c_next;
5642 5642 }
5643 5643 return (fdc);
5644 5644 }
5645 5645
5646 5646 static int
5647 5647 fd_unit_is_open(struct fdunit *un)
5648 5648 {
5649 5649 int i;
5650 5650 for (i = 0; i < NDKMAP; i++)
5651 5651 if (un->un_lyropen[i])
5652 5652 return (1);
5653 5653 for (i = 0; i < OTYPCNT - 1; i++)
5654 5654 if (un->un_regopen[i])
5655 5655 return (1);
5656 5656 return (0);
5657 5657 }
5658 5658
5659 5659 /*
5660 5660 * Return the a vtoc structure in *vtoc.
5661 5661 * The vtoc is built from information in
5662 5662 * the diskette's label.
5663 5663 */
5664 5664 static void
5665 5665 fd_build_user_vtoc(struct fdunit *un, struct vtoc *vtoc)
5666 5666 {
5667 5667 int i;
5668 5668 int nblks; /* DEV_BSIZE sectors per cylinder */
5669 5669 struct dk_map2 *lpart;
5670 5670 struct dk_map32 *lmap;
5671 5671 struct partition *vpart;
5672 5672
5673 5673 bzero(vtoc, sizeof (struct vtoc));
5674 5674
5675 5675 /* Initialize info. needed by mboot. (unsupported) */
5676 5676 vtoc->v_bootinfo[0] = un->un_label.dkl_vtoc.v_bootinfo[0];
5677 5677 vtoc->v_bootinfo[1] = un->un_label.dkl_vtoc.v_bootinfo[1];
5678 5678 vtoc->v_bootinfo[2] = un->un_label.dkl_vtoc.v_bootinfo[2];
5679 5679
5680 5680 /* Fill in vtoc sanity and version information */
5681 5681 vtoc->v_sanity = un->un_label.dkl_vtoc.v_sanity;
5682 5682 vtoc->v_version = un->un_label.dkl_vtoc.v_version;
5683 5683
5684 5684 /* Copy the volume name */
5685 5685 bcopy(un->un_label.dkl_vtoc.v_volume,
5686 5686 vtoc->v_volume, LEN_DKL_VVOL);
5687 5687
5688 5688 /*
5689 5689 * The dk_map32 structure is based on DEV_BSIZE byte blocks.
5690 5690 * However, medium density diskettes have 1024 byte blocks.
5691 5691 * The number of sectors per partition listed in the dk_map32 structure
5692 5692 * accounts for this by multiplying the number of 1024 byte
5693 5693 * blocks by 2. (See the packed_label initializations.) The
5694 5694 * 1024 byte block size can not be listed for medium density
5695 5695 * diskettes because the kernel is hard coded for DEV_BSIZE
5696 5696 * blocks.
5697 5697 */
5698 5698 vtoc->v_sectorsz = DEV_BSIZE;
5699 5699 vtoc->v_nparts = un->un_label.dkl_vtoc.v_nparts;
5700 5700
5701 5701 /* Copy the reserved space */
5702 5702 bcopy(un->un_label.dkl_vtoc.v_reserved,
5703 5703 vtoc->v_reserved, sizeof (un->un_label.dkl_vtoc.v_reserved));
5704 5704 /*
5705 5705 * Convert partitioning information.
5706 5706 *
5707 5707 * Note the conversion from starting cylinder number
5708 5708 * to starting sector number.
5709 5709 */
5710 5710 lmap = un->un_label.dkl_map;
5711 5711 lpart = un->un_label.dkl_vtoc.v_part;
5712 5712 vpart = vtoc->v_part;
5713 5713
5714 5714 nblks = (un->un_chars->fdc_nhead * un->un_chars->fdc_secptrack *
5715 5715 un->un_chars->fdc_sec_size) / DEV_BSIZE;
5716 5716
5717 5717 for (i = 0; i < V_NUMPAR; i++) {
5718 5718 vpart->p_tag = lpart->p_tag;
5719 5719 vpart->p_flag = lpart->p_flag;
5720 5720 vpart->p_start = lmap->dkl_cylno * nblks;
5721 5721 vpart->p_size = lmap->dkl_nblk;
5722 5722
5723 5723 lmap++;
5724 5724 lpart++;
5725 5725 vpart++;
5726 5726 }
5727 5727
5728 5728 /* Initialize timestamp and label */
5729 5729 bcopy(un->un_label.dkl_vtoc.v_timestamp,
5730 5730 vtoc->timestamp, sizeof (vtoc->timestamp));
5731 5731
5732 5732 bcopy(un->un_label.dkl_asciilabel,
5733 5733 vtoc->v_asciilabel, LEN_DKL_ASCII);
5734 5734 }
5735 5735
5736 5736 /*
5737 5737 * Build a label out of a vtoc structure.
5738 5738 */
5739 5739 static int
5740 5740 fd_build_label_vtoc(struct fdunit *un, struct vtoc *vtoc)
5741 5741 {
5742 5742 struct dk_map32 *lmap;
5743 5743 struct dk_map2 *lpart;
5744 5744 struct partition *vpart;
5745 5745 int nblks; /* no. blocks per cylinder */
5746 5746 int ncyl;
5747 5747 int i;
5748 5748 short sum, *sp;
5749 5749
5750 5750 /* Sanity-check the vtoc */
5751 5751 if ((vtoc->v_sanity != VTOC_SANE) ||
5752 5752 (vtoc->v_nparts > NDKMAP) || (vtoc->v_nparts <= 0)) {
5753 5753 FDERRPRINT(FDEP_L1, FDEM_IOCT,
5754 5754 (C, "fd_build_label: sanity check on vtoc failed\n"));
5755 5755 return (EINVAL);
5756 5756 }
5757 5757
5758 5758 nblks = (un->un_chars->fdc_nhead * un->un_chars->fdc_secptrack *
5759 5759 un->un_chars->fdc_sec_size) / DEV_BSIZE;
5760 5760
5761 5761 vpart = vtoc->v_part;
5762 5762
5763 5763 /*
5764 5764 * Check the partition information in the vtoc. The starting sectors
5765 5765 * must lie along partition boundaries. (NDKMAP entries are checked
5766 5766 * to ensure that the unused entries are set to 0 if vtoc->v_nparts
5767 5767 * is less than NDKMAP)
5768 5768 */
5769 5769
5770 5770 for (i = 0; i < NDKMAP; i++) {
5771 5771 if ((vpart->p_start % nblks) != 0) {
5772 5772 return (EINVAL);
5773 5773 }
5774 5774 ncyl = vpart->p_start % nblks;
5775 5775 ncyl += vpart->p_size % nblks;
5776 5776 if ((vpart->p_size % nblks) != 0)
5777 5777 ncyl++;
5778 5778 if (ncyl > un->un_chars->fdc_ncyl) {
5779 5779 return (EINVAL);
5780 5780 }
5781 5781 vpart++;
5782 5782 }
5783 5783
5784 5784 /*
5785 5785 * reinitialize the existing label
5786 5786 */
5787 5787 bzero(&un->un_label, sizeof (un->un_label));
5788 5788
5789 5789 /* Put appropriate vtoc structure fields into the disk label */
5790 5790 un->un_label.dkl_vtoc.v_bootinfo[0] = (uint32_t)vtoc->v_bootinfo[0];
5791 5791 un->un_label.dkl_vtoc.v_bootinfo[1] = (uint32_t)vtoc->v_bootinfo[1];
5792 5792 un->un_label.dkl_vtoc.v_bootinfo[2] = (uint32_t)vtoc->v_bootinfo[2];
5793 5793
5794 5794 un->un_label.dkl_vtoc.v_sanity = vtoc->v_sanity;
5795 5795 un->un_label.dkl_vtoc.v_version = vtoc->v_version;
5796 5796
5797 5797 bcopy(vtoc->v_volume, un->un_label.dkl_vtoc.v_volume, LEN_DKL_VVOL);
5798 5798
5799 5799 un->un_label.dkl_vtoc.v_nparts = vtoc->v_nparts;
5800 5800
5801 5801 bcopy(vtoc->v_reserved, un->un_label.dkl_vtoc.v_reserved,
5802 5802 sizeof (un->un_label.dkl_vtoc.v_reserved));
5803 5803
5804 5804 /*
5805 5805 * Initialize cylinder information in the label.
5806 5806 * Note the conversion from starting sector number
5807 5807 * to starting cylinder number.
5808 5808 * Return error if division results in a remainder.
5809 5809 */
5810 5810 lmap = un->un_label.dkl_map;
5811 5811 lpart = un->un_label.dkl_vtoc.v_part;
5812 5812 vpart = vtoc->v_part;
5813 5813
5814 5814 for (i = 0; i < (int)vtoc->v_nparts; i++) {
5815 5815 lpart->p_tag = vtoc->v_part[i].p_tag;
5816 5816 lpart->p_flag = vtoc->v_part[i].p_flag;
5817 5817 lmap->dkl_cylno = vpart->p_start / nblks;
5818 5818 lmap->dkl_nblk = vpart->p_size;
5819 5819
5820 5820 lmap++;
5821 5821 lpart++;
5822 5822 vpart++;
5823 5823 }
5824 5824
5825 5825 /* Copy the timestamp and ascii label */
5826 5826 for (i = 0; i < NDKMAP; i++) {
5827 5827 un->un_label.dkl_vtoc.v_timestamp[i] = vtoc->timestamp[i];
5828 5828 }
5829 5829
5830 5830
5831 5831 bcopy(vtoc->v_asciilabel, un->un_label.dkl_asciilabel, LEN_DKL_ASCII);
5832 5832
5833 5833 FDERRPRINT(FDEP_L1, FDEM_IOCT,
5834 5834 (C, "fd_build_label: asciilabel %s\n",
5835 5835 un->un_label.dkl_asciilabel));
5836 5836
5837 5837 /* Initialize the magic number */
5838 5838 un->un_label.dkl_magic = DKL_MAGIC;
5839 5839
5840 5840 un->un_label.dkl_pcyl = un->un_chars->fdc_ncyl;
5841 5841
5842 5842 /*
5843 5843 * The fdc_secptrack filed of the fd_char structure is the number
5844 5844 * of sectors per track where the sectors are fdc_sec_size. The
5845 5845 * dkl_nsect field of the dk_label structure is the number of
5846 5846 * 512 (DEVBSIZE) byte sectors per track.
5847 5847 */
5848 5848 un->un_label.dkl_nsect = (un->un_chars->fdc_secptrack *
5849 5849 un->un_chars->fdc_sec_size) / DEV_BSIZE;
5850 5850
5851 5851
5852 5852 un->un_label.dkl_ncyl = un->un_label.dkl_pcyl;
5853 5853 un->un_label.dkl_nhead = un->un_chars->fdc_nhead;
5854 5854 un->un_label.dkl_rpm = un->un_chars->fdc_medium ? 360 : 300;
5855 5855 un->un_label.dkl_intrlv = 1;
5856 5856
5857 5857 /* Create the checksum */
5858 5858 sum = 0;
5859 5859 un->un_label.dkl_cksum = 0;
5860 5860 sp = (short *)&un->un_label;
5861 5861 i = sizeof (struct dk_label)/sizeof (short);
5862 5862 while (i--) {
5863 5863 sum ^= *sp++;
5864 5864 }
5865 5865 un->un_label.dkl_cksum = sum;
5866 5866
5867 5867 return (0);
5868 5868 }
5869 5869
5870 5870 /*
5871 5871 * Check for auxio register node
5872 5872 */
5873 5873
5874 5874 int
5875 5875 fd_isauxiodip(dev_info_t *dip)
5876 5876 {
5877 5877 if (strcmp(ddi_get_name(dip), "auxio") == 0 ||
5878 5878 strcmp(ddi_get_name(dip), "auxiliary-io") == 0) {
5879 5879 return (1);
5880 5880 }
5881 5881 return (0);
5882 5882 }
5883 5883
5884 5884 /*
5885 5885 * Search for auxio register node, then for address property
5886 5886 */
5887 5887
5888 5888 caddr_t
5889 5889 fd_getauxiova(dev_info_t *dip)
5890 5890 {
5891 5891 dev_info_t *auxdip;
5892 5892 caddr_t addr;
5893 5893
5894 5894 /*
5895 5895 * Search sibling list, which happens to be safe inside attach
5896 5896 */
5897 5897 auxdip = ddi_get_child(ddi_get_parent(dip));
5898 5898 while (auxdip) {
5899 5899 if (fd_isauxiodip(auxdip))
5900 5900 break;
5901 5901 auxdip = ddi_get_next_sibling(auxdip);
5902 5902 }
5903 5903
5904 5904 if (auxdip == NULL)
5905 5905 return (NULL);
5906 5906
5907 5907 addr = (caddr_t)(uintptr_t)(caddr32_t)ddi_getprop(DDI_DEV_T_ANY,
5908 5908 auxdip, DDI_PROP_DONTPASS, "address", 0);
5909 5909
5910 5910 return (addr);
5911 5911 }
5912 5912
5913 5913
5914 5914 /*
5915 5915 * set_rotational speed
5916 5916 * 300 rpm for high and low density.
5917 5917 * 360 rpm for medium density.
5918 5918 * for now, we assume that 3rd density is supported only for Sun4M,
5919 5919 * not for Clones. (else we would have to check for 82077, and do
5920 5920 * specific things for the MEDIUM_DENSITY BIT for clones.
5921 5921 * this code should not break CLONES.
5922 5922 *
5923 5923 * REMARK: there is a SOny requirement, to deselect the drive then
5924 5924 * select it again after the medium density change, since the
5925 5925 * leading edge of the select line latches the rotational Speed.
5926 5926 * then after that, we have to wait 500 ms for the rotation to
5927 5927 * stabilize.
5928 5928 *
5929 5929 */
5930 5930 static void
5931 5931 set_rotational_speed(struct fdctlr *fdc, int unit)
5932 5932 {
5933 5933 int check;
5934 5934 int is_medium;
5935 5935
5936 5936 ASSERT(fdc->c_un->un_unit_no == unit);
5937 5937
5938 5938 /*
5939 5939 * if we do not have a Sun4m, medium density is not supported.
5940 5940 */
5941 5941 if (fdc->c_fdtype & FDCTYPE_MACHIO)
5942 5942 return;
5943 5943
5944 5944 /*
5945 5945 * if FDUNIT_SET_SPEED is set, set the speed.
5946 5946 * else,
5947 5947 * if there is a change, do it, if not leave it alone.
5948 5948 * there is a change if un->un_chars->fdc_medium does not match
5949 5949 * un->un_flags & FDUNIT_MEDIUM
5950 5950 * un->un_flags & FDUNIT_MEDIUM specifies the last setting.
5951 5951 * un->un_chars->fdc_medium specifies next setting.
5952 5952 * if there is a change, wait 500ms according to Sony spec.
5953 5953 */
5954 5954
5955 5955 is_medium = fdc->c_un->un_chars->fdc_medium;
5956 5956
5957 5957 if (fdc->c_un->un_flags & FDUNIT_SET_SPEED) {
5958 5958 check = 1;
5959 5959 } else {
5960 5960 check = is_medium ^
5961 5961 ((fdc->c_un->un_flags & FDUNIT_MEDIUM) ? 1 : 0);
5962 5962
5963 5963 /* Set the un_flags if necessary */
5964 5964
5965 5965 if (check)
5966 5966 fdc->c_un->un_flags ^= FDUNIT_MEDIUM;
5967 5967 }
5968 5968
5969 5969 fdc->c_un->un_flags &= ~FDUNIT_SET_SPEED;
5970 5970
5971 5971
5972 5972 if (check) {
5973 5973
5974 5974 fdselect(fdc, unit, 0);
5975 5975 drv_usecwait(5);
5976 5976
5977 5977 if ((fdc->c_fdtype & FDCTYPE_AUXIOMASK) == FDCTYPE_SLAVIO) {
5978 5978 Set_dor(fdc, MEDIUM_DENSITY, is_medium);
5979 5979 }
5980 5980
5981 5981 if ((fdc->c_fdtype & FDCTYPE_AUXIOMASK) == FDCTYPE_CHEERIO) {
5982 5982 if (is_medium) {
5983 5983 Set_auxio(fdc, AUX_MEDIUM_DENSITY);
5984 5984 } else {
5985 5985 Set_auxio(fdc, AUX_HIGH_DENSITY);
5986 5986 }
5987 5987
5988 5988 }
5989 5989
5990 5990 if (is_medium) {
5991 5991 drv_usecwait(5);
5992 5992 }
5993 5993
5994 5994 fdselect(fdc, unit, 1); /* Sony requirement */
5995 5995 FDERRPRINT(FDEP_L1, FDEM_EXEC, (C, "rotation:medium\n"));
5996 5996 drv_usecwait(500000);
5997 5997 }
5998 5998 }
5999 5999
6000 6000 static void
6001 6001 fd_media_watch(void *arg)
6002 6002 {
6003 6003 dev_t dev;
6004 6004 struct fdunit *un;
6005 6005 struct fdctlr *fdc;
6006 6006 int unit;
6007 6007
6008 6008 dev = (dev_t)arg;
6009 6009 fdc = fd_getctlr(dev);
6010 6010 unit = fdc->c_un->un_unit_no;
6011 6011 un = fdc->c_un;
6012 6012
6013 6013 mutex_enter(&fdc->c_lolock);
6014 6014
6015 6015 if (un->un_media_timeout_id == 0) {
6016 6016 /*
6017 6017 * Untimeout is about to be called.
6018 6018 * Don't call fd_get_media_state again
6019 6019 */
6020 6020 mutex_exit(&fdc->c_lolock);
6021 6021 return;
6022 6022 }
6023 6023
6024 6024
6025 6025 un->un_media_state = fd_get_media_state(fdc, unit);
6026 6026 cv_broadcast(&fdc->c_statecv);
6027 6027
6028 6028 mutex_exit(&fdc->c_lolock);
6029 6029
6030 6030 if (un->un_media_timeout) {
6031 6031 un->un_media_timeout_id = timeout(fd_media_watch,
6032 6032 (void *)(ulong_t)dev, un->un_media_timeout);
6033 6033 }
6034 6034 }
6035 6035
6036 6036 enum dkio_state
6037 6037 fd_get_media_state(struct fdctlr *fdc, int unit)
6038 6038 {
6039 6039 enum dkio_state state;
6040 6040
6041 6041 ASSERT(fdc->c_un->un_unit_no == unit);
6042 6042
6043 6043 if (fdsense_chng(fdc, unit)) {
6044 6044 /* check disk only if DSKCHG "high" */
6045 6045 if (fdcheckdisk(fdc, unit)) {
6046 6046 state = DKIO_EJECTED;
6047 6047 } else {
6048 6048 state = DKIO_INSERTED;
6049 6049 }
6050 6050 } else {
6051 6051 state = DKIO_INSERTED;
6052 6052 }
6053 6053 return (state);
6054 6054 }
6055 6055
6056 6056 static int
6057 6057 fd_check_media(dev_t dev, enum dkio_state state)
6058 6058 {
6059 6059 struct fdunit *un;
6060 6060 struct fdctlr *fdc;
6061 6061 int unit;
6062 6062
6063 6063 FDERRPRINT(FDEP_L1, FDEM_RW, (C, "fd_check_media: start\n"));
6064 6064
6065 6065 fdc = fd_getctlr(dev);
6066 6066 unit = fdc->c_un->un_unit_no;
6067 6067 un = fdc->c_un;
6068 6068
6069 6069 mutex_enter(&fdc->c_lolock);
6070 6070
6071 6071 CHECK_AND_WAIT_FD_STATE_SUSPENDED(fdc);
6072 6072
6073 6073 if (fdc->c_un->un_state == FD_STATE_STOPPED) {
6074 6074 mutex_exit(&fdc->c_lolock);
6075 6075 if ((pm_raise_power(fdc->c_dip, 0, PM_LEVEL_ON))
6076 6076 != DDI_SUCCESS) {
6077 6077 FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "Power change \
6078 6078 failed. \n"));
6079 6079
6080 6080 (void) pm_idle_component(fdc->c_dip, 0);
6081 6081 return (EIO);
6082 6082 }
6083 6083
6084 6084 mutex_enter(&fdc->c_lolock);
6085 6085 }
6086 6086
6087 6087 un->un_media_state = fd_get_media_state(fdc, unit);
6088 6088
6089 6089 /* turn on timeout */
6090 6090 un->un_media_timeout = drv_usectohz(fd_check_media_time);
6091 6091 un->un_media_timeout_id = timeout(fd_media_watch,
6092 6092 (void *)(ulong_t)dev, un->un_media_timeout);
6093 6093
6094 6094 while (un->un_media_state == state) {
6095 6095 if (cv_wait_sig(&fdc->c_statecv, &fdc->c_lolock) == 0) {
6096 6096 un->un_media_timeout = 0;
6097 6097 mutex_exit(&fdc->c_lolock);
6098 6098 return (EINTR);
6099 6099 }
6100 6100 }
6101 6101
6102 6102 if (un->un_media_timeout_id) {
6103 6103 timeout_id_t timeid = un->un_media_timeout_id;
6104 6104 un->un_media_timeout_id = 0;
6105 6105
6106 6106 mutex_exit(&fdc->c_lolock);
6107 6107 (void) untimeout(timeid);
6108 6108 mutex_enter(&fdc->c_lolock);
6109 6109 }
6110 6110
6111 6111 if (un->un_media_state == DKIO_INSERTED) {
6112 6112 if (fdgetlabel(fdc, unit)) {
6113 6113 mutex_exit(&fdc->c_lolock);
6114 6114 return (EIO);
6115 6115 }
6116 6116 }
6117 6117 mutex_exit(&fdc->c_lolock);
6118 6118
6119 6119 FDERRPRINT(FDEP_L1, FDEM_RW, (C, "fd_check_media: end\n"));
6120 6120 return (0);
6121 6121 }
6122 6122
6123 6123 /*
6124 6124 * fd_get_media_info :
6125 6125 * Collects medium information for
6126 6126 * DKIOCGMEDIAINFO ioctl.
6127 6127 */
6128 6128
6129 6129 static int
6130 6130 fd_get_media_info(struct fdunit *un, caddr_t buf, int flag)
6131 6131 {
6132 6132 struct dk_minfo media_info;
6133 6133 int err = 0;
6134 6134
6135 6135 media_info.dki_media_type = DK_FLOPPY;
6136 6136 media_info.dki_lbsize = un->un_chars->fdc_sec_size;
6137 6137 media_info.dki_capacity = un->un_chars->fdc_ncyl *
6138 6138 un->un_chars->fdc_secptrack * un->un_chars->fdc_nhead;
6139 6139
6140 6140 if (ddi_copyout((caddr_t)&media_info, buf,
6141 6141 sizeof (struct dk_minfo), flag))
6142 6142 err = EFAULT;
6143 6143 return (err);
6144 6144 }
6145 6145
6146 6146 /*
6147 6147 * fd_power :
6148 6148 * Power entry point of fd driver.
6149 6149 */
6150 6150
6151 6151 static int
6152 6152 fd_power(dev_info_t *dip, int component, int level)
6153 6153 {
6154 6154
6155 6155 struct fdctlr *fdc;
6156 6156 int instance;
6157 6157 int rval;
6158 6158
6159 6159 if ((level < PM_LEVEL_OFF) || (level > PM_LEVEL_ON) ||
6160 6160 (component != 0)) {
6161 6161 return (DDI_FAILURE);
6162 6162 }
6163 6163
6164 6164 instance = ddi_get_instance(dip);
6165 6165 fdc = fd_getctlr(instance << FDINSTSHIFT);
6166 6166 if (fdc->c_un == NULL)
6167 6167 return (DDI_FAILURE);
6168 6168
6169 6169 if (level == PM_LEVEL_OFF) {
6170 6170 rval = fd_pm_lower_power(fdc);
6171 6171 }
6172 6172 if (level == PM_LEVEL_ON) {
6173 6173 rval = fd_pm_raise_power(fdc);
6174 6174 }
6175 6175 return (rval);
6176 6176 }
6177 6177
6178 6178 /*
6179 6179 * fd_pm_lower_power :
6180 6180 * This function is called only during pm suspend. At this point,
6181 6181 * the power management framework thinks the device is idle for
6182 6182 * long enough to go to a low power mode. If the device is busy,
6183 6183 * then this function returns DDI_FAILURE.
6184 6184 */
6185 6185
6186 6186 static int
6187 6187 fd_pm_lower_power(struct fdctlr *fdc)
6188 6188 {
6189 6189
6190 6190 mutex_enter(&fdc->c_lolock);
6191 6191
6192 6192 if ((fdc->c_un->un_state == FD_STATE_SUSPENDED) ||
6193 6193 (fdc->c_un->un_state == FD_STATE_STOPPED)) {
6194 6194 mutex_exit(&fdc->c_lolock);
6195 6195 return (DDI_SUCCESS);
6196 6196 }
6197 6197
6198 6198
6199 6199 FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "fd_pm_lower_power called\n"));
6200 6200
6201 6201 /* if the device is busy then we fail the lower power request */
6202 6202 if (fdc->c_flags & FDCFLG_BUSY) {
6203 6203 FDERRPRINT(FDEP_L2, FDEM_PWR, (C, "fd_pm_lower_power : \
6204 6204 controller is busy.\n"));
6205 6205 mutex_exit(&fdc->c_lolock);
6206 6206 return (DDI_FAILURE);
6207 6207 }
6208 6208
6209 6209 fdc->c_un->un_state = FD_STATE_STOPPED;
6210 6210
6211 6211 mutex_exit(&fdc->c_lolock);
6212 6212 return (DDI_SUCCESS);
6213 6213 }
6214 6214
6215 6215 /*
6216 6216 * fd_pm_raise_power :
6217 6217 * This function performs the necessary steps for resuming a
6218 6218 * device, either from pm suspend or CPR. Here the controller
6219 6219 * is reset, initialized and the state is set to FD_STATE_NORMAL.
6220 6220 */
6221 6221
6222 6222 static int
6223 6223 fd_pm_raise_power(struct fdctlr *fdc)
6224 6224 {
6225 6225
6226 6226 struct fdunit *un = fdc->c_un;
6227 6227 int unit;
6228 6228
6229 6229 FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "fd_pm_raise_power called\n"));
6230 6230 mutex_enter(&fdc->c_lolock);
6231 6231 fdgetcsb(fdc);
6232 6232
6233 6233 /* Reset the dma engine */
6234 6234 if (fdc->c_fdtype & FDCTYPE_DMA) {
6235 6235 mutex_enter(&fdc->c_hilock);
6236 6236 reset_dma_controller(fdc);
6237 6237 set_dma_control_register(fdc, DCSR_INIT_BITS);
6238 6238 mutex_exit(&fdc->c_hilock);
6239 6239 }
6240 6240
6241 6241 /*
6242 6242 * Force a rotational speed set in the next
6243 6243 * call to set_rotational_speed().
6244 6244 */
6245 6245
6246 6246 fdc->c_un->un_flags |= FDUNIT_SET_SPEED;
6247 6247
6248 6248 /* Reset and configure the controller */
6249 6249 (void) fdreset(fdc);
6250 6250
6251 6251 unit = fdc->c_un->un_unit_no;
6252 6252
6253 6253 /* Recalibrate the drive */
6254 6254 if (fdrecalseek(fdc, unit, -1, 0) != 0) {
6255 6255 FDERRPRINT(FDEP_L1, FDEM_PWR, (C, "raise_power : recalibrate \
6256 6256 failed\n"));
6257 6257 fdretcsb(fdc);
6258 6258 mutex_exit(&fdc->c_lolock);
6259 6259 return (DDI_FAILURE);
6260 6260 }
6261 6261
6262 6262 /* Select the drive through the AUXIO registers */
6263 6263 fdselect(fdc, unit, 0);
6264 6264 un->un_state = FD_STATE_NORMAL;
6265 6265 fdretcsb(fdc);
6266 6266 mutex_exit(&fdc->c_lolock);
6267 6267 return (DDI_SUCCESS);
6268 6268 }
6269 6269
6270 6270 /*
6271 6271 * create_pm_components :
6272 6272 * creates the power management components for auto pm framework.
6273 6273 */
6274 6274
6275 6275 static void
6276 6276 create_pm_components(dev_info_t *dip)
6277 6277 {
6278 6278 char *un_pm_comp[] = { "NAME=spindle-motor", "0=off", "1=on"};
6279 6279
6280 6280 if (ddi_prop_update_string_array(DDI_DEV_T_NONE, dip,
6281 6281 "pm-components", un_pm_comp, 3) == DDI_PROP_SUCCESS) {
6282 6282
6283 6283 (void) pm_raise_power(dip, 0, PM_LEVEL_ON);
6284 6284 }
6285 6285 }
6286 6286
6287 6287 /*
6288 6288 * set_data_count_register(struct fdctlr *fdc, uint32_t count)
6289 6289 * Set the data count in appropriate dma register.
6290 6290 */
6291 6291
6292 6292 static void
6293 6293 set_data_count_register(struct fdctlr *fdc, uint32_t count)
6294 6294 {
6295 6295 if (fdc->c_fdtype & FDCTYPE_CHEERIO) {
6296 6296 struct cheerio_dma_reg *dma_reg;
6297 6297 dma_reg = (struct cheerio_dma_reg *)fdc->c_dma_regs;
6298 6298 ddi_put32(fdc->c_handlep_dma, &dma_reg->fdc_dbcr, count);
6299 6299 } else if (fdc->c_fdtype & FDCTYPE_SB) {
6300 6300 struct sb_dma_reg *dma_reg;
6301 6301 count = count - 1; /* 8237 needs it */
6302 6302 dma_reg = (struct sb_dma_reg *)fdc->c_dma_regs;
6303 6303 switch (fdc->sb_dma_channel) {
6304 6304 case 0 :
6305 6305 ddi_put16(fdc->c_handlep_dma,
6306 6306 (ushort_t *)&dma_reg->sb_dma_regs[DMA_0WCNT],
6307 6307 count & 0xFFFF);
6308 6308 break;
6309 6309 case 1 :
6310 6310 ddi_put16(fdc->c_handlep_dma,
6311 6311 (ushort_t *)&dma_reg->sb_dma_regs[DMA_1WCNT],
6312 6312 count & 0xFFFF);
6313 6313 break;
6314 6314 case 2 :
6315 6315 ddi_put16(fdc->c_handlep_dma,
6316 6316 (ushort_t *)&dma_reg->sb_dma_regs[DMA_2WCNT],
6317 6317 count & 0xFFFF);
6318 6318 break;
6319 6319 case 3 :
6320 6320 ddi_put16(fdc->c_handlep_dma,
6321 6321 (ushort_t *)&dma_reg->sb_dma_regs[DMA_3WCNT],
6322 6322 count & 0xFFFF);
6323 6323 break;
6324 6324 default :
6325 6325 FDERRPRINT(FDEP_L3, FDEM_SDMA,
6326 6326 (C, "set_data_count: wrong channel %x\n",
6327 6327 fdc->sb_dma_channel));
6328 6328 break;
6329 6329 }
6330 6330 }
6331 6331 }
6332 6332
6333 6333 /*
6334 6334 * get_data_count_register(struct fdctlr *fdc)
6335 6335 * Read the data count from appropriate dma register.
6336 6336 */
6337 6337
6338 6338 static uint32_t
6339 6339 get_data_count_register(struct fdctlr *fdc)
6340 6340 {
6341 6341 uint32_t retval = 0;
6342 6342 if (fdc->c_fdtype & FDCTYPE_CHEERIO) {
6343 6343 struct cheerio_dma_reg *dma_reg;
6344 6344 dma_reg = (struct cheerio_dma_reg *)fdc->c_dma_regs;
6345 6345 retval = ddi_get32(fdc->c_handlep_dma, &dma_reg->fdc_dbcr);
6346 6346 } else if (fdc->c_fdtype & FDCTYPE_SB) {
6347 6347 struct sb_dma_reg *dma_reg;
6348 6348 dma_reg = (struct sb_dma_reg *)fdc->c_dma_regs;
6349 6349 switch (fdc->sb_dma_channel) {
6350 6350 case 0 :
6351 6351 retval = ddi_get16(fdc->c_handlep_dma,
6352 6352 (ushort_t *)&dma_reg->sb_dma_regs[DMA_0WCNT]);
6353 6353 break;
6354 6354 case 1 :
6355 6355 retval = ddi_get16(fdc->c_handlep_dma,
6356 6356 (ushort_t *)&dma_reg->sb_dma_regs[DMA_1WCNT]);
6357 6357 break;
6358 6358 case 2 :
6359 6359 retval = ddi_get16(fdc->c_handlep_dma,
6360 6360 (ushort_t *)&dma_reg->sb_dma_regs[DMA_2WCNT]);
6361 6361 break;
6362 6362 case 3 :
6363 6363 retval = ddi_get16(fdc->c_handlep_dma,
6364 6364 (ushort_t *)&dma_reg->sb_dma_regs[DMA_3WCNT]);
6365 6365 break;
6366 6366 default :
6367 6367 FDERRPRINT(FDEP_L3, FDEM_SDMA,
6368 6368 (C, "get_data_count: wrong channel %x\n",
6369 6369 fdc->sb_dma_channel));
6370 6370 break;
6371 6371 }
6372 6372 retval = (uint32_t)((uint16_t)(retval +1));
6373 6373 }
6374 6374
6375 6375 return (retval);
6376 6376
6377 6377 }
6378 6378
6379 6379 /*
6380 6380 * reset_dma_controller(struct fdctlr *fdc)
6381 6381 * Reset and initialize the dma controller.
6382 6382 */
6383 6383
6384 6384 static void
6385 6385 reset_dma_controller(struct fdctlr *fdc)
6386 6386 {
6387 6387 if (fdc->c_fdtype & FDCTYPE_CHEERIO) {
6388 6388 struct cheerio_dma_reg *dma_reg;
6389 6389 dma_reg = (struct cheerio_dma_reg *)fdc->c_dma_regs;
6390 6390 ddi_put32(fdc->c_handlep_dma, &dma_reg->fdc_dcsr, DCSR_RESET);
6391 6391 while (get_dma_control_register(fdc) & DCSR_CYC_PEND)
6392 6392 ;
6393 6393 ddi_put32(fdc->c_handlep_dma, &dma_reg->fdc_dcsr, 0);
6394 6394 } else if (fdc->c_fdtype & FDCTYPE_SB) {
6395 6395 struct sb_dma_reg *dma_reg;
6396 6396 dma_reg = (struct sb_dma_reg *)fdc->c_dma_regs;
6397 6397 ddi_put8(fdc->c_handlep_dma, &dma_reg->sb_dma_regs[DMAC1_MASK],
6398 6398 (fdc->sb_dma_channel & 0x3));
6399 6399
6400 6400 }
6401 6401 }
6402 6402
6403 6403 /*
6404 6404 * Get the DMA control register for CHEERIO.
6405 6405 * For SouthBridge 8237 DMA controller, this register is not valid.
6406 6406 * So, just return 0.
6407 6407 */
6408 6408 static uint32_t
6409 6409 get_dma_control_register(struct fdctlr *fdc)
6410 6410 {
6411 6411 uint32_t retval = 0;
6412 6412 if (fdc->c_fdtype & FDCTYPE_CHEERIO) {
6413 6413 struct cheerio_dma_reg *dma_reg;
6414 6414 dma_reg = (struct cheerio_dma_reg *)fdc->c_dma_regs;
6415 6415 retval = ddi_get32(fdc->c_handlep_dma, &dma_reg->fdc_dcsr);
6416 6416 }
6417 6417
6418 6418 return (retval);
6419 6419 }
6420 6420
6421 6421
6422 6422 /*
6423 6423 * set_data_address_register(struct fdctlr *fdc)
6424 6424 * Set the data address in appropriate dma register.
6425 6425 */
6426 6426 static void
6427 6427 set_data_address_register(struct fdctlr *fdc, uint32_t address)
6428 6428 {
6429 6429 if (fdc->c_fdtype & FDCTYPE_CHEERIO) {
6430 6430 struct cheerio_dma_reg *dma_reg;
6431 6431 dma_reg = (struct cheerio_dma_reg *)fdc->c_dma_regs;
6432 6432 ddi_put32(fdc->c_handlep_dma, &dma_reg->fdc_dacr, address);
6433 6433 } else if (fdc->c_fdtype & FDCTYPE_SB) {
6434 6434 struct sb_dma_reg *dma_reg;
6435 6435 dma_reg = (struct sb_dma_reg *)fdc->c_dma_regs;
6436 6436 switch (fdc->sb_dma_channel) {
6437 6437 case 0 :
6438 6438 ddi_put8(fdc->c_handlep_dma,
6439 6439 &dma_reg->sb_dma_regs[DMA_0PAGE],
6440 6440 (address & 0xFF0000) >>16);
6441 6441 ddi_put8(fdc->c_handlep_dma,
6442 6442 &dma_reg->sb_dma_regs[DMA_0HPG],
6443 6443 (address & 0xFF000000) >>24);
6444 6444 ddi_put16(fdc->c_handlep_dma,
6445 6445 (ushort_t *)&dma_reg->sb_dma_regs[DMA_0ADR],
6446 6446 address & 0xFFFF);
6447 6447 break;
6448 6448 case 1 :
6449 6449 ddi_put8(fdc->c_handlep_dma,
6450 6450 &dma_reg->sb_dma_regs[DMA_1PAGE],
6451 6451 (address & 0xFF0000) >>16);
6452 6452 ddi_put8(fdc->c_handlep_dma,
6453 6453 &dma_reg->sb_dma_regs[DMA_1HPG],
6454 6454 (address & 0xFF000000) >>24);
6455 6455 ddi_put16(fdc->c_handlep_dma,
6456 6456 (ushort_t *)&dma_reg->sb_dma_regs[DMA_1ADR],
6457 6457 address & 0xFFFF);
6458 6458 break;
6459 6459 case 2 :
6460 6460 ddi_put8(fdc->c_handlep_dma,
6461 6461 &dma_reg->sb_dma_regs[DMA_2PAGE],
6462 6462 (address & 0xFF0000) >>16);
6463 6463 ddi_put8(fdc->c_handlep_dma,
6464 6464 &dma_reg->sb_dma_regs[DMA_2HPG],
6465 6465 (address & 0xFF000000) >>24);
6466 6466 ddi_put16(fdc->c_handlep_dma,
6467 6467 (ushort_t *)&dma_reg->sb_dma_regs[DMA_2ADR],
6468 6468 address & 0xFFFF);
6469 6469 break;
6470 6470 case 3 :
6471 6471 ddi_put8(fdc->c_handlep_dma,
6472 6472 &dma_reg->sb_dma_regs[DMA_3PAGE],
6473 6473 (address & 0xFF0000) >>16);
6474 6474 ddi_put8(fdc->c_handlep_dma,
6475 6475 &dma_reg->sb_dma_regs[DMA_3HPG],
6476 6476 (address & 0xFF000000) >>24);
6477 6477 ddi_put16(fdc->c_handlep_dma,
6478 6478 (ushort_t *)&dma_reg->sb_dma_regs[DMA_3ADR],
6479 6479 address & 0xFFFF);
6480 6480 break;
6481 6481 default :
6482 6482 FDERRPRINT(FDEP_L3, FDEM_SDMA,
6483 6483 (C, "set_data_address: wrong channel %x\n",
6484 6484 fdc->sb_dma_channel));
6485 6485 break;
6486 6486 }
6487 6487 }
6488 6488
6489 6489 }
6490 6490
6491 6491
6492 6492 /*
6493 6493 * set_dma_mode(struct fdctlr *fdc, int val)
6494 6494 * Set the appropriate dma direction and registers.
6495 6495 */
6496 6496 static void
6497 6497 set_dma_mode(struct fdctlr *fdc, int val)
6498 6498 {
6499 6499 if (fdc->c_fdtype & FDCTYPE_CHEERIO) {
6500 6500 struct cheerio_dma_reg *dma_reg;
6501 6501 dma_reg = (struct cheerio_dma_reg *)fdc->c_dma_regs;
6502 6502 if (val == CSB_READ)
6503 6503 ddi_put32(fdc->c_handlep_dma, &dma_reg->fdc_dcsr,
6504 6504 DCSR_INIT_BITS|DCSR_WRITE);
6505 6505 else
6506 6506 ddi_put32(fdc->c_handlep_dma, &dma_reg->fdc_dcsr,
6507 6507 DCSR_INIT_BITS);
6508 6508
6509 6509 } else if (fdc->c_fdtype & FDCTYPE_SB) {
6510 6510 uint8_t mode_reg_val, chn_mask;
6511 6511 struct sb_dma_reg *dma_reg;
6512 6512 dma_reg = (struct sb_dma_reg *)fdc->c_dma_regs;
6513 6513
6514 6514 if (val == CSB_READ) {
6515 6515 mode_reg_val = fdc->sb_dma_channel | DMAMODE_READ
6516 6516 | DMAMODE_SINGLE;
6517 6517 } else { /* Read operation */
6518 6518 mode_reg_val = fdc->sb_dma_channel | DMAMODE_WRITE
6519 6519 | DMAMODE_SINGLE;
6520 6520 }
6521 6521 ddi_put8(fdc->c_handlep_dma, &dma_reg->sb_dma_regs[DMAC1_MODE],
6522 6522 mode_reg_val);
6523 6523 chn_mask = 1 << (fdc->sb_dma_channel & 0x3);
6524 6524 ddi_put8(fdc->c_handlep_dma,
6525 6525 &dma_reg->sb_dma_regs[DMAC1_ALLMASK], ~chn_mask);
6526 6526 fdc->sb_dma_lock = 1;
6527 6527 }
6528 6528 }
6529 6529
6530 6530 /*
6531 6531 * This function is valid only for CHEERIO/RIO based
6532 6532 * controllers. The control register for the dma channel
6533 6533 * is initialized by this function.
6534 6534 */
6535 6535
6536 6536 static void
6537 6537 set_dma_control_register(struct fdctlr *fdc, uint32_t val)
6538 6538 {
6539 6539 if (fdc->c_fdtype & FDCTYPE_CHEERIO) {
6540 6540 struct cheerio_dma_reg *dma_reg;
6541 6541 dma_reg = (struct cheerio_dma_reg *)fdc->c_dma_regs;
6542 6542 ddi_put32(fdc->c_handlep_dma, &dma_reg->fdc_dcsr, val);
6543 6543 }
6544 6544 }
6545 6545
6546 6546 static void
6547 6547 release_sb_dma(struct fdctlr *fdc)
6548 6548 {
6549 6549 struct sb_dma_reg *dma_reg;
6550 6550 dma_reg = (struct sb_dma_reg *)fdc->c_dma_regs;
6551 6551 /* Unmask all the channels to release the DMA controller */
6552 6552 ddi_put8(fdc->c_handlep_dma,
6553 6553 &dma_reg->sb_dma_regs[DMAC1_ALLMASK], NULL);
6554 6554 fdc->sb_dma_lock = 0;
6555 6555 }
6556 6556
6557 6557 static void
6558 6558 quiesce_fd_interrupt(struct fdctlr *fdc)
6559 6559 {
6560 6560 /*
6561 6561 * The following code is put here to take care of HW problem.
6562 6562 * The HW problem is as follows:
6563 6563 *
6564 6564 * After poweron the Southbridge floppy controller asserts the
6565 6565 * interrupt in tristate. This causes continuous interrupts to
6566 6566 * be generated.
6567 6567 * Until the Hardware is FIXED we will have to use the following code
6568 6568 * to set the interrupt line to proper state after poweron.
6569 6569 */
6570 6570 if (fdc->c_fdtype & FDCTYPE_SB) {
6571 6571 ddi_put8(fdc->c_handlep_cont, ((uint8_t *)fdc->c_dor),
6572 6572 0x0);
6573 6573 drv_usecwait(200);
6574 6574 ddi_put8(fdc->c_handlep_cont, ((uint8_t *)fdc->c_dor),
6575 6575 0xC);
6576 6576 drv_usecwait(200);
6577 6577 Set_Fifo(fdc, 0xE6);
6578 6578 drv_usecwait(200);
6579 6579 }
6580 6580 }
↓ open down ↓ |
1725 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX