Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/fdc.c
+++ new/usr/src/uts/common/io/fdc.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 2008 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25 /*
26 26 * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved.
27 27 */
28 28
29 29
30 30 /*
31 31 * Floppy Disk Controller Driver
32 32 *
33 33 * for the standard PC architecture using the Intel 8272A fdc.
34 34 * Note that motor control and drive select use a latch external
35 35 * to the fdc.
36 36 *
37 37 * This driver is EISA capable, and uses DMA buffer chaining if available.
38 38 * If this driver is attached to the ISA bus nexus (or if the EISA bus driver
39 39 * does not support DMA buffer chaining), then the bus driver must ensure
40 40 * that dma mapping (breakup) and dma engine requests are properly degraded.
41 41 */
42 42
43 43 /*
44 44 * hack for bugid 1160621:
45 45 * workaround compiler optimization bug by turning on DEBUG
46 46 */
47 47 #ifndef DEBUG
48 48 #define DEBUG 1
49 49 #endif
50 50
51 51 #include <sys/param.h>
52 52 #include <sys/buf.h>
53 53 #include <sys/ioctl.h>
54 54 #include <sys/uio.h>
55 55 #include <sys/open.h>
56 56 #include <sys/conf.h>
57 57 #include <sys/file.h>
58 58 #include <sys/cmn_err.h>
59 59 #include <sys/note.h>
60 60 #include <sys/debug.h>
61 61 #include <sys/kmem.h>
62 62 #include <sys/stat.h>
63 63
64 64 #include <sys/autoconf.h>
65 65 #include <sys/dkio.h>
66 66 #include <sys/vtoc.h>
67 67 #include <sys/kstat.h>
68 68
69 69 #include <sys/fdio.h>
70 70 #include <sys/fdc.h>
71 71 #include <sys/i8272A.h>
72 72 #include <sys/fd_debug.h>
73 73 #include <sys/promif.h>
74 74 #include <sys/ddi.h>
75 75 #include <sys/sunddi.h>
76 76
77 77 /*
78 78 * bss (uninitialized data)
79 79 */
80 80 static void *fdc_state_head; /* opaque handle top of state structs */
81 81 static ddi_dma_attr_t fdc_dma_attr;
82 82 static ddi_device_acc_attr_t fdc_accattr = {DDI_DEVICE_ATTR_V0,
83 83 DDI_STRUCTURE_LE_ACC, DDI_STRICTORDER_ACC};
84 84
85 85 /*
86 86 * Local static data
87 87 */
88 88 #define OURUN_TRIES 12
89 89 static uchar_t rwretry = 4;
90 90 static uchar_t skretry = 3;
91 91 static uchar_t configurecmd[4] = {FO_CNFG, 0, 0x0F, 0};
92 92 static uchar_t recalcmd[2] = {FO_RECAL, 0};
93 93 static uchar_t senseintcmd = FO_SINT;
94 94
95 95 /*
96 96 * error handling
97 97 *
98 98 * for debugging, set rwretry and skretry = 1
99 99 * set fcerrlevel to 1
100 100 * set fcerrmask to 224 or 644
101 101 *
102 102 * after debug, set rwretry to 4, skretry to 3, and fcerrlevel to 5
103 103 * set fcerrmask to FDEM_ALL
104 104 * or remove the define DEBUG
105 105 */
106 106 static uint_t fcerrmask = FDEM_ALL;
107 107 static int fcerrlevel = 6;
108 108
109 109 #define KIOIP KSTAT_INTR_PTR(fcp->c_intrstat)
110 110
111 111
112 112 static xlate_tbl_t drate_mfm[] = {
113 113 { 250, 2},
114 114 { 300, 1},
115 115 { 417, 0},
116 116 { 500, 0},
117 117 { 1000, 3},
118 118 { 0, 0}
119 119 };
120 120
121 121 static xlate_tbl_t sector_size[] = {
122 122 { 256, 1},
123 123 { 512, 2},
124 124 { 1024, 3},
125 125 { 0, 2}
126 126 };
127 127
128 128 static xlate_tbl_t motor_onbits[] = {
129 129 { 0, 0x10},
130 130 { 1, 0x20},
131 131 { 2, 0x40},
132 132 { 3, 0x80},
133 133 { 0, 0x80}
134 134 };
135 135
136 136 static xlate_tbl_t step_rate[] = {
137 137 { 10, 0xF0}, /* for 500K data rate */
138 138 { 20, 0xE0},
139 139 { 30, 0xD0},
140 140 { 40, 0xC0},
141 141 { 50, 0xB0},
142 142 { 60, 0xA0},
143 143 { 70, 0x90},
144 144 { 80, 0x80},
145 145 { 90, 0x70},
146 146 { 100, 0x60},
147 147 { 110, 0x50},
148 148 { 120, 0x40},
149 149 { 130, 0x30},
150 150 { 140, 0x20},
151 151 { 150, 0x10},
152 152 { 160, 0x00},
153 153 { 0, 0x00}
154 154 };
155 155
156 156 #ifdef notdef
157 157 static xlate_tbl_t head_unld[] = {
158 158 { 16, 0x1}, /* for 500K data rate */
159 159 { 32, 0x2},
160 160 { 48, 0x3},
161 161 { 64, 0x4},
162 162 { 80, 0x5},
163 163 { 96, 0x6},
164 164 { 112, 0x7},
165 165 { 128, 0x8},
166 166 { 144, 0x9},
167 167 { 160, 0xA},
168 168 { 176, 0xB},
169 169 { 192, 0xC},
170 170 { 208, 0xD},
171 171 { 224, 0xE},
172 172 { 240, 0xF},
173 173 { 256, 0x0},
↓ open down ↓ |
173 lines elided |
↑ open up ↑ |
174 174 { 0, 0x0}
175 175 };
176 176 #endif
177 177
178 178 static struct fdcmdinfo {
179 179 char *cmdname; /* command name */
180 180 uchar_t ncmdbytes; /* number of bytes of command */
181 181 uchar_t nrsltbytes; /* number of bytes in result */
182 182 uchar_t cmdtype; /* characteristics */
183 183 } fdcmds[] = {
184 - "", 0, 0, 0, /* - */
185 - "", 0, 0, 0, /* - */
186 - "read_track", 9, 7, 1, /* 2 */
187 - "specify", 3, 0, 3, /* 3 */
188 - "sense_drv_status", 2, 1, 3, /* 4 */
189 - "write", 9, 7, 1, /* 5 */
190 - "read", 9, 7, 1, /* 6 */
191 - "recalibrate", 2, 0, 2, /* 7 */
192 - "sense_int_status", 1, 2, 3, /* 8 */
193 - "write_del", 9, 7, 1, /* 9 */
194 - "read_id", 2, 7, 2, /* A */
195 - "", 0, 0, 0, /* - */
196 - "read_del", 9, 7, 1, /* C */
197 - "format_track", 10, 7, 1, /* D */
198 - "dump_reg", 1, 10, 4, /* E */
199 - "seek", 3, 0, 2, /* F */
200 - "version", 1, 1, 3, /* 10 */
201 - "", 0, 0, 0, /* - */
202 - "perp_mode", 2, 0, 3, /* 12 */
203 - "configure", 4, 0, 4, /* 13 */
184 + {"", 0, 0, 0}, /* - */
185 + {"", 0, 0, 0}, /* - */
186 + {"read_track", 9, 7, 1}, /* 2 */
187 + {"specify", 3, 0, 3}, /* 3 */
188 + {"sense_drv_status", 2, 1, 3}, /* 4 */
189 + {"write", 9, 7, 1}, /* 5 */
190 + {"read", 9, 7, 1}, /* 6 */
191 + {"recalibrate", 2, 0, 2}, /* 7 */
192 + {"sense_int_status", 1, 2, 3}, /* 8 */
193 + {"write_del", 9, 7, 1}, /* 9 */
194 + {"read_id", 2, 7, 2}, /* A */
195 + {"", 0, 0, 0}, /* - */
196 + {"read_del", 9, 7, 1}, /* C */
197 + {"format_track", 10, 7, 1}, /* D */
198 + {"dump_reg", 1, 10, 4}, /* E */
199 + {"seek", 3, 0, 2}, /* F */
200 + {"version", 1, 1, 3}, /* 10 */
201 + {"", 0, 0, 0}, /* - */
202 + {"perp_mode", 2, 0, 3}, /* 12 */
203 + {"configure", 4, 0, 4}, /* 13 */
204 204 /* relative seek */
205 205 };
206 206
207 207
208 208 static int
209 209 fdc_bus_ctl(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *, void *);
210 210 static int get_ioaddr(dev_info_t *dip, int *ioaddr);
211 211 static int get_unit(dev_info_t *dip, int *cntrl_num);
212 212
213 213 struct bus_ops fdc_bus_ops = {
214 214 BUSO_REV,
215 215 nullbusmap,
216 216 0, /* ddi_intrspec_t (*bus_get_intrspec)(); */
217 217 0, /* int (*bus_add_intrspec)(); */
218 218 0, /* void (*bus_remove_intrspec)(); */
219 219 i_ddi_map_fault,
220 220 0,
221 221 ddi_dma_allochdl,
222 222 ddi_dma_freehdl,
223 223 ddi_dma_bindhdl,
224 224 ddi_dma_unbindhdl,
225 225 ddi_dma_flush,
226 226 ddi_dma_win,
227 227 ddi_dma_mctl,
228 228 fdc_bus_ctl,
229 229 ddi_bus_prop_op,
230 230 };
231 231
232 232 static int fdc_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
233 233 static int fdc_probe(dev_info_t *);
234 234 static int fdc_attach(dev_info_t *, ddi_attach_cmd_t);
235 235 static int fdc_detach(dev_info_t *, ddi_detach_cmd_t);
236 236 static int fdc_quiesce(dev_info_t *);
237 237 static int fdc_enhance_probe(struct fdcntlr *fcp);
238 238
239 239 struct dev_ops fdc_ops = {
240 240 DEVO_REV, /* devo_rev, */
241 241 0, /* refcnt */
242 242 fdc_getinfo, /* getinfo */
243 243 nulldev, /* identify */
244 244 fdc_probe, /* probe */
245 245 fdc_attach, /* attach */
246 246 fdc_detach, /* detach */
247 247 nodev, /* reset */
248 248 (struct cb_ops *)0, /* driver operations */
249 249 &fdc_bus_ops, /* bus operations */
250 250 NULL, /* power */
251 251 fdc_quiesce, /* quiesce */
252 252 };
253 253
254 254 /*
255 255 * This is the loadable module wrapper.
256 256 */
257 257 #include <sys/modctl.h>
↓ open down ↓ |
44 lines elided |
↑ open up ↑ |
258 258
259 259 extern struct mod_ops mod_driverops;
260 260
261 261 static struct modldrv modldrv = {
262 262 &mod_driverops, /* Type of module. This one is a driver */
263 263 "Floppy Controller", /* Name of the module. */
264 264 &fdc_ops, /* Driver ops vector */
265 265 };
266 266
267 267 static struct modlinkage modlinkage = {
268 - MODREV_1, (void *)&modldrv, NULL
268 + MODREV_1, { (void *)&modldrv, NULL }
269 269 };
270 270
271 271 int
272 272 _init(void)
273 273 {
274 274 int retval;
275 275
276 276 if ((retval = ddi_soft_state_init(&fdc_state_head,
277 277 sizeof (struct fdcntlr) + NFDUN * sizeof (struct fcu_obj), 0)) != 0)
278 278 return (retval);
279 279
280 280 if ((retval = mod_install(&modlinkage)) != 0)
281 281 ddi_soft_state_fini(&fdc_state_head);
282 282 return (retval);
283 283 }
284 284
285 285 int
286 286 _fini(void)
287 287 {
288 288 int retval;
289 289
290 290 if ((retval = mod_remove(&modlinkage)) != 0)
291 291 return (retval);
292 292 ddi_soft_state_fini(&fdc_state_head);
293 293 return (retval);
294 294 }
295 295
296 296 int
297 297 _info(struct modinfo *modinfop)
298 298 {
299 299 return (mod_info(&modlinkage, modinfop));
300 300 }
301 301
302 302
303 303 int fdc_abort(struct fcu_obj *);
304 304 int fdc_dkinfo(struct fcu_obj *, struct dk_cinfo *);
305 305 int fdc_select(struct fcu_obj *, int, int);
306 306 int fdgetchng(struct fcu_obj *, int);
307 307 int fdresetchng(struct fcu_obj *, int);
308 308 int fdrecalseek(struct fcu_obj *, int, int, int);
309 309 int fdrw(struct fcu_obj *, int, int, int, int, int, caddr_t, uint_t);
310 310 int fdtrkformat(struct fcu_obj *, int, int, int, int);
311 311 int fdrawioctl(struct fcu_obj *, int, caddr_t);
312 312
313 313 static struct fcobjops fdc_iops = {
314 314 fdc_abort, /* controller abort */
315 315 fdc_dkinfo, /* get disk controller info */
316 316
317 317 fdc_select, /* select / deselect unit */
318 318 fdgetchng, /* get media change */
319 319 fdresetchng, /* reset media change */
320 320 fdrecalseek, /* recal / seek */
321 321 NULL, /* read /write request (UNUSED) */
322 322 fdrw, /* read /write sector */
323 323 fdtrkformat, /* format track */
324 324 fdrawioctl /* raw ioctl */
325 325 };
326 326
327 327
328 328 /*
329 329 * Function prototypes
330 330 */
331 331 void encode(xlate_tbl_t *tablep, int val, uchar_t *rcode);
332 332 int decode(xlate_tbl_t *, int, int *);
333 333 static int fdc_propinit1(struct fdcntlr *, int);
334 334 static void fdc_propinit2(struct fdcntlr *);
335 335 void fdcquiesce(struct fdcntlr *);
336 336 int fdcsense_chng(struct fdcntlr *, int);
337 337 int fdcsense_drv(struct fdcntlr *, int);
338 338 int fdcsense_int(struct fdcntlr *, int *, int *);
339 339 int fdcspecify(struct fdcntlr *, int, int, int);
340 340 int fdcspdchange(struct fdcntlr *, struct fcu_obj *, int);
341 341 static int fdc_exec(struct fdcntlr *, int, int);
342 342 int fdcheckdisk(struct fdcntlr *, int);
343 343 static uint_t fdc_intr(caddr_t arg);
344 344 static void fdwatch(void *arg);
345 345 static void fdmotort(void *arg);
346 346 static int fdrecover(struct fdcntlr *);
347 347 static int fdc_motorsm(struct fcu_obj *, int, int);
348 348 static int fdc_statemach(struct fdcntlr *);
349 349 int fdc_docmd(struct fdcntlr *, uchar_t *, uchar_t);
350 350 int fdc_result(struct fdcntlr *, uchar_t *, uchar_t);
351 351
352 352
353 353 static int
354 354 fdc_bus_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop,
355 355 void *arg, void *result)
356 356 {
357 357 struct fdcntlr *fcp;
358 358 struct fcu_obj *fjp;
359 359
360 360 _NOTE(ARGUNUSED(result));
361 361
362 362 FCERRPRINT(FDEP_L0, FDEM_ATTA,
363 363 (CE_CONT, "fdc_bus_ctl: cmd= %x\n", ctlop));
364 364
365 365 if ((fcp = ddi_get_driver_private(dip)) == NULL)
366 366 return (DDI_FAILURE);
367 367
368 368 switch (ctlop) {
369 369
370 370 case DDI_CTLOPS_REPORTDEV:
371 371 cmn_err(CE_CONT, "?%s%d at %s%d\n",
372 372 ddi_get_name(rdip), ddi_get_instance(rdip),
373 373 ddi_get_name(dip), ddi_get_instance(dip));
374 374 FCERRPRINT(FDEP_L3, FDEM_ATTA,
375 375 (CE_WARN, "fdc_bus_ctl: report %s%d at %s%d",
376 376 ddi_get_name(rdip), ddi_get_instance(rdip),
377 377 ddi_get_name(dip), ddi_get_instance(dip)));
378 378 return (DDI_SUCCESS);
379 379
380 380 case DDI_CTLOPS_INITCHILD:
381 381 {
382 382 dev_info_t *udip = (dev_info_t *)arg;
383 383 int cntlr;
384 384 int len;
385 385 int unit;
386 386 char name[MAXNAMELEN];
387 387
388 388 FCERRPRINT(FDEP_L3, FDEM_ATTA,
389 389 (CE_WARN, "fdc_bus_ctl: init child 0x%p", (void*)udip));
390 390 cntlr = fcp->c_number;
391 391
392 392 len = sizeof (unit);
393 393 if (ddi_prop_op(DDI_DEV_T_ANY, udip, PROP_LEN_AND_VAL_BUF,
394 394 DDI_PROP_DONTPASS, "unit", (caddr_t)&unit, &len)
395 395 != DDI_PROP_SUCCESS ||
396 396 cntlr != FDCTLR(unit) ||
397 397 (fcp->c_unit[FDUNIT(unit)])->fj_dip)
398 398 return (DDI_NOT_WELL_FORMED);
399 399
400 400 (void) sprintf(name, "%d,%d", cntlr, FDUNIT(unit));
401 401 ddi_set_name_addr(udip, name);
402 402
403 403 fjp = fcp->c_unit[FDUNIT(unit)];
404 404 fjp->fj_unit = unit;
405 405 fjp->fj_dip = udip;
406 406 fjp->fj_ops = &fdc_iops;
407 407 fjp->fj_fdc = fcp;
408 408 fjp->fj_iblock = &fcp->c_iblock;
409 409
410 410 ddi_set_driver_private(udip, fjp);
411 411
412 412 return (DDI_SUCCESS);
413 413 }
414 414 case DDI_CTLOPS_UNINITCHILD:
415 415 {
416 416 dev_info_t *udip = (dev_info_t *)arg;
417 417
418 418 FCERRPRINT(FDEP_L3, FDEM_ATTA,
419 419 (CE_WARN, "fdc_bus_ctl: uninit child 0x%p", (void *)udip));
420 420 fjp = ddi_get_driver_private(udip);
421 421 ddi_set_driver_private(udip, NULL);
422 422 fjp->fj_dip = NULL;
423 423 ddi_set_name_addr(udip, NULL);
424 424 return (DDI_SUCCESS);
425 425 }
426 426 default:
427 427 return (DDI_FAILURE);
428 428 }
429 429 }
430 430
431 431 static int
432 432 fdc_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
433 433 {
434 434 struct fdcntlr *fcp;
435 435 int rval;
436 436
437 437 _NOTE(ARGUNUSED(dip));
438 438
439 439 switch (cmd) {
440 440 case DDI_INFO_DEVT2DEVINFO:
441 441 if (fcp = ddi_get_soft_state(fdc_state_head, (dev_t)arg)) {
442 442 *result = fcp->c_dip;
443 443 rval = DDI_SUCCESS;
444 444 break;
445 445 } else {
446 446 rval = DDI_FAILURE;
447 447 break;
448 448 }
449 449 case DDI_INFO_DEVT2INSTANCE:
450 450 *result = (void *)(uintptr_t)getminor((dev_t)arg);
451 451 rval = DDI_SUCCESS;
452 452 break;
453 453 default:
454 454 rval = DDI_FAILURE;
455 455 }
456 456 return (rval);
457 457 }
458 458
459 459 static int
460 460 fdc_probe(dev_info_t *dip)
461 461 {
462 462 int debug[2];
463 463 int ioaddr;
464 464 int len;
465 465 uchar_t stat;
466 466
467 467 len = sizeof (debug);
468 468 if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
469 469 DDI_PROP_DONTPASS, "debug", (caddr_t)debug, &len) ==
470 470 DDI_PROP_SUCCESS) {
471 471 fcerrlevel = debug[0];
472 472 fcerrmask = (uint_t)debug[1];
473 473 }
474 474
475 475 FCERRPRINT(FDEP_L3, FDEM_ATTA, (CE_WARN, "fdc_probe: dip %p",
476 476 (void*)dip));
477 477
478 478 if (get_ioaddr(dip, &ioaddr) != DDI_SUCCESS)
479 479 return (DDI_PROBE_FAILURE);
480 480
481 481 stat = inb(ioaddr + FCR_MSR);
482 482 if ((stat & (MS_RQM | MS_DIO | MS_CB)) != MS_RQM &&
483 483 (stat & ~MS_DIO) != MS_CB)
484 484 return (DDI_PROBE_FAILURE);
485 485
486 486 return (DDI_PROBE_SUCCESS);
487 487 }
488 488
489 489 static int
490 490 fdc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
491 491 {
492 492 struct fdcntlr *fcp;
493 493 struct fcu_obj *fjp;
494 494 int cntlr_num, ctlr, unit;
495 495 int intr_set = 0;
496 496 int len;
497 497 char name[MAXNAMELEN];
498 498
499 499 FCERRPRINT(FDEP_L3, FDEM_ATTA, (CE_WARN, "fdc_attach: dip %p",
500 500 (void*)dip));
501 501
502 502 switch (cmd) {
503 503 case DDI_ATTACH:
504 504 if (ddi_getprop
505 505 (DDI_DEV_T_ANY, dip, 0, "ignore-hardware-nodes", 0)) {
506 506 len = sizeof (cntlr_num);
507 507 if (ddi_prop_op(DDI_DEV_T_ANY, dip,
508 508 PROP_LEN_AND_VAL_BUF, DDI_PROP_DONTPASS, "unit",
509 509 (caddr_t)&cntlr_num, &len) != DDI_PROP_SUCCESS) {
510 510 FCERRPRINT(FDEP_L3, FDEM_ATTA, (CE_WARN,
511 511 "fdc_attach failed: dip %p", (void*)dip));
512 512 return (DDI_FAILURE);
513 513 }
514 514 } else {
515 515 if (get_unit(dip, &cntlr_num) != DDI_SUCCESS)
516 516 return (DDI_FAILURE);
517 517 }
518 518
519 519 ctlr = ddi_get_instance(dip);
520 520 if (ddi_soft_state_zalloc(fdc_state_head, ctlr) != 0)
521 521 return (DDI_FAILURE);
522 522 fcp = ddi_get_soft_state(fdc_state_head, ctlr);
523 523
524 524 for (unit = 0, fjp = (struct fcu_obj *)(fcp+1);
525 525 unit < NFDUN; unit++) {
526 526 fcp->c_unit[unit] = fjp++;
527 527 }
528 528 fcp->c_dip = dip;
529 529
530 530 if (fdc_propinit1(fcp, cntlr_num) != DDI_SUCCESS)
531 531 goto no_attach;
532 532
533 533 /* get iblock cookie to initialize mutex used in the ISR */
534 534 if (ddi_get_iblock_cookie(dip, (uint_t)0, &fcp->c_iblock) !=
535 535 DDI_SUCCESS) {
536 536 cmn_err(CE_WARN,
537 537 "fdc_attach: cannot get iblock cookie");
538 538 goto no_attach;
539 539 }
540 540 mutex_init(&fcp->c_lock, NULL, MUTEX_DRIVER, fcp->c_iblock);
541 541 intr_set = 1;
542 542
543 543 /* setup interrupt handler */
544 544 if (ddi_add_intr(dip, (uint_t)0, NULL,
545 545 (ddi_idevice_cookie_t *)0, fdc_intr, (caddr_t)fcp) !=
546 546 DDI_SUCCESS) {
547 547 cmn_err(CE_WARN, "fdc: cannot add intr");
548 548 goto no_attach;
549 549 }
550 550 intr_set++;
551 551
552 552 /*
553 553 * acquire the DMA channel
554 554 * this assumes that the chnl is not shared; else allocate
555 555 * and free the chnl with each fdc request
556 556 */
557 557 if (ddi_dmae_alloc(dip, fcp->c_dmachan, DDI_DMA_DONTWAIT, NULL)
558 558 != DDI_SUCCESS) {
559 559 cmn_err(CE_WARN, "fdc: cannot acquire dma%d",
560 560 fcp->c_dmachan);
561 561 goto no_attach;
562 562 }
563 563 (void) ddi_dmae_getattr(dip, &fdc_dma_attr);
564 564 fdc_dma_attr.dma_attr_align = MMU_PAGESIZE;
565 565
566 566 mutex_init(&fcp->c_dorlock, NULL, MUTEX_DRIVER, fcp->c_iblock);
567 567 cv_init(&fcp->c_iocv, NULL, CV_DRIVER, fcp->c_iblock);
568 568 sema_init(&fcp->c_selsem, 1, NULL, SEMA_DRIVER, NULL);
569 569
570 570 (void) sprintf(name, "fdc%d", ctlr);
571 571 fcp->c_intrstat = kstat_create("fdc", ctlr, name,
572 572 "controller", KSTAT_TYPE_INTR, 1, KSTAT_FLAG_PERSISTENT);
573 573 if (fcp->c_intrstat) {
574 574 kstat_install(fcp->c_intrstat);
575 575 }
576 576
577 577 ddi_set_driver_private(dip, fcp);
578 578
579 579 /*
580 580 * reset the controller
581 581 */
582 582 sema_p(&fcp->c_selsem);
583 583 mutex_enter(&fcp->c_lock);
584 584 fcp->c_csb.csb_xstate = FXS_RESET;
585 585 fcp->c_flags |= FCFLG_WAITING;
586 586 fdcquiesce(fcp);
587 587
588 588 /* first test for mode == Model 30 */
589 589 fcp->c_mode = (inb(fcp->c_regbase + FCR_SRB) & 0x1c) ?
590 590 FDCMODE_AT : FDCMODE_30;
591 591
592 592 while (fcp->c_flags & FCFLG_WAITING) {
593 593 cv_wait(&fcp->c_iocv, &fcp->c_lock);
594 594 }
595 595 mutex_exit(&fcp->c_lock);
596 596 sema_v(&fcp->c_selsem);
597 597
598 598 fdc_propinit2(fcp);
599 599
600 600 ddi_report_dev(dip);
601 601 return (DDI_SUCCESS);
602 602
603 603 case DDI_RESUME:
604 604
605 605 fcp = ddi_get_driver_private(dip);
606 606
607 607 mutex_enter(&fcp->c_lock);
608 608 fcp->c_suspended = B_FALSE;
609 609 fcp->c_csb.csb_xstate = FXS_RESET;
610 610 fcp->c_flags |= FCFLG_WAITING;
611 611 fdcquiesce(fcp);
612 612
613 613 while (fcp->c_flags & FCFLG_WAITING) {
614 614 cv_wait(&fcp->c_iocv, &fcp->c_lock);
615 615 }
616 616 mutex_exit(&fcp->c_lock);
617 617
618 618 /* should be good to go now */
619 619 sema_v(&fcp->c_selsem);
620 620
621 621 return (DDI_SUCCESS);
622 622 /* break; */
623 623
624 624 default:
625 625 return (DDI_FAILURE);
626 626 }
627 627
628 628 no_attach:
629 629 if (intr_set) {
630 630 if (intr_set > 1)
631 631 ddi_remove_intr(dip, 0, fcp->c_iblock);
632 632 mutex_destroy(&fcp->c_lock);
633 633 }
634 634 ddi_soft_state_free(fdc_state_head, cntlr_num);
635 635 return (DDI_FAILURE);
636 636 }
637 637
638 638 static int
639 639 fdc_propinit1(struct fdcntlr *fcp, int cntlr)
640 640 {
641 641 dev_info_t *dip;
642 642 int len;
643 643 int value;
644 644
645 645 dip = fcp->c_dip;
646 646 len = sizeof (value);
647 647
648 648 if (get_ioaddr(dip, &value) != DDI_SUCCESS)
649 649 return (DDI_FAILURE);
650 650
651 651 fcp->c_regbase = (ushort_t)value;
652 652
653 653 if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
654 654 DDI_PROP_DONTPASS, "dma-channels", (caddr_t)&value, &len)
655 655 != DDI_PROP_SUCCESS) {
656 656 cmn_err(CE_WARN,
657 657 "fdc_attach: Error, could not find a dma channel");
658 658 return (DDI_FAILURE);
659 659 }
660 660 fcp->c_dmachan = (ushort_t)value;
661 661 fcp->c_number = cntlr;
662 662 return (DDI_SUCCESS);
663 663 }
664 664
665 665 static void
666 666 fdc_propinit2(struct fdcntlr *fcp)
667 667 {
668 668 dev_info_t *dip;
669 669 int ccr;
670 670 int len;
671 671 int value;
672 672
673 673 dip = fcp->c_dip;
674 674 len = sizeof (value);
675 675
676 676 if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
677 677 DDI_PROP_DONTPASS, "chip", (caddr_t)&value, &len)
678 678 == DDI_PROP_SUCCESS)
679 679 fcp->c_chip = value;
680 680 else {
681 681 static uchar_t perpindcmd[2] = {FO_PERP, 0};
682 682 static uchar_t versioncmd = FO_VRSN;
683 683 uchar_t result;
684 684
685 685 fcp->c_chip = i8272A;
686 686 (void) fdc_docmd(fcp, &versioncmd, 1);
687 687 /*
688 688 * Ignored return. If failed, warning was issued by fdc_docmd.
689 689 * fdc_results retrieves the controller/drive status
690 690 */
691 691 if (!fdc_result(fcp, &result, 1) && result == 0x90) {
692 692 /*
693 693 * try a perpendicular_mode cmd to ensure
694 694 * that we really have an enhanced controller
695 695 */
696 696 if (fdc_docmd(fcp, perpindcmd, 2) ||
697 697 fdc_docmd(fcp, configurecmd, 4))
698 698 /*
699 699 * perpindicular_mode will be rejected by
700 700 * older controllers; make sure we don't hang.
701 701 */
702 702 (void) fdc_result(fcp, &result, 1);
703 703 /*
704 704 * Ignored return. If failed, warning was
705 705 * issued by fdc_result.
706 706 */
707 707 else
708 708 /* enhanced type controller */
709 709
710 710 if ((fcp->c_chip = fdc_enhance_probe(fcp)) == 0)
711 711 /* default enhanced cntlr */
712 712 fcp->c_chip = i82077;
713 713 }
714 714 (void) ddi_prop_update_int(DDI_DEV_T_NONE, dip,
715 715 "chip", fcp->c_chip);
716 716 /*
717 717 * Ignoring return value because, for passed arguments, only
718 718 * DDI_SUCCESS is returned.
719 719 */
720 720 }
721 721 if (fcp->c_chip >= i82077 && fcp->c_mode == FDCMODE_30 &&
722 722 (inb(fcp->c_regbase + FCR_DIR) & 0x70) == 0)
723 723 for (ccr = 0; ccr <= (FCC_NOPREC | FCC_DRATE); ccr++) {
724 724 /*
725 725 * run through all the combinations of NOPREC and
726 726 * datarate selection, and see if they show up in the
727 727 * Model 30 DIR
728 728 */
729 729 outb(fcp->c_regbase + FCR_CCR, ccr);
730 730 drv_usecwait(5);
731 731 if ((inb(fcp->c_regbase + FCR_DIR) &
732 732 (FCC_NOPREC | FCC_DRATE)) != ccr) {
733 733 fcp->c_mode = FDCMODE_AT;
734 734 break;
735 735 }
736 736 }
737 737 else
738 738 fcp->c_mode = FDCMODE_AT;
739 739 outb(fcp->c_regbase + FCR_CCR, 0);
740 740 }
741 741
742 742 static int
743 743 fdc_enhance_probe(struct fdcntlr *fcp)
744 744 {
745 745 static uchar_t nsccmd = FO_NSC;
746 746 uint_t ddic;
747 747 int retcode = 0;
748 748 uchar_t result;
749 749 uchar_t save;
750 750
751 751 /*
752 752 * Try to identify the enhanced floppy controller.
753 753 * This is required so that we can program the DENSEL output to
754 754 * control 3D mode (1.0 MB, 1.6 MB and 2.0 MB unformatted capacity,
755 755 * 720 KB, 1.2 MB, and 1.44 MB formatted capacity) 3.5" dual-speed
756 756 * floppy drives. Refer to bugid 1195155.
757 757 */
758 758
759 759 (void) fdc_docmd(fcp, &nsccmd, 1);
760 760 /*
761 761 * Ignored return. If failed, warning was issued by fdc_docmd.
762 762 * fdc_results retrieves the controller/drive status
763 763 */
764 764 if (!fdc_result(fcp, &result, 1) && result != S0_IVCMD) {
765 765 /*
766 766 * only enhanced National Semi PC8477 core
767 767 * should respond to this command
768 768 */
769 769 if ((result & 0xf0) == 0x70) {
770 770 /* low 4 bits may change */
771 771 fcp->c_flags |= FCFLG_3DMODE;
772 772 retcode = PC87322;
773 773 } else
774 774 cmn_err(CE_CONT,
775 775 "?fdc: unidentified, enhanced, National Semiconductor cntlr %x\n", result);
776 776 } else {
777 777 save = inb(fcp->c_regbase + FCR_SRA);
778 778
779 779 do {
780 780 /* probe for motherboard version of SMC cntlr */
781 781
782 782 /* try to enable configuration mode */
783 783 ddic = ddi_enter_critical();
784 784 outb(fcp->c_regbase + FCR_SRA, FSA_ENA5);
785 785 outb(fcp->c_regbase + FCR_SRA, FSA_ENA5);
786 786 ddi_exit_critical(ddic);
787 787
788 788 outb(fcp->c_regbase + FCR_SRA, 0x0F);
789 789 if (inb(fcp->c_regbase + FCR_SRB) != 0x00)
790 790 /* always expect 0 from config reg F */
791 791 break;
792 792 outb(fcp->c_regbase + FCR_SRA, 0x0D);
793 793 if (inb(fcp->c_regbase + FCR_SRB) != 0x65)
794 794 /* expect 0x65 from config reg D */
795 795 break;
796 796 outb(fcp->c_regbase + FCR_SRA, 0x0E);
797 797 result = inb(fcp->c_regbase + FCR_SRB);
798 798 if (result != 0x02) {
799 799 /* expect revision level 2 from config reg E */
800 800 cmn_err(CE_CONT,
801 801 "?fdc: unidentified, enhanced, SMC cntlr revision %x\n", result);
802 802 /* break; */
803 803 }
804 804 fcp->c_flags |= FCFLG_3DMODE;
805 805 retcode = FDC37C665;
806 806 } while (retcode == 0);
807 807 outb(fcp->c_regbase + FCR_SRA, FSA_DISB);
808 808
809 809 while (retcode == 0) {
810 810 /* probe for adapter version of SMC cntlr */
811 811 ddic = ddi_enter_critical();
812 812 outb(fcp->c_regbase + FCR_SRA, FSA_ENA6);
813 813 outb(fcp->c_regbase + FCR_SRA, FSA_ENA6);
814 814 ddi_exit_critical(ddic);
815 815
816 816 outb(fcp->c_regbase + FCR_SRA, 0x0F);
817 817 if (inb(fcp->c_regbase + FCR_SRB) != 0x00)
818 818 /* always expect 0 from config reg F */
819 819 break;
820 820 outb(fcp->c_regbase + FCR_SRA, 0x0D);
821 821 if (inb(fcp->c_regbase + FCR_SRB) != 0x66)
822 822 /* expect 0x66 from config reg D */
823 823 break;
824 824 outb(fcp->c_regbase + FCR_SRA, 0x0E);
825 825 result = inb(fcp->c_regbase + FCR_SRB);
826 826 if (result != 0x02) {
827 827 /* expect revision level 2 from config reg E */
828 828 cmn_err(CE_CONT,
829 829 "?fdc: unidentified, enhanced, SMC cntlr revision %x\n", result);
830 830 /* break; */
831 831 }
832 832 fcp->c_flags |= FCFLG_3DMODE;
833 833 retcode = FDC37C666;
834 834 }
835 835 outb(fcp->c_regbase + FCR_SRA, FSA_DISB);
836 836
837 837 drv_usecwait(10);
838 838 outb(fcp->c_regbase + FCR_SRA, save);
839 839 }
840 840 return (retcode);
841 841 }
842 842
843 843 static int
844 844 fdc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
845 845 {
846 846 struct fdcntlr *fcp;
847 847 int unit;
848 848 int rval = 0;
849 849
850 850 FCERRPRINT(FDEP_L3, FDEM_ATTA, (CE_WARN, "fdc_detach: dip %p",
851 851 (void*)dip));
852 852
853 853 fcp = ddi_get_driver_private(dip);
854 854
855 855 switch (cmd) {
856 856 case DDI_DETACH:
857 857 for (unit = 0; unit < NFDUN; unit++)
858 858 if ((fcp->c_unit[unit])->fj_dip) {
859 859 rval = EBUSY;
860 860 break;
861 861 }
862 862 kstat_delete(fcp->c_intrstat);
863 863 fcp->c_intrstat = NULL;
864 864 ddi_remove_intr(fcp->c_dip, 0, fcp->c_iblock);
865 865 if (ddi_dmae_release(fcp->c_dip, fcp->c_dmachan) !=
866 866 DDI_SUCCESS)
867 867 cmn_err(CE_WARN, "fdc_detach: dma release failed, "
868 868 "dip %p, dmachan %x",
869 869 (void*)fcp->c_dip, fcp->c_dmachan);
870 870 ddi_prop_remove_all(fcp->c_dip);
871 871 ddi_set_driver_private(fcp->c_dip, NULL);
872 872
873 873 mutex_destroy(&fcp->c_lock);
874 874 mutex_destroy(&fcp->c_dorlock);
875 875 cv_destroy(&fcp->c_iocv);
876 876 sema_destroy(&fcp->c_selsem);
877 877 ddi_soft_state_free(fdc_state_head, ddi_get_instance(dip));
878 878 break;
879 879
880 880 case DDI_SUSPEND:
881 881 /*
882 882 * For suspend, we just use the semaphore to
883 883 * keep any child devices from accessing any of our
884 884 * hardware routines, and then shutdown the hardware.
885 885 *
886 886 * On resume, we'll reinit the hardware and release the
887 887 * semaphore.
888 888 */
889 889 sema_p(&fcp->c_selsem);
890 890
891 891 if (ddi_dmae_disable(fcp->c_dip, fcp->c_dmachan) !=
892 892 DDI_SUCCESS) {
893 893 cmn_err(CE_WARN, "fdc_suspend: dma disable failed, "
894 894 "dip %p, dmachan %x", (void *)fcp->c_dip,
895 895 fcp->c_dmachan);
896 896 /* give it back on failure */
897 897 sema_v(&fcp->c_selsem);
898 898 return (DDI_FAILURE);
899 899 }
900 900
901 901 mutex_enter(&fcp->c_lock);
902 902 fcp->c_suspended = B_TRUE;
903 903 mutex_exit(&fcp->c_lock);
904 904
905 905 rval = DDI_SUCCESS;
906 906 break;
907 907
908 908 default:
909 909 rval = EINVAL;
910 910 break;
911 911 }
912 912 return (rval);
913 913 }
914 914
915 915
916 916 int
917 917 fdc_abort(struct fcu_obj *fjp)
918 918 {
919 919 struct fdcntlr *fcp = fjp->fj_fdc;
920 920 int unit = fjp->fj_unit & 3;
921 921
922 922 FCERRPRINT(FDEP_L3, FDEM_RESE, (CE_WARN, "fdc_abort"));
923 923 if (fcp->c_curunit == unit) {
924 924 mutex_enter(&fcp->c_lock);
925 925 if (fcp->c_flags & FCFLG_WAITING) {
926 926 /*
927 927 * this can cause data corruption !
928 928 */
929 929 fdcquiesce(fcp);
930 930 fcp->c_csb.csb_xstate = FXS_RESET;
931 931 fcp->c_flags |= FCFLG_TIMEOUT;
932 932 if (ddi_dmae_stop(fcp->c_dip, fcp->c_dmachan) !=
933 933 DDI_SUCCESS)
934 934 cmn_err(CE_WARN,
935 935 "fdc_detach: dma release failed, "
936 936 "dip %p, dmachan %x",
937 937 (void*)fcp->c_dip, fcp->c_dmachan);
938 938 }
939 939 mutex_exit(&fcp->c_lock);
940 940 drv_usecwait(500);
941 941 return (DDI_SUCCESS);
942 942 }
943 943 return (DDI_FAILURE);
944 944 }
945 945
946 946 int
947 947 fdc_dkinfo(struct fcu_obj *fjp, struct dk_cinfo *dcp)
948 948 {
949 949 struct fdcntlr *fcp = fjp->fj_fdc;
950 950
951 951 (void) strncpy((char *)&dcp->dki_cname, ddi_get_name(fcp->c_dip),
952 952 DK_DEVLEN);
953 953 dcp->dki_ctype = DKC_UNKNOWN; /* no code for generic PC/AT fdc */
954 954 dcp->dki_flags = DKI_FMTTRK;
955 955 dcp->dki_addr = fcp->c_regbase;
956 956 dcp->dki_space = 0;
957 957 dcp->dki_prio = fcp->c_intprio;
958 958 dcp->dki_vec = fcp->c_intvec;
959 959 (void) strncpy((char *)&dcp->dki_dname, ddi_driver_name(fjp->fj_dip),
960 960 DK_DEVLEN);
961 961 dcp->dki_slave = fjp->fj_unit & 3;
962 962 dcp->dki_maxtransfer = maxphys / DEV_BSIZE;
963 963 return (DDI_SUCCESS);
964 964 }
965 965
966 966 /*
967 967 * on=> non-zero = select, 0 = de-select
968 968 */
969 969 int
970 970 fdc_select(struct fcu_obj *fjp, int funit, int on)
971 971 {
972 972 struct fdcntlr *fcp = fjp->fj_fdc;
973 973 int unit = funit & 3;
974 974
975 975 if (on) {
976 976 /* possess controller */
977 977 sema_p(&fcp->c_selsem);
978 978 FCERRPRINT(FDEP_L2, FDEM_DSEL,
979 979 (CE_NOTE, "fdc_select unit %d: on", funit));
980 980
981 981 if (fcp->c_curunit != unit || !(fjp->fj_flags & FUNIT_CHAROK)) {
982 982 fcp->c_curunit = unit;
983 983 fjp->fj_flags |= FUNIT_CHAROK;
984 984 if (fdcspecify(fcp,
985 985 fjp->fj_chars->fdc_transfer_rate,
986 986 fjp->fj_drive->fdd_steprate, 40))
987 987 cmn_err(CE_WARN,
988 988 "fdc_select: controller setup rejected "
989 989 "fdcntrl %p transfer rate %x step rate %x"
990 990 " head load time 40", (void*)fcp,
991 991 fjp->fj_chars->fdc_transfer_rate,
992 992 fjp->fj_drive->fdd_steprate);
993 993 }
994 994
995 995 mutex_enter(&fcp->c_dorlock);
996 996
997 997 /* make sure drive is not selected in case we change speed */
998 998 fcp->c_digout = (fcp->c_digout & ~FD_DRSEL) |
999 999 (~unit & FD_DRSEL);
1000 1000 outb(fcp->c_regbase + FCR_DOR, fcp->c_digout);
1001 1001
1002 1002 (void) fdc_motorsm(fjp, FMI_STARTCMD,
1003 1003 fjp->fj_drive->fdd_motoron);
1004 1004 /*
1005 1005 * Return value ignored - fdcmotort deals with failure.
1006 1006 */
1007 1007 if (fdcspdchange(fcp, fjp, fjp->fj_attr->fda_rotatespd)) {
1008 1008 /* 3D drive requires 500 ms for speed change */
1009 1009 (void) fdc_motorsm(fjp, FMI_RSTARTCMD, 5);
1010 1010 /*
1011 1011 * Return value ignored - fdcmotort deals with failure.
1012 1012 */
1013 1013 }
1014 1014
1015 1015 fcp->c_digout = (fcp->c_digout & ~FD_DRSEL) | (unit & FD_DRSEL);
1016 1016 outb(fcp->c_regbase + FCR_DOR, fcp->c_digout);
1017 1017
1018 1018 mutex_exit(&fcp->c_dorlock);
1019 1019 fcp->c_csb.csb_drive = (uchar_t)unit;
1020 1020 } else {
1021 1021 FCERRPRINT(FDEP_L2, FDEM_DSEL,
1022 1022 (CE_NOTE, "fdc_select unit %d: off", funit));
1023 1023
1024 1024 mutex_enter(&fcp->c_dorlock);
1025 1025
1026 1026 fcp->c_digout |= FD_DRSEL;
1027 1027 outb(fcp->c_regbase + FCR_DOR, fcp->c_digout);
1028 1028 (void) fdc_motorsm(fjp, FMI_IDLECMD,
1029 1029 fjp->fj_drive->fdd_motoroff);
1030 1030 /*
1031 1031 * Return value ignored - fdcmotort deals with failure.
1032 1032 */
1033 1033
1034 1034 mutex_exit(&fcp->c_dorlock);
1035 1035
1036 1036 /* give up controller */
1037 1037 sema_v(&fcp->c_selsem);
1038 1038 }
1039 1039 return (0);
1040 1040 }
1041 1041
1042 1042
1043 1043 int
1044 1044 fdgetchng(struct fcu_obj *fjp, int funit)
1045 1045 {
1046 1046 if (fdcsense_drv(fjp->fj_fdc, funit & 3))
1047 1047 cmn_err(CE_WARN, "fdgetchng: write protect check failed");
1048 1048 return (fdcsense_chng(fjp->fj_fdc, funit & 3));
1049 1049 }
1050 1050
1051 1051
1052 1052 int
1053 1053 fdresetchng(struct fcu_obj *fjp, int funit)
1054 1054 {
1055 1055 struct fdcntlr *fcp = fjp->fj_fdc;
1056 1056 int unit = funit & 3;
1057 1057 int newcyl; /* where to seek for reset of DSKCHG */
1058 1058
1059 1059 FCERRPRINT(FDEP_L2, FDEM_CHEK, (CE_NOTE, "fdmediachng unit %d", funit));
1060 1060
1061 1061 if (fcp->c_curpcyl[unit])
1062 1062 newcyl = fcp->c_curpcyl[unit] - 1;
1063 1063 else
1064 1064 newcyl = 1;
1065 1065 return (fdrecalseek(fjp, funit, newcyl, 0));
1066 1066 }
1067 1067
1068 1068
1069 1069 /*
1070 1070 * fdrecalseek
1071 1071 */
1072 1072 int
1073 1073 fdrecalseek(struct fcu_obj *fjp, int funit, int arg, int execflg)
1074 1074 {
1075 1075 struct fdcntlr *fcp = fjp->fj_fdc;
1076 1076 struct fdcsb *csb;
1077 1077 int unit = funit & 3;
1078 1078 int rval;
1079 1079
1080 1080 FCERRPRINT(FDEP_L2, FDEM_RECA, (CE_NOTE, "fdrecalseek unit %d to %d",
1081 1081 funit, arg));
1082 1082
1083 1083 csb = &fcp->c_csb;
1084 1084 csb->csb_cmd[1] = (uchar_t)unit;
1085 1085 if (arg < 0) { /* is recal... */
1086 1086 *csb->csb_cmd = FO_RECAL;
1087 1087 csb->csb_ncmds = 2;
1088 1088 csb->csb_timer = 28;
1089 1089 } else {
1090 1090 *csb->csb_cmd = FO_SEEK;
1091 1091 csb->csb_cmd[2] = (uchar_t)arg;
1092 1092 csb->csb_ncmds = 3;
1093 1093 csb->csb_timer = 10;
1094 1094 }
1095 1095 csb->csb_nrslts = 2; /* 2 for SENSE INTERRUPTS */
1096 1096 csb->csb_opflags = CSB_OFINRPT;
1097 1097 csb->csb_maxretry = skretry;
1098 1098 csb->csb_dmahandle = NULL;
1099 1099 csb->csb_handle_bound = 0;
1100 1100 csb->csb_dmacookiecnt = 0;
1101 1101 csb->csb_dmacurrcookie = 0;
1102 1102 csb->csb_dmawincnt = 0;
1103 1103 csb->csb_dmacurrwin = 0;
1104 1104
1105 1105 /* send cmd off to fdc_exec */
1106 1106 if (rval = fdc_exec(fcp, 1, execflg))
1107 1107 goto out;
1108 1108
1109 1109 if (!(*csb->csb_rslt & S0_SEKEND) ||
1110 1110 (*csb->csb_rslt & S0_ICMASK) ||
1111 1111 ((*csb->csb_rslt & S0_ECHK) && arg < 0) ||
1112 1112 csb->csb_cmdstat)
1113 1113 rval = ENODEV;
1114 1114
1115 1115 if (fdcsense_drv(fcp, unit))
1116 1116 cmn_err(CE_WARN, "fdgetchng: write protect check failed");
1117 1117 out:
1118 1118 return (rval);
1119 1119 }
1120 1120
1121 1121
1122 1122 /*
1123 1123 * fdrw- used only for read/writing sectors into/from kernel buffers.
1124 1124 */
1125 1125 int
1126 1126 fdrw(struct fcu_obj *fjp, int funit, int rw, int cyl, int head,
1127 1127 int sector, caddr_t bufp, uint_t len)
1128 1128 {
1129 1129 struct fdcntlr *fcp = fjp->fj_fdc;
1130 1130 struct fdcsb *csb;
1131 1131 uint_t dmar_flags = 0;
1132 1132 int unit = funit & 3;
1133 1133 int rval;
1134 1134 ddi_acc_handle_t mem_handle = NULL;
1135 1135 caddr_t aligned_buf;
1136 1136 size_t real_size;
1137 1137
1138 1138 FCERRPRINT(FDEP_L1, FDEM_RW, (CE_CONT, "fdrw unit %d\n", funit));
1139 1139
1140 1140 csb = &fcp->c_csb;
1141 1141 if (rw) {
1142 1142 dmar_flags = DDI_DMA_READ;
1143 1143 csb->csb_opflags = CSB_OFDMARD | CSB_OFINRPT;
1144 1144 *csb->csb_cmd = FO_MT | FO_MFM | FO_SK | FO_RDDAT;
1145 1145 } else { /* write */
1146 1146 dmar_flags = DDI_DMA_WRITE;
1147 1147 csb->csb_opflags = CSB_OFDMAWT | CSB_OFINRPT;
1148 1148 *csb->csb_cmd = FO_MT | FO_MFM | FO_WRDAT;
1149 1149 }
1150 1150 csb->csb_cmd[1] = (uchar_t)(unit | ((head & 0x1) << 2));
1151 1151 csb->csb_cmd[2] = (uchar_t)cyl;
1152 1152 csb->csb_cmd[3] = (uchar_t)head;
1153 1153 csb->csb_cmd[4] = (uchar_t)sector;
1154 1154 encode(sector_size, fjp->fj_chars->fdc_sec_size,
1155 1155 &csb->csb_cmd[5]);
1156 1156 csb->csb_cmd[6] = (uchar_t)max(fjp->fj_chars->fdc_secptrack, sector);
1157 1157 csb->csb_cmd[7] = fjp->fj_attr->fda_gapl;
1158 1158 csb->csb_cmd[8] = 0xFF;
1159 1159
1160 1160 csb->csb_ncmds = 9;
1161 1161 csb->csb_nrslts = 7;
1162 1162 csb->csb_timer = 36;
1163 1163 if (rw == FDRDONE)
1164 1164 csb->csb_maxretry = 1;
1165 1165 else
1166 1166 csb->csb_maxretry = rwretry;
1167 1167
1168 1168 csb->csb_dmahandle = NULL;
1169 1169 csb->csb_handle_bound = 0;
1170 1170 csb->csb_dmacookiecnt = 0;
1171 1171 csb->csb_dmacurrcookie = 0;
1172 1172 csb->csb_dmawincnt = 0;
1173 1173 csb->csb_dmacurrwin = 0;
1174 1174 dmar_flags |= (DDI_DMA_STREAMING | DDI_DMA_PARTIAL);
1175 1175
1176 1176 if (ddi_dma_alloc_handle(fcp->c_dip, &fdc_dma_attr, DDI_DMA_SLEEP,
1177 1177 0, &csb->csb_dmahandle) != DDI_SUCCESS) {
1178 1178 rval = EINVAL;
1179 1179 goto out;
1180 1180 }
1181 1181
1182 1182 /*
1183 1183 * allocate a page aligned buffer to dma to/from. This way we can
1184 1184 * ensure the cookie is a whole multiple of granularity and avoids
1185 1185 * any alignment issues.
1186 1186 */
1187 1187 rval = ddi_dma_mem_alloc(csb->csb_dmahandle, len, &fdc_accattr,
1188 1188 DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &aligned_buf,
1189 1189 &real_size, &mem_handle);
1190 1190 if (rval != DDI_SUCCESS) {
1191 1191 rval = EINVAL;
1192 1192 goto out;
1193 1193 }
1194 1194
1195 1195 if (dmar_flags & DDI_DMA_WRITE) {
1196 1196 bcopy(bufp, aligned_buf, len);
1197 1197 }
1198 1198
1199 1199 rval = ddi_dma_addr_bind_handle(csb->csb_dmahandle, NULL, aligned_buf,
1200 1200 len, dmar_flags, DDI_DMA_SLEEP, 0, &csb->csb_dmacookie,
1201 1201 &csb->csb_dmacookiecnt);
1202 1202
1203 1203 if (rval == DDI_DMA_MAPPED) {
1204 1204 csb->csb_dmawincnt = 1;
1205 1205 csb->csb_handle_bound = 1;
1206 1206 } else if (rval == DDI_DMA_PARTIAL_MAP) {
1207 1207 csb->csb_handle_bound = 1;
1208 1208 if (ddi_dma_numwin(csb->csb_dmahandle, &csb->csb_dmawincnt) !=
1209 1209 DDI_SUCCESS) {
1210 1210 cmn_err(CE_WARN, "fdrw: dma numwin failed");
1211 1211 rval = EINVAL;
1212 1212 goto out;
1213 1213 }
1214 1214 } else {
1215 1215 cmn_err(CE_WARN,
1216 1216 "fdrw: dma addr bind handle failed, rval = %d", rval);
1217 1217 rval = EINVAL;
1218 1218 goto out;
1219 1219 }
1220 1220 rval = fdc_exec(fcp, 1, 1);
1221 1221
1222 1222 if (dmar_flags & DDI_DMA_READ) {
1223 1223 bcopy(aligned_buf, bufp, len);
1224 1224 }
1225 1225
1226 1226 out:
1227 1227 if (csb->csb_dmahandle) {
1228 1228 if (csb->csb_handle_bound) {
1229 1229 if (ddi_dma_unbind_handle(csb->csb_dmahandle) !=
1230 1230 DDI_SUCCESS)
1231 1231 cmn_err(CE_WARN, "fdrw: "
1232 1232 "dma unbind handle failed");
1233 1233 csb->csb_handle_bound = 0;
1234 1234 }
1235 1235 if (mem_handle != NULL) {
1236 1236 ddi_dma_mem_free(&mem_handle);
1237 1237 }
1238 1238 ddi_dma_free_handle(&csb->csb_dmahandle);
1239 1239 csb->csb_dmahandle = NULL;
1240 1240 }
1241 1241 return (rval);
1242 1242 }
1243 1243
1244 1244
1245 1245 int
1246 1246 fdtrkformat(struct fcu_obj *fjp, int funit, int cyl, int head, int filldata)
1247 1247 {
1248 1248 struct fdcntlr *fcp = fjp->fj_fdc;
1249 1249 struct fdcsb *csb;
1250 1250 int unit = funit & 3;
1251 1251 int fmdatlen, lsector, lstart;
1252 1252 int interleave, numsctr, offset, psector;
1253 1253 uchar_t *dp;
1254 1254 int rval;
1255 1255 ddi_acc_handle_t mem_handle = NULL;
1256 1256 caddr_t aligned_buf;
1257 1257 size_t real_size;
1258 1258
1259 1259 FCERRPRINT(FDEP_L2, FDEM_FORM,
1260 1260 (CE_NOTE, "fdformattrk unit %d cyl=%d, hd=%d", funit, cyl, head));
1261 1261
1262 1262 csb = &fcp->c_csb;
1263 1263
1264 1264 csb->csb_opflags = CSB_OFDMAWT | CSB_OFINRPT;
1265 1265
1266 1266 *csb->csb_cmd = FO_FRMT | FO_MFM;
1267 1267 csb->csb_cmd[1] = (head << 2) | unit;
1268 1268 encode(sector_size, fjp->fj_chars->fdc_sec_size,
1269 1269 &csb->csb_cmd[2]);
1270 1270 csb->csb_cmd[3] = numsctr = fjp->fj_chars->fdc_secptrack;
1271 1271 csb->csb_cmd[4] = fjp->fj_attr->fda_gapf;
1272 1272 csb->csb_cmd[5] = (uchar_t)filldata;
1273 1273
1274 1274 csb->csb_npcyl = (uchar_t)(cyl * fjp->fj_chars->fdc_steps);
1275 1275
1276 1276 csb->csb_dmahandle = NULL;
1277 1277 csb->csb_handle_bound = 0;
1278 1278 csb->csb_dmacookiecnt = 0;
1279 1279 csb->csb_dmacurrcookie = 0;
1280 1280 csb->csb_dmawincnt = 0;
1281 1281 csb->csb_dmacurrwin = 0;
1282 1282 csb->csb_ncmds = 6;
1283 1283 csb->csb_nrslts = 7;
1284 1284 csb->csb_timer = 32;
1285 1285 csb->csb_maxretry = rwretry;
1286 1286
1287 1287 /*
1288 1288 * alloc space for format track cmd
1289 1289 */
1290 1290 /*
1291 1291 * NOTE: have to add size of fifo also - for dummy format action
1292 1292 */
1293 1293 fmdatlen = 4 * numsctr;
1294 1294
1295 1295 if (ddi_dma_alloc_handle(fcp->c_dip, &fdc_dma_attr, DDI_DMA_SLEEP,
1296 1296 0, &csb->csb_dmahandle) != DDI_SUCCESS) {
1297 1297 rval = EINVAL;
1298 1298 goto out;
1299 1299 }
1300 1300
1301 1301 /*
1302 1302 * allocate a page aligned buffer to dma to/from. This way we can
1303 1303 * ensure the cookie is a whole multiple of granularity and avoids
1304 1304 * any alignment issues.
1305 1305 */
1306 1306 rval = ddi_dma_mem_alloc(csb->csb_dmahandle, fmdatlen, &fdc_accattr,
1307 1307 DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &aligned_buf,
1308 1308 &real_size, &mem_handle);
1309 1309 if (rval != DDI_SUCCESS) {
1310 1310 rval = EINVAL;
1311 1311 goto out;
1312 1312 }
1313 1313 dp = (uchar_t *)aligned_buf;
1314 1314
1315 1315 interleave = fjp->fj_attr->fda_intrlv;
1316 1316 offset = (numsctr + interleave - 1) / interleave;
1317 1317 for (psector = lstart = 1;
1318 1318 psector <= numsctr; psector += interleave, lstart++) {
1319 1319 for (lsector = lstart; lsector <= numsctr; lsector += offset) {
1320 1320 *dp++ = (uchar_t)cyl;
1321 1321 *dp++ = (uchar_t)head;
1322 1322 *dp++ = (uchar_t)lsector;
1323 1323 *dp++ = csb->csb_cmd[2];
1324 1324 }
1325 1325 }
1326 1326
1327 1327 rval = ddi_dma_addr_bind_handle(csb->csb_dmahandle, NULL, aligned_buf,
1328 1328 fmdatlen, DDI_DMA_WRITE | DDI_DMA_STREAMING | DDI_DMA_PARTIAL,
1329 1329 DDI_DMA_SLEEP, 0, &csb->csb_dmacookie, &csb->csb_dmacookiecnt);
1330 1330
1331 1331 if (rval == DDI_DMA_MAPPED) {
1332 1332 csb->csb_dmawincnt = 1;
1333 1333 csb->csb_handle_bound = 1;
1334 1334 } else if (rval == DDI_DMA_PARTIAL_MAP) {
1335 1335 csb->csb_handle_bound = 1;
1336 1336 if (ddi_dma_numwin(csb->csb_dmahandle, &csb->csb_dmawincnt) !=
1337 1337 DDI_SUCCESS) {
1338 1338 cmn_err(CE_WARN, "fdtrkformat: dma numwin failed");
1339 1339 rval = EINVAL;
1340 1340 goto out;
1341 1341 }
1342 1342 } else {
1343 1343 cmn_err(CE_WARN,
1344 1344 "fdtrkformat: dma buf bind handle failed, rval = %d",
1345 1345 rval);
1346 1346 rval = EINVAL;
1347 1347 goto out;
1348 1348 }
1349 1349
1350 1350 rval = fdc_exec(fcp, 1, 1);
1351 1351 out:
1352 1352 if (csb->csb_dmahandle) {
1353 1353 if (csb->csb_handle_bound) {
1354 1354 if (ddi_dma_unbind_handle(csb->csb_dmahandle) !=
1355 1355 DDI_SUCCESS)
1356 1356 cmn_err(CE_WARN, "fdtrkformat: "
1357 1357 "dma unbind handle failed");
1358 1358 csb->csb_handle_bound = 0;
1359 1359 }
1360 1360 if (mem_handle != NULL) {
1361 1361 ddi_dma_mem_free(&mem_handle);
1362 1362 }
1363 1363 ddi_dma_free_handle(&csb->csb_dmahandle);
1364 1364 csb->csb_dmahandle = NULL;
1365 1365 }
1366 1366 return (rval);
1367 1367 }
1368 1368
1369 1369 int
1370 1370 fdrawioctl(struct fcu_obj *fjp, int funit, caddr_t arg)
1371 1371 {
1372 1372 struct fdcntlr *fcp = fjp->fj_fdc;
1373 1373 struct fd_raw *fdrp = (struct fd_raw *)arg;
1374 1374 struct fdcsb *csb;
1375 1375 uint_t dmar_flags = 0;
1376 1376 int i;
1377 1377 int change = 1;
1378 1378 int sleep = 1;
1379 1379 int rval = 0;
1380 1380 int rval_exec = 0;
1381 1381 ddi_acc_handle_t mem_handle = NULL;
1382 1382 caddr_t aligned_buf;
1383 1383 size_t real_size;
1384 1384
1385 1385 _NOTE(ARGUNUSED(funit));
1386 1386
1387 1387 FCERRPRINT(FDEP_L2, FDEM_RAWI,
1388 1388 (CE_NOTE, "fdrawioctl: cmd[0]=0x%x", fdrp->fdr_cmd[0]));
1389 1389
1390 1390 csb = &fcp->c_csb;
1391 1391
1392 1392 /* copy cmd bytes into csb */
1393 1393 for (i = 0; i <= fdrp->fdr_cnum; i++)
1394 1394 csb->csb_cmd[i] = fdrp->fdr_cmd[i];
1395 1395 csb->csb_ncmds = (uchar_t)fdrp->fdr_cnum;
1396 1396
1397 1397 csb->csb_maxretry = 0; /* let the application deal with errors */
1398 1398 csb->csb_opflags = CSB_OFRAWIOCTL;
1399 1399 csb->csb_nrslts = 0;
1400 1400 csb->csb_timer = 50;
1401 1401
1402 1402 switch (fdrp->fdr_cmd[0] & 0x0f) {
1403 1403
1404 1404 case FO_SEEK:
1405 1405 change = 0;
1406 1406 /* FALLTHROUGH */
1407 1407 case FO_RECAL:
1408 1408 csb->csb_opflags |= CSB_OFINRPT;
1409 1409 break;
1410 1410
1411 1411 case FO_FRMT:
1412 1412 csb->csb_npcyl = *(uchar_t *)(fdrp->fdr_addr) *
1413 1413 fjp->fj_chars->fdc_steps;
1414 1414 /* FALLTHROUGH */
1415 1415 case FO_WRDAT:
1416 1416 case FO_WRDEL:
1417 1417 csb->csb_opflags |= CSB_OFDMAWT | CSB_OFRESLT | CSB_OFINRPT;
1418 1418 csb->csb_nrslts = 7;
1419 1419 if (fdrp->fdr_nbytes == 0)
1420 1420 return (EINVAL);
1421 1421 dmar_flags = DDI_DMA_WRITE;
1422 1422 break;
1423 1423
1424 1424 case FO_RDDAT:
1425 1425 case FO_RDDEL:
1426 1426 case FO_RDTRK:
1427 1427 csb->csb_opflags |= CSB_OFDMARD | CSB_OFRESLT | CSB_OFINRPT;
1428 1428 csb->csb_nrslts = 7;
1429 1429 dmar_flags = DDI_DMA_READ;
1430 1430 break;
1431 1431
1432 1432 case FO_RDID:
1433 1433 csb->csb_opflags |= CSB_OFRESLT | CSB_OFINRPT;
1434 1434 csb->csb_nrslts = 7;
1435 1435 break;
1436 1436
1437 1437 case FO_SDRV:
1438 1438 sleep = 0;
1439 1439 csb->csb_nrslts = 1;
1440 1440 break;
1441 1441
1442 1442 case FO_SINT:
1443 1443 sleep = 0;
1444 1444 change = 0;
1445 1445 csb->csb_nrslts = 2;
1446 1446 break;
1447 1447
1448 1448 case FO_SPEC:
1449 1449 sleep = 0;
1450 1450 change = 0;
1451 1451 break;
1452 1452
1453 1453 default:
1454 1454 return (EINVAL);
1455 1455 }
1456 1456
1457 1457 csb->csb_dmahandle = NULL;
1458 1458 csb->csb_handle_bound = 0;
1459 1459 csb->csb_dmacookiecnt = 0;
1460 1460 csb->csb_dmacurrcookie = 0;
1461 1461 csb->csb_dmawincnt = 0;
1462 1462 csb->csb_dmacurrwin = 0;
1463 1463
1464 1464 if (csb->csb_opflags & (CSB_OFDMARD | CSB_OFDMAWT)) {
1465 1465 if (ddi_dma_alloc_handle(fcp->c_dip, &fdc_dma_attr,
1466 1466 DDI_DMA_SLEEP, 0, &csb->csb_dmahandle) != DDI_SUCCESS) {
1467 1467 rval = EINVAL;
1468 1468 goto out;
1469 1469 }
1470 1470
1471 1471 /*
1472 1472 * allocate a page aligned buffer to dma to/from. This way we
1473 1473 * can ensure the cookie is a whole multiple of granularity and
1474 1474 * avoids any alignment issues.
1475 1475 */
1476 1476 rval = ddi_dma_mem_alloc(csb->csb_dmahandle,
1477 1477 (uint_t)fdrp->fdr_nbytes, &fdc_accattr, DDI_DMA_CONSISTENT,
1478 1478 DDI_DMA_SLEEP, NULL, &aligned_buf, &real_size, &mem_handle);
1479 1479 if (rval != DDI_SUCCESS) {
1480 1480 rval = EINVAL;
1481 1481 goto out;
1482 1482 }
1483 1483
1484 1484 if (dmar_flags & DDI_DMA_WRITE) {
1485 1485 bcopy(fdrp->fdr_addr, aligned_buf,
1486 1486 (uint_t)fdrp->fdr_nbytes);
1487 1487 }
1488 1488
1489 1489 dmar_flags |= (DDI_DMA_STREAMING | DDI_DMA_PARTIAL);
1490 1490 rval = ddi_dma_addr_bind_handle(csb->csb_dmahandle, NULL,
1491 1491 aligned_buf, (uint_t)fdrp->fdr_nbytes, dmar_flags,
1492 1492 DDI_DMA_SLEEP, 0, &csb->csb_dmacookie,
1493 1493 &csb->csb_dmacookiecnt);
1494 1494
1495 1495 if (rval == DDI_DMA_MAPPED) {
1496 1496 csb->csb_dmawincnt = 1;
1497 1497 csb->csb_handle_bound = 1;
1498 1498 } else if (rval == DDI_DMA_PARTIAL_MAP) {
1499 1499 csb->csb_handle_bound = 1;
1500 1500 if (ddi_dma_numwin(csb->csb_dmahandle,
1501 1501 &csb->csb_dmawincnt) != DDI_SUCCESS) {
1502 1502 cmn_err(CE_WARN,
1503 1503 "fdrawioctl: dma numwin failed");
1504 1504 rval = EINVAL;
1505 1505 goto out;
1506 1506 }
1507 1507 } else {
1508 1508 cmn_err(CE_WARN, "fdrawioctl: "
1509 1509 "dma buf bind handle failed, rval = %d", rval);
1510 1510 rval = EINVAL;
1511 1511 goto out;
1512 1512 }
1513 1513 }
1514 1514
1515 1515 FCERRPRINT(FDEP_L1, FDEM_RAWI,
1516 1516 (CE_CONT, "cmd: %x %x %x %x %x %x %x %x %x %x\n", csb->csb_cmd[0],
1517 1517 csb->csb_cmd[1], csb->csb_cmd[2], csb->csb_cmd[3],
1518 1518 csb->csb_cmd[4], csb->csb_cmd[5], csb->csb_cmd[6],
1519 1519 csb->csb_cmd[7], csb->csb_cmd[8], csb->csb_cmd[9]));
1520 1520 FCERRPRINT(FDEP_L1, FDEM_RAWI,
1521 1521 (CE_CONT, "nbytes: %x, opflags: %x, addr: %p, len: %x\n",
1522 1522 csb->csb_ncmds, csb->csb_opflags, (void *)fdrp->fdr_addr,
1523 1523 fdrp->fdr_nbytes));
1524 1524
1525 1525 /*
1526 1526 * Note that we ignore any error returns from fdexec.
1527 1527 * This is the way the driver has been, and it may be
1528 1528 * that the raw ioctl senders simply don't want to
1529 1529 * see any errors returned in this fashion.
1530 1530 */
1531 1531
1532 1532 /*
1533 1533 * VP/ix sense drive ioctl call checks for the error return.
1534 1534 */
1535 1535
1536 1536 rval_exec = fdc_exec(fcp, sleep, change);
1537 1537
1538 1538 if (dmar_flags & DDI_DMA_READ) {
1539 1539 bcopy(aligned_buf, fdrp->fdr_addr, (uint_t)fdrp->fdr_nbytes);
1540 1540 }
1541 1541
1542 1542 FCERRPRINT(FDEP_L1, FDEM_RAWI,
1543 1543 (CE_CONT, "rslt: %x %x %x %x %x %x %x %x %x %x\n", csb->csb_rslt[0],
1544 1544 csb->csb_rslt[1], csb->csb_rslt[2], csb->csb_rslt[3],
1545 1545 csb->csb_rslt[4], csb->csb_rslt[5], csb->csb_rslt[6],
1546 1546 csb->csb_rslt[7], csb->csb_rslt[8], csb->csb_rslt[9]));
1547 1547
1548 1548 /* copy results into fdr */
1549 1549 for (i = 0; i <= (int)csb->csb_nrslts; i++)
1550 1550 fdrp->fdr_result[i] = csb->csb_rslt[i];
1551 1551 /* fdrp->fdr_nbytes = fdc->c_csb.csb_rlen; return resid */
1552 1552
1553 1553 out:
1554 1554 if (csb->csb_dmahandle) {
1555 1555 if (csb->csb_handle_bound) {
1556 1556 if (ddi_dma_unbind_handle(csb->csb_dmahandle) !=
1557 1557 DDI_SUCCESS)
1558 1558 cmn_err(CE_WARN, "fdrawioctl: "
1559 1559 "dma unbind handle failed");
1560 1560 csb->csb_handle_bound = 0;
1561 1561 }
1562 1562 if (mem_handle != NULL) {
1563 1563 ddi_dma_mem_free(&mem_handle);
1564 1564 }
1565 1565 ddi_dma_free_handle(&csb->csb_dmahandle);
1566 1566 csb->csb_dmahandle = NULL;
1567 1567 }
1568 1568 if ((fdrp->fdr_cmd[0] & 0x0f) == FO_SDRV) {
1569 1569 return (rval_exec);
1570 1570 }
1571 1571 return (rval);
1572 1572 }
1573 1573
1574 1574 void
1575 1575 encode(xlate_tbl_t *tablep, int val, uchar_t *rcode)
1576 1576 {
1577 1577 do {
1578 1578 if (tablep->value >= val) {
1579 1579 *rcode = tablep->code;
1580 1580 return;
1581 1581 }
1582 1582 } while ((++tablep)->value);
1583 1583 *rcode = tablep->code;
1584 1584 cmn_err(CE_WARN, "fdc encode failed, table %p val %x code %x",
1585 1585 (void *)tablep, val, (uint_t)*rcode);
1586 1586 }
1587 1587
1588 1588 int
1589 1589 decode(xlate_tbl_t *tablep, int kode, int *rvalue)
1590 1590 {
1591 1591 do {
1592 1592 if (tablep->code == kode) {
1593 1593 *rvalue = tablep->value;
1594 1594 return (0);
1595 1595 }
1596 1596 } while ((++tablep)->value);
1597 1597 return (-1);
1598 1598 }
1599 1599
1600 1600 /*
1601 1601 * quiesce(9E) entry point.
1602 1602 *
1603 1603 * This function is called when the system is single-threaded at high
1604 1604 * PIL with preemption disabled. Therefore, this function must not be
1605 1605 * blocked.
1606 1606 *
1607 1607 * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
1608 1608 * DDI_FAILURE indicates an error condition and should almost never happen.
1609 1609 */
1610 1610 int
1611 1611 fdc_quiesce(dev_info_t *dip)
1612 1612 {
1613 1613 struct fdcntlr *fcp;
1614 1614 int ctlr = ddi_get_instance(dip);
1615 1615 int unit;
1616 1616
1617 1617 fcp = ddi_get_soft_state(fdc_state_head, ctlr);
1618 1618
1619 1619 if (fcp == NULL)
1620 1620 return (DDI_FAILURE);
1621 1621
1622 1622 /*
1623 1623 * If no FD units are attached, there is no need to quiesce.
1624 1624 */
1625 1625 for (unit = 0; unit < NFDUN; unit++) {
1626 1626 struct fcu_obj *fjp = fcp->c_unit[unit];
1627 1627 if (fjp->fj_flags & FUNIT_DRVATCH) {
1628 1628 break;
1629 1629 }
1630 1630 }
1631 1631
1632 1632 if (unit == NFDUN)
1633 1633 return (DDI_SUCCESS);
1634 1634
1635 1635 (void) ddi_dmae_disable(fcp->c_dip, fcp->c_dmachan);
1636 1636
1637 1637 fcp->c_digout = (fcp->c_digout & (FD_DMTREN | FD_DRSEL)) | FD_ENABLE;
1638 1638 outb(fcp->c_regbase + FCR_DOR, fcp->c_digout);
1639 1639 drv_usecwait(20);
1640 1640 fcp->c_digout |= FD_RSETZ;
1641 1641 outb(fcp->c_regbase + FCR_DOR, fcp->c_digout);
1642 1642
1643 1643 if (fcp->c_chip >= i82077) {
1644 1644 int count = 4;
1645 1645 uchar_t *oplistp = configurecmd;
1646 1646 do {
1647 1647 int ntries = FDC_RQM_RETRY;
1648 1648 do {
1649 1649 if ((inb(fcp->c_regbase + FCR_MSR) &
1650 1650 (MS_RQM|MS_DIO)) == MS_RQM)
1651 1651 break;
1652 1652 else
1653 1653 drv_usecwait(1);
1654 1654 } while (--ntries);
1655 1655 if (ntries == 0) {
1656 1656 break;
1657 1657 }
1658 1658 outb(fcp->c_regbase + FCR_DATA, *oplistp++);
1659 1659 drv_usecwait(16); /* See comment in fdc_result() */
1660 1660 } while (--count);
1661 1661 }
1662 1662
1663 1663 return (DDI_SUCCESS);
1664 1664 }
1665 1665
1666 1666 void
1667 1667 fdcquiesce(struct fdcntlr *fcp)
1668 1668 {
1669 1669 int unit;
1670 1670
1671 1671 FCERRPRINT(FDEP_L2, FDEM_RESE, (CE_NOTE, "fdcquiesce fcp %p",
1672 1672 (void*)fcp));
1673 1673
1674 1674 ASSERT(MUTEX_HELD(&fcp->c_lock));
1675 1675 mutex_enter(&fcp->c_dorlock);
1676 1676
1677 1677 if (ddi_dmae_stop(fcp->c_dip, fcp->c_dmachan) != DDI_SUCCESS)
1678 1678 cmn_err(CE_WARN, "fdcquiesce: dmae stop failed, "
1679 1679 "dip %p, dmachan %x",
1680 1680 (void*)fcp->c_dip, fcp->c_dmachan);
1681 1681
1682 1682 fcp->c_digout = (fcp->c_digout & (FD_DMTREN | FD_DRSEL)) | FD_ENABLE;
1683 1683 outb(fcp->c_regbase + FCR_DOR, fcp->c_digout);
1684 1684 drv_usecwait(20);
1685 1685 fcp->c_digout |= FD_RSETZ;
1686 1686 outb(fcp->c_regbase + FCR_DOR, fcp->c_digout);
1687 1687
1688 1688 mutex_exit(&fcp->c_dorlock);
1689 1689
1690 1690 /* count resets */
1691 1691 fcp->fdstats.reset++;
1692 1692 fcp->c_curunit = -1;
1693 1693 for (unit = 0; unit < NFDUN; unit++)
1694 1694 fcp->c_curpcyl[unit] = -1;
1695 1695
1696 1696 if (fcp->c_chip >= i82077) {
1697 1697 (void) fdc_docmd(fcp, configurecmd, 4);
1698 1698 /*
1699 1699 * Ignored return. If failed, warning was issued by fdc_docmd.
1700 1700 */
1701 1701 }
1702 1702 }
1703 1703
1704 1704 void
1705 1705 fdcreadid(struct fdcntlr *fcp, struct fdcsb *csb)
1706 1706 {
1707 1707 static uchar_t readidcmd[2] = {FO_RDID | FO_MFM, 0};
1708 1708
1709 1709 readidcmd[1] = csb->csb_cmd[1];
1710 1710 (void) fdc_docmd(fcp, readidcmd, 2);
1711 1711 }
1712 1712
1713 1713 int
1714 1714 fdcseek(struct fdcntlr *fcp, int unit, int cyl)
1715 1715 {
1716 1716 static uchar_t seekabscmd[3] = {FO_SEEK, 0, 0};
1717 1717
1718 1718 FCERRPRINT(FDEP_L0, FDEM_RECA, (CE_CONT, "fdcseek unit %d to cyl %d\n",
1719 1719 unit, cyl));
1720 1720 seekabscmd[1] = (uchar_t)unit;
1721 1721 seekabscmd[2] = (uchar_t)cyl;
1722 1722 return (fdc_docmd(fcp, seekabscmd, 3));
1723 1723 }
1724 1724
1725 1725 /*
1726 1726 * Returns status of disk change line of selected drive.
1727 1727 * = 0 means diskette is present
1728 1728 * != 0 means diskette was removed and current state is unknown
1729 1729 */
1730 1730 int
1731 1731 fdcsense_chng(struct fdcntlr *fcp, int unit)
1732 1732 {
1733 1733 int digital_input;
1734 1734
1735 1735 FCERRPRINT(FDEP_L0, FDEM_SCHG,
1736 1736 (CE_CONT, "fdcsense_chng unit %d\n", unit));
1737 1737 digital_input = inb(fcp->c_regbase + FCR_DIR);
1738 1738 if (fcp->c_mode == FDCMODE_30)
1739 1739 digital_input ^= FDI_DKCHG;
1740 1740 return (digital_input & FDI_DKCHG);
1741 1741 }
1742 1742
1743 1743 int
1744 1744 fdcsense_drv(struct fdcntlr *fcp, int unit)
1745 1745 {
1746 1746 static uchar_t sensedrvcmd[2] = {FO_SDRV, 0};
1747 1747 uchar_t senser;
1748 1748 int rval;
1749 1749
1750 1750 sensedrvcmd[1] = (uchar_t)unit;
1751 1751 (void) fdc_docmd(fcp, sensedrvcmd, 2);
1752 1752 /*
1753 1753 * Ignored return. If failed, warning was issued by fdc_docmd.
1754 1754 * fdc_results retrieves the controller/drive status
1755 1755 */
1756 1756 if (rval = fdc_result(fcp, &senser, 1))
1757 1757 goto done;
1758 1758 if (senser & S3_WPROT)
1759 1759 fcp->c_unit[unit]->fj_flags |= FUNIT_WPROT;
1760 1760 else
1761 1761 fcp->c_unit[unit]->fj_flags &= ~FUNIT_WPROT;
1762 1762 done:
1763 1763 return (rval);
1764 1764 }
1765 1765
1766 1766 int
1767 1767 fdcsense_int(struct fdcntlr *fcp, int *unitp, int *cylp)
1768 1768 {
1769 1769 uchar_t senser[2];
1770 1770 int rval;
1771 1771
1772 1772 (void) fdc_docmd(fcp, &senseintcmd, 1);
1773 1773 /*
1774 1774 * Ignored return. If failed, warning was issued by fdc_docmd.
1775 1775 * fdc_results retrieves the controller/drive status
1776 1776 */
1777 1777
1778 1778 if (!(rval = fdc_result(fcp, senser, 2))) {
1779 1779 if ((*senser & (S0_IVCMD | S0_SEKEND | S0_ECHK)) != S0_SEKEND)
1780 1780 rval = 1;
1781 1781 if (unitp)
1782 1782 *unitp = *senser & 3;
1783 1783 if (cylp)
1784 1784 *cylp = senser[1];
1785 1785 }
1786 1786 return (rval);
1787 1787 }
1788 1788
1789 1789 int
1790 1790 fdcspecify(struct fdcntlr *fcp, int xferrate, int steprate, int hlt)
1791 1791 {
1792 1792 static uchar_t perpindcmd[2] = {FO_PERP, 0};
1793 1793 static uchar_t specifycmd[3] = {FO_SPEC, 0, 0};
1794 1794
1795 1795 encode(drate_mfm, xferrate, &fcp->c_config);
1796 1796 outb(fcp->c_regbase + FCR_CCR, fcp->c_config);
1797 1797
1798 1798 if (fcp->c_chip >= i82077) {
1799 1799 /*
1800 1800 * Use old style perpendicular mode command of 82077.
1801 1801 */
1802 1802 if (xferrate == 1000) {
1803 1803 /* Set GAP and WGATE */
1804 1804 perpindcmd[1] = 3;
1805 1805 /* double step rate because xlate table is for 500Kb */
1806 1806 steprate <<= 1;
1807 1807 hlt <<= 1;
1808 1808 } else
1809 1809 perpindcmd[1] = 0;
1810 1810 (void) fdc_docmd(fcp, perpindcmd, 2);
1811 1811 /*
1812 1812 * Ignored return. If failed, warning was issued by fdc_docmd.
1813 1813 */
1814 1814 }
1815 1815 encode(step_rate, steprate, &fcp->c_hutsrt);
1816 1816 specifycmd[1] = fcp->c_hutsrt |= 0x0F; /* use max head unload time */
1817 1817 hlt = (hlt >= 256) ? 0 : (hlt >> 1); /* encode head load time */
1818 1818 specifycmd[2] = fcp->c_hlt = hlt << 1; /* make room for DMA bit */
1819 1819 return (fdc_docmd(fcp, specifycmd, 3));
1820 1820 }
1821 1821
1822 1822 int
1823 1823 fdcspdchange(struct fdcntlr *fcp, struct fcu_obj *fjp, int rpm)
1824 1824 {
1825 1825 int retcode = 0;
1826 1826 uint_t ddic;
1827 1827 uchar_t deselect = 0;
1828 1828 uchar_t ds_code;
1829 1829 uchar_t enable_code;
1830 1830 uchar_t save;
1831 1831
1832 1832 if (((fcp->c_flags & FCFLG_DSOUT) == 0 && rpm <= fjp->fj_rotspd) ||
1833 1833 ((fcp->c_flags & FCFLG_DSOUT) && (fjp->fj_flags & FUNIT_3DMODE) &&
1834 1834 rpm > fjp->fj_rotspd)) {
1835 1835 return (0);
1836 1836 }
1837 1837
1838 1838 FCERRPRINT(FDEP_L1, FDEM_SCHG,
1839 1839 (CE_CONT, "fdcspdchange: %d rpm\n", rpm));
1840 1840 ASSERT(MUTEX_HELD(&fcp->c_dorlock));
1841 1841
1842 1842 switch (fcp->c_chip) {
1843 1843 default:
1844 1844 break;
1845 1845 case i82077:
1846 1846 break;
1847 1847
1848 1848 case PC87322:
1849 1849 {
1850 1850 uchar_t nscmodecmd[5] = {FO_MODE, 0x02, 0x00, 0xC8, 0x00};
1851 1851
1852 1852 if (rpm > fjp->fj_rotspd) {
1853 1853 nscmodecmd[3] ^= 0xC0;
1854 1854 retcode = (fcp->c_flags ^ FCFLG_DSOUT) ||
1855 1855 (fjp->fj_flags ^ FUNIT_3DMODE);
1856 1856 fcp->c_flags |= FCFLG_DSOUT;
1857 1857 fjp->fj_flags |= FUNIT_3DMODE;
1858 1858 } else {
1859 1859 /* program DENSEL to default output */
1860 1860 fcp->c_flags &= ~FCFLG_DSOUT;
1861 1861 retcode = fjp->fj_flags & FUNIT_3DMODE;
1862 1862 fjp->fj_flags &= ~FUNIT_3DMODE;
1863 1863 }
1864 1864 if (retcode && (fcp->c_digout & FD_DRSEL) == fcp->c_curunit) {
1865 1865 /* de-select drive while changing speed */
1866 1866 deselect = fcp->c_digout ^ FD_DRSEL;
1867 1867 outb(fcp->c_regbase + FCR_DOR, deselect);
1868 1868 }
1869 1869
1870 1870 (void) fdc_docmd(fcp, nscmodecmd, 5);
1871 1871 /*
1872 1872 * Ignored return. If failed, warning was issued by fdc_docmd.
1873 1873 */
1874 1874 break;
1875 1875 }
1876 1876
1877 1877 case FDC37C665:
1878 1878 enable_code = FSA_ENA5;
1879 1879 goto SMC_config;
1880 1880
1881 1881 case FDC37C666:
1882 1882 enable_code = FSA_ENA6;
1883 1883 SMC_config:
1884 1884 if (rpm > fjp->fj_rotspd) {
1885 1885 /* force DENSEL output to active LOW */
1886 1886 ds_code = FSB_DSHI;
1887 1887 retcode = (fcp->c_flags ^ FCFLG_DSOUT) ||
1888 1888 (fjp->fj_flags ^ FUNIT_3DMODE);
1889 1889 fcp->c_flags |= FCFLG_DSOUT;
1890 1890 fjp->fj_flags |= FUNIT_3DMODE;
1891 1891 } else {
1892 1892 /* program DENSEL to default output */
1893 1893 ds_code = 0;
1894 1894 fcp->c_flags &= ~FCFLG_DSOUT;
1895 1895 retcode = fjp->fj_flags & FUNIT_3DMODE;
1896 1896 fjp->fj_flags &= ~FUNIT_3DMODE;
1897 1897 }
1898 1898 if (retcode && (fcp->c_digout & FD_DRSEL) == fcp->c_curunit) {
1899 1899 /* de-select drive while changing speed */
1900 1900 deselect = fcp->c_digout ^ FD_DRSEL;
1901 1901 outb(fcp->c_regbase + FCR_DOR, deselect);
1902 1902 }
1903 1903 save = inb(fcp->c_regbase + FCR_SRA);
1904 1904
1905 1905 /* enter configuration mode */
1906 1906 ddic = ddi_enter_critical();
1907 1907 outb(fcp->c_regbase + FCR_SRA, enable_code);
1908 1908 outb(fcp->c_regbase + FCR_SRA, enable_code);
1909 1909 ddi_exit_critical(ddic);
1910 1910
1911 1911 outb(fcp->c_regbase + FCR_SRA, FSA_CR5);
1912 1912 enable_code = inb(fcp->c_regbase + FCR_SRB) & FSB_DSDEF;
1913 1913 /* update DENSEL mode bits */
1914 1914 outb(fcp->c_regbase + FCR_SRB, enable_code | ds_code);
1915 1915
1916 1916 /* exit configuration mode */
1917 1917 outb(fcp->c_regbase + FCR_SRA, FSA_DISB);
1918 1918 drv_usecwait(10);
1919 1919 outb(fcp->c_regbase + FCR_SRA, save);
1920 1920 break;
1921 1921 }
1922 1922 if (deselect)
1923 1923 /* reselect drive */
1924 1924 outb(fcp->c_regbase + FCR_DOR, fcp->c_digout);
1925 1925 return (retcode);
1926 1926 }
1927 1927
1928 1928 static int
1929 1929 fdc_motorsm(struct fcu_obj *fjp, int input, int timeval)
1930 1930 {
1931 1931 struct fdcntlr *fcp = fjp->fj_fdc;
1932 1932 int unit = fjp->fj_unit & 3;
1933 1933 int old_mstate;
1934 1934 int rval = 0;
1935 1935 uchar_t motorbit;
1936 1936
1937 1937 ASSERT(MUTEX_HELD(&fcp->c_dorlock));
1938 1938 old_mstate = fcp->c_mtrstate[unit];
1939 1939 encode(motor_onbits, unit, &motorbit);
1940 1940
1941 1941 switch (input) {
1942 1942 case FMI_TIMER: /* timer expired */
1943 1943 fcp->c_motort[unit] = 0;
1944 1944 switch (old_mstate) {
1945 1945 case FMS_START:
1946 1946 case FMS_DELAY:
1947 1947 fcp->c_mtrstate[unit] = FMS_ON;
1948 1948 break;
1949 1949 case FMS_KILLST:
1950 1950 fcp->c_motort[unit] = timeout(fdmotort, (void *)fjp,
1951 1951 drv_usectohz(1000000));
1952 1952 fcp->c_mtrstate[unit] = FMS_IDLE;
1953 1953 break;
1954 1954 case FMS_IDLE:
1955 1955 fcp->c_digout &= ~motorbit;
1956 1956 outb(fcp->c_regbase + FCR_DOR, fcp->c_digout);
1957 1957 fcp->c_mtrstate[unit] = FMS_OFF;
1958 1958 fjp->fj_flags &= ~FUNIT_3DMODE;
1959 1959 break;
1960 1960 case 86:
1961 1961 rval = -1;
1962 1962 break;
1963 1963 case FMS_OFF:
1964 1964 case FMS_ON:
1965 1965 default:
1966 1966 rval = -2;
1967 1967 }
1968 1968 break;
1969 1969
1970 1970 case FMI_STARTCMD: /* start command */
1971 1971 switch (old_mstate) {
1972 1972 case FMS_IDLE:
1973 1973 fcp->c_mtrstate[unit] = 86;
1974 1974 mutex_exit(&fcp->c_dorlock);
1975 1975 (void) untimeout(fcp->c_motort[unit]);
1976 1976 mutex_enter(&fcp->c_dorlock);
1977 1977 fcp->c_motort[unit] = 0;
1978 1978 fcp->c_mtrstate[unit] = FMS_ON;
1979 1979 break;
1980 1980 case FMS_OFF:
1981 1981 fcp->c_digout |= motorbit;
1982 1982 outb(fcp->c_regbase + FCR_DOR, fcp->c_digout);
1983 1983
1984 1984 /* start motor_spinup_timer */
1985 1985 ASSERT(timeval > 0);
1986 1986 fcp->c_motort[unit] = timeout(fdmotort, (void *)fjp,
1987 1987 drv_usectohz(100000 * timeval));
1988 1988 /* FALLTHROUGH */
1989 1989 case FMS_KILLST:
1990 1990 fcp->c_mtrstate[unit] = FMS_START;
1991 1991 break;
1992 1992 default:
1993 1993 rval = -2;
1994 1994 }
1995 1995 break;
1996 1996
1997 1997 case FMI_RSTARTCMD: /* restart command */
1998 1998 if (fcp->c_motort[unit] != 0) {
1999 1999 fcp->c_mtrstate[unit] = 86;
2000 2000 mutex_exit(&fcp->c_dorlock);
2001 2001 (void) untimeout(fcp->c_motort[unit]);
2002 2002 mutex_enter(&fcp->c_dorlock);
2003 2003 }
2004 2004 ASSERT(timeval > 0);
2005 2005 fcp->c_motort[unit] = timeout(fdmotort, (void *)fjp,
2006 2006 drv_usectohz(100000 * timeval));
2007 2007 fcp->c_mtrstate[unit] = FMS_START;
2008 2008 break;
2009 2009
2010 2010 case FMI_DELAYCMD: /* delay command */
2011 2011 if (fcp->c_motort[unit] == 0)
2012 2012 fcp->c_motort[unit] = timeout(fdmotort, (void *)fjp,
2013 2013 drv_usectohz(15000));
2014 2014 fcp->c_mtrstate[unit] = FMS_DELAY;
2015 2015 break;
2016 2016
2017 2017 case FMI_IDLECMD: /* idle command */
2018 2018 switch (old_mstate) {
2019 2019 case FMS_DELAY:
2020 2020 fcp->c_mtrstate[unit] = 86;
2021 2021 mutex_exit(&fcp->c_dorlock);
2022 2022 (void) untimeout(fcp->c_motort[unit]);
2023 2023 mutex_enter(&fcp->c_dorlock);
2024 2024 /* FALLTHROUGH */
2025 2025 case FMS_ON:
2026 2026 ASSERT(timeval > 0);
2027 2027 fcp->c_motort[unit] = timeout(fdmotort, (void *)fjp,
2028 2028 drv_usectohz(100000 * timeval));
2029 2029 fcp->c_mtrstate[unit] = FMS_IDLE;
2030 2030 break;
2031 2031 case FMS_START:
2032 2032 fcp->c_mtrstate[unit] = FMS_KILLST;
2033 2033 break;
2034 2034 default:
2035 2035 rval = -2;
2036 2036 }
2037 2037 break;
2038 2038
2039 2039 default:
2040 2040 rval = -3;
2041 2041 }
2042 2042 if (rval) {
2043 2043 FCERRPRINT(FDEP_L4, FDEM_EXEC, (CE_WARN,
2044 2044 "fdc_motorsm: unit %d bad input %d or bad state %d",
2045 2045 (int)fjp->fj_unit, input, old_mstate));
2046 2046 #if 0
2047 2047 cmn_err(CE_WARN,
2048 2048 "fdc_motorsm: unit %d bad input %d or bad state %d",
2049 2049 (int)fjp->fj_unit, input, old_mstate);
2050 2050 fcp->c_mtrstate[unit] = FMS_OFF;
2051 2051 if (fcp->c_motort[unit] != 0) {
2052 2052 mutex_exit(&fcp->c_dorlock);
2053 2053 (void) untimeout(fcp->c_motort[unit]);
2054 2054 mutex_enter(&fcp->c_dorlock);
2055 2055 fcp->c_motort[unit] = 0;
2056 2056 }
2057 2057 #endif
2058 2058 } else
2059 2059 FCERRPRINT(FDEP_L0, FDEM_EXEC,
2060 2060 (CE_CONT, "fdc_motorsm unit %d: input %d, %d -> %d\n",
2061 2061 (int)fjp->fj_unit, input, old_mstate,
2062 2062 fcp->c_mtrstate[unit]));
2063 2063 return (rval);
2064 2064 }
2065 2065
2066 2066 /*
2067 2067 * fdmotort
2068 2068 * is called from timeout() when a motor timer has expired.
2069 2069 */
2070 2070 static void
2071 2071 fdmotort(void *arg)
2072 2072 {
2073 2073 struct fcu_obj *fjp = (struct fcu_obj *)arg;
2074 2074 struct fdcntlr *fcp = fjp->fj_fdc;
2075 2075 struct fdcsb *csb = &fcp->c_csb;
2076 2076 int unit = fjp->fj_unit & 3;
2077 2077 int mval;
2078 2078 int newxstate = 0;
2079 2079
2080 2080 mutex_enter(&fcp->c_dorlock);
2081 2081 mval = fdc_motorsm(fjp, FMI_TIMER, 0);
2082 2082 mutex_exit(&fcp->c_dorlock);
2083 2083 if (mval < 0)
2084 2084 return;
2085 2085
2086 2086 mutex_enter(&fcp->c_lock);
2087 2087
2088 2088 if ((fcp->c_flags & FCFLG_WAITING) &&
2089 2089 fcp->c_mtrstate[unit] == FMS_ON &&
2090 2090 (csb->csb_xstate == FXS_MTRON || csb->csb_xstate == FXS_HDST ||
2091 2091 csb->csb_xstate == FXS_DKCHGX))
2092 2092 newxstate = fdc_statemach(fcp);
2093 2093 if (newxstate == -1) {
2094 2094 FCERRPRINT(FDEP_L3, FDEM_EXEC,
2095 2095 (CE_WARN,
2096 2096 "fdc_motort unit %d: motor ready but bad xstate",
2097 2097 (int)fjp->fj_unit));
2098 2098 fcp->c_csb.csb_cmdstat = EIO;
2099 2099 }
2100 2100 if (newxstate == -1 || newxstate == FXS_END) {
2101 2101 fcp->c_flags ^= FCFLG_WAITING;
2102 2102 cv_signal(&fcp->c_iocv);
2103 2103 }
2104 2104 mutex_exit(&fcp->c_lock);
2105 2105 }
2106 2106
2107 2107 /*
2108 2108 * DMA interrupt service routine
2109 2109 *
2110 2110 * Called by EISA dma interrupt service routine when buffer chaining
2111 2111 * is required.
2112 2112 */
2113 2113
2114 2114 ddi_dma_cookie_t *
2115 2115 fdc_dmae_isr(struct fdcntlr *fcp)
2116 2116 {
2117 2117 struct fdcsb *csb = &fcp->c_csb;
2118 2118 off_t off;
2119 2119 size_t len;
2120 2120
2121 2121 if (csb->csb_dmahandle && !csb->csb_cmdstat) {
2122 2122 if (++csb->csb_dmacurrcookie < csb->csb_dmacookiecnt) {
2123 2123 ddi_dma_nextcookie(csb->csb_dmahandle,
2124 2124 &csb->csb_dmacookie);
2125 2125 return (&csb->csb_dmacookie);
2126 2126 } else if (++csb->csb_dmacurrwin < csb->csb_dmawincnt) {
2127 2127 if (ddi_dma_getwin(csb->csb_dmahandle,
2128 2128 csb->csb_dmacurrwin, &off, &len,
2129 2129 &csb->csb_dmacookie,
2130 2130 &csb->csb_dmacookiecnt) != DDI_SUCCESS) {
2131 2131 return (NULL);
2132 2132 }
2133 2133 csb->csb_dmacurrcookie = 0;
2134 2134 return (&csb->csb_dmacookie);
2135 2135 }
2136 2136 } else
2137 2137 cmn_err(CE_WARN, "fdc: unsolicited DMA interrupt");
2138 2138 return (NULL);
2139 2139 }
2140 2140
2141 2141
2142 2142 /*
2143 2143 * returns:
2144 2144 * 0 if all ok,
2145 2145 * ENXIO - diskette not in drive
2146 2146 * ETIMEDOUT - for immediate operations that timed out
2147 2147 * EBUSY - if stupid chip is locked busy???
2148 2148 * ENOEXEC - for timeout during sending cmds to chip
2149 2149 *
2150 2150 * to sleep: set sleep
2151 2151 * to check for disk changed: set change
2152 2152 */
2153 2153 static int
2154 2154 fdc_exec(struct fdcntlr *fcp, int sleep, int change)
2155 2155 {
2156 2156 struct ddi_dmae_req dmaereq;
2157 2157 struct fcu_obj *fjp;
2158 2158 struct fdcsb *csb;
2159 2159 off_t off;
2160 2160 size_t len;
2161 2161 int unit;
2162 2162
2163 2163 mutex_enter(&fcp->c_lock);
2164 2164 FCERRPRINT(FDEP_L0, FDEM_EXEC,
2165 2165 (CE_CONT, "fdc_exec: sleep %x change %x\n", sleep, change));
2166 2166 csb = &fcp->c_csb;
2167 2167 unit = csb->csb_drive;
2168 2168 fjp = fcp->c_unit[unit];
2169 2169
2170 2170 if (csb->csb_opflags & CSB_OFINRPT) {
2171 2171 if (*csb->csb_cmd == FO_RECAL)
2172 2172 csb->csb_npcyl = 0;
2173 2173 else if ((*csb->csb_cmd & ~FO_MFM) != FO_FRMT)
2174 2174 csb->csb_npcyl =
2175 2175 csb->csb_cmd[2] * fjp->fj_chars->fdc_steps;
2176 2176 csb->csb_xstate = FXS_START;
2177 2177 } else
2178 2178 csb->csb_xstate = FXS_DOIT;
2179 2179 csb->csb_retrys = 0;
2180 2180 csb->csb_ourtrys = 0;
2181 2181
2182 2182 if (csb->csb_dmahandle) {
2183 2183 /* ensure that entire format xfer is in one cookie */
2184 2184 /*
2185 2185 * The change from ddi_dma_buf/addr_setup() to
2186 2186 * ddi_dma_buf/addr_bind_handle() has already loaded
2187 2187 * the first DMA window and cookie.
2188 2188 */
2189 2189 if ((*csb->csb_cmd & ~FO_MFM) == FO_FRMT &&
2190 2190 (4 * csb->csb_cmd[3]) != csb->csb_dmacookie.dmac_size) {
2191 2191 mutex_exit(&fcp->c_lock);
2192 2192 return (EINVAL);
2193 2193 }
2194 2194 }
2195 2195
2196 2196 retry:
2197 2197 if (fcp->c_curunit != unit || !(fjp->fj_flags & FUNIT_CHAROK)) {
2198 2198 fcp->c_curunit = unit;
2199 2199 fjp->fj_flags |= FUNIT_CHAROK;
2200 2200 if (fjp->fj_chars->fdc_transfer_rate == 417) {
2201 2201 /* XXX hack for fdformat */
2202 2202 /* fjp->fj_chars->fdc_transfer_rate == 500; */
2203 2203 fjp->fj_attr->fda_rotatespd = 360;
2204 2204 }
2205 2205 if (fdcspecify(fcp, fjp->fj_chars->fdc_transfer_rate,
2206 2206 fjp->fj_drive->fdd_steprate, 40))
2207 2207 cmn_err(CE_WARN,
2208 2208 "fdc_select: controller setup rejected "
2209 2209 "fdcntrl %p transfer rate %x step rate %x "
2210 2210 "head load time 40", (void*)fcp,
2211 2211 fjp->fj_chars->fdc_transfer_rate,
2212 2212 fjp->fj_drive->fdd_steprate);
2213 2213
2214 2214 mutex_enter(&fcp->c_dorlock);
2215 2215 if (fdcspdchange(fcp, fjp, fjp->fj_attr->fda_rotatespd)) {
2216 2216 /* 3D drive requires 500 ms for speed change */
2217 2217 (void) fdc_motorsm(fjp, FMI_RSTARTCMD, 5);
2218 2218 /*
2219 2219 * Return value ignored - fdcmotort deals with failure.
2220 2220 */
2221 2221 }
2222 2222 mutex_exit(&fcp->c_dorlock);
2223 2223 }
2224 2224
2225 2225 /*
2226 2226 * If checking for disk_change is enabled
2227 2227 * (i.e. not seeking in fdresetchng),
2228 2228 * we sample the DSKCHG line to see if the diskette has wandered away.
2229 2229 */
2230 2230 if (change && fdcsense_chng(fcp, unit)) {
2231 2231 FCERRPRINT(FDEP_L3, FDEM_EXEC,
2232 2232 (CE_WARN, "diskette %d changed!!!", csb->csb_drive));
2233 2233 fcp->c_unit[unit]->fj_flags |= FUNIT_CHANGED;
2234 2234 /*
2235 2235 * If the diskette is still gone... so are we, adios!
2236 2236 */
2237 2237 if (fdcheckdisk(fcp, unit)) {
2238 2238 mutex_exit(&fcp->c_lock);
2239 2239
2240 2240 /* VP/ix expects an EBUSY return here */
2241 2241 if (*csb->csb_cmd == FO_SDRV) {
2242 2242 return (EBUSY);
2243 2243 }
2244 2244 return (ENXIO);
2245 2245 }
2246 2246 /*
2247 2247 * delay to ensure that new diskette is up to speed
2248 2248 */
2249 2249 mutex_enter(&fcp->c_dorlock);
2250 2250 (void) fdc_motorsm(fjp, FMI_RSTARTCMD,
2251 2251 fjp->fj_drive->fdd_motoron);
2252 2252 /*
2253 2253 * Return value ignored - fdcmotort deals with failure.
2254 2254 */
2255 2255 mutex_exit(&fcp->c_dorlock);
2256 2256 }
2257 2257
2258 2258 /*
2259 2259 * gather some statistics
2260 2260 */
2261 2261 switch (csb->csb_cmd[0] & 0x1f) {
2262 2262 case FO_RDDAT:
2263 2263 fcp->fdstats.rd++;
2264 2264 break;
2265 2265 case FO_WRDAT:
2266 2266 fcp->fdstats.wr++;
2267 2267 break;
2268 2268 case FO_RECAL:
2269 2269 fcp->fdstats.recal++;
2270 2270 break;
2271 2271 case FO_FRMT:
2272 2272 fcp->fdstats.form++;
2273 2273 break;
2274 2274 default:
2275 2275 fcp->fdstats.other++;
2276 2276 break;
2277 2277 }
2278 2278
2279 2279 bzero(csb->csb_rslt, 10);
2280 2280 csb->csb_cmdstat = 0;
2281 2281
2282 2282 if (csb->csb_dmahandle) {
2283 2283 bzero(&dmaereq, sizeof (struct ddi_dmae_req));
2284 2284 dmaereq.der_command = (csb->csb_opflags & CSB_OFDMAWT) ?
2285 2285 DMAE_CMD_WRITE : DMAE_CMD_READ;
2286 2286 /*
2287 2287 * setup for dma buffer chaining regardless of bus capability
2288 2288 */
2289 2289 dmaereq.der_bufprocess = DMAE_BUF_CHAIN;
2290 2290 dmaereq.proc = fdc_dmae_isr;
2291 2291 dmaereq.procparms = (void *)fcp;
2292 2292 if (ddi_dmae_prog(fcp->c_dip, &dmaereq, &csb->csb_dmacookie,
2293 2293 fcp->c_dmachan) != DDI_SUCCESS)
2294 2294 cmn_err(CE_WARN, "fdc_exec: dmae prog failed, "
2295 2295 "dip %p, dmachan %x",
2296 2296 (void*)fcp->c_dip, fcp->c_dmachan);
2297 2297 }
2298 2298
2299 2299 if ((fdc_statemach(fcp) == FXS_DOWT) && !sleep) {
2300 2300 /*
2301 2301 * If the operation has no results - then just return
2302 2302 */
2303 2303 if (!csb->csb_nrslts) {
2304 2304 mutex_exit(&fcp->c_lock);
2305 2305 return (0);
2306 2306 }
2307 2307 /*
2308 2308 * this operation has no interrupt and an immediate result
2309 2309 * so wait for the results and stuff them into the csb
2310 2310 */
2311 2311 if (fdc_statemach(fcp) == -1) {
2312 2312 mutex_exit(&fcp->c_lock);
2313 2313 return (EIO);
2314 2314 }
2315 2315 } else {
2316 2316 fcp->c_flags |= FCFLG_WAITING;
2317 2317 /*
2318 2318 * wait for completion interrupt
2319 2319 */
2320 2320 while (fcp->c_flags & FCFLG_WAITING) {
2321 2321 cv_wait(&fcp->c_iocv, &fcp->c_lock);
2322 2322 }
2323 2323 }
2324 2324
2325 2325 /*
2326 2326 * See if there was an error detected, if so, fdrecover()
2327 2327 * will check it out and say what to do.
2328 2328 *
2329 2329 * Don't do this, though, if this was the Sense Drive Status
2330 2330 * or the Dump Registers command.
2331 2331 */
2332 2332 if (csb->csb_cmdstat && *csb->csb_cmd != FO_SDRV) {
2333 2333 /* if it can restarted OK, then do so, else return error */
2334 2334 if (fdrecover(fcp)) {
2335 2335 mutex_exit(&fcp->c_lock);
2336 2336 return (EIO);
2337 2337 }
2338 2338 /* ASSUMES that cmd is still intact in csb */
2339 2339 if (csb->csb_xstate == FXS_END)
2340 2340 csb->csb_xstate = FXS_START;
2341 2341 if (fdc_dma_attr.dma_attr_sgllen > 1 && csb->csb_dmahandle) {
2342 2342 /*
2343 2343 * restarted read/write operation requires
2344 2344 * first DMA cookie of current window
2345 2345 */
2346 2346 if (ddi_dma_getwin(csb->csb_dmahandle,
2347 2347 csb->csb_dmacurrwin, &off, &len,
2348 2348 &csb->csb_dmacookie,
2349 2349 &csb->csb_dmacookiecnt) != DDI_SUCCESS) {
2350 2350
2351 2351 mutex_exit(&fcp->c_lock);
2352 2352 return (EIO);
2353 2353 }
2354 2354 csb->csb_dmacurrcookie = 0;
2355 2355 }
2356 2356 goto retry;
2357 2357 }
2358 2358 /* things went ok */
2359 2359 mutex_exit(&fcp->c_lock);
2360 2360 return (0);
2361 2361 }
2362 2362
2363 2363 /*
2364 2364 * fdcheckdisk
2365 2365 * called by fdc_exec to check if the disk is still there - do a seek
2366 2366 * then see if DSKCHG line went away; if so, diskette is in; else
2367 2367 * it's (still) out.
2368 2368 */
2369 2369 int
2370 2370 fdcheckdisk(struct fdcntlr *fcp, int unit)
2371 2371 {
2372 2372 struct fdcsb *csb = &fcp->c_csb;
2373 2373 int newcyl; /* where to seek for reset of DSKCHG */
2374 2374 int rval;
2375 2375 enum fxstate save_xstate;
2376 2376 uchar_t save_cmd, save_cd1, save_npcyl;
2377 2377
2378 2378 ASSERT(MUTEX_HELD(&fcp->c_lock));
2379 2379 FCERRPRINT(FDEP_L1, FDEM_CHEK,
2380 2380 (CE_CONT, "fdcheckdisk unit %d\n", unit));
2381 2381
2382 2382 if (fcp->c_curpcyl[unit])
2383 2383 newcyl = fcp->c_curpcyl[unit] - 1;
2384 2384 else
2385 2385 newcyl = 1;
2386 2386
2387 2387 save_cmd = *csb->csb_cmd;
2388 2388 save_cd1 = csb->csb_cmd[1];
2389 2389 save_npcyl = csb->csb_npcyl;
2390 2390 save_xstate = csb->csb_xstate;
2391 2391
2392 2392 *csb->csb_cmd = FO_SEEK;
2393 2393 csb->csb_cmd[1] = (uchar_t)unit;
2394 2394 csb->csb_npcyl = (uchar_t)newcyl;
2395 2395 fcp->c_flags |= FCFLG_WAITING;
2396 2396
2397 2397 if (fcp->c_mtrstate[unit] != FMS_ON && fcp->c_motort[unit] != 0)
2398 2398 /*
2399 2399 * wait for motor to get up to speed,
2400 2400 * and let motor_timer issue seek cmd
2401 2401 */
2402 2402 csb->csb_xstate = FXS_DKCHGX;
2403 2403 else {
2404 2404 /*
2405 2405 * motor is up to speed; issue seek cmd now
2406 2406 */
2407 2407 csb->csb_xstate = FXS_SEEK;
2408 2408 if (rval = fdcseek(fcp, unit, newcyl)) {
2409 2409 /*
2410 2410 * any recal/seek errors are too serious to attend to
2411 2411 */
2412 2412 FCERRPRINT(FDEP_L3, FDEM_CHEK,
2413 2413 (CE_WARN, "fdcheckdisk err %d", rval));
2414 2414 fcp->c_flags ^= FCFLG_WAITING;
2415 2415 }
2416 2416 }
2417 2417 /*
2418 2418 * wait for completion interrupt
2419 2419 * XXX This should be backed up with a watchdog timer!
2420 2420 */
2421 2421 while (fcp->c_flags & FCFLG_WAITING) {
2422 2422 cv_wait(&fcp->c_iocv, &fcp->c_lock);
2423 2423 }
2424 2424
2425 2425 /*
2426 2426 * if disk change still asserted, no diskette in drive!
2427 2427 */
2428 2428 if (rval = fdcsense_chng(fcp, unit)) {
2429 2429 FCERRPRINT(FDEP_L3, FDEM_CHEK,
2430 2430 (CE_WARN, "fdcheckdisk no disk %d", unit));
2431 2431 }
2432 2432
2433 2433 *csb->csb_cmd = save_cmd;
2434 2434 csb->csb_cmd[1] = save_cd1;
2435 2435 csb->csb_npcyl = save_npcyl;
2436 2436 csb->csb_xstate = save_xstate;
2437 2437 return (rval);
2438 2438 }
2439 2439
2440 2440 static int
2441 2441 fdrecover(struct fdcntlr *fcp)
2442 2442 {
2443 2443 struct fcu_obj *fjp;
2444 2444 struct fdcsb *csb = &fcp->c_csb;
2445 2445 int residual;
2446 2446 int unit;
2447 2447 char *failure;
2448 2448
2449 2449 FCERRPRINT(FDEP_L2, FDEM_RECO,
2450 2450 (CE_NOTE, "fdrecover unit %d", csb->csb_drive));
2451 2451
2452 2452 unit = csb->csb_drive;
2453 2453 fjp = fcp->c_unit[unit];
2454 2454 if (fcp->c_flags & FCFLG_TIMEOUT) {
2455 2455 fcp->c_flags ^= FCFLG_TIMEOUT;
2456 2456 csb->csb_rslt[1] |= 0x08;
2457 2457 FCERRPRINT(FDEP_L3, FDEM_RECO,
2458 2458 (CE_WARN, "fd unit %d: %s timed out", csb->csb_drive,
2459 2459 fdcmds[*csb->csb_cmd & 0x1f].cmdname));
2460 2460 }
2461 2461
2462 2462 if (csb->csb_status & S0_SEKEND)
2463 2463 fcp->c_curpcyl[unit] = -1;
2464 2464
2465 2465 switch (csb->csb_oldxs) {
2466 2466 case FXS_RCAL: /* recalibrate */
2467 2467 case FXS_SEEK: /* seek */
2468 2468 case FXS_RESET: /* cntlr reset */
2469 2469 FCERRPRINT(FDEP_L4, FDEM_RECO, (CE_WARN,
2470 2470 "fd unit %d: %s error: st0=0x%x pcn=%d", csb->csb_drive,
2471 2471 fdcmds[*csb->csb_cmd & 0x1f].cmdname,
2472 2472 *csb->csb_rslt, csb->csb_rslt[1]));
2473 2473 if (csb->csb_retrys++ < skretry &&
2474 2474 !(csb->csb_opflags & CSB_OFRAWIOCTL))
2475 2475 return (0);
2476 2476 break;
2477 2477
2478 2478 case FXS_RDID: /* read ID */
2479 2479 if (!(csb->csb_status & S0_SEKEND))
2480 2480 csb->csb_xstate = FXS_HDST;
2481 2481 /* FALLTHROUGH */
2482 2482 case FXS_DOIT: /* original operation */
2483 2483 case FXS_DOWT: /* waiting on operation */
2484 2484 if (csb->csb_opflags & (CSB_OFDMARD | CSB_OFDMAWT)) {
2485 2485 if (ddi_dmae_getcnt(fcp->c_dip, fcp->c_dmachan,
2486 2486 &residual) != DDI_SUCCESS)
2487 2487 cmn_err(CE_WARN,
2488 2488 "fdc_recover: dmae getcnt failed, "
2489 2489 "dip %p dmachan %x residual %x",
2490 2490 (void*)fcp->c_dip, fcp->c_dmachan,
2491 2491 residual);
2492 2492 FCERRPRINT(FDEP_L2, FDEM_RECO,
2493 2493 (CE_NOTE,
2494 2494 "fd unit %d: %s error: "
2495 2495 "dma count=0x%lx residual=0x%x",
2496 2496 csb->csb_drive,
2497 2497 fdcmds[*csb->csb_cmd & 0x1f].cmdname,
2498 2498 csb->csb_dmacookie.dmac_size, residual));
2499 2499 }
2500 2500 if (csb->csb_rslt[1] == S1_OVRUN)
2501 2501 /*
2502 2502 * handle retries of over/underrun
2503 2503 * with a secondary retry counter
2504 2504 */
2505 2505 if (++csb->csb_ourtrys <= OURUN_TRIES) {
2506 2506 FCERRPRINT(FDEP_L2, FDEM_RECO,
2507 2507 (CE_NOTE,
2508 2508 "fd unit %d: %s error: over/under-run",
2509 2509 csb->csb_drive,
2510 2510 fdcmds[*csb->csb_cmd & 0x1f].cmdname));
2511 2511 return (0);
2512 2512 } else
2513 2513 /*
2514 2514 * count 1 set of over/underruns
2515 2515 * as 1 primary retry effort
2516 2516 */
2517 2517 csb->csb_ourtrys = 0;
2518 2518
2519 2519 if ((fjp->fj_flags & (FUNIT_UNLABELED | FUNIT_LABELOK)) &&
2520 2520 !(csb->csb_opflags & CSB_OFRAWIOCTL)) {
2521 2521 /*
2522 2522 * device is open so keep trying and
2523 2523 * gather statistics on errors
2524 2524 */
2525 2525 if (csb->csb_rslt[1] & S1_CRCER)
2526 2526 fcp->fdstats.de++;
2527 2527 if (csb->csb_rslt[1] & S1_OVRUN)
2528 2528 fcp->fdstats.run++;
2529 2529 if (csb->csb_rslt[1] & (S1_NODATA | S1_MADMK))
2530 2530 fcp->fdstats.bfmt++;
2531 2531 if (csb->csb_rslt[1] & 0x08)
2532 2532 fcp->fdstats.to++;
2533 2533
2534 2534 /*
2535 2535 * if we have not run out of retries, return 0
2536 2536 */
2537 2537 if (csb->csb_retrys++ < csb->csb_maxretry &&
2538 2538 (*csb->csb_cmd & ~FO_MFM) != FO_FRMT) {
2539 2539 if (csb->csb_opflags &
2540 2540 (CSB_OFDMARD | CSB_OFDMAWT)) {
2541 2541 FCERRPRINT(FDEP_L4, FDEM_RECO,
2542 2542 (CE_WARN,
2543 2543 "fd unit %d: %s error: "
2544 2544 "st0=0x%x st1=0x%x st2=0x%x",
2545 2545 csb->csb_drive,
2546 2546 fdcmds[*csb->csb_cmd &
2547 2547 0x1f].cmdname,
2548 2548 *csb->csb_rslt, csb->csb_rslt[1],
2549 2549 csb->csb_rslt[2]));
2550 2550 }
2551 2551 if ((csb->csb_retrys & 1) &&
2552 2552 csb->csb_xstate == FXS_END)
2553 2553 csb->csb_xstate = FXS_DOIT;
2554 2554 else if (csb->csb_retrys == 3)
2555 2555 csb->csb_xstate = FXS_RESTART;
2556 2556 return (0);
2557 2557 }
2558 2558 if (csb->csb_rslt[1] & S1_CRCER)
2559 2559 failure = "crc error";
2560 2560 else if (csb->csb_rslt[1] & S1_OVRUN)
2561 2561 failure = "over/under-run";
2562 2562 else if (csb->csb_rslt[1] & (S1_NODATA | S1_MADMK))
2563 2563 failure = "bad format";
2564 2564 else if (csb->csb_rslt[1] & 0x08)
2565 2565 failure = "timeout";
2566 2566 else
2567 2567 failure = "failed";
2568 2568 cmn_err(CE_NOTE, "!fd unit %d: %s %s (%x %x %x)",
2569 2569 csb->csb_drive,
2570 2570 fdcmds[*csb->csb_cmd & 0x1f].cmdname, failure,
2571 2571 *csb->csb_rslt, csb->csb_rslt[1], csb->csb_rslt[2]);
2572 2572 } else {
2573 2573 FCERRPRINT(FDEP_L2, FDEM_RECO,
2574 2574 (CE_NOTE, "fd unit %d: %s failed (%x %x %x)",
2575 2575 csb->csb_drive,
2576 2576 fdcmds[*csb->csb_cmd & 0x1f].cmdname,
2577 2577 *csb->csb_rslt, csb->csb_rslt[1],
2578 2578 csb->csb_rslt[2]));
2579 2579 }
2580 2580 break;
2581 2581
2582 2582 default:
2583 2583 FCERRPRINT(FDEP_L4, FDEM_RECO, (CE_WARN,
2584 2584 "fd unit %d: %s failed: st0=0x%x st1=0x%x st2=0x%x",
2585 2585 csb->csb_drive, fdcmds[*csb->csb_cmd & 0x1f].cmdname,
2586 2586 *csb->csb_rslt, csb->csb_rslt[1], csb->csb_rslt[2]));
2587 2587 break;
2588 2588 }
2589 2589 return (1);
2590 2590 }
2591 2591
2592 2592
2593 2593 /* Autovector Interrupt Entry Point */
2594 2594 static uint_t
2595 2595 fdc_intr(caddr_t arg)
2596 2596 {
2597 2597 struct fdcntlr *fcp = (struct fdcntlr *)arg;
2598 2598 struct fdcsb *csb;
2599 2599 off_t off;
2600 2600 size_t blklen;
2601 2601 int drive;
2602 2602 int newstate;
2603 2603 int pendstate;
2604 2604 int rval = DDI_DMA_DONE;
2605 2605 int state;
2606 2606 int maxspin = 10;
2607 2607
2608 2608 csb = &fcp->c_csb;
2609 2609
2610 2610 mutex_enter(&fcp->c_lock);
2611 2611 if (fcp->c_suspended) {
2612 2612 mutex_exit(&fcp->c_lock);
2613 2613 return (DDI_INTR_UNCLAIMED);
2614 2614 }
2615 2615
2616 2616 /*
2617 2617 * Wait for the RQM bit to be set, or until we've tested it
2618 2618 * a bunch of times (which may imply this isn't our interrupt).
2619 2619 */
2620 2620 state = inb(fcp->c_regbase + FCR_MSR);
2621 2621 pendstate = state & (MS_RQM | MS_DIO | MS_CB);
2622 2622 while (((pendstate & MS_RQM) == 0) && (maxspin-- > 0)) {
2623 2623 /* Small pause in between reading the status port */
2624 2624 drv_usecwait(10);
2625 2625 /* Reread the status port */
2626 2626 state = inb(fcp->c_regbase + FCR_MSR);
2627 2627 pendstate = state & (MS_RQM | MS_DIO | MS_CB);
2628 2628 }
2629 2629 FCERRPRINT(FDEP_L0, FDEM_INTR,
2630 2630 (CE_CONT, "fdc_intr unit %d: xstate=%d MSR=0x%x\n",
2631 2631 csb->csb_drive, csb->csb_xstate, state));
2632 2632
2633 2633 /*
2634 2634 * If there is an operation outstanding AND the controller is ready
2635 2635 * to receive a command or send us the result of a command (OR if the
2636 2636 * controller is ready to accept a new command), AND if
2637 2637 * someone has been waiting for a command to finish AND (if no unit
2638 2638 * is BUSY OR if the unit that we're waiting for is BUSY (i.e. it's in
2639 2639 * the middle of a seek/recalibrate)) then this interrupt is for us.
2640 2640 */
2641 2641 if ((pendstate == (MS_RQM | MS_DIO | MS_CB) || pendstate == MS_RQM) &&
2642 2642 (fcp->c_flags & FCFLG_WAITING) &&
2643 2643 (!(state & 0x0f) || ((1 << csb->csb_drive) & state))) {
2644 2644 /*
2645 2645 * Remove one of the conditions for entering this code.
2646 2646 * The state_machine will release the c_lock if it
2647 2647 * calls untimeout()
2648 2648 */
2649 2649 fcp->c_flags ^= FCFLG_WAITING;
2650 2650
2651 2651 if ((newstate = fdc_statemach(fcp)) == -1) {
2652 2652 /* restore waiting flag */
2653 2653 fcp->c_flags |= FCFLG_WAITING;
2654 2654 mutex_exit(&fcp->c_lock);
2655 2655 return (DDI_INTR_CLAIMED);
2656 2656 }
2657 2657
2658 2658 if (fcp->c_intrstat)
2659 2659 KIOIP->intrs[KSTAT_INTR_HARD]++;
2660 2660 if (newstate == FXS_END) {
2661 2661
2662 2662 if (csb->csb_dmahandle && !csb->csb_cmdstat &&
2663 2663 /*
2664 2664 * read/write operation may have multiple DMA
2665 2665 * cookies: process next one
2666 2666 */
2667 2667 ((csb->csb_dmacurrcookie <
2668 2668 (csb->csb_dmacookiecnt - 1)) ||
2669 2669 (csb->csb_dmacurrwin) < (csb->csb_dmawincnt - 1))) {
2670 2670 /*
2671 2671 * read/write operation requires another
2672 2672 * DMA cookie: process next one
2673 2673 */
2674 2674
2675 2675 if (++csb->csb_dmacurrcookie <
2676 2676 csb->csb_dmacookiecnt) {
2677 2677 ddi_dma_nextcookie(csb->csb_dmahandle,
2678 2678 &csb->csb_dmacookie);
2679 2679 } else if (++csb->csb_dmacurrwin <
2680 2680 csb->csb_dmawincnt) {
2681 2681 if (ddi_dma_getwin(csb->csb_dmahandle,
2682 2682 csb->csb_dmacurrwin, &off, &blklen,
2683 2683 &csb->csb_dmacookie,
2684 2684 &csb->csb_dmacookiecnt) !=
2685 2685 DDI_SUCCESS) {
2686 2686 cmn_err(CE_WARN,
2687 2687 "fdc_intr: "
2688 2688 "dma getwin failed");
2689 2689 }
2690 2690 csb->csb_dmacurrcookie = 0;
2691 2691 }
2692 2692
2693 2693 if (ddi_dmae_prog(fcp->c_dip, NULL,
2694 2694 &csb->csb_dmacookie, fcp->c_dmachan) !=
2695 2695 DDI_SUCCESS)
2696 2696 cmn_err(CE_WARN,
2697 2697 "fdc_intr: dmae prog failed, "
2698 2698 "dip %p dmachannel %x",
2699 2699 (void*)fcp->c_dip,
2700 2700 fcp->c_dmachan);
2701 2701
2702 2702 /*
2703 2703 * status of last operation has disk
2704 2704 * address for continuation
2705 2705 */
2706 2706 csb->csb_cmd[2] = csb->csb_rslt[3];
2707 2707 csb->csb_cmd[3] = csb->csb_rslt[4];
2708 2708 csb->csb_cmd[4] = csb->csb_rslt[5];
2709 2709 csb->csb_cmd[1] = (csb->csb_cmd[1] & ~0x04) |
2710 2710 (csb->csb_cmd[3] << 2);
2711 2711
2712 2712 csb->csb_xstate = FXS_START;
2713 2713 (void) fdc_statemach(fcp);
2714 2714 /*
2715 2715 * Ignored return. If failed, warning already
2716 2716 * posted. Returned state irrelevant.
2717 2717 */
2718 2718 /* restore waiting flag */
2719 2719 fcp->c_flags |= FCFLG_WAITING;
2720 2720 goto fi_exit;
2721 2721 }
2722 2722 if (rval != DDI_DMA_DONE)
2723 2723 csb->csb_cmdstat = EIO;
2724 2724 /*
2725 2725 * somebody's waiting for completion of fdcntlr/csb,
2726 2726 * wake them
2727 2727 */
2728 2728 cv_signal(&fcp->c_iocv);
2729 2729 }
2730 2730 else
2731 2731 /* restore waiting flag */
2732 2732 fcp->c_flags |= FCFLG_WAITING;
2733 2733 fi_exit:
2734 2734 mutex_exit(&fcp->c_lock);
2735 2735 return (DDI_INTR_CLAIMED);
2736 2736 }
2737 2737
2738 2738 if (state & MS_RQM) {
2739 2739 (void) fdcsense_int(fcp, &drive, NULL);
2740 2740 /*
2741 2741 * Ignored return - senser state already saved
2742 2742 */
2743 2743 FCERRPRINT(FDEP_L4, FDEM_INTR,
2744 2744 (CE_WARN, "fdc_intr unit %d: nobody sleeping 0x%x",
2745 2745 drive, state));
2746 2746 } else {
2747 2747 FCERRPRINT(FDEP_L4, FDEM_INTR,
2748 2748 (CE_WARN, "fdc_intr: nobody sleeping on %d 0x%x",
2749 2749 csb->csb_drive, state));
2750 2750 }
2751 2751 /*
2752 2752 * This should probably be protected, but, what the
2753 2753 * heck...the cost isn't worth the accuracy for this
2754 2754 * statistic.
2755 2755 */
2756 2756 if (fcp->c_intrstat)
2757 2757 KIOIP->intrs[KSTAT_INTR_SPURIOUS]++;
2758 2758 mutex_exit(&fcp->c_lock);
2759 2759 return (DDI_INTR_UNCLAIMED);
2760 2760 }
2761 2761
2762 2762 /*
2763 2763 * fdwatch
2764 2764 * is called from timeout() when a floppy operation timer has expired.
2765 2765 */
2766 2766 static void
2767 2767 fdwatch(void *arg)
2768 2768 {
2769 2769 struct fdcntlr *fcp = (struct fdcntlr *)arg;
2770 2770 struct fdcsb *csb;
2771 2771
2772 2772 mutex_enter(&fcp->c_lock);
2773 2773
2774 2774 if (fcp->c_timeid == 0) {
2775 2775 /*
2776 2776 * fdc_intr got here first, ergo, no timeout condition..
2777 2777 */
2778 2778 mutex_exit(&fcp->c_lock);
2779 2779 return;
2780 2780 }
2781 2781
2782 2782 if (fcp->c_flags & FCFLG_WAITING) {
2783 2783 if (ddi_dmae_stop(fcp->c_dip, fcp->c_dmachan) != DDI_SUCCESS)
2784 2784 cmn_err(CE_WARN, "fdwatch: dmae stop failed, "
2785 2785 "dip %p, dmachan %x",
2786 2786 (void*)fcp->c_dip, fcp->c_dmachan);
2787 2787 csb = &fcp->c_csb;
2788 2788 FCERRPRINT(FDEP_L3, FDEM_WATC,
2789 2789 (CE_WARN, "fdcwatch unit %d: xstate = %d",
2790 2790 csb->csb_drive, csb->csb_xstate));
2791 2791 drv_usecwait(50);
2792 2792
2793 2793 if (inb(fcp->c_regbase + FCR_MSR) != MS_RQM) {
2794 2794 /*
2795 2795 * cntlr is still busy, so reset it
2796 2796 */
2797 2797 csb->csb_xstate = FXS_KILL;
2798 2798 (void) fdc_statemach(fcp);
2799 2799 /*
2800 2800 * Ignored return. If failed, warning already
2801 2801 * posted. Returned state irrelevant.
2802 2802 */
2803 2803 } else {
2804 2804 csb->csb_xstate = FXS_END;
2805 2805 fcp->c_timeid = 0;
2806 2806 fcp->c_flags ^= FCFLG_WAITING;
2807 2807 cv_signal(&fcp->c_iocv);
2808 2808 }
2809 2809 csb->csb_cmdstat = EIO;
2810 2810 fcp->c_flags |= FCFLG_TIMEOUT;
2811 2811 } else {
2812 2812 FCERRPRINT(FDEP_L4, FDEM_INTR,
2813 2813 (CE_WARN, "fdcwatch: not sleeping for unit %d",
2814 2814 fcp->c_csb.csb_drive));
2815 2815 }
2816 2816 if (fcp->c_intrstat)
2817 2817 KIOIP->intrs[KSTAT_INTR_WATCHDOG]++;
2818 2818 mutex_exit(&fcp->c_lock);
2819 2819 }
2820 2820
2821 2821
2822 2822 static int
2823 2823 fdc_statemach(struct fdcntlr *fcp)
2824 2824 {
2825 2825 struct fcu_obj *fjp;
2826 2826 struct fdcsb *csb = &fcp->c_csb;
2827 2827 int backoff;
2828 2828 clock_t time;
2829 2829 int unit;
2830 2830
2831 2831 ASSERT(MUTEX_HELD(&fcp->c_lock));
2832 2832
2833 2833 unit = csb->csb_drive;
2834 2834 fjp = fcp->c_unit[unit];
2835 2835
2836 2836 csb->csb_oldxs = csb->csb_xstate;
2837 2837 switch (csb->csb_xstate) {
2838 2838
2839 2839 case FXS_START: /* start of operation */
2840 2840 ASSERT(fcp->c_timeid == 0);
2841 2841 time = drv_usectohz(100000 * (unsigned int)csb->csb_timer);
2842 2842 if (time == 0)
2843 2843 time = drv_usectohz(2000000);
2844 2844 fcp->c_timeid = timeout(fdwatch, (void *)fcp, time);
2845 2845
2846 2846 if (fcp->c_mtrstate[unit] == FMS_START) {
2847 2847 /*
2848 2848 * wait for motor to get up to speed
2849 2849 */
2850 2850 csb->csb_xstate = FXS_MTRON;
2851 2851 break;
2852 2852 }
2853 2853 /* FALLTHROUGH */
2854 2854
2855 2855 case FXS_MTRON: /* motor is at speed */
2856 2856 if (fcp->c_mtrstate[unit] != FMS_ON) {
2857 2857 /* how did we get here ?? */
2858 2858 cmn_err(CE_WARN, "fdc: selected but motor off");
2859 2859 return (-1);
2860 2860 }
2861 2861 if (fcp->c_curpcyl[unit] != -1 && *csb->csb_cmd != FO_RECAL)
2862 2862 goto nxs_seek;
2863 2863 recalcmd[1] = (uchar_t)unit;
2864 2864 if (fdc_docmd(fcp, recalcmd, 2) == -1) {
2865 2865 /* cntlr did not accept command bytes */
2866 2866 fdcquiesce(fcp);
2867 2867 csb->csb_cmdstat = EIO;
2868 2868 csb->csb_xstate = FXS_RESET;
2869 2869 break;
2870 2870 }
2871 2871 fcp->c_sekdir[unit] = 0;
2872 2872 csb->csb_xstate = FXS_RCAL;
2873 2873 break;
2874 2874
2875 2875 case FXS_RCAL: /* forced recalibrate is complete */
2876 2876 #if 0 /* #ifdef _VPIX */
2877 2877 /* WARNING: this code breaks SPARC compatibility */
2878 2878 if (csb->csb_opflags & CSB_OFRAWIOCTL &&
2879 2879 *csb->csb_cmd == FO_RECAL) {
2880 2880 fcp->c_curpcyl[unit] = 0;
2881 2881 csb->csb_status = 0;
2882 2882 goto nxs_cmpl;
2883 2883 }
2884 2884 #endif
2885 2885 (void) fdc_docmd(fcp, &senseintcmd, 1);
2886 2886 /*
2887 2887 * Ignored return. If failed, warning was issued by fdc_docmd.
2888 2888 * fdc_results retrieves the controller/drive status
2889 2889 */
2890 2890 (void) fdc_result(fcp, csb->csb_rslt, 2);
2891 2891 /*
2892 2892 * Ignored return. If failed, warning was issued by fdc_result.
2893 2893 * Actual results checked below
2894 2894 */
2895 2895 if ((csb->csb_status = ((*csb->csb_rslt ^ S0_SEKEND) &
2896 2896 (S0_ICMASK | S0_SEKEND | S0_ECHK | S0_NOTRDY))) != 0) {
2897 2897 FCERRPRINT(FDEP_L3, FDEM_EXEC,
2898 2898 (CE_WARN, "fdc_statemach unit %d: recal result %x",
2899 2899 csb->csb_drive, *csb->csb_rslt));
2900 2900 fdcquiesce(fcp);
2901 2901 csb->csb_cmdstat = EIO;
2902 2902 csb->csb_xstate = FXS_RESET;
2903 2903 break;
2904 2904 }
2905 2905 if (unit != (*csb->csb_rslt & 3) || csb->csb_rslt[1]) {
2906 2906 csb->csb_status = S0_SEKEND;
2907 2907 goto nxs_cmpl;
2908 2908 }
2909 2909 fcp->c_curpcyl[unit] = csb->csb_rslt[1];
2910 2910 if (*csb->csb_cmd == FO_RECAL)
2911 2911 goto nxs_cmpl;
2912 2912 nxs_seek:
2913 2913 if (*csb->csb_cmd != FO_SEEK &&
2914 2914 csb->csb_npcyl == fcp->c_curpcyl[unit])
2915 2915 goto nxs_doit;
2916 2916 fcp->c_sekdir[unit] = csb->csb_npcyl - fcp->c_curpcyl[unit];
2917 2917 /* FALLTHROUGH */
2918 2918
2919 2919 case FXS_DKCHGX: /* reset Disk-Change latch */
2920 2920 (void) fdcseek(fcp, csb->csb_cmd[1], csb->csb_npcyl);
2921 2921 /*
2922 2922 * Ignored return. If command rejected, warnig already posted
2923 2923 * by fdc_docmd().
2924 2924 */
2925 2925 csb->csb_xstate = FXS_SEEK;
2926 2926 break;
2927 2927
2928 2928 case FXS_RESTART: /* special restart of read/write operation */
2929 2929 ASSERT(fcp->c_timeid == 0);
2930 2930 time = drv_usectohz(100000 * csb->csb_timer);
2931 2931 if (time == 0)
2932 2932 time = drv_usectohz(2000000);
2933 2933 fcp->c_timeid = timeout(fdwatch, (void *)fcp, time);
2934 2934
2935 2935 if (fcp->c_mtrstate[unit] != FMS_ON) {
2936 2936 cmn_err(CE_WARN, "fdc: selected but motor off");
2937 2937 return (-1);
2938 2938 }
2939 2939 if ((csb->csb_npcyl == 0 || fcp->c_sekdir[unit] >= 0) &&
2940 2940 (int)csb->csb_cmd[2] < (fjp->fj_chars->fdc_ncyl - 1))
2941 2941 backoff = csb->csb_npcyl + 1;
2942 2942 else
2943 2943 backoff = csb->csb_npcyl - 1;
2944 2944 (void) fdcseek(fcp, csb->csb_cmd[1], backoff);
2945 2945 /*
2946 2946 * Ignored return. If command rejected, warnig already posted
2947 2947 * by fdc_docmd().
2948 2948 */
2949 2949 csb->csb_xstate = FXS_RESEEK;
2950 2950 break;
2951 2951
2952 2952 case FXS_RESEEK: /* seek to backoff-cyl complete */
2953 2953 (void) fdc_docmd(fcp, &senseintcmd, 1);
2954 2954 /*
2955 2955 * Ignored return. If failed, warning was issued by fdc_docmd.
2956 2956 * fdc_results retrieves the controller/drive status
2957 2957 */
2958 2958 (void) fdc_result(fcp, csb->csb_rslt, 2);
2959 2959 /*
2960 2960 * Ignored return. If failed, warning was issued by fdc_result.
2961 2961 * Actual results checked below
2962 2962 */
2963 2963 if ((csb->csb_status = ((*csb->csb_rslt ^ S0_SEKEND) &
2964 2964 (S0_ICMASK | S0_SEKEND | S0_ECHK | S0_NOTRDY))) != 0)
2965 2965 goto nxs_cmpl;
2966 2966 (void) fdcseek(fcp, csb->csb_cmd[1], csb->csb_npcyl);
2967 2967 /*
2968 2968 * Ignored return. If command rejected, warnig already posted
2969 2969 * by fdc_docmd().
2970 2970 */
2971 2971 csb->csb_xstate = FXS_SEEK;
2972 2972 break;
2973 2973
2974 2974 case FXS_SEEK: /* seek complete */
2975 2975 #if 0 /* #ifdef _VPIX */
2976 2976 /* WARNING: this code breaks SPARC compatibility and */
2977 2977 /* rawioctls in fdformat */
2978 2978 if (csb->csb_opflags & CSB_OFRAWIOCTL) {
2979 2979 fcp->c_curpcyl[unit] = csb->csb_npcyl;
2980 2980 csb->csb_status = 0;
2981 2981 goto nxs_cmpl;
2982 2982 }
2983 2983 #endif
2984 2984 (void) fdc_docmd(fcp, &senseintcmd, 1);
2985 2985 /*
2986 2986 * Ignored return. If failed, warning was issued by fdc_docmd.
2987 2987 * fdc_results retrieves the controller/drive status
2988 2988 */
2989 2989 (void) fdc_result(fcp, csb->csb_rslt, 2);
2990 2990 /*
2991 2991 * Ignored return. If failed, warning was issued by fdc_result.
2992 2992 * Actual results checked below
2993 2993 */
2994 2994 if ((csb->csb_status = ((*csb->csb_rslt ^ S0_SEKEND) &
2995 2995 (S0_ICMASK | S0_SEKEND | S0_ECHK | S0_NOTRDY))) != 0)
2996 2996 goto nxs_cmpl;
2997 2997 if (unit != (*csb->csb_rslt & 3) ||
2998 2998 csb->csb_rslt[1] != csb->csb_npcyl) {
2999 2999 csb->csb_status = S0_SEKEND;
3000 3000 goto nxs_cmpl;
3001 3001 };
3002 3002 fcp->c_curpcyl[unit] = csb->csb_rslt[1];
3003 3003 /* use motor_timer to delay for head settle */
3004 3004 mutex_enter(&fcp->c_dorlock);
3005 3005 (void) fdc_motorsm(fjp, FMI_DELAYCMD,
3006 3006 fjp->fj_drive->fdd_headsettle / 1000);
3007 3007 /*
3008 3008 * Return value ignored - fdcmotort deals with failure.
3009 3009 */
3010 3010 mutex_exit(&fcp->c_dorlock);
3011 3011 csb->csb_xstate = FXS_HDST;
3012 3012 break;
3013 3013
3014 3014 case FXS_HDST: /* head settle */
3015 3015 if (*csb->csb_cmd == FO_SEEK)
3016 3016 goto nxs_cmpl;
3017 3017 if ((*csb->csb_cmd & ~FO_MFM) == FO_FRMT)
3018 3018 goto nxs_doit;
3019 3019 fdcreadid(fcp, csb);
3020 3020 csb->csb_xstate = FXS_RDID;
3021 3021 break;
3022 3022
3023 3023 case FXS_RDID: /* read ID complete */
3024 3024 (void) fdc_result(fcp, csb->csb_rslt, 7);
3025 3025 /*
3026 3026 * Ignored return. If failed, warning was issued by fdc_result.
3027 3027 * Actual results checked below
3028 3028 */
3029 3029 if ((csb->csb_status = (*csb->csb_rslt &
3030 3030 (S0_ICMASK | S0_ECHK | S0_NOTRDY))) != 0)
3031 3031 goto nxs_cmpl;
3032 3032 if (csb->csb_cmd[2] != csb->csb_rslt[3]) {
3033 3033 /* at wrong logical cylinder */
3034 3034 csb->csb_status = S0_SEKEND;
3035 3035 goto nxs_cmpl;
3036 3036 };
3037 3037 goto nxs_doit;
3038 3038
3039 3039 case FXS_DOIT: /* do original operation */
3040 3040 ASSERT(fcp->c_timeid == 0);
3041 3041 time = drv_usectohz(100000 * csb->csb_timer);
3042 3042 if (time == 0)
3043 3043 time = drv_usectohz(2000000);
3044 3044 fcp->c_timeid = timeout(fdwatch, (void *)fcp, time);
3045 3045 nxs_doit:
3046 3046 if (fdc_docmd(fcp, csb->csb_cmd, csb->csb_ncmds) == -1) {
3047 3047 /* cntlr did not accept command bytes */
3048 3048 fdcquiesce(fcp);
3049 3049 csb->csb_xstate = FXS_RESET;
3050 3050 csb->csb_cmdstat = EIO;
3051 3051 break;
3052 3052 }
3053 3053 csb->csb_xstate = FXS_DOWT;
3054 3054 break;
3055 3055
3056 3056 case FXS_DOWT: /* operation complete */
3057 3057 (void) fdc_result(fcp, csb->csb_rslt, csb->csb_nrslts);
3058 3058 /*
3059 3059 * Ignored return. If failed, warning was issued by fdc_result.
3060 3060 * Actual results checked below.
3061 3061 */
3062 3062 if (*csb->csb_cmd == FO_SDRV) {
3063 3063 csb->csb_status =
3064 3064 (*csb->csb_rslt ^ (S3_DRRDY | S3_2SIDE)) &
3065 3065 ~(S3_HEAD | S3_UNIT);
3066 3066 } else {
3067 3067 csb->csb_status = *csb->csb_rslt &
3068 3068 (S0_ICMASK | S0_ECHK | S0_NOTRDY);
3069 3069 }
3070 3070 nxs_cmpl:
3071 3071 if (csb->csb_status)
3072 3072 csb->csb_cmdstat = EIO;
3073 3073 csb->csb_xstate = FXS_END;
3074 3074
3075 3075 /* remove watchdog timer if armed and not already triggered */
3076 3076 if (fcp->c_timeid != 0) {
3077 3077 timeout_id_t timeid;
3078 3078 timeid = fcp->c_timeid;
3079 3079 fcp->c_timeid = 0;
3080 3080 mutex_exit(&fcp->c_lock);
3081 3081 (void) untimeout(timeid);
3082 3082 mutex_enter(&fcp->c_lock);
3083 3083 }
3084 3084 break;
3085 3085
3086 3086 case FXS_KILL: /* quiesce cntlr by reset */
3087 3087 fdcquiesce(fcp);
3088 3088 fcp->c_timeid = timeout(fdwatch, (void *)fcp,
3089 3089 drv_usectohz(2000000));
3090 3090 csb->csb_xstate = FXS_RESET;
3091 3091 break;
3092 3092
3093 3093 case FXS_RESET: /* int from reset */
3094 3094 for (unit = 0; unit < NFDUN; unit++) {
3095 3095 (void) fdcsense_int(fcp, NULL, NULL);
3096 3096 fcp->c_curpcyl[unit] = -1;
3097 3097 }
3098 3098 if (fcp->c_timeid != 0) {
3099 3099 timeout_id_t timeid;
3100 3100 timeid = fcp->c_timeid;
3101 3101 fcp->c_timeid = 0;
3102 3102 mutex_exit(&fcp->c_lock);
3103 3103 (void) untimeout(timeid);
3104 3104 mutex_enter(&fcp->c_lock);
3105 3105 }
3106 3106 csb->csb_xstate = FXS_END;
3107 3107 break;
3108 3108
3109 3109 default:
3110 3110 cmn_err(CE_WARN, "fdc: statemach, unknown state");
3111 3111 return (-1);
3112 3112 }
3113 3113 FCERRPRINT(FDEP_L1, FDEM_EXEC,
3114 3114 (CE_CONT, "fdc_statemach unit %d: %d -> %d\n",
3115 3115 csb->csb_drive, csb->csb_oldxs, csb->csb_xstate));
3116 3116 return (csb->csb_xstate);
3117 3117 }
3118 3118
3119 3119
3120 3120 /*
3121 3121 * routine to program a command into the floppy disk controller.
3122 3122 */
3123 3123 int
3124 3124 fdc_docmd(struct fdcntlr *fcp, uchar_t *oplistp, uchar_t count)
3125 3125 {
3126 3126 int ntries;
3127 3127
3128 3128 ASSERT(count >= 1);
3129 3129 FCERRPRINT(FDEP_L0, FDEM_EXEC,
3130 3130 (CE_CONT, "fdc_docmd: %x %x %x %x %x %x %x %x %x\n",
3131 3131 oplistp[0], oplistp[1], oplistp[2], oplistp[3], oplistp[4],
3132 3132 oplistp[5], oplistp[6], oplistp[7], oplistp[8]));
3133 3133
3134 3134 do {
3135 3135 ntries = FDC_RQM_RETRY;
3136 3136 do {
3137 3137 if ((inb(fcp->c_regbase + FCR_MSR) & (MS_RQM|MS_DIO))
3138 3138 == MS_RQM)
3139 3139 break;
3140 3140 else
3141 3141 drv_usecwait(1);
3142 3142 } while (--ntries);
3143 3143 if (ntries == 0) {
3144 3144 FCERRPRINT(FDEP_L3, FDEM_EXEC,
3145 3145 (CE_WARN, "fdc_docmd: ctlr not ready"));
3146 3146 return (-1);
3147 3147 }
3148 3148 outb(fcp->c_regbase + FCR_DATA, *oplistp++);
3149 3149 drv_usecwait(16); /* See comment in fdc_result() */
3150 3150 } while (--count);
3151 3151 return (0);
3152 3152 }
3153 3153
3154 3154
3155 3155 /*
3156 3156 * Routine to return controller/drive status information.
3157 3157 * The diskette-controller data-register is read the
3158 3158 * requested number of times and the results are placed in
3159 3159 * consecutive memory locations starting at the passed
3160 3160 * address.
3161 3161 */
3162 3162 int
3163 3163 fdc_result(struct fdcntlr *fcp, uchar_t *rsltp, uchar_t rcount)
3164 3164 {
3165 3165 int ntries;
3166 3166 uchar_t *abresultp = rsltp;
3167 3167 uchar_t stat;
3168 3168 int laxative = 7;
3169 3169
3170 3170 ntries = 10 * FDC_RQM_RETRY;
3171 3171 do {
3172 3172 do {
3173 3173 if ((inb(fcp->c_regbase + FCR_MSR) &
3174 3174 (MS_RQM | MS_DIO)) == (MS_RQM | MS_DIO))
3175 3175 break;
3176 3176 else
3177 3177 drv_usecwait(10);
3178 3178 } while (--ntries);
3179 3179 if (!ntries) {
3180 3180 FCERRPRINT(FDEP_L3, FDEM_EXEC,
3181 3181 (CE_WARN, "fdc_result: ctlr not ready"));
3182 3182 return (-2);
3183 3183 }
3184 3184 *rsltp++ = inb(fcp->c_regbase + FCR_DATA);
3185 3185
3186 3186 /*
3187 3187 * The PRM suggests waiting for 14.5 us.
3188 3188 * Adding a bit more to cover the case of bad calibration
3189 3189 * of drv_usecwait().
3190 3190 */
3191 3191 drv_usecwait(16);
3192 3192 ntries = FDC_RQM_RETRY;
3193 3193 } while (--rcount);
3194 3194 while ((inb(fcp->c_regbase + FCR_MSR) & MS_CB) && laxative--) {
3195 3195 FCERRPRINT(FDEP_L3, FDEM_EXEC,
3196 3196 (CE_WARN, "fdc_result: ctlr still busy"));
3197 3197 /*
3198 3198 * try to complete Result phase by purging
3199 3199 * result bytes queued for reading
3200 3200 */
3201 3201 *abresultp = S0_IVCMD;
3202 3202 do {
3203 3203 stat = inb(fcp->c_regbase + FCR_MSR) &
3204 3204 (MS_RQM | MS_DIO);
3205 3205 if (stat == MS_RQM) {
3206 3206 /*
3207 3207 * Result phase is complete
3208 3208 * but did we get the results corresponding to
3209 3209 * the command we think we executed?
3210 3210 */
3211 3211 return (-1);
3212 3212 }
3213 3213 if (stat == (MS_RQM | MS_DIO))
3214 3214 break;
3215 3215 else
3216 3216 drv_usecwait(10);
3217 3217 } while (--ntries);
3218 3218 if (!ntries || !laxative) {
3219 3219 FCERRPRINT(FDEP_L3, FDEM_EXEC,
3220 3220 (CE_WARN,
3221 3221 "fdc_result: ctlr still busy and not ready"));
3222 3222 return (-3);
3223 3223 }
3224 3224 (void) inb(fcp->c_regbase + FCR_DATA);
3225 3225
3226 3226 drv_usecwait(16); /* See comment above */
3227 3227 ntries = FDC_RQM_RETRY;
3228 3228 }
3229 3229 return (0);
3230 3230 }
3231 3231
3232 3232 /*
3233 3233 * Function: get_unit()
3234 3234 *
3235 3235 * Assumptions: ioaddr is either 0x3f0 or 0x370
3236 3236 */
3237 3237 static int
3238 3238 get_unit(dev_info_t *dip, int *cntrl_num)
3239 3239 {
3240 3240 int ioaddr;
3241 3241
3242 3242 if (get_ioaddr(dip, &ioaddr) != DDI_SUCCESS)
3243 3243 return (DDI_FAILURE);
3244 3244
3245 3245 switch (ioaddr) {
3246 3246 case 0x3f0:
3247 3247 *cntrl_num = 0;
3248 3248 break;
3249 3249
3250 3250 case 0x370:
3251 3251 *cntrl_num = 1;
3252 3252 break;
3253 3253
3254 3254 default:
3255 3255 return (DDI_FAILURE);
3256 3256 }
3257 3257 return (DDI_SUCCESS);
3258 3258 }
3259 3259
3260 3260 static int
3261 3261 get_ioaddr(dev_info_t *dip, int *ioaddr)
3262 3262 {
3263 3263 int reglen, nregs, i;
3264 3264 int status = DDI_FAILURE;
3265 3265 struct {
3266 3266 int bustype;
3267 3267 int base;
3268 3268 int size;
3269 3269 } *reglist;
3270 3270
3271 3271 if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
3272 3272 "reg", (caddr_t)®list, ®len) != DDI_PROP_SUCCESS) {
3273 3273 cmn_err(CE_WARN, "fdc: reg property not found");
3274 3274 return (DDI_FAILURE);
3275 3275 }
3276 3276
3277 3277 nregs = reglen / sizeof (*reglist);
3278 3278 for (i = 0; i < nregs; i++) {
3279 3279 if (reglist[i].bustype == 1) {
3280 3280 *ioaddr = reglist[i].base;
3281 3281 status = DDI_SUCCESS;
3282 3282 break;
3283 3283 }
3284 3284 }
3285 3285 kmem_free(reglist, reglen);
3286 3286
3287 3287 if (status == DDI_SUCCESS) {
3288 3288 if (*ioaddr == 0x3f2 || *ioaddr == 0x372) {
3289 3289 /*
3290 3290 * Some BIOS's (ASUS is one) don't include first
3291 3291 * two IO ports in the floppy controller resources.
3292 3292 */
3293 3293
3294 3294 *ioaddr -= 2; /* step back to 0x3f0 or 0x370 */
3295 3295
3296 3296 /*
3297 3297 * It would be nice to update the regs property as well
3298 3298 * so device pathname contains 3f0 instead of 3f2, but
3299 3299 * updating the regs now won't have this effect as that
3300 3300 * component of the device pathname has already been
3301 3301 * constructed by the ISA nexus driver.
3302 3302 *
3303 3303 * reglist[i].base -= 2;
3304 3304 * reglist[i].size += 2;
3305 3305 * dev = makedevice(ddi_driver_major(dip), 0);
3306 3306 * ddi_prop_update_int_array(dev, dip, "reg",
3307 3307 * (int *)reglist, reglen / sizeof (int));
3308 3308 */
3309 3309 }
3310 3310 }
3311 3311
3312 3312 return (status);
3313 3313 }
↓ open down ↓ |
3035 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX