Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/fd.c
+++ new/usr/src/uts/common/io/fd.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 26
27 27 /*
28 28 * Floppy Disk driver
29 29 */
30 30
31 31 /*
32 32 * Set CMOS feature:
33 33 * CMOS_CONF_MEM: CMOS memory contains configuration info
34 34 */
35 35 #define CMOS_CONF_MEM
36 36
37 37 #include <sys/types.h>
38 38 #include <sys/param.h>
39 39 #include <sys/systm.h>
40 40 #include <sys/buf.h>
41 41 #include <sys/file.h>
42 42 #include <sys/open.h>
43 43 #include <sys/ioctl.h>
44 44 #include <sys/uio.h>
45 45 #include <sys/conf.h>
46 46 #include <sys/stat.h>
47 47 #include <sys/autoconf.h>
48 48 #include <sys/vtoc.h>
49 49 #include <sys/dkio.h>
50 50 #include <sys/ddi.h>
51 51 #include <sys/sunddi.h>
52 52 #include <sys/kstat.h>
53 53 #include <sys/kmem.h>
54 54 #include <sys/ddidmareq.h>
55 55 #include <sys/fdio.h>
56 56 #include <sys/fdc.h>
57 57 #include <sys/fd_debug.h>
58 58 #include <sys/fdmedia.h>
59 59 #include <sys/debug.h>
60 60 #include <sys/modctl.h>
61 61
62 62 /*
63 63 * Local Function Prototypes
64 64 */
65 65 static int fd_unit_is_open(struct fdisk *);
66 66 static int fdgetlabel(struct fcu_obj *, int);
67 67 static void fdstart(struct fcu_obj *);
68 68 static int fd_build_label_vtoc(struct fcu_obj *, struct fdisk *,
69 69 struct vtoc *, struct dk_label *);
70 70 static void fd_build_user_vtoc(struct fcu_obj *, struct fdisk *,
71 71 struct vtoc *);
72 72 static int fd_rawioctl(struct fcu_obj *, int, caddr_t, int);
73 73 static void fd_media_watch(void *);
74 74
75 75 static int fd_open(dev_t *, int, int, cred_t *);
76 76 static int fd_close(dev_t, int, int, cred_t *);
77 77 static int fd_strategy(struct buf *);
78 78 static int fd_read(dev_t, struct uio *, cred_t *);
79 79 static int fd_write(dev_t, struct uio *, cred_t *);
80 80 static int fd_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
81 81 static int fd_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, int, char *,
82 82 caddr_t, int *);
83 83 static int fd_check_media(dev_t dev, enum dkio_state state);
84 84 static int fd_get_media_info(struct fcu_obj *fjp, caddr_t buf, int flag);
85 85
86 86 static struct cb_ops fd_cb_ops = {
87 87 fd_open, /* open */
88 88 fd_close, /* close */
89 89 fd_strategy, /* strategy */
90 90 nodev, /* print */
91 91 nodev, /* dump */
92 92 fd_read, /* read */
93 93 fd_write, /* write */
94 94 fd_ioctl, /* ioctl */
95 95 nodev, /* devmap */
96 96 nodev, /* mmap */
97 97 nodev, /* segmap */
98 98 nochpoll, /* poll */
99 99 fd_prop_op, /* cb_prop_op */
100 100 0, /* streamtab */
101 101 D_NEW | D_MP /* Driver compatibility flag */
102 102 };
103 103
104 104 static int fd_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
105 105 static int fd_probe(dev_info_t *);
106 106 static int fd_attach(dev_info_t *, ddi_attach_cmd_t);
107 107 static int fd_detach(dev_info_t *, ddi_detach_cmd_t);
108 108
109 109 static struct dev_ops fd_ops = {
110 110 DEVO_REV, /* devo_rev, */
111 111 0, /* refcnt */
112 112 fd_getinfo, /* getinfo */
113 113 nulldev, /* identify */
114 114 fd_probe, /* probe */
115 115 fd_attach, /* attach */
116 116 fd_detach, /* detach */
117 117 nodev, /* reset */
118 118 &fd_cb_ops, /* driver operations */
119 119 (struct bus_ops *)0, /* bus operations */
120 120 NULL, /* power */
121 121 ddi_quiesce_not_supported, /* devo_quiesce */
122 122 };
123 123
124 124
125 125 /*
126 126 * static data
127 127 */
128 128 static void *fd_state_head; /* opaque handle top of state structs */
129 129 static int fd_check_media_time = 5000000; /* 5 second state check */
130 130
131 131 /*
132 132 * error handling
133 133 *
134 134 * for debugging,
135 135 * set fderrlevel to 1
136 136 * set fderrmask to 224 or 644
137 137 */
138 138 #ifdef DEBUG
139 139 static uint_t fderrmask = FDEM_ALL;
140 140 #endif
141 141 static int fderrlevel = 5;
142 142
143 143 #define KIOSP KSTAT_IO_PTR(fdp->d_iostat)
144 144
145 145 static struct driver_minor_data {
146 146 char *name;
147 147 int minor;
148 148 int type;
149 149 } fd_minor [] = {
150 150 { "a", 0, S_IFBLK},
151 151 { "b", 1, S_IFBLK},
152 152 { "c", 2, S_IFBLK},
153 153 { "a,raw", 0, S_IFCHR},
154 154 { "b,raw", 1, S_IFCHR},
155 155 { "c,raw", 2, S_IFCHR},
↓ open down ↓ |
155 lines elided |
↑ open up ↑ |
156 156 {0}
157 157 };
158 158
159 159 static struct modldrv modldrv = {
160 160 &mod_driverops, /* Type of module. This one is a driver */
161 161 "Floppy Disk driver", /* Name of the module. */
162 162 &fd_ops, /* driver ops */
163 163 };
164 164
165 165 static struct modlinkage modlinkage = {
166 - MODREV_1, (void *)&modldrv, NULL
166 + MODREV_1, { (void *)&modldrv, NULL }
167 167 };
168 168
169 169
170 170 int
171 171 _init(void)
172 172 {
173 173 int retval;
174 174
175 175 if ((retval = ddi_soft_state_init(&fd_state_head,
176 176 sizeof (struct fdisk) + sizeof (struct fd_drive) +
177 177 sizeof (struct fd_char) + sizeof (struct fdattr), 0)) != 0)
178 178 return (retval);
179 179
180 180 if ((retval = mod_install(&modlinkage)) != 0)
181 181 ddi_soft_state_fini(&fd_state_head);
182 182 return (retval);
183 183 }
184 184
185 185 int
186 186 _fini(void)
187 187 {
188 188 int retval;
189 189
190 190 if ((retval = mod_remove(&modlinkage)) != 0)
191 191 return (retval);
192 192 ddi_soft_state_fini(&fd_state_head);
193 193 return (retval);
194 194 }
195 195
196 196 int
197 197 _info(struct modinfo *modinfop)
198 198 {
199 199 return (mod_info(&modlinkage, modinfop));
200 200 }
201 201
202 202
203 203 static int
204 204 fd_getdrive(dev_t dev, struct fcu_obj **fjpp, struct fdisk **fdpp)
205 205 {
206 206 if (fdpp) {
207 207 *fdpp = ddi_get_soft_state(fd_state_head, DRIVE(dev));
208 208 if (*fdpp && fjpp) {
209 209 *fjpp = (*fdpp)->d_obj;
210 210 if (*fjpp)
211 211 return ((*fjpp)->fj_unit);
212 212 }
213 213 }
214 214 return (-1);
215 215 }
216 216
217 217 /*ARGSUSED*/
218 218 static int
219 219 fd_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
220 220 {
221 221 dev_t dev = (dev_t)arg;
222 222 struct fcu_obj *fjp = NULL;
223 223 struct fdisk *fdp = NULL;
224 224 int rval;
225 225
226 226 switch (cmd) {
227 227 case DDI_INFO_DEVT2DEVINFO:
228 228 (void) fd_getdrive(dev, &fjp, &fdp);
229 229 /*
230 230 * Ignoring return value because success is checked by
231 231 * verifying fjp and fdp and returned unit value is not used.
232 232 */
233 233 if (fjp && fdp) {
234 234 *result = fjp->fj_dip;
235 235 rval = DDI_SUCCESS;
236 236 } else
237 237 rval = DDI_FAILURE;
238 238 break;
239 239 case DDI_INFO_DEVT2INSTANCE:
240 240 *result = (void *)(uintptr_t)DRIVE(dev);
241 241 rval = DDI_SUCCESS;
242 242 break;
243 243 default:
244 244 rval = DDI_FAILURE;
245 245 }
246 246 return (rval);
247 247 }
248 248
249 249 #ifdef CMOS_CONF_MEM
250 250 #define CMOS_ADDR 0x70
251 251 #define CMOS_DATA 0x71
252 252 #define CMOS_FDRV 0x10
253 253 #endif /* CMOS_CONF_MEM */
254 254
255 255 static int
256 256 fd_probe(dev_info_t *dip)
257 257 {
258 258 #ifdef CMOS_CONF_MEM
259 259 int cmos;
260 260 int drive_type;
261 261 #endif /* CMOS_CONF_MEM */
262 262 int debug[2];
263 263 int drive_size;
264 264 int len;
265 265 int unit_num;
266 266 char density[8];
267 267
268 268 len = sizeof (debug);
269 269 if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
270 270 DDI_PROP_DONTPASS, "debug", (caddr_t)debug, &len) ==
271 271 DDI_PROP_SUCCESS) {
272 272 fderrlevel = debug[0];
273 273 #ifdef DEBUG
274 274 fderrmask = (uint_t)debug[1];
275 275 #endif
276 276 }
277 277 len = sizeof (unit_num);
278 278 if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
279 279 DDI_PROP_DONTPASS, "unit", (caddr_t)&unit_num, &len) !=
280 280 DDI_PROP_SUCCESS) {
281 281 FDERRPRINT(FDEP_L3, FDEM_ATTA,
282 282 (CE_WARN, "fd_probe failed: dip %p", (void *)dip));
283 283 return (DDI_PROBE_FAILURE);
284 284 }
285 285
286 286 #ifdef CMOS_CONF_MEM
287 287 /* get the cmos memory values quick and dirty */
288 288 outb(CMOS_ADDR, CMOS_FDRV);
289 289 cmos = drive_type = (int)inb(CMOS_DATA);
290 290 #endif /* CMOS_CONF_MEM */
291 291
292 292 switch (unit_num) {
293 293 #ifdef CMOS_CONF_MEM
294 294 case 0:
295 295 drive_type = drive_type >> 4;
296 296 /* FALLTHROUGH */
297 297 case 1:
298 298 if (cmos && (drive_type & 0x0F)) {
299 299 break;
300 300 }
301 301 /*
302 302 * Some enhanced floppy-disk controller adaptor cards
303 303 * require NO drives defined in the CMOS configuration
304 304 * memory.
305 305 * So fall through
306 306 */
307 307 #endif /* CMOS_CONF_MEM */
308 308 default: /* need to check conf file */
309 309 len = sizeof (density);
310 310 if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
311 311 DDI_PROP_DONTPASS, "density", (caddr_t)&density, &len) !=
312 312 DDI_PROP_SUCCESS) {
313 313 FDERRPRINT(FDEP_L3, FDEM_ATTA,
314 314 (CE_WARN,
315 315 "fd_probe failed density: dip %p unit %d",
316 316 (void *)dip, unit_num));
317 317 return (DDI_PROBE_FAILURE);
318 318 }
319 319 len = sizeof (drive_size);
320 320 if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
321 321 DDI_PROP_DONTPASS, "size", (caddr_t)&drive_size, &len) !=
322 322 DDI_PROP_SUCCESS) {
323 323 FDERRPRINT(FDEP_L3, FDEM_ATTA,
324 324 (CE_WARN, "fd_probe failed size: dip %p unit %d",
325 325 (void *)dip, unit_num));
326 326 return (DDI_PROBE_FAILURE);
327 327 }
328 328 }
329 329 FDERRPRINT(FDEP_L3, FDEM_ATTA,
330 330 (CE_WARN, "fd_probe dip %p unit %d", (void *)dip, unit_num));
331 331 return (DDI_PROBE_SUCCESS);
332 332 }
333 333
334 334
335 335 /* ARGSUSED */
336 336 static int
337 337 fd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
338 338 {
339 339 struct fcu_obj *fjp;
340 340 struct fdisk *fdp;
341 341 struct driver_minor_data *dmdp;
342 342 int mode_3D;
343 343 int drive_num, drive_size, drive_type;
344 344 #ifdef CMOS_CONF_MEM
345 345 int cmos;
346 346 #endif /* CMOS_CONF_MEM */
347 347 int len, sig_minor;
348 348 int unit_num;
349 349 char density[8];
350 350 char name[MAXNAMELEN];
351 351
352 352 switch (cmd) {
353 353 case DDI_ATTACH:
354 354 len = sizeof (unit_num);
355 355 if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
356 356 DDI_PROP_DONTPASS, "unit", (caddr_t)&unit_num, &len) !=
357 357 DDI_PROP_SUCCESS) {
358 358 FDERRPRINT(FDEP_L3, FDEM_ATTA,
359 359 (CE_WARN, "fd_attach failed: dip %p", (void *)dip));
360 360 return (DDI_FAILURE);
361 361 }
362 362
363 363 #ifdef CMOS_CONF_MEM
364 364 outb(CMOS_ADDR, CMOS_FDRV);
365 365 cmos = drive_type = (int)inb(CMOS_DATA);
366 366 #endif /* CMOS_CONF_MEM */
367 367
368 368 switch (unit_num) {
369 369 #ifdef CMOS_CONF_MEM
370 370 case 0:
371 371 drive_type = drive_type >> 4;
372 372 /* FALLTHROUGH */
373 373 case 1:
374 374 drive_type = drive_type & 0x0F;
375 375 if (cmos)
376 376 break;
377 377 /*
378 378 * Some enhanced floppy-disk controller adaptor cards
379 379 * require NO drives defined in the CMOS configuration
380 380 * memory.
381 381 * So fall through
382 382 */
383 383 #endif /* CMOS_CONF_MEM */
384 384 default: /* need to check .conf file */
385 385 drive_type = 0;
386 386 len = sizeof (density);
387 387 if (ddi_prop_op(DDI_DEV_T_ANY, dip,
388 388 PROP_LEN_AND_VAL_BUF, DDI_PROP_DONTPASS, "density",
389 389 (caddr_t)&density, &len) != DDI_PROP_SUCCESS)
390 390 density[0] = '\0';
391 391 len = sizeof (drive_size);
392 392 if (ddi_prop_op(DDI_DEV_T_ANY, dip,
393 393 PROP_LEN_AND_VAL_BUF, DDI_PROP_DONTPASS, "size",
394 394 (caddr_t)&drive_size, &len) != DDI_PROP_SUCCESS)
395 395 drive_size = 0;
396 396 if (strcmp(density, "DSDD") == 0) {
397 397 if (drive_size == 5)
398 398 drive_type = 1;
399 399 else if (drive_size == 3)
400 400 drive_type = 3;
401 401 } else if (strcmp(density, "DSHD") == 0) {
402 402 if (drive_size == 5)
403 403 drive_type = 2;
404 404 else if (drive_size == 3)
405 405 drive_type = 4;
406 406 } else if (strcmp(density, "DSED") == 0 &&
407 407 drive_size == 3) {
408 408 drive_type = 6;
409 409 }
410 410 break;
411 411 }
412 412 if (drive_type == 0) {
413 413 FDERRPRINT(FDEP_L3, FDEM_ATTA,
414 414 (CE_WARN, "fd_attach failed type: dip %p unit %d",
415 415 (void *)dip, unit_num));
416 416 return (DDI_FAILURE);
417 417 }
418 418
419 419 drive_num = ddi_get_instance(dip);
420 420 if (ddi_soft_state_zalloc(fd_state_head, drive_num) != 0)
421 421 return (DDI_FAILURE);
422 422 fdp = ddi_get_soft_state(fd_state_head, drive_num);
423 423 fjp = fdp->d_obj = ddi_get_driver_private(dip);
424 424
425 425 mutex_init(&fjp->fj_lock, NULL, MUTEX_DRIVER, *fjp->fj_iblock);
426 426 sema_init(&fdp->d_ocsem, 1, NULL, SEMA_DRIVER, NULL);
427 427
428 428 fjp->fj_drive = (struct fd_drive *)(fdp + 1);
429 429 fjp->fj_chars = (struct fd_char *)(fjp->fj_drive + 1);
430 430 fjp->fj_attr = (struct fdattr *)(fjp->fj_chars + 1);
431 431
432 432 /*
433 433 * set default floppy drive characteristics & geometry
434 434 */
435 435 switch (drive_type) { /* assume doubled sided */
436 436 case 2: /* 5.25 high density */
437 437 *fjp->fj_drive = dfd_525HD;
438 438 fdp->d_media = 1<<FMT_5H | 1<<FMT_5D9 | 1<<FMT_5D8 |
439 439 1<<FMT_5D4 | 1<<FMT_5D16;
440 440 fdp->d_deffdtype = fdp->d_curfdtype = FMT_5H;
441 441 break;
442 442 case 4: /* 3.5 high density */
443 443 *fjp->fj_drive = dfd_350HD;
444 444 fdp->d_media = 1<<FMT_3H | 1<<FMT_3I | 1<<FMT_3D;
445 445 len = sizeof (mode_3D);
446 446 if (ddi_prop_op(DDI_DEV_T_ANY, dip,
447 447 PROP_LEN_AND_VAL_BUF, DDI_PROP_DONTPASS, "mode_3D",
448 448 (caddr_t)&mode_3D, &len) != DDI_PROP_SUCCESS)
449 449 mode_3D = 0;
450 450 if (mode_3D && (fjp->fj_fdc->c_flags & FCFLG_3DMODE))
451 451 /*
452 452 * 3D mode should be enabled only if a dual-
453 453 * speed 3.5" high-density drive and a
454 454 * supported floppy controller are installed.
455 455 */
456 456 fdp->d_media |= 1 << FMT_3M;
457 457 fdp->d_deffdtype = fdp->d_curfdtype = FMT_3H;
458 458 break;
459 459 case 1: /* 5.25 double density */
460 460 *fjp->fj_drive = dfd_525DD;
461 461 fdp->d_media = 1<<FMT_5D9 | 1<<FMT_5D8 | 1<<FMT_5D4 |
462 462 1<<FMT_5D16;
463 463 fdp->d_deffdtype = fdp->d_curfdtype = FMT_5D9;
464 464 break;
465 465 case 3: /* 3.5 double density */
466 466 *fjp->fj_drive = dfd_350HD;
467 467 fdp->d_media = 1<<FMT_3D;
468 468 fdp->d_deffdtype = fdp->d_curfdtype = FMT_3D;
469 469 break;
470 470 case 5: /* 3.5 extended density */
471 471 case 6:
472 472 case 7:
473 473 *fjp->fj_drive = dfd_350ED;
474 474 fdp->d_media = 1<<FMT_3E | 1<<FMT_3H | 1<<FMT_3I |
475 475 1<<FMT_3D;
476 476 fdp->d_deffdtype = fdp->d_curfdtype = FMT_3E;
477 477 break;
478 478 case 0: /* no drive defined */
479 479 default:
480 480 goto no_attach;
481 481 }
482 482 *fjp->fj_chars = *defchar[fdp->d_deffdtype];
483 483 *fjp->fj_attr = fdtypes[fdp->d_deffdtype];
484 484 bcopy(fdparts[fdp->d_deffdtype], fdp->d_part,
485 485 sizeof (struct partition) * NDKMAP);
486 486 fjp->fj_rotspd = fdtypes[fdp->d_deffdtype].fda_rotatespd;
487 487
488 488 sig_minor = drive_num << 3;
489 489 for (dmdp = fd_minor; dmdp->name != NULL; dmdp++) {
490 490 if (ddi_create_minor_node(dip, dmdp->name, dmdp->type,
491 491 sig_minor | dmdp->minor, DDI_NT_FD, NULL)
492 492 == DDI_FAILURE) {
493 493 ddi_remove_minor_node(dip, NULL);
494 494 goto no_attach;
495 495 }
496 496 }
497 497
498 498 FDERRPRINT(FDEP_L3, FDEM_ATTA,
499 499 (CE_WARN, "fd_attach: dip %p unit %d",
500 500 (void *)dip, unit_num));
501 501 (void) sprintf(name, "fd%d", drive_num);
502 502 fdp->d_iostat = kstat_create("fd", drive_num, name, "disk",
503 503 KSTAT_TYPE_IO, 1, KSTAT_FLAG_PERSISTENT);
504 504 if (fdp->d_iostat) {
505 505 fdp->d_iostat->ks_lock = &fjp->fj_lock;
506 506 kstat_install(fdp->d_iostat);
507 507 }
508 508
509 509 fjp->fj_data = (caddr_t)fdp;
510 510 fjp->fj_flags |= FUNIT_DRVATCH;
511 511
512 512 /*
513 513 * Add a zero-length attribute to tell the world we support
514 514 * kernel ioctls (for layered drivers)
515 515 */
516 516 (void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
517 517 DDI_KERNEL_IOCTL, NULL, 0);
518 518
519 519 /*
520 520 * We want to get suspend/resume events, so that we can
521 521 * refuse to suspend when pcfs is mounted.
522 522 */
523 523 (void) ddi_prop_update_string(DDI_DEV_T_NONE, dip,
524 524 "pm-hardware-state", "needs-suspend-resume");
525 525
526 526 /*
527 527 * Ignoring return value because, for passed arguments, only
528 528 * DDI_SUCCESS is returned.
529 529 */
530 530 ddi_report_dev(dip);
531 531 return (DDI_SUCCESS);
532 532
533 533 case DDI_RESUME:
534 534 /* nothing for us to do */
535 535 return (DDI_SUCCESS);
536 536
537 537 default:
538 538 return (DDI_FAILURE);
539 539 }
540 540 no_attach:
541 541 fjp->fj_drive = NULL;
542 542 fjp->fj_chars = NULL;
543 543 fjp->fj_attr = NULL;
544 544 mutex_destroy(&fjp->fj_lock);
545 545 sema_destroy(&fdp->d_ocsem);
546 546 ddi_soft_state_free(fd_state_head, drive_num);
547 547 FDERRPRINT(FDEP_L3, FDEM_ATTA,
548 548 (CE_WARN, "fd_attach failed: dip %p unit %d",
549 549 (void *)dip, unit_num));
550 550 return (DDI_FAILURE);
551 551 }
552 552
553 553
554 554 /* ARGSUSED */
555 555 static int
556 556 fd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
557 557 {
558 558 struct fcu_obj *fjp;
559 559 struct fdisk *fdp;
560 560 int drive_num;
561 561 int rval = DDI_SUCCESS;
562 562
563 563 FDERRPRINT(FDEP_L3, FDEM_ATTA, (CE_WARN, "fd_detach dip %p",
564 564 (void *)dip));
565 565
566 566 drive_num = ddi_get_instance(dip);
567 567 if (!(fdp = ddi_get_soft_state(fd_state_head, drive_num)))
568 568 return (rval);
569 569
570 570 switch (cmd) {
571 571 case DDI_DETACH:
572 572 if (fd_unit_is_open(fdp)) {
573 573 rval = DDI_FAILURE;
574 574 break;
575 575 }
576 576 kstat_delete(fdp->d_iostat);
577 577 fdp->d_iostat = NULL;
578 578 fjp = (struct fcu_obj *)fdp->d_obj;
579 579 fjp->fj_flags &= ~FUNIT_DRVATCH;
580 580 fjp->fj_data = NULL;
581 581 fjp->fj_drive = NULL;
582 582 fjp->fj_chars = NULL;
583 583 fjp->fj_attr = NULL;
584 584 ddi_prop_remove_all(dip);
585 585 mutex_destroy(&fjp->fj_lock);
586 586 sema_destroy(&fdp->d_ocsem);
587 587 ddi_soft_state_free(fd_state_head, drive_num);
588 588 break;
589 589
590 590 case DDI_SUSPEND:
591 591 /*
592 592 * Bad, bad, bad things will happen if someone
593 593 * *changes* the disk in the drive while it is mounted
594 594 * and the system is suspended. We have no way to
595 595 * detect that. (Undetected filesystem corruption.
596 596 * Its akin to changing the boot disk while the system
597 597 * is suspended. Don't do it!)
598 598 *
599 599 * So we refuse to suspend if there is a mounted filesystem.
600 600 * (We guess this by looking for a block open. Character
601 601 * opens are fine.) This limits some of the usability of
602 602 * suspend/resume, but it certainly avoids this
603 603 * potential filesytem corruption from pilot error.
604 604 * Given the decreasing popularity of floppy media, we
605 605 * don't see this as much of a limitation.
606 606 */
607 607 if (fdp->d_regopen[OTYP_BLK]) {
608 608 cmn_err(CE_NOTE,
609 609 "Unable to suspend while floppy is in use.");
610 610 rval = DDI_FAILURE;
611 611 }
612 612 break;
613 613
614 614 default:
615 615 rval = DDI_FAILURE;
616 616 break;
617 617 }
618 618 return (rval);
619 619 }
620 620
621 621
622 622 static int
623 623 fd_part_is_open(struct fdisk *fdp, int part)
624 624 {
625 625 int i;
626 626
627 627 for (i = 0; i < (OTYPCNT - 1); i++)
628 628 if (fdp->d_regopen[i] & (1 << part))
629 629 return (1);
630 630 return (0);
631 631 }
632 632
633 633 static int
634 634 fd_unit_is_open(struct fdisk *fdp)
635 635 {
636 636 int i;
637 637
638 638 for (i = 0; i < NDKMAP; i++)
639 639 if (fdp->d_lyropen[i])
640 640 return (1);
641 641 for (i = 0; i < (OTYPCNT - 1); i++)
642 642 if (fdp->d_regopen[i])
643 643 return (1);
644 644 return (0);
645 645 }
646 646
647 647 /*ARGSUSED*/
648 648 static int
649 649 fd_open(dev_t *devp, int flag, int otyp, cred_t *cred_p)
650 650 {
651 651 struct fcu_obj *fjp = NULL;
652 652 struct fdisk *fdp = NULL;
653 653 struct partition *pp;
654 654 dev_t dev;
655 655 int part, unit;
656 656 int part_is_open;
657 657 int rval;
658 658 uint_t pbit;
659 659
660 660 dev = *devp;
661 661 unit = fd_getdrive(dev, &fjp, &fdp);
662 662 if (!fjp || !fdp)
663 663 return (ENXIO);
664 664 part = PARTITION(dev);
665 665 pbit = 1 << part;
666 666 pp = &fdp->d_part[part];
667 667
668 668 /*
669 669 * Serialize opens/closes
670 670 */
671 671 sema_p(&fdp->d_ocsem);
672 672 FDERRPRINT(FDEP_L1, FDEM_OPEN,
673 673 (CE_CONT, "fd_open: fd%d part %d flag %x otype %x\n", DRIVE(dev),
674 674 part, flag, otyp));
675 675
676 676 /*
677 677 * Check for previous exclusive open, or trying to exclusive open
678 678 * An "exclusive open" on any partition is not guaranteed to
679 679 * protect against opens on another partition that overlaps it.
680 680 */
681 681 if (otyp == OTYP_LYR) {
682 682 part_is_open = (fdp->d_lyropen[part] != 0);
683 683 } else {
684 684 part_is_open = fd_part_is_open(fdp, part);
685 685 }
686 686 if ((fdp->d_exclmask & pbit) || ((flag & FEXCL) && part_is_open)) {
687 687 FDERRPRINT(FDEP_L0, FDEM_OPEN, (CE_CONT,
688 688 "fd_open: exclparts %lx openparts %lx lyrcnt %lx pbit %x\n",
689 689 fdp->d_exclmask, fdp->d_regopen[otyp], fdp->d_lyropen[part],
690 690 pbit));
691 691 sema_v(&fdp->d_ocsem);
692 692 return (EBUSY);
693 693 }
694 694
695 695 /*
696 696 * Ensure that drive is recalibrated on first open of new diskette.
697 697 */
698 698 fjp->fj_ops->fco_select(fjp, unit, 1);
699 699 if (fjp->fj_ops->fco_getchng(fjp, unit) != 0) {
700 700 if (fjp->fj_ops->fco_rcseek(fjp, unit, -1, 0)) {
701 701 FDERRPRINT(FDEP_L2, FDEM_OPEN,
702 702 (CE_NOTE, "fd_open fd%d: not ready", DRIVE(dev)));
703 703 fjp->fj_ops->fco_select(fjp, unit, 0);
704 704 sema_v(&fdp->d_ocsem);
705 705 return (ENXIO);
706 706 }
707 707 fjp->fj_flags &= ~(FUNIT_LABELOK | FUNIT_UNLABELED);
708 708 }
709 709 if (flag & (FNDELAY | FNONBLOCK)) {
710 710 /* don't attempt access, just return successfully */
711 711 fjp->fj_ops->fco_select(fjp, unit, 0);
712 712 goto out;
713 713 }
714 714
715 715 /*
716 716 * auto-sense the density/format of the diskette
717 717 */
718 718 rval = fdgetlabel(fjp, unit);
719 719 fjp->fj_ops->fco_select(fjp, unit, 0);
720 720 if (rval) {
721 721 /* didn't find label (couldn't read anything) */
722 722 FDERRPRINT(FDEP_L2, FDEM_OPEN,
723 723 (CE_NOTE, "fd%d: drive not ready", DRIVE(dev)));
724 724 sema_v(&fdp->d_ocsem);
725 725 return (EIO);
726 726 }
727 727 /* check partition */
728 728 if (pp->p_size == 0) {
729 729 sema_v(&fdp->d_ocsem);
730 730 return (ENXIO);
731 731 }
732 732 /*
733 733 * if opening for writing, check write protect on diskette
734 734 */
735 735 if ((flag & FWRITE) && (fdp->d_obj->fj_flags & FUNIT_WPROT)) {
736 736 sema_v(&fdp->d_ocsem);
737 737 return (EROFS);
738 738 }
739 739
740 740 out:
741 741 /*
742 742 * mark open as having succeeded
743 743 */
744 744 if (flag & FEXCL)
745 745 fdp->d_exclmask |= pbit;
746 746 if (otyp == OTYP_LYR)
747 747 fdp->d_lyropen[part]++;
748 748 else
749 749 fdp->d_regopen[otyp] |= 1 << part;
750 750
751 751 sema_v(&fdp->d_ocsem);
752 752 return (0);
753 753 }
754 754
755 755 /*
756 756 * fdgetlabel - read the SunOS label off the diskette
757 757 * if it can read a valid label it does so, else it will use a
758 758 * default. If it can`t read the diskette - that is an error.
759 759 *
760 760 * RETURNS: 0 for ok - meaning that it could at least read the device,
761 761 * !0 for error XXX TBD NYD error codes
762 762 */
763 763 static int
764 764 fdgetlabel(struct fcu_obj *fjp, int unit)
765 765 {
766 766 struct dk_label *label;
767 767 struct fdisk *fdp;
768 768 char *newlabel;
769 769 short *sp;
770 770 short count;
771 771 short xsum;
772 772 int tries, try_this;
773 773 uint_t nexttype;
774 774 int rval;
775 775 short oldlvl;
776 776 int i;
777 777
778 778 FDERRPRINT(FDEP_L0, FDEM_GETL,
779 779 (CE_CONT, "fdgetlabel fd unit %d\n", unit));
780 780 fdp = (struct fdisk *)fjp->fj_data;
781 781 fjp->fj_flags &= ~(FUNIT_UNLABELED);
782 782
783 783 /*
784 784 * get some space to play with the label
785 785 */
786 786 label = kmem_zalloc(sizeof (struct dk_label), KM_SLEEP);
787 787 FDERRPRINT(FDEP_L0, FDEM_GETL, (CE_CONT,
788 788 "fdgetlabel fd unit %d kmem_zalloc: ptr = %p, size = %lx\n",
789 789 unit, (void *)label, (size_t)sizeof (struct dk_label)));
790 790
791 791 /*
792 792 * read block 0 (0/0/1) to find the label
793 793 * (disk is potentially not present or unformatted)
794 794 */
795 795 /* noerrprint since this is a private cmd */
796 796 oldlvl = fderrlevel;
797 797 fderrlevel = FDEP_LMAX;
798 798 /*
799 799 * try different characteristics (ie densities)
800 800 *
801 801 * if fdp->d_curfdtype is -1 then the current characteristics
802 802 * were set by ioctl and need to try it as well as everything
803 803 * in the table
804 804 */
805 805 nexttype = fdp->d_deffdtype;
806 806 try_this = 1; /* always try the current characteristics */
807 807
808 808 for (tries = nfdtypes; tries; tries--) {
809 809 if (try_this) {
810 810 fjp->fj_flags &= ~FUNIT_CHAROK;
811 811
812 812 /* try reading last sector of cyl 1, head 0 */
813 813 if (!(rval = fjp->fj_ops->fco_rw(fjp, unit,
814 814 FDREAD, 1, 0, fjp->fj_chars->fdc_secptrack,
815 815 (caddr_t)label,
816 816 sizeof (struct dk_label))) &&
817 817 /* and last sector plus 1 of cylinder 1 */
818 818 fjp->fj_ops->fco_rw(fjp, unit, FDREAD, 1,
819 819 0, fjp->fj_chars->fdc_secptrack + 1,
820 820 (caddr_t)label,
821 821 sizeof (struct dk_label)) &&
822 822 /* and label sector on cylinder 0 */
823 823 !(rval = fjp->fj_ops->fco_rw(fjp, unit,
824 824 FDREAD, 0, 0, 1, (caddr_t)label,
825 825 sizeof (struct dk_label))))
826 826 break;
827 827 if (rval == ENXIO)
828 828 break;
829 829 }
830 830 /*
831 831 * try the next entry in the characteristics tbl
832 832 */
833 833 fdp->d_curfdtype = (signed char)nexttype;
834 834 nexttype = (nexttype + 1) % nfdtypes;
835 835 if ((1 << fdp->d_curfdtype) & fdp->d_media) {
836 836 *fjp->fj_chars = *defchar[fdp->d_curfdtype];
837 837 *fjp->fj_attr = fdtypes[fdp->d_curfdtype];
838 838 bcopy(fdparts[fdp->d_curfdtype], fdp->d_part,
839 839 sizeof (struct partition) * NDKMAP);
840 840 /*
841 841 * check for a double_density diskette
842 842 * in a high_density 5.25" drive
843 843 */
844 844 if (fjp->fj_chars->fdc_transfer_rate == 250 &&
845 845 fjp->fj_rotspd > fjp->fj_attr->fda_rotatespd) {
846 846 /*
847 847 * yes - adjust transfer rate since we don't
848 848 * know if we have a 5.25" dual-speed drive
849 849 */
850 850 fjp->fj_attr->fda_rotatespd = 360;
851 851 fjp->fj_chars->fdc_transfer_rate = 300;
852 852 fjp->fj_chars->fdc_medium = 5;
853 853 }
854 854 if ((2 * fjp->fj_chars->fdc_ncyl) ==
855 855 defchar[fdp->d_deffdtype]->fdc_ncyl) {
856 856 /* yes - adjust steps per cylinder */
857 857 fjp->fj_chars->fdc_steps = 2;
858 858 } else
859 859 fjp->fj_chars->fdc_steps = 1;
860 860 try_this = 1;
861 861 } else
862 862 try_this = 0;
863 863 }
864 864 fderrlevel = oldlvl; /* print errors again */
865 865
866 866 if (rval) {
867 867 fdp->d_curfdtype = fdp->d_deffdtype;
868 868 goto out; /* couldn't read anything */
869 869 }
870 870
871 871 FDERRPRINT(FDEP_L0, FDEM_GETL,
872 872 (CE_CONT,
873 873 "fdgetlabel fd unit=%d ncyl=%d nsct=%d step=%d rpm=%d intlv=%d\n",
874 874 unit, fjp->fj_chars->fdc_ncyl, fjp->fj_chars->fdc_secptrack,
875 875 fjp->fj_chars->fdc_steps, fjp->fj_attr->fda_rotatespd,
876 876 fjp->fj_attr->fda_intrlv));
877 877
878 878 /*
879 879 * _something_ was read - look for unixtype label
880 880 */
881 881 if (label->dkl_magic != DKL_MAGIC ||
882 882 label->dkl_vtoc.v_sanity != VTOC_SANE) {
883 883 /* not a label - no magic number */
884 884 goto nolabel; /* no errors, but no label */
885 885 }
886 886
887 887 count = sizeof (struct dk_label) / sizeof (short);
888 888 sp = (short *)label;
889 889 xsum = 0;
890 890 while (count--)
891 891 xsum ^= *sp++; /* should add up to 0 */
892 892 if (xsum) {
893 893 /* not a label - checksum didn't compute */
894 894 goto nolabel; /* no errors, but no label */
895 895 }
896 896
897 897 /*
898 898 * the SunOS label overrides current diskette characteristics
899 899 */
900 900 fjp->fj_chars->fdc_ncyl = label->dkl_pcyl;
901 901 fjp->fj_chars->fdc_nhead = label->dkl_nhead;
902 902 fjp->fj_chars->fdc_secptrack = (label->dkl_nsect * DEV_BSIZE) /
903 903 fjp->fj_chars->fdc_sec_size;
904 904 if (defchar[fdp->d_deffdtype]->fdc_ncyl == 2 * fjp->fj_chars->fdc_ncyl)
905 905 fjp->fj_chars->fdc_steps = 2;
906 906 else
907 907 fjp->fj_chars->fdc_steps = 1;
908 908
909 909 fjp->fj_attr->fda_rotatespd = label->dkl_rpm;
910 910 fjp->fj_attr->fda_intrlv = label->dkl_intrlv;
911 911
912 912 fdp->d_vtoc_version = label->dkl_vtoc.v_version;
913 913 bcopy(label->dkl_vtoc.v_volume, fdp->d_vtoc_volume, LEN_DKL_VVOL);
914 914 bcopy(label->dkl_vtoc.v_asciilabel,
915 915 fdp->d_vtoc_asciilabel, LEN_DKL_ASCII);
916 916 /*
917 917 * logical partitions
918 918 */
919 919 for (i = 0; i < NDKMAP; i++) {
920 920 fdp->d_part[i].p_tag = label->dkl_vtoc.v_part[i].p_tag;
921 921 fdp->d_part[i].p_flag = label->dkl_vtoc.v_part[i].p_flag;
922 922 fdp->d_part[i].p_start = label->dkl_vtoc.v_part[i].p_start;
923 923 fdp->d_part[i].p_size = label->dkl_vtoc.v_part[i].p_size;
924 924
925 925 fdp->d_vtoc_timestamp[i] = label->dkl_vtoc.timestamp[i];
926 926 }
927 927
928 928 fjp->fj_flags |= FUNIT_LABELOK;
929 929 goto out;
930 930
931 931 nolabel:
932 932 /*
933 933 * if not found, fill in label info from default (mark default used)
934 934 */
935 935 if (fdp->d_media & (1<<FMT_3D))
936 936 newlabel = deflabel_35;
937 937 else /* if (fdp->d_media & (1<<FMT_5D9)) */
938 938 newlabel = deflabel_525;
939 939 bzero(fdp->d_vtoc_volume, LEN_DKL_VVOL);
940 940 (void) sprintf(fdp->d_vtoc_asciilabel, newlabel,
941 941 fjp->fj_chars->fdc_ncyl, fjp->fj_chars->fdc_nhead,
942 942 fjp->fj_chars->fdc_secptrack);
943 943 fjp->fj_flags |= FUNIT_UNLABELED;
944 944
945 945 out:
946 946 kmem_free(label, sizeof (struct dk_label));
947 947 return (rval);
948 948 }
949 949
950 950
951 951 /*ARGSUSED*/
952 952 static int
953 953 fd_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
954 954 {
955 955 struct fcu_obj *fjp = NULL;
956 956 struct fdisk *fdp = NULL;
957 957 int part, part_is_closed;
958 958
959 959 #ifdef DEBUG
960 960 int unit;
961 961 #define DEBUG_ASSIGN unit=
962 962 #else
963 963 #define DEBUG_ASSIGN (void)
964 964 #endif
965 965
966 966 DEBUG_ASSIGN fd_getdrive(dev, &fjp, &fdp);
967 967 /*
968 968 * Ignoring return in non DEBUG mode because success is checked by
969 969 * verifying fjp and fdp and returned unit value is not used.
970 970 */
971 971 if (!fjp || !fdp)
972 972 return (ENXIO);
973 973 part = PARTITION(dev);
974 974
975 975 sema_p(&fdp->d_ocsem);
976 976 FDERRPRINT(FDEP_L1, FDEM_CLOS,
977 977 (CE_CONT, "fd_close: fd unit %d part %d otype %x\n",
978 978 unit, part, otyp));
979 979
980 980 if (otyp == OTYP_LYR) {
981 981 if (fdp->d_lyropen[part])
982 982 fdp->d_lyropen[part]--;
983 983 part_is_closed = (fdp->d_lyropen[part] == 0);
984 984 } else {
985 985 fdp->d_regopen[otyp] &= ~(1<<part);
986 986 part_is_closed = 1;
987 987 }
988 988 if (part_is_closed) {
989 989 if (part == 2 && fdp->d_exclmask&(1<<part))
990 990 fdp->d_exclmask = 0;
991 991 else
992 992 fdp->d_exclmask &= ~(1<<part);
993 993 FDERRPRINT(FDEP_L0, FDEM_CLOS,
994 994 (CE_CONT,
995 995 "fd_close: exclparts %lx openparts %lx lyrcnt %lx\n",
996 996 fdp->d_exclmask, fdp->d_regopen[otyp],
997 997 fdp->d_lyropen[part]));
998 998
999 999 if (fd_unit_is_open(fdp) == 0)
1000 1000 fdp->d_obj->fj_flags &= ~FUNIT_CHANGED;
1001 1001 }
1002 1002 sema_v(&fdp->d_ocsem);
1003 1003 return (0);
1004 1004 }
1005 1005
1006 1006 /* ARGSUSED */
1007 1007 static int
1008 1008 fd_read(dev_t dev, struct uio *uio, cred_t *cred_p)
1009 1009 {
1010 1010 return (physio(fd_strategy, NULL, dev, B_READ, minphys, uio));
1011 1011 }
1012 1012
1013 1013 /* ARGSUSED */
1014 1014 static int
1015 1015 fd_write(dev_t dev, struct uio *uio, cred_t *cred_p)
1016 1016 {
1017 1017 return (physio(fd_strategy, NULL, dev, B_WRITE, minphys, uio));
1018 1018 }
1019 1019
1020 1020 /*
1021 1021 * fd_strategy
1022 1022 * checks operation, hangs buf struct off fdcntlr, calls fdstart
1023 1023 * if not already busy. Note that if we call start, then the operation
1024 1024 * will already be done on return (start sleeps).
1025 1025 */
1026 1026 static int
1027 1027 fd_strategy(struct buf *bp)
1028 1028 {
1029 1029 struct fcu_obj *fjp;
1030 1030 struct fdisk *fdp;
1031 1031 struct partition *pp;
1032 1032
1033 1033 FDERRPRINT(FDEP_L1, FDEM_STRA,
1034 1034 (CE_CONT, "fd_strategy: bp = 0x%p, dev = 0x%lx\n",
1035 1035 (void *)bp, bp->b_edev));
1036 1036
1037 1037 (void) fd_getdrive(bp->b_edev, &fjp, &fdp);
1038 1038
1039 1039 /*
1040 1040 * Ignoring return because device exist.
1041 1041 * Returned unit value is not used.
1042 1042 */
1043 1043 pp = &fdp->d_part[PARTITION(bp->b_edev)];
1044 1044
1045 1045 if (fjp->fj_chars->fdc_sec_size > NBPSCTR && (bp->b_blkno & 1)) {
1046 1046 FDERRPRINT(FDEP_L3, FDEM_STRA,
1047 1047 (CE_WARN, "fd%d: block %ld is not start of sector!",
1048 1048 DRIVE(bp->b_edev), (long)bp->b_blkno));
1049 1049 bp->b_error = EINVAL;
1050 1050 goto bad;
1051 1051 }
1052 1052
1053 1053 if ((bp->b_blkno > pp->p_size)) {
1054 1054 FDERRPRINT(FDEP_L3, FDEM_STRA,
1055 1055 (CE_WARN, "fd%d: block %ld is past the end! (nblk=%ld)",
1056 1056 DRIVE(bp->b_edev), (long)bp->b_blkno, pp->p_size));
1057 1057 bp->b_error = ENOSPC;
1058 1058 goto bad;
1059 1059 }
1060 1060
1061 1061 /* if at end of file, skip out now */
1062 1062 if (bp->b_blkno == pp->p_size) {
1063 1063 if ((bp->b_flags & B_READ) == 0) {
1064 1064 /* a write needs to get an error! */
1065 1065 bp->b_error = ENOSPC;
1066 1066 goto bad;
1067 1067 }
1068 1068 bp->b_resid = bp->b_bcount;
1069 1069 biodone(bp);
1070 1070 return (0);
1071 1071 }
1072 1072
1073 1073 /* if operation not a multiple of sector size, is error! */
1074 1074 if (bp->b_bcount % fjp->fj_chars->fdc_sec_size) {
1075 1075 FDERRPRINT(FDEP_L3, FDEM_STRA,
1076 1076 (CE_WARN, "fd%d: count %ld must be a multiple of %d",
1077 1077 DRIVE(bp->b_edev), bp->b_bcount,
1078 1078 fjp->fj_chars->fdc_sec_size));
1079 1079 bp->b_error = EINVAL;
1080 1080 goto bad;
1081 1081 }
1082 1082
1083 1083 /*
1084 1084 * Put the buf request in the drive's queue, FIFO.
1085 1085 */
1086 1086 bp->av_forw = 0;
1087 1087 mutex_enter(&fjp->fj_lock);
1088 1088 if (fdp->d_iostat)
1089 1089 kstat_waitq_enter(KIOSP);
1090 1090 if (fdp->d_actf)
1091 1091 fdp->d_actl->av_forw = bp;
1092 1092 else
1093 1093 fdp->d_actf = bp;
1094 1094 fdp->d_actl = bp;
1095 1095 if (!(fjp->fj_flags & FUNIT_BUSY)) {
1096 1096 fdstart(fjp);
1097 1097 }
1098 1098 mutex_exit(&fjp->fj_lock);
1099 1099 return (0);
1100 1100
1101 1101 bad:
1102 1102 bp->b_resid = bp->b_bcount;
1103 1103 bp->b_flags |= B_ERROR;
1104 1104 biodone(bp);
1105 1105 return (0);
1106 1106 }
1107 1107
1108 1108 /*
1109 1109 * fdstart
1110 1110 * called from fd_strategy() or from fdXXXX() to setup and
1111 1111 * start operations of read or write only (using buf structs).
1112 1112 * Because the chip doesn't handle crossing cylinder boundaries on
1113 1113 * the fly, this takes care of those boundary conditions. Note that
1114 1114 * it sleeps until the operation is done *within fdstart* - so that
1115 1115 * when fdstart returns, the operation is already done.
1116 1116 */
1117 1117 static void
1118 1118 fdstart(struct fcu_obj *fjp)
1119 1119 {
1120 1120 struct buf *bp;
1121 1121 struct fdisk *fdp = (struct fdisk *)fjp->fj_data;
1122 1122 struct fd_char *chp;
1123 1123 struct partition *pp;
1124 1124 uint_t ptend;
1125 1125 uint_t bincyl; /* (the number of the desired) block in cyl. */
1126 1126 uint_t blk, len, tlen;
1127 1127 uint_t secpcyl; /* number of sectors per cylinder */
1128 1128 int cyl, head, sect;
1129 1129 int sctrshft, unit;
1130 1130 caddr_t addr;
1131 1131
1132 1132 ASSERT(MUTEX_HELD(&fjp->fj_lock));
1133 1133 fjp->fj_flags |= FUNIT_BUSY;
1134 1134
1135 1135 while ((bp = fdp->d_actf) != NULL) {
1136 1136 fdp->d_actf = bp->av_forw;
1137 1137 fdp->d_current = bp;
1138 1138 if (fdp->d_iostat) {
1139 1139 kstat_waitq_to_runq(KIOSP);
1140 1140 }
1141 1141 mutex_exit(&fjp->fj_lock);
1142 1142
1143 1143 FDERRPRINT(FDEP_L0, FDEM_STRT,
1144 1144 (CE_CONT, "fdstart: bp=0x%p blkno=0x%lx bcount=0x%lx\n",
1145 1145 (void *)bp, (long)bp->b_blkno, bp->b_bcount));
1146 1146 bp->b_flags &= ~B_ERROR;
1147 1147 bp->b_error = 0;
1148 1148 bp->b_resid = bp->b_bcount; /* init resid */
1149 1149
1150 1150 ASSERT(DRIVE(bp->b_edev) == ddi_get_instance(fjp->fj_dip));
1151 1151 unit = fjp->fj_unit;
1152 1152 fjp->fj_ops->fco_select(fjp, unit, 1);
1153 1153
1154 1154 bp_mapin(bp); /* map in buffers */
1155 1155
1156 1156 pp = &fdp->d_part[PARTITION(bp->b_edev)];
1157 1157 /* starting blk adjusted for the partition */
1158 1158 blk = bp->b_blkno + pp->p_start;
1159 1159 ptend = pp->p_start + pp->p_size; /* end of the partition */
1160 1160
1161 1161 chp = fjp->fj_chars;
1162 1162 secpcyl = chp->fdc_nhead * chp->fdc_secptrack;
1163 1163 switch (chp->fdc_sec_size) {
1164 1164 /* convert logical block numbers to sector numbers */
1165 1165 case 1024:
1166 1166 sctrshft = SCTRSHFT + 1;
1167 1167 blk >>= 1;
1168 1168 ptend >>= 1;
1169 1169 break;
1170 1170 default:
1171 1171 case NBPSCTR:
1172 1172 sctrshft = SCTRSHFT;
1173 1173 break;
1174 1174 case 256:
1175 1175 sctrshft = SCTRSHFT - 1;
1176 1176 blk <<= 1;
1177 1177 ptend <<= 1;
1178 1178 break;
1179 1179 }
1180 1180
1181 1181 /*
1182 1182 * If off the end, limit to actual amount that
1183 1183 * can be transferred.
1184 1184 */
1185 1185 if ((blk + (bp->b_bcount >> sctrshft)) > ptend)
1186 1186 /* to end of partition */
1187 1187 len = (ptend - blk) << sctrshft;
1188 1188 else
1189 1189 len = bp->b_bcount;
1190 1190 addr = bp->b_un.b_addr; /* data buffer address */
1191 1191
1192 1192 /*
1193 1193 * now we have the real start blk, addr and len for xfer op
1194 1194 */
1195 1195 while (len != 0) {
1196 1196 /* start cyl of req */
1197 1197 cyl = blk / secpcyl;
1198 1198 bincyl = blk % secpcyl;
1199 1199 /* start head of req */
1200 1200 head = bincyl / chp->fdc_secptrack;
1201 1201 /* start sector of req */
1202 1202 sect = (bincyl % chp->fdc_secptrack) + 1;
1203 1203 /*
1204 1204 * If the desired block and length will go beyond the
1205 1205 * cylinder end, then limit it to the cylinder end.
1206 1206 */
1207 1207 if (bp->b_flags & B_READ) {
1208 1208 if (len > ((secpcyl - bincyl) << sctrshft))
1209 1209 tlen = (secpcyl - bincyl) << sctrshft;
1210 1210 else
1211 1211 tlen = len;
1212 1212 } else {
1213 1213 if (len >
1214 1214 ((chp->fdc_secptrack - sect + 1) <<
1215 1215 sctrshft))
1216 1216 tlen =
1217 1217 (chp->fdc_secptrack - sect + 1) <<
1218 1218 sctrshft;
1219 1219 else
1220 1220 tlen = len;
1221 1221 }
1222 1222
1223 1223 FDERRPRINT(FDEP_L0, FDEM_STRT, (CE_CONT,
1224 1224 " blk 0x%x addr 0x%p len 0x%x "
1225 1225 "cyl %d head %d sec %d\n resid 0x%lx, tlen %d\n",
1226 1226 blk, (void *)addr, len, cyl, head, sect,
1227 1227 bp->b_resid, tlen));
1228 1228
1229 1229 /*
1230 1230 * (try to) do the operation - failure returns an errno
1231 1231 */
1232 1232 bp->b_error = fjp->fj_ops->fco_rw(fjp, unit,
1233 1233 bp->b_flags & B_READ, cyl, head, sect, addr, tlen);
1234 1234 if (bp->b_error != 0) {
1235 1235 FDERRPRINT(FDEP_L3, FDEM_STRT, (CE_WARN,
1236 1236 "fdstart: bad exec of bp: 0x%p, err=%d",
1237 1237 (void *)bp, bp->b_error));
1238 1238 bp->b_flags |= B_ERROR;
1239 1239 break;
1240 1240 }
1241 1241 blk += tlen >> sctrshft;
1242 1242 len -= tlen;
1243 1243 addr += tlen;
1244 1244 bp->b_resid -= tlen;
1245 1245 }
1246 1246 FDERRPRINT(FDEP_L0, FDEM_STRT,
1247 1247 (CE_CONT, "fdstart done: b_resid %lu, b_count %lu\n",
1248 1248 bp->b_resid, bp->b_bcount));
1249 1249 if (fdp->d_iostat) {
1250 1250 if (bp->b_flags & B_READ) {
1251 1251 KIOSP->reads++;
1252 1252 KIOSP->nread += (bp->b_bcount - bp->b_resid);
1253 1253 } else {
1254 1254 KIOSP->writes++;
1255 1255 KIOSP->nwritten += (bp->b_bcount - bp->b_resid);
1256 1256 }
1257 1257 kstat_runq_exit(KIOSP);
1258 1258 }
1259 1259 bp_mapout(bp);
1260 1260 biodone(bp);
1261 1261
1262 1262 fjp->fj_ops->fco_select(fjp, unit, 0);
1263 1263 mutex_enter(&fjp->fj_lock);
1264 1264 fdp->d_current = 0;
1265 1265 }
1266 1266 fjp->fj_flags ^= FUNIT_BUSY;
1267 1267 }
1268 1268
1269 1269 /* ARGSUSED */
1270 1270 static int
1271 1271 fd_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cred_p,
1272 1272 int *rval_p)
1273 1273 {
1274 1274 union {
1275 1275 struct dk_cinfo dki;
1276 1276 struct dk_geom dkg;
1277 1277 struct dk_allmap dka;
1278 1278 struct fd_char fdchar;
1279 1279 struct fd_drive drvchar;
1280 1280 int temp;
1281 1281 } cpy;
1282 1282 struct vtoc vtoc;
1283 1283 struct fcu_obj *fjp = NULL;
1284 1284 struct fdisk *fdp = NULL;
1285 1285 struct dk_map *dmp;
1286 1286 struct dk_label *label;
1287 1287 int nblks, part, unit;
1288 1288 int rval = 0;
1289 1289 enum dkio_state state;
1290 1290
1291 1291 unit = fd_getdrive(dev, &fjp, &fdp);
1292 1292 if (!fjp || !fdp)
1293 1293 return (ENXIO);
1294 1294
1295 1295 FDERRPRINT(FDEP_L1, FDEM_IOCT,
1296 1296 (CE_CONT, "fd_ioctl fd unit %d: cmd %x, arg %lx\n",
1297 1297 unit, cmd, arg));
1298 1298
1299 1299 switch (cmd) {
1300 1300 case DKIOCINFO:
1301 1301 fjp->fj_ops->fco_dkinfo(fjp, &cpy.dki);
1302 1302 cpy.dki.dki_cnum = FDCTLR(fjp->fj_unit);
1303 1303 cpy.dki.dki_unit = FDUNIT(fjp->fj_unit);
1304 1304 cpy.dki.dki_partition = PARTITION(dev);
1305 1305 if (ddi_copyout(&cpy.dki, (void *)arg, sizeof (cpy.dki), flag))
1306 1306 rval = EFAULT;
1307 1307 break;
1308 1308
1309 1309 case DKIOCG_PHYGEOM:
1310 1310 case DKIOCG_VIRTGEOM:
1311 1311 cpy.dkg.dkg_nsect = fjp->fj_chars->fdc_secptrack;
1312 1312 goto get_geom;
1313 1313 case DKIOCGGEOM:
1314 1314 if (fjp->fj_flags & FUNIT_LABELOK)
1315 1315 cpy.dkg.dkg_nsect = (fjp->fj_chars->fdc_secptrack *
1316 1316 fjp->fj_chars->fdc_sec_size) / DEV_BSIZE;
1317 1317 else
1318 1318 cpy.dkg.dkg_nsect = fjp->fj_chars->fdc_secptrack;
1319 1319 get_geom:
1320 1320 cpy.dkg.dkg_pcyl = fjp->fj_chars->fdc_ncyl;
1321 1321 cpy.dkg.dkg_ncyl = fjp->fj_chars->fdc_ncyl;
1322 1322 cpy.dkg.dkg_nhead = fjp->fj_chars->fdc_nhead;
1323 1323 cpy.dkg.dkg_intrlv = fjp->fj_attr->fda_intrlv;
1324 1324 cpy.dkg.dkg_rpm = fjp->fj_attr->fda_rotatespd;
1325 1325 cpy.dkg.dkg_read_reinstruct =
1326 1326 (int)(cpy.dkg.dkg_nsect * cpy.dkg.dkg_rpm * 4) / 60000;
1327 1327 cpy.dkg.dkg_write_reinstruct = cpy.dkg.dkg_read_reinstruct;
1328 1328 if (ddi_copyout(&cpy.dkg, (void *)arg, sizeof (cpy.dkg), flag))
1329 1329 rval = EFAULT;
1330 1330 break;
1331 1331
1332 1332 case DKIOCSGEOM:
1333 1333 if (ddi_copyin((void *)arg, &cpy.dkg,
1334 1334 sizeof (struct dk_geom), flag)) {
1335 1335 rval = EFAULT;
1336 1336 break;
1337 1337 }
1338 1338 mutex_enter(&fjp->fj_lock);
1339 1339 fjp->fj_chars->fdc_ncyl = cpy.dkg.dkg_ncyl;
1340 1340 fjp->fj_chars->fdc_nhead = cpy.dkg.dkg_nhead;
1341 1341 fjp->fj_chars->fdc_secptrack = cpy.dkg.dkg_nsect;
1342 1342 fjp->fj_attr->fda_intrlv = cpy.dkg.dkg_intrlv;
1343 1343 fjp->fj_attr->fda_rotatespd = cpy.dkg.dkg_rpm;
1344 1344 fdp->d_curfdtype = -1;
1345 1345 mutex_exit(&fjp->fj_lock);
1346 1346 break;
1347 1347
1348 1348 /*
1349 1349 * return the map of all logical partitions
1350 1350 */
1351 1351 case DKIOCGAPART:
1352 1352 /*
1353 1353 * Note the conversion from starting sector number
1354 1354 * to starting cylinder number.
1355 1355 * Return error if division results in a remainder.
1356 1356 */
1357 1357 nblks = fjp->fj_chars->fdc_nhead * fjp->fj_chars->fdc_secptrack;
1358 1358
1359 1359 #ifdef _MULTI_DATAMODEL
1360 1360 switch (ddi_model_convert_from(flag & FMODELS)) {
1361 1361 case DDI_MODEL_ILP32:
1362 1362 {
1363 1363 struct dk_allmap32 dka32;
1364 1364
1365 1365 for (part = 0; part < NDKMAP; part++) {
1366 1366 if ((fdp->d_part[part].p_start % nblks) != 0)
1367 1367 return (EINVAL);
1368 1368 dka32.dka_map[part].dkl_cylno =
1369 1369 fdp->d_part[part].p_start / nblks;
1370 1370 dka32.dka_map[part].dkl_nblk =
1371 1371 fdp->d_part[part].p_size;
1372 1372 }
1373 1373
1374 1374 if (ddi_copyout(&dka32, (void *)arg,
1375 1375 sizeof (struct dk_allmap32), flag))
1376 1376 rval = EFAULT;
1377 1377
1378 1378 break;
1379 1379 }
1380 1380 case DDI_MODEL_NONE:
1381 1381
1382 1382 #endif /* _MULTI_DATAMODEL */
1383 1383
1384 1384 dmp = (struct dk_map *)&cpy.dka;
1385 1385 for (part = 0; part < NDKMAP; part++) {
1386 1386 if ((fdp->d_part[part].p_start % nblks) != 0)
1387 1387 return (EINVAL);
1388 1388 dmp->dkl_cylno =
1389 1389 fdp->d_part[part].p_start / nblks;
1390 1390 dmp->dkl_nblk = fdp->d_part[part].p_size;
1391 1391 dmp++;
1392 1392 }
1393 1393
1394 1394 if (ddi_copyout(&cpy.dka, (void *)arg,
1395 1395 sizeof (struct dk_allmap), flag))
1396 1396 rval = EFAULT;
1397 1397 #ifdef _MULTI_DATAMODEL
1398 1398 break;
1399 1399
1400 1400 }
1401 1401 #endif /* _MULTI_DATAMODEL */
1402 1402
1403 1403 break;
1404 1404
1405 1405 /*
1406 1406 * Set the map of all logical partitions
1407 1407 */
1408 1408 case DKIOCSAPART:
1409 1409
1410 1410 #ifdef _MULTI_DATAMODEL
1411 1411 switch (ddi_model_convert_from(flag & FMODELS)) {
1412 1412 case DDI_MODEL_ILP32:
1413 1413 {
1414 1414 struct dk_allmap32 dka32;
1415 1415
1416 1416 if (ddi_copyin((void *)arg, &dka32,
1417 1417 sizeof (dka32), flag)) {
1418 1418 rval = EFAULT;
1419 1419 break;
1420 1420 }
1421 1421 for (part = 0; part < NDKMAP; part++) {
1422 1422 cpy.dka.dka_map[part].dkl_cylno =
1423 1423 dka32.dka_map[part].dkl_cylno;
1424 1424 cpy.dka.dka_map[part].dkl_nblk =
1425 1425 dka32.dka_map[part].dkl_nblk;
1426 1426 }
1427 1427 break;
1428 1428 }
1429 1429 case DDI_MODEL_NONE:
1430 1430
1431 1431 #endif /* _MULTI_DATAMODEL */
1432 1432 if (ddi_copyin((void *)arg, &cpy.dka, sizeof (cpy.dka), flag))
1433 1433 rval = EFAULT;
1434 1434 #ifdef _MULTI_DATAMODEL
1435 1435
1436 1436 break;
1437 1437 }
1438 1438 #endif /* _MULTI_DATAMODEL */
1439 1439
1440 1440 if (rval != 0)
1441 1441 break;
1442 1442
1443 1443 dmp = (struct dk_map *)&cpy.dka;
1444 1444 nblks = fjp->fj_chars->fdc_nhead *
1445 1445 fjp->fj_chars->fdc_secptrack;
1446 1446 mutex_enter(&fjp->fj_lock);
1447 1447 /*
1448 1448 * Note the conversion from starting cylinder number
1449 1449 * to starting sector number.
1450 1450 */
1451 1451 for (part = 0; part < NDKMAP; part++) {
1452 1452 fdp->d_part[part].p_start = dmp->dkl_cylno *
1453 1453 nblks;
1454 1454 fdp->d_part[part].p_size = dmp->dkl_nblk;
1455 1455 dmp++;
1456 1456 }
1457 1457 mutex_exit(&fjp->fj_lock);
1458 1458
1459 1459 break;
1460 1460
1461 1461 case DKIOCGVTOC:
1462 1462 mutex_enter(&fjp->fj_lock);
1463 1463
1464 1464 /*
1465 1465 * Exit if the diskette has no label.
1466 1466 * Also, get the label to make sure the correct one is
1467 1467 * being used since the diskette may have changed
1468 1468 */
1469 1469 fjp->fj_ops->fco_select(fjp, unit, 1);
1470 1470 rval = fdgetlabel(fjp, unit);
1471 1471 fjp->fj_ops->fco_select(fjp, unit, 0);
1472 1472 if (rval) {
1473 1473 mutex_exit(&fjp->fj_lock);
1474 1474 rval = EINVAL;
1475 1475 break;
1476 1476 }
1477 1477
1478 1478 fd_build_user_vtoc(fjp, fdp, &vtoc);
1479 1479 mutex_exit(&fjp->fj_lock);
1480 1480
1481 1481 #ifdef _MULTI_DATAMODEL
1482 1482 switch (ddi_model_convert_from(flag & FMODELS)) {
1483 1483 case DDI_MODEL_ILP32:
1484 1484 {
1485 1485 struct vtoc32 vtoc32;
1486 1486
1487 1487 vtoctovtoc32(vtoc, vtoc32);
1488 1488
1489 1489 if (ddi_copyout(&vtoc32, (void *)arg,
1490 1490 sizeof (vtoc32), flag))
1491 1491 rval = EFAULT;
1492 1492
1493 1493 break;
1494 1494 }
1495 1495 case DDI_MODEL_NONE:
1496 1496
1497 1497 #endif /* _MULTI_DATAMODEL */
1498 1498 if (ddi_copyout(&vtoc, (void *)arg,
1499 1499 sizeof (vtoc), flag))
1500 1500 rval = EFAULT;
1501 1501 #ifdef _MULTI_DATAMODEL
1502 1502 break;
1503 1503 }
1504 1504 #endif /* _MULTI_DATAMODEL */
1505 1505
1506 1506 break;
1507 1507
1508 1508 case DKIOCSVTOC:
1509 1509
1510 1510 #ifdef _MULTI_DATAMODEL
1511 1511 switch (ddi_model_convert_from(flag & FMODELS)) {
1512 1512 case DDI_MODEL_ILP32:
1513 1513 {
1514 1514 struct vtoc32 vtoc32;
1515 1515
1516 1516 if (ddi_copyin((void *)arg, &vtoc32,
1517 1517 sizeof (vtoc32), flag)) {
1518 1518 rval = EFAULT;
1519 1519 break;
1520 1520 }
1521 1521
1522 1522 vtoc32tovtoc(vtoc32, vtoc);
1523 1523
1524 1524 break;
1525 1525 }
1526 1526 case DDI_MODEL_NONE:
1527 1527
1528 1528 #endif /* _MULTI_DATAMODEL */
1529 1529 if (ddi_copyin((void *)arg, &vtoc, sizeof (vtoc), flag))
1530 1530 rval = EFAULT;
1531 1531 #ifdef _MULTI_DATAMODEL
1532 1532 break;
1533 1533 }
1534 1534 #endif /* _MULTI_DATAMODEL */
1535 1535
1536 1536 if (rval != 0)
1537 1537 break;
1538 1538
1539 1539
1540 1540 label = kmem_zalloc(sizeof (struct dk_label), KM_SLEEP);
1541 1541
1542 1542 mutex_enter(&fjp->fj_lock);
1543 1543
1544 1544 if ((rval = fd_build_label_vtoc(fjp, fdp, &vtoc, label)) == 0) {
1545 1545 fjp->fj_ops->fco_select(fjp, unit, 1);
1546 1546 rval = fjp->fj_ops->fco_rw(fjp, unit, FDWRITE,
1547 1547 0, 0, 1, (caddr_t)label, sizeof (struct dk_label));
1548 1548 fjp->fj_ops->fco_select(fjp, unit, 0);
1549 1549 }
1550 1550 mutex_exit(&fjp->fj_lock);
1551 1551 kmem_free(label, sizeof (struct dk_label));
1552 1552 break;
1553 1553
1554 1554 case DKIOCSTATE:
1555 1555 FDERRPRINT(FDEP_L1, FDEM_IOCT,
1556 1556 (CE_CONT, "fd_ioctl fd unit %d: DKIOCSTATE\n", unit));
1557 1557
1558 1558 if (ddi_copyin((void *)arg, &state, sizeof (int), flag)) {
1559 1559 rval = EFAULT;
1560 1560 break;
1561 1561 }
1562 1562
1563 1563 rval = fd_check_media(dev, state);
1564 1564
1565 1565 if (ddi_copyout(&fdp->d_media_state, (void *)arg,
1566 1566 sizeof (int), flag))
1567 1567 rval = EFAULT;
1568 1568 break;
1569 1569
1570 1570 case FDIOGCHAR:
1571 1571 if (ddi_copyout(fjp->fj_chars, (void *)arg,
1572 1572 sizeof (struct fd_char), flag))
1573 1573 rval = EFAULT;
1574 1574 break;
1575 1575
1576 1576 case FDIOSCHAR:
1577 1577 if (ddi_copyin((void *)arg, &cpy.fdchar,
1578 1578 sizeof (struct fd_char), flag)) {
1579 1579 rval = EFAULT;
1580 1580 break;
1581 1581 }
1582 1582 switch (cpy.fdchar.fdc_transfer_rate) {
1583 1583 case 417:
1584 1584 if ((fdp->d_media & (1 << FMT_3M)) == 0) {
1585 1585 cmn_err(CE_CONT,
1586 1586 "fdioschar:Medium density not supported\n");
1587 1587 rval = EINVAL;
1588 1588 break;
1589 1589 }
1590 1590 mutex_enter(&fjp->fj_lock);
1591 1591 fjp->fj_attr->fda_rotatespd = 360;
1592 1592 mutex_exit(&fjp->fj_lock);
1593 1593 /* cpy.fdchar.fdc_transfer_rate = 500; */
1594 1594 /* FALLTHROUGH */
1595 1595 case 1000:
1596 1596 case 500:
1597 1597 case 300:
1598 1598 case 250:
1599 1599 mutex_enter(&fjp->fj_lock);
1600 1600 *(fjp->fj_chars) = cpy.fdchar;
1601 1601 fdp->d_curfdtype = -1;
1602 1602 fjp->fj_flags &= ~FUNIT_CHAROK;
1603 1603 mutex_exit(&fjp->fj_lock);
1604 1604
1605 1605 break;
1606 1606
1607 1607 default:
1608 1608 FDERRPRINT(FDEP_L4, FDEM_IOCT,
1609 1609 (CE_WARN, "fd_ioctl fd unit %d: FDIOSCHAR odd "
1610 1610 "xfer rate %dkbs",
1611 1611 unit, cpy.fdchar.fdc_transfer_rate));
1612 1612 rval = EINVAL;
1613 1613 break;
1614 1614 }
1615 1615 break;
1616 1616
1617 1617 /*
1618 1618 * set all characteristics and geometry to the defaults
1619 1619 */
1620 1620 case FDDEFGEOCHAR:
1621 1621 mutex_enter(&fjp->fj_lock);
1622 1622 fdp->d_curfdtype = fdp->d_deffdtype;
1623 1623 *fjp->fj_chars = *defchar[fdp->d_curfdtype];
1624 1624 *fjp->fj_attr = fdtypes[fdp->d_curfdtype];
1625 1625 bcopy(fdparts[fdp->d_curfdtype],
1626 1626 fdp->d_part, sizeof (struct partition) * NDKMAP);
1627 1627 fjp->fj_flags &= ~FUNIT_CHAROK;
1628 1628 mutex_exit(&fjp->fj_lock);
1629 1629 break;
1630 1630
1631 1631 case FDEJECT: /* eject disk */
1632 1632 case DKIOCEJECT:
1633 1633 fjp->fj_flags &= ~(FUNIT_LABELOK | FUNIT_UNLABELED);
1634 1634 rval = ENOSYS;
1635 1635 break;
1636 1636
1637 1637 case FDGETCHANGE: /* disk changed */
1638 1638 if (ddi_copyin((void *)arg, &cpy.temp, sizeof (int), flag)) {
1639 1639 rval = EFAULT;
1640 1640 break;
1641 1641 }
1642 1642 mutex_enter(&fjp->fj_lock);
1643 1643 fjp->fj_ops->fco_select(fjp, unit, 1);
1644 1644
1645 1645 if (fjp->fj_flags & FUNIT_CHANGED)
1646 1646 cpy.temp |= FDGC_HISTORY;
1647 1647 else
1648 1648 cpy.temp &= ~FDGC_HISTORY;
1649 1649 fjp->fj_flags &= ~FUNIT_CHANGED;
1650 1650
1651 1651 if (fjp->fj_ops->fco_getchng(fjp, unit)) {
1652 1652 cpy.temp |= FDGC_DETECTED;
1653 1653 fjp->fj_ops->fco_resetchng(fjp, unit);
1654 1654 /*
1655 1655 * check diskette again only if it was removed
1656 1656 */
1657 1657 if (fjp->fj_ops->fco_getchng(fjp, unit)) {
1658 1658 /*
1659 1659 * no diskette is present
1660 1660 */
1661 1661 cpy.temp |= FDGC_CURRENT;
1662 1662 if (fjp->fj_flags & FUNIT_CHGDET)
1663 1663 /*
1664 1664 * again no diskette; not a new change
1665 1665 */
1666 1666 cpy.temp ^= FDGC_DETECTED;
1667 1667 else
1668 1668 fjp->fj_flags |= FUNIT_CHGDET;
1669 1669 } else {
1670 1670 /*
1671 1671 * a new diskette is present
1672 1672 */
1673 1673 cpy.temp &= ~FDGC_CURRENT;
1674 1674 fjp->fj_flags &= ~FUNIT_CHGDET;
1675 1675 }
1676 1676 } else {
1677 1677 cpy.temp &= ~(FDGC_DETECTED | FDGC_CURRENT);
1678 1678 fjp->fj_flags &= ~FUNIT_CHGDET;
1679 1679 }
1680 1680 /*
1681 1681 * also get state of write protection
1682 1682 */
1683 1683 if (fjp->fj_flags & FUNIT_WPROT) {
1684 1684 cpy.temp |= FDGC_CURWPROT;
1685 1685 } else {
1686 1686 cpy.temp &= ~FDGC_CURWPROT;
1687 1687 }
1688 1688 fjp->fj_ops->fco_select(fjp, unit, 0);
1689 1689 mutex_exit(&fjp->fj_lock);
1690 1690
1691 1691 if (ddi_copyout(&cpy.temp, (void *)arg, sizeof (int), flag))
1692 1692 rval = EFAULT;
1693 1693 break;
1694 1694
1695 1695 case FDGETDRIVECHAR:
1696 1696 if (ddi_copyout(fjp->fj_drive, (void *)arg,
1697 1697 sizeof (struct fd_drive), flag))
1698 1698 rval = EFAULT;
1699 1699 break;
1700 1700
1701 1701 case FDSETDRIVECHAR:
1702 1702 if (ddi_copyin((void *)arg, &cpy.drvchar,
1703 1703 sizeof (struct fd_drive), flag)) {
1704 1704 rval = EFAULT;
1705 1705 break;
1706 1706 }
1707 1707 mutex_enter(&fjp->fj_lock);
1708 1708 *(fjp->fj_drive) = cpy.drvchar;
1709 1709 fdp->d_curfdtype = -1;
1710 1710 fjp->fj_flags &= ~FUNIT_CHAROK;
1711 1711 mutex_exit(&fjp->fj_lock);
1712 1712 break;
1713 1713
1714 1714 case DKIOCREMOVABLE: {
1715 1715 int i = 1;
1716 1716
1717 1717 /* no brainer: floppies are always removable */
1718 1718 if (ddi_copyout(&i, (void *)arg, sizeof (int), flag)) {
1719 1719 rval = EFAULT;
1720 1720 }
1721 1721 break;
1722 1722 }
1723 1723
1724 1724 case DKIOCGMEDIAINFO:
1725 1725 rval = fd_get_media_info(fjp, (caddr_t)arg, flag);
1726 1726 break;
1727 1727
1728 1728 case FDIOCMD:
1729 1729 {
1730 1730 struct fd_cmd fc;
1731 1731 int cyl, head, spc, spt;
1732 1732
1733 1733 #ifdef _MULTI_DATAMODEL
1734 1734 switch (ddi_model_convert_from(flag & FMODELS)) {
1735 1735 case DDI_MODEL_ILP32:
1736 1736 {
1737 1737 struct fd_cmd32 fc32;
1738 1738
1739 1739 if (ddi_copyin((void *)arg, &fc32,
1740 1740 sizeof (fc32), flag)) {
1741 1741 rval = EFAULT;
1742 1742 break;
1743 1743 }
1744 1744
1745 1745 fc.fdc_cmd = fc32.fdc_cmd;
1746 1746 fc.fdc_flags = fc32.fdc_flags;
1747 1747 fc.fdc_blkno = fc32.fdc_blkno;
1748 1748 fc.fdc_secnt = fc32.fdc_secnt;
1749 1749 fc.fdc_bufaddr = (caddr_t)(uintptr_t)fc32.fdc_bufaddr;
1750 1750 fc.fdc_buflen = fc32.fdc_buflen;
1751 1751
1752 1752 break;
1753 1753 }
1754 1754 case DDI_MODEL_NONE:
1755 1755
1756 1756 #endif /* _MULTI_DATAMODEL */
1757 1757
1758 1758 if (ddi_copyin((void *)arg, &fc, sizeof (fc), flag)) {
1759 1759 rval = EFAULT;
1760 1760 break;
1761 1761 }
1762 1762 #ifdef _MULTI_DATAMODEL
1763 1763 break;
1764 1764 }
1765 1765 #endif /* _MULTI_DATAMODEL */
1766 1766
1767 1767 if (rval != 0)
1768 1768 break;
1769 1769
1770 1770 if (fc.fdc_cmd == FDCMD_READ || fc.fdc_cmd == FDCMD_WRITE) {
1771 1771 auto struct iovec aiov;
1772 1772 auto struct uio auio;
1773 1773 struct uio *uio = &auio;
1774 1774
1775 1775 spc = (fc.fdc_cmd == FDCMD_READ)? B_READ: B_WRITE;
1776 1776
1777 1777 bzero(&auio, sizeof (struct uio));
1778 1778 bzero(&aiov, sizeof (struct iovec));
1779 1779 aiov.iov_base = fc.fdc_bufaddr;
1780 1780 aiov.iov_len = (uint_t)fc.fdc_secnt *
1781 1781 fjp->fj_chars->fdc_sec_size;
1782 1782 uio->uio_iov = &aiov;
1783 1783
1784 1784 uio->uio_iovcnt = 1;
1785 1785 uio->uio_resid = aiov.iov_len;
1786 1786 uio->uio_segflg = UIO_USERSPACE;
1787 1787
1788 1788 rval = physio(fd_strategy, (struct buf *)0, dev,
1789 1789 spc, minphys, uio);
1790 1790 break;
1791 1791 } else if (fc.fdc_cmd == FDCMD_FORMAT_TRACK) {
1792 1792 spt = fjp->fj_chars->fdc_secptrack; /* sec/trk */
1793 1793 spc = fjp->fj_chars->fdc_nhead * spt; /* sec/cyl */
1794 1794 cyl = fc.fdc_blkno / spc;
1795 1795 head = (fc.fdc_blkno % spc) / spt;
1796 1796 if ((cyl | head) == 0)
1797 1797 fjp->fj_flags &=
1798 1798 ~(FUNIT_LABELOK | FUNIT_UNLABELED);
1799 1799
1800 1800 FDERRPRINT(FDEP_L0, FDEM_FORM,
1801 1801 (CE_CONT, "fd_format cyl %d, hd %d\n", cyl, head));
1802 1802 fjp->fj_ops->fco_select(fjp, unit, 1);
1803 1803 rval = fjp->fj_ops->fco_format(fjp, unit, cyl, head,
1804 1804 (int)fc.fdc_flags);
1805 1805 fjp->fj_ops->fco_select(fjp, unit, 0);
1806 1806
1807 1807 break;
1808 1808 }
1809 1809 FDERRPRINT(FDEP_L4, FDEM_IOCT,
1810 1810 (CE_WARN, "fd_ioctl fd unit %d: FDIOCSCMD not yet complete",
1811 1811 unit));
1812 1812 rval = EINVAL;
1813 1813 break;
1814 1814 }
1815 1815
1816 1816 case FDRAW:
1817 1817 rval = fd_rawioctl(fjp, unit, (caddr_t)arg, flag);
1818 1818 break;
1819 1819
1820 1820 default:
1821 1821 FDERRPRINT(FDEP_L4, FDEM_IOCT,
1822 1822 (CE_WARN, "fd_ioctl fd unit %d: invalid ioctl 0x%x",
1823 1823 unit, cmd));
1824 1824 rval = ENOTTY;
1825 1825 break;
1826 1826 }
1827 1827 return (rval);
1828 1828 }
1829 1829
1830 1830 static void
1831 1831 fd_build_user_vtoc(struct fcu_obj *fjp, struct fdisk *fdp, struct vtoc *vtocp)
1832 1832 {
1833 1833 struct partition *vpart;
1834 1834 int i;
1835 1835 int xblk;
1836 1836
1837 1837 /*
1838 1838 * Return vtoc structure fields in the provided VTOC area, addressed
1839 1839 * by *vtocp.
1840 1840 *
1841 1841 */
1842 1842 bzero(vtocp, sizeof (struct vtoc));
1843 1843
1844 1844 bcopy(fdp->d_vtoc_bootinfo,
1845 1845 vtocp->v_bootinfo, sizeof (vtocp->v_bootinfo));
1846 1846
1847 1847 vtocp->v_sanity = VTOC_SANE;
1848 1848 vtocp->v_version = fdp->d_vtoc_version;
1849 1849 bcopy(fdp->d_vtoc_volume, vtocp->v_volume, LEN_DKL_VVOL);
1850 1850 if (fjp->fj_flags & FUNIT_LABELOK) {
1851 1851 vtocp->v_sectorsz = DEV_BSIZE;
1852 1852 xblk = 1;
1853 1853 } else {
1854 1854 vtocp->v_sectorsz = fjp->fj_chars->fdc_sec_size;
1855 1855 xblk = vtocp->v_sectorsz / DEV_BSIZE;
1856 1856 }
1857 1857 vtocp->v_nparts = 3; /* <= NDKMAP; */
1858 1858
1859 1859 /*
1860 1860 * Copy partitioning information.
1861 1861 */
1862 1862 bcopy(fdp->d_part, vtocp->v_part, sizeof (struct partition) * NDKMAP);
1863 1863 for (i = NDKMAP, vpart = vtocp->v_part; i && (xblk > 1); i--, vpart++) {
1864 1864 /* correct partition info if sector size > 512 bytes */
1865 1865 vpart->p_start /= xblk;
1866 1866 vpart->p_size /= xblk;
1867 1867 }
1868 1868
1869 1869 bcopy(fdp->d_vtoc_timestamp,
1870 1870 vtocp->timestamp, sizeof (fdp->d_vtoc_timestamp));
1871 1871 bcopy(fdp->d_vtoc_asciilabel, vtocp->v_asciilabel, LEN_DKL_ASCII);
1872 1872 }
1873 1873
1874 1874
1875 1875 static int
1876 1876 fd_build_label_vtoc(struct fcu_obj *fjp, struct fdisk *fdp, struct vtoc *vtocp,
1877 1877 struct dk_label *labelp)
1878 1878 {
1879 1879 struct partition *vpart;
1880 1880 int i;
1881 1881 int nblks;
1882 1882 int ncyl;
1883 1883 ushort_t sum, *sp;
1884 1884
1885 1885
1886 1886 /*
1887 1887 * Sanity-check the vtoc
1888 1888 */
1889 1889 if (vtocp->v_sanity != VTOC_SANE ||
1890 1890 vtocp->v_nparts > NDKMAP || vtocp->v_nparts <= 0) {
1891 1891 FDERRPRINT(FDEP_L3, FDEM_IOCT,
1892 1892 (CE_WARN, "fd_build_label: sanity check on vtoc failed"));
1893 1893 return (EINVAL);
1894 1894 }
1895 1895
1896 1896 /*
1897 1897 * before copying the vtoc, the partition information in it should be
1898 1898 * checked against the information the driver already has on the
1899 1899 * diskette.
1900 1900 */
1901 1901
1902 1902 nblks = (fjp->fj_chars->fdc_nhead * fjp->fj_chars->fdc_secptrack *
1903 1903 fjp->fj_chars->fdc_sec_size) / DEV_BSIZE;
1904 1904 if (nblks == 0 || fjp->fj_chars->fdc_ncyl == 0)
1905 1905 return (EFAULT);
1906 1906 vpart = vtocp->v_part;
1907 1907
1908 1908 /*
1909 1909 * Check the partition information in the vtoc. The starting sectors
1910 1910 * must lie along cylinder boundaries. (NDKMAP entries are checked
1911 1911 * to ensure that the unused entries are set to 0 if vtoc->v_nparts
1912 1912 * is less than NDKMAP)
1913 1913 */
1914 1914 for (i = NDKMAP; i; i--) {
1915 1915 if ((vpart->p_start % nblks) != 0) {
1916 1916 return (EINVAL);
1917 1917 }
1918 1918 ncyl = vpart->p_start / nblks;
1919 1919 ncyl += vpart->p_size / nblks;
1920 1920 if ((vpart->p_size % nblks) != 0)
1921 1921 ncyl++;
1922 1922 if (ncyl > (long)fjp->fj_chars->fdc_ncyl) {
1923 1923 return (EINVAL);
1924 1924 }
1925 1925 vpart++;
1926 1926 }
1927 1927
1928 1928
1929 1929 bcopy(vtocp->v_bootinfo, fdp->d_vtoc_bootinfo,
1930 1930 sizeof (vtocp->v_bootinfo));
1931 1931 fdp->d_vtoc_version = vtocp->v_version;
1932 1932 bcopy(vtocp->v_volume, fdp->d_vtoc_volume, LEN_DKL_VVOL);
1933 1933
1934 1934 /*
1935 1935 * Copy partitioning information.
1936 1936 */
1937 1937 bcopy(vtocp->v_part, fdp->d_part, sizeof (struct partition) * NDKMAP);
1938 1938 bcopy(vtocp->timestamp, fdp->d_vtoc_timestamp,
1939 1939 sizeof (fdp->d_vtoc_timestamp));
1940 1940 bcopy(vtocp->v_asciilabel, fdp->d_vtoc_asciilabel, LEN_DKL_ASCII);
1941 1941
1942 1942 /*
1943 1943 * construct the diskette label in supplied buffer
1944 1944 */
1945 1945
1946 1946 /* Put appropriate vtoc structure fields into the disk label */
1947 1947 labelp->dkl_vtoc.v_bootinfo[0] = (uint32_t)vtocp->v_bootinfo[0];
1948 1948 labelp->dkl_vtoc.v_bootinfo[1] = (uint32_t)vtocp->v_bootinfo[1];
1949 1949 labelp->dkl_vtoc.v_bootinfo[2] = (uint32_t)vtocp->v_bootinfo[2];
1950 1950
1951 1951 labelp->dkl_vtoc.v_sanity = vtocp->v_sanity;
1952 1952 labelp->dkl_vtoc.v_version = vtocp->v_version;
1953 1953
1954 1954 bcopy(vtocp->v_volume, labelp->dkl_vtoc.v_volume, LEN_DKL_VVOL);
1955 1955
1956 1956 labelp->dkl_vtoc.v_nparts = vtocp->v_nparts;
1957 1957
1958 1958 bcopy(vtocp->v_reserved, labelp->dkl_vtoc.v_reserved,
1959 1959 sizeof (labelp->dkl_vtoc.v_reserved));
1960 1960
1961 1961 for (i = 0; i < (int)vtocp->v_nparts; i++) {
1962 1962 labelp->dkl_vtoc.v_part[i].p_tag = vtocp->v_part[i].p_tag;
1963 1963 labelp->dkl_vtoc.v_part[i].p_flag = vtocp->v_part[i].p_flag;
1964 1964 labelp->dkl_vtoc.v_part[i].p_start = vtocp->v_part[i].p_start;
1965 1965 labelp->dkl_vtoc.v_part[i].p_size = vtocp->v_part[i].p_size;
1966 1966 }
1967 1967
1968 1968 for (i = 0; i < NDKMAP; i++) {
1969 1969 labelp->dkl_vtoc.v_timestamp[i] = vtocp->timestamp[i];
1970 1970 }
1971 1971 bcopy(vtocp->v_asciilabel, labelp->dkl_asciilabel, LEN_DKL_ASCII);
1972 1972
1973 1973
1974 1974 labelp->dkl_pcyl = fjp->fj_chars->fdc_ncyl;
1975 1975 labelp->dkl_ncyl = fjp->fj_chars->fdc_ncyl;
1976 1976 labelp->dkl_nhead = fjp->fj_chars->fdc_nhead;
1977 1977 /*
1978 1978 * The fdc_secptrack field of the fd_char structure is the number
1979 1979 * of sectors per track where the sectors are fdc_sec_size.
1980 1980 * The dkl_nsect field of the dk_label structure is the number of
1981 1981 * DEV_BSIZE (512) byte sectors per track.
1982 1982 */
1983 1983 labelp->dkl_nsect = (fjp->fj_chars->fdc_secptrack *
1984 1984 fjp->fj_chars->fdc_sec_size) / DEV_BSIZE;
1985 1985 labelp->dkl_intrlv = fjp->fj_attr->fda_intrlv;
1986 1986 labelp->dkl_rpm = fjp->fj_attr->fda_rotatespd;
1987 1987 labelp->dkl_read_reinstruct =
1988 1988 (int)(labelp->dkl_nsect * labelp->dkl_rpm * 4) / 60000;
1989 1989 labelp->dkl_write_reinstruct = labelp->dkl_read_reinstruct;
1990 1990
1991 1991 labelp->dkl_magic = DKL_MAGIC;
1992 1992
1993 1993 sum = 0;
1994 1994 labelp->dkl_cksum = 0;
1995 1995 sp = (ushort_t *)labelp;
1996 1996 while (sp < &(labelp->dkl_cksum)) {
1997 1997 sum ^= *sp++;
1998 1998 }
1999 1999 labelp->dkl_cksum = sum;
2000 2000
2001 2001 return (0);
2002 2002 }
2003 2003
2004 2004 static int
2005 2005 fd_rawioctl(struct fcu_obj *fjp, int unit, caddr_t arg, int mode)
2006 2006 {
2007 2007 struct fd_raw fdr;
2008 2008 char *arg_result = NULL;
2009 2009 int flag = B_READ;
2010 2010 int rval = 0;
2011 2011 caddr_t uaddr;
2012 2012 uint_t ucount;
2013 2013
2014 2014 FDERRPRINT(FDEP_L1, FDEM_RAWI,
2015 2015 (CE_CONT, "fd_rawioctl: cmd[0]=0x%x\n", fdr.fdr_cmd[0]));
2016 2016
2017 2017 if (fjp->fj_chars->fdc_medium != 3 && fjp->fj_chars->fdc_medium != 5) {
2018 2018 cmn_err(CE_CONT, "fd_rawioctl: Medium density not supported\n");
2019 2019 return (ENXIO);
2020 2020 }
2021 2021
2022 2022 #ifdef _MULTI_DATAMODEL
2023 2023 switch (ddi_model_convert_from(mode & FMODELS)) {
2024 2024 case DDI_MODEL_ILP32:
2025 2025 {
2026 2026 struct fd_raw32 fdr32;
2027 2027
2028 2028 if (ddi_copyin(arg, &fdr32, sizeof (fdr32), mode))
2029 2029 return (EFAULT);
2030 2030
2031 2031 bcopy(fdr32.fdr_cmd, fdr.fdr_cmd, sizeof (fdr.fdr_cmd));
2032 2032 fdr.fdr_cnum = fdr32.fdr_cnum;
2033 2033 fdr.fdr_nbytes = fdr32.fdr_nbytes;
2034 2034 fdr.fdr_addr = (caddr_t)(uintptr_t)fdr32.fdr_addr;
2035 2035 arg_result = ((struct fd_raw32 *)arg)->fdr_result;
2036 2036
2037 2037 break;
2038 2038 }
2039 2039 case DDI_MODEL_NONE:
2040 2040 #endif /* ! _MULTI_DATAMODEL */
2041 2041
2042 2042 if (ddi_copyin(arg, &fdr, sizeof (fdr), mode))
2043 2043 return (EFAULT);
2044 2044
2045 2045 arg_result = ((struct fd_raw *)arg)->fdr_result;
2046 2046
2047 2047 #ifdef _MULTI_DATAMODEL
2048 2048 break;
2049 2049 }
2050 2050 #endif /* _MULTI_DATAMODEL */
2051 2051
2052 2052
2053 2053
2054 2054 /*
2055 2055 * copy user address & nbytes from raw_req so that we can
2056 2056 * put kernel address in req structure
2057 2057 */
2058 2058 uaddr = fdr.fdr_addr;
2059 2059 ucount = (uint_t)fdr.fdr_nbytes;
2060 2060 unit &= 3;
2061 2061
2062 2062 switch (fdr.fdr_cmd[0] & 0x0f) {
2063 2063
2064 2064 case FDRAW_FORMAT:
2065 2065 ucount += 16;
2066 2066 fdr.fdr_addr = kmem_zalloc(ucount, KM_SLEEP);
2067 2067 if (ddi_copyin(uaddr, fdr.fdr_addr,
2068 2068 (size_t)fdr.fdr_nbytes, mode)) {
2069 2069 kmem_free(fdr.fdr_addr, ucount);
2070 2070 return (EFAULT);
2071 2071 }
2072 2072 if ((*fdr.fdr_addr | fdr.fdr_addr[1]) == 0)
2073 2073 fjp->fj_flags &= ~(FUNIT_LABELOK | FUNIT_UNLABELED);
2074 2074 flag = B_WRITE;
2075 2075 fdr.fdr_cmd[1] = (fdr.fdr_cmd[1] & ~3) | unit;
2076 2076 break;
2077 2077
2078 2078 case FDRAW_WRCMD:
2079 2079 case FDRAW_WRITEDEL:
2080 2080 flag = B_WRITE;
2081 2081 /* FALLTHROUGH */
2082 2082 case FDRAW_RDCMD:
2083 2083 case FDRAW_READDEL:
2084 2084 case FDRAW_READTRACK:
2085 2085 if (ucount) {
2086 2086 /*
2087 2087 * In SunOS 4.X, we used to as_fault things in.
2088 2088 * We really cannot do this in 5.0/SVr4. Unless
2089 2089 * someone really believes that speed is of the
2090 2090 * essence here, it is just much simpler to do
2091 2091 * this in kernel space and use copyin/copyout.
2092 2092 */
2093 2093 fdr.fdr_addr = kmem_alloc((size_t)ucount, KM_SLEEP);
2094 2094 if (flag == B_WRITE) {
2095 2095 if (ddi_copyin(uaddr, fdr.fdr_addr, ucount,
2096 2096 mode)) {
2097 2097 kmem_free(fdr.fdr_addr, ucount);
2098 2098 return (EFAULT);
2099 2099 }
2100 2100 }
2101 2101 } else
2102 2102 return (EINVAL);
2103 2103 fdr.fdr_cmd[1] = (fdr.fdr_cmd[1] & ~3) | unit;
2104 2104 break;
2105 2105
2106 2106 case FDRAW_READID:
2107 2107 case FDRAW_REZERO:
2108 2108 case FDRAW_SEEK:
2109 2109 case FDRAW_SENSE_DRV:
2110 2110 ucount = 0;
2111 2111 fdr.fdr_cmd[1] = (fdr.fdr_cmd[1] & ~3) | unit;
2112 2112 break;
2113 2113
2114 2114 case FDRAW_SPECIFY:
2115 2115 fdr.fdr_cmd[2] &= 0xfe; /* keep NoDMA bit clear */
2116 2116 /* FALLTHROUGH */
2117 2117 case FDRAW_SENSE_INT:
2118 2118 ucount = 0;
2119 2119 break;
2120 2120
2121 2121 default:
2122 2122 return (EINVAL);
2123 2123 }
2124 2124
2125 2125 /*
2126 2126 * Note that we ignore any error returns from controller
2127 2127 * This is the way the driver has been, and it may be
2128 2128 * that the raw ioctl senders simply don't want to
2129 2129 * see any errors returned in this fashion.
2130 2130 */
2131 2131
2132 2132 fjp->fj_ops->fco_select(fjp, unit, 1);
2133 2133 rval = fjp->fj_ops->fco_rwioctl(fjp, unit, (caddr_t)&fdr);
2134 2134
2135 2135 if (ucount && flag == B_READ && rval == 0) {
2136 2136 if (ddi_copyout(fdr.fdr_addr, uaddr, ucount, mode)) {
2137 2137 rval = EFAULT;
2138 2138 }
2139 2139 }
2140 2140 if (ddi_copyout(fdr.fdr_result, arg_result, sizeof (fdr.fdr_cmd), mode))
2141 2141 rval = EFAULT;
2142 2142
2143 2143 fjp->fj_ops->fco_select(fjp, unit, 0);
2144 2144 if (ucount)
2145 2145 kmem_free(fdr.fdr_addr, ucount);
2146 2146
2147 2147 return (rval);
2148 2148 }
2149 2149
2150 2150 /*
2151 2151 * property operation routine. return the number of blocks for the partition
2152 2152 * in question or forward the request to the property facilities.
2153 2153 */
2154 2154 static int
2155 2155 fd_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags,
2156 2156 char *name, caddr_t valuep, int *lengthp)
2157 2157 {
2158 2158 struct fcu_obj *fjp = NULL;
2159 2159 struct fdisk *fdp = NULL;
2160 2160 uint64_t nblocks64;
2161 2161
2162 2162 FDERRPRINT(FDEP_L1, FDEM_PROP,
2163 2163 (CE_CONT, "fd_prop_op: dip %p %s\n", (void *)dip, name));
2164 2164
2165 2165 /*
2166 2166 * Our dynamic properties are all device specific and size oriented.
2167 2167 * Requests issued under conditions where size is valid are passed
2168 2168 * to ddi_prop_op_nblocks with the size information, otherwise the
2169 2169 * request is passed to ddi_prop_op.
2170 2170 */
2171 2171 if (dev == DDI_DEV_T_ANY) {
2172 2172 pass: return (ddi_prop_op(dev, dip, prop_op, mod_flags,
2173 2173 name, valuep, lengthp));
2174 2174 } else {
2175 2175 /*
2176 2176 * Ignoring return value because success is checked by
2177 2177 * verifying fjp and fdp and returned unit value is not used.
2178 2178 */
2179 2179 (void) fd_getdrive(dev, &fjp, &fdp);
2180 2180 if (!fjp || !fdp)
2181 2181 goto pass;
2182 2182
2183 2183 /* get nblocks value */
2184 2184 nblocks64 = (ulong_t)fdp->d_part[PARTITION(dev)].p_size;
2185 2185
2186 2186 return (ddi_prop_op_nblocks(dev, dip, prop_op, mod_flags,
2187 2187 name, valuep, lengthp, nblocks64));
2188 2188 }
2189 2189 }
2190 2190
2191 2191 static void
2192 2192 fd_media_watch(void *arg)
2193 2193 {
2194 2194 struct fcu_obj *fjp;
2195 2195 struct fdisk *fdp;
2196 2196
2197 2197 #ifdef DEBUG
2198 2198 int unit;
2199 2199 #define DEBUG_ASSIGN unit=
2200 2200 #else
2201 2201 #define DEBUG_ASSIGN (void)
2202 2202 #endif
2203 2203 DEBUG_ASSIGN fd_getdrive((dev_t)arg, &fjp, &fdp);
2204 2204 /*
2205 2205 * Ignoring return in non DEBUG mode because device exist.
2206 2206 * Returned unit value is not used.
2207 2207 */
2208 2208
2209 2209 FDERRPRINT(FDEP_L0, FDEM_IOCT,
2210 2210 (CE_CONT, "fd_media_watch unit %d\n", unit));
2211 2211
2212 2212 /*
2213 2213 * fd_get_media_state() cannot be called from this timeout function
2214 2214 * because the floppy drive has to be selected first, and that could
2215 2215 * force this function to sleep (while waiting for the select
2216 2216 * semaphore).
2217 2217 * Instead, just wakeup up driver.
2218 2218 */
2219 2219 mutex_enter(&fjp->fj_lock);
2220 2220 cv_broadcast(&fdp->d_statecv);
2221 2221 mutex_exit(&fjp->fj_lock);
2222 2222 }
2223 2223
2224 2224 enum dkio_state
2225 2225 fd_get_media_state(struct fcu_obj *fjp, int unit)
2226 2226 {
2227 2227 enum dkio_state state;
2228 2228
2229 2229 if (fjp->fj_ops->fco_getchng(fjp, unit)) {
2230 2230 /* recheck disk only if DSKCHG "high" */
2231 2231 fjp->fj_ops->fco_resetchng(fjp, unit);
2232 2232 if (fjp->fj_ops->fco_getchng(fjp, unit)) {
2233 2233 if (fjp->fj_flags & FUNIT_CHGDET) {
2234 2234 /*
2235 2235 * again no diskette; not a new change
2236 2236 */
2237 2237 state = DKIO_NONE;
2238 2238 } else {
2239 2239 /*
2240 2240 * a new change; diskette was ejected
2241 2241 */
2242 2242 fjp->fj_flags |= FUNIT_CHGDET;
2243 2243 state = DKIO_EJECTED;
2244 2244 }
2245 2245 } else {
2246 2246 fjp->fj_flags &= ~FUNIT_CHGDET;
2247 2247 state = DKIO_INSERTED;
2248 2248 }
2249 2249 } else {
2250 2250 fjp->fj_flags &= ~FUNIT_CHGDET;
2251 2251 state = DKIO_INSERTED;
2252 2252 }
2253 2253 FDERRPRINT(FDEP_L0, FDEM_IOCT,
2254 2254 (CE_CONT, "fd_get_media_state unit %d: state %x\n", unit, state));
2255 2255 return (state);
2256 2256 }
2257 2257
2258 2258 static int
2259 2259 fd_check_media(dev_t dev, enum dkio_state state)
2260 2260 {
2261 2261 struct fcu_obj *fjp;
2262 2262 struct fdisk *fdp;
2263 2263 int unit;
2264 2264 int err;
2265 2265
2266 2266 unit = fd_getdrive(dev, &fjp, &fdp);
2267 2267
2268 2268 mutex_enter(&fjp->fj_lock);
2269 2269
2270 2270 fjp->fj_ops->fco_select(fjp, unit, 1);
2271 2271 fdp->d_media_state = fd_get_media_state(fjp, unit);
2272 2272 fdp->d_media_timeout = drv_usectohz(fd_check_media_time);
2273 2273
2274 2274 while (fdp->d_media_state == state) {
2275 2275 /* release the controller and drive */
2276 2276 fjp->fj_ops->fco_select(fjp, unit, 0);
2277 2277
2278 2278 /* turn on timer */
2279 2279 fdp->d_media_timeout_id = timeout(fd_media_watch,
2280 2280 (void *)dev, fdp->d_media_timeout);
2281 2281
2282 2282 if (cv_wait_sig(&fdp->d_statecv, &fjp->fj_lock) == 0) {
2283 2283 fdp->d_media_timeout = 0;
2284 2284 mutex_exit(&fjp->fj_lock);
2285 2285 return (EINTR);
2286 2286 }
2287 2287 fjp->fj_ops->fco_select(fjp, unit, 1);
2288 2288 fdp->d_media_state = fd_get_media_state(fjp, unit);
2289 2289 }
2290 2290
2291 2291 if (fdp->d_media_state == DKIO_INSERTED) {
2292 2292 err = fdgetlabel(fjp, unit);
2293 2293 if (err) {
2294 2294 fjp->fj_ops->fco_select(fjp, unit, 0);
2295 2295 mutex_exit(&fjp->fj_lock);
2296 2296 return (EIO);
2297 2297 }
2298 2298 }
2299 2299 fjp->fj_ops->fco_select(fjp, unit, 0);
2300 2300 mutex_exit(&fjp->fj_lock);
2301 2301 return (0);
2302 2302 }
2303 2303
2304 2304 /*
2305 2305 * fd_get_media_info :
2306 2306 * Collects medium information for
2307 2307 * DKIOCGMEDIAINFO ioctl.
2308 2308 */
2309 2309
2310 2310 static int
2311 2311 fd_get_media_info(struct fcu_obj *fjp, caddr_t buf, int flag)
2312 2312 {
2313 2313 struct dk_minfo media_info;
2314 2314 int err = 0;
2315 2315
2316 2316 media_info.dki_media_type = DK_FLOPPY;
2317 2317 media_info.dki_lbsize = fjp->fj_chars->fdc_sec_size;
2318 2318 media_info.dki_capacity = fjp->fj_chars->fdc_ncyl *
2319 2319 fjp->fj_chars->fdc_secptrack * fjp->fj_chars->fdc_nhead;
2320 2320
2321 2321 if (ddi_copyout(&media_info, buf, sizeof (struct dk_minfo), flag))
2322 2322 err = EFAULT;
2323 2323 return (err);
2324 2324 }
↓ open down ↓ |
2148 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX