1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* 24 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 /* 29 * f_format.c : 30 * This file contains the format functions for floppy plug-in for 31 * library libsm.so. 32 */ 33 34 #include <stdio.h> 35 #include <sys/types.h> 36 #include <sys/dklabel.h> 37 #include <sys/dkio.h> 38 #include <sys/fdio.h> 39 #include <fcntl.h> 40 #include <unistd.h> 41 #include <locale.h> 42 #include <errno.h> 43 #include <sys/param.h> 44 #include <stdlib.h> 45 #include <sys/smedia.h> 46 #include "../../../library/inc/rmedia.h" 47 #include "f_defines.h" 48 49 /* 50 * extern functions 51 */ 52 53 extern void my_perror(char *err_string); 54 /* 55 * local functions 56 */ 57 static void restore_default_chars(int32_t fd, 58 struct fd_char save_fdchar, 59 struct dk_allmap save_allmap); 60 static int32_t 61 format_floppy(int32_t fd, void *ip) 62 { 63 struct format_track *ft = (struct format_track *)ip; 64 int32_t format_flags; 65 int32_t transfer_rate = 1000; /* transfer rate code */ 66 int32_t sec_size = 512; /* sector size */ 67 uchar_t gap = 0x54; /* format gap size */ 68 uchar_t *fbuf, *p; 69 int32_t cyl_size; 70 int32_t i; 71 int32_t chgd; /* for testing disk changed/present */ 72 int32_t cyl, hd; 73 int32_t size_of_part, size_of_dev; 74 int32_t spt = 36; /* sectors per track */ 75 int32_t drive_size; 76 uchar_t num_cyl = 80; /* max number of cylinders */ 77 struct fd_char save_fdchar; /* original diskette characteristics */ 78 struct dk_allmap save_allmap; /* original diskette partition info */ 79 int32_t D_flag = 0; /* double (aka low) density flag */ 80 int32_t E_flag = 0; /* extended density */ 81 int32_t H_flag = 0; /* high density */ 82 int32_t M_flag = 0; /* medium density */ 83 struct fd_char fdchar; 84 struct dk_geom fdgeom; 85 struct dk_allmap allmap; 86 struct dk_cinfo dkinfo; 87 int32_t start_head, end_head, start_cyl, end_cyl; 88 89 /* for verify buffers */ 90 static uchar_t *obuf; 91 92 93 /* FDRAW ioctl command structures for seeking and formatting */ 94 struct fd_raw fdr_seek = { 95 FDRAW_SEEK, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96 3, 97 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 98 0, 99 0 100 }; 101 102 struct fd_raw fdr_form = { 103 0x4D, 0, 2, 0, 0x54, (char)0xA5, 0, 0, 0, 0, 104 6, 105 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106 0, /* nbytes */ 107 0 /* addr */ 108 }; 109 110 format_flags = ft->flag; 111 112 DPRINTF1("Format flag is %d\n", format_flags); 113 if (format_flags == SM_FORMAT_HD) { 114 H_flag = 1; 115 } else if (format_flags == SM_FORMAT_DD) { 116 D_flag = 1; 117 } else if (format_flags == SM_FORMAT_ED) { 118 E_flag = 1; 119 } else if (format_flags == SM_FORMAT_MD) { 120 M_flag = 1; 121 } else { 122 DPRINTF("Invalid operation \n"); 123 errno = ENOTSUP; 124 return (-1); 125 } 126 127 128 /* 129 * restore drive to default geometry and characteristics 130 * (probably not implemented on sparc) 131 */ 132 (void) ioctl(fd, FDDEFGEOCHAR, NULL); 133 134 135 if (ioctl(fd, DKIOCINFO, &dkinfo) < 0) { 136 PERROR("DKIOCINFO failed."); 137 exit(3); 138 } 139 140 141 /* get the default partititon maps */ 142 if (ioctl(fd, DKIOCGAPART, &allmap) < 0) { 143 PERROR("DKIOCGAPART failed."); 144 return (-1); 145 } 146 147 /* Save the original default partition maps */ 148 save_allmap = allmap; 149 150 /* find out the characteristics of the default diskette */ 151 if (ioctl(fd, FDIOGCHAR, &fdchar) < 0) { 152 PERROR("FDIOGCHAR failed."); 153 return (-1); 154 } 155 156 /* Save the original characteristics of the default diskette */ 157 save_fdchar = fdchar; 158 159 /* 160 * The user may only format the entire diskette. 161 * formatting partion a or b is not allowed 162 */ 163 size_of_part = allmap.dka_map[dkinfo.dki_partition].dkl_nblk 164 * DEV_BSIZE; 165 size_of_dev = fdchar.fdc_ncyl * fdchar.fdc_nhead 166 * fdchar.fdc_secptrack * fdchar.fdc_sec_size; 167 168 if (size_of_part != size_of_dev) { 169 DPRINTF("The entire diskette must be formatted\n"); 170 DPRINTF1("size_of_part %d\n", size_of_part); 171 DPRINTF1("size_of_dev %d\n", size_of_dev); 172 errno = ENOTSUP; 173 return (-1); 174 } 175 176 /* find out the geometry of the drive */ 177 if (ioctl(fd, DKIOCGGEOM, &fdgeom) < 0) { 178 PERROR("DKIOCGGEOM failed."); 179 return (-1); 180 } 181 182 #ifdef sparc 183 fdchar.fdc_medium = 3; 184 #endif 185 if (fdchar.fdc_medium == 5) 186 drive_size = 5; 187 else 188 drive_size = 3; 189 190 /* 191 * set proper density flag in case we're formating to default 192 * characteristics because no density switch was input 193 */ 194 195 /* XXX */ 196 if ((E_flag | H_flag | D_flag | M_flag) == 0) { 197 switch (fdchar.fdc_transfer_rate) { 198 case 1000: 199 /* assumes only ED uses 1.0 MB/sec */ 200 E_flag++; 201 break; 202 case 500: 203 default: 204 /* 205 * default to HD even though High density and 206 * "medium" density both use 500 KB/sec 207 */ 208 H_flag++; 209 break; 210 #ifndef sparc 211 case 250: 212 /* assumes only DD uses 250 KB/sec */ 213 D_flag++; 214 break; 215 #endif 216 } 217 } 218 219 if (H_flag) { 220 transfer_rate = 500; 221 num_cyl = 80; 222 sec_size = 512; 223 if (drive_size == 5) { 224 spt = 15; 225 } else { 226 spt = 18; 227 } 228 gap = 0x54; 229 } else if (D_flag) { 230 transfer_rate = 250; 231 if (drive_size == 5) { 232 if (fdchar.fdc_transfer_rate == 500) { 233 /* 234 * formatting a 360KB DD diskette in 235 * a 1.2MB drive is not a good idea 236 */ 237 transfer_rate = 300; 238 fdchar.fdc_steps = 2; 239 } 240 num_cyl = 40; 241 gap = 0x50; 242 } else { 243 num_cyl = 80; 244 gap = 0x54; 245 } 246 sec_size = 512; 247 spt = 9; 248 } else if (M_flag) { 249 #ifdef sparc 250 transfer_rate = 500; 251 #else 252 /* 253 * 416.67 KB/sec is the effective transfer rate of a "medium" 254 * density diskette spun at 300 rpm instead of 360 rpm 255 */ 256 transfer_rate = 417; 257 #endif 258 num_cyl = 77; 259 sec_size = 1024; 260 spt = 8; 261 gap = 0x74; 262 } else if (E_flag) { 263 transfer_rate = 1000; 264 num_cyl = 80; 265 sec_size = 512; 266 spt = 36; 267 gap = 0x54; 268 } 269 270 /* 271 * Medium density diskettes have 1024 byte blocks. The dk_map 272 * structure in dklabel.h assumes the blocks size is DEVBSIZE (512) 273 * bytes. The dkl_nblk field is in terms of DEVBSIZE byte blocks 274 * while the spt variable is in terms of the true block size on 275 * the diskette. 276 */ 277 if (allmap.dka_map[2].dkl_nblk != 278 (2 * num_cyl * spt * (M_flag ? 2 : 1))) { 279 allmap.dka_map[1].dkl_cylno = num_cyl - 1; 280 allmap.dka_map[0].dkl_nblk = 2 * (num_cyl - 1) * spt * 281 (M_flag ? 2 : 1); 282 allmap.dka_map[1].dkl_nblk = 2 * spt * (M_flag ? 2 : 1); 283 allmap.dka_map[2].dkl_nblk = 2 * num_cyl * spt * 284 (M_flag ? 2 : 1); 285 if (allmap.dka_map[3].dkl_nblk) 286 allmap.dka_map[3].dkl_nblk = 2 * (num_cyl - 1) * spt * 287 (M_flag ? 2 : 1); 288 if (allmap.dka_map[4].dkl_nblk) 289 allmap.dka_map[4].dkl_nblk = 290 2 * spt * (M_flag ? 2 : 1); 291 } 292 293 294 295 #ifndef sparc 296 if (num_cyl > fdchar.fdc_ncyl || spt > fdchar.fdc_secptrack || 297 transfer_rate > fdchar.fdc_transfer_rate) { 298 PERROR("drive not capable of requested density"); 299 return (-1); 300 } 301 #endif 302 if (num_cyl != fdchar.fdc_ncyl || spt != fdchar.fdc_secptrack || 303 transfer_rate != fdchar.fdc_transfer_rate) { 304 /* 305 * -- CAUTION -- 306 * The SPARC fd driver is using a non-zero value in 307 * fdc_medium to indicate the 360 rpm, 77 track, 308 * 9 sectors/track, 1024 bytes/sector mode of operation 309 * (similar to an 8", DS/DD, 1.2 MB floppy). 310 * 311 * The x86 fd driver uses fdc_medium as the diameter 312 * indicator, either 3 or 5. It should not be modified. 313 */ 314 #ifdef sparc 315 fdchar.fdc_medium = M_flag ? 1 : 0; 316 #endif 317 fdchar.fdc_transfer_rate = transfer_rate; 318 fdchar.fdc_ncyl = num_cyl; 319 fdchar.fdc_sec_size = sec_size; 320 fdchar.fdc_secptrack = spt; 321 322 if (ioctl(fd, FDIOSCHAR, &fdchar) < 0) { 323 PERROR("FDIOSCHAR (density selection) failed"); 324 /* restore the default characteristics */ 325 restore_default_chars(fd, save_fdchar, save_allmap); 326 return (-1); 327 } 328 if (ioctl(fd, DKIOCSAPART, &allmap) < 0) { 329 PERROR("DKIOCSAPART failed"); 330 331 /* restore the default characteristics */ 332 restore_default_chars(fd, save_fdchar, save_allmap); 333 return (-1); 334 } 335 } 336 337 cyl_size = 2 * sec_size * spt; 338 339 if ((obuf = (uchar_t *)malloc((size_t)cyl_size)) == 0) { 340 PERROR("car't malloc verify buffer"); 341 /* restore the default characteristics */ 342 restore_default_chars(fd, save_fdchar, save_allmap); 343 return (-1); 344 } 345 /* 346 * for those systems that support this ioctl, they will 347 * return whether or not a diskette is in the drive. 348 */ 349 if (ioctl(fd, FDGETCHANGE, &chgd) == 0) { 350 if (chgd & FDGC_CURRENT) { 351 (void) fprintf(stderr, 352 gettext("no diskette in drive \n")); 353 354 /* restore the default characteristics */ 355 restore_default_chars(fd, save_fdchar, save_allmap); 356 return (-1); 357 } 358 if (chgd & FDGC_CURWPROT) { 359 (void) fprintf(stderr, 360 gettext("Media is write protected\n")); 361 362 /* restore the default characteristics */ 363 restore_default_chars(fd, save_fdchar, save_allmap); 364 return (-1); 365 } 366 } 367 368 if ((fbuf = (uchar_t *)malloc((unsigned)(4 * spt))) == 0) { 369 PERROR("Could not malloc format header buffer"); 370 restore_default_chars(fd, save_fdchar, save_allmap); 371 return (-1); 372 } 373 /* 374 * do the format, a track at a time 375 */ 376 if (ft->track_no == -1) { 377 start_cyl = 0; 378 end_cyl = num_cyl; 379 start_head = 0; 380 end_head = fdchar.fdc_nhead; 381 } else { 382 start_cyl = ft->track_no; 383 end_cyl = ft->track_no + 1; 384 start_head = ft->head; 385 end_head = ft->head + 1; 386 if ((end_cyl > num_cyl) || (end_head > fdchar.fdc_nhead)) { 387 errno = EINVAL; 388 return (-1); 389 } 390 } 391 392 for (cyl = start_cyl; cyl < (int32_t)end_cyl; cyl++) { 393 /* 394 * This is not the optimal ioctl to format the floppy. 395 * The device driver should do do the work, 396 * instead of this program mucking with a lot 397 * of low-level, device-dependent code. 398 */ 399 fdr_seek.fdr_cmd[2] = cyl; 400 if (ioctl(fd, FDRAW, &fdr_seek) < 0) { 401 (void) fprintf(stderr, 402 gettext(" seek to cyl %d failed\n"), 403 cyl); 404 405 /* restore the default characteristics */ 406 restore_default_chars(fd, save_fdchar, save_allmap); 407 return (-1); 408 } 409 /* 410 * Assume that the fd driver has issued a SENSE_INT 411 * command to complete the seek operation. 412 */ 413 414 for (hd = start_head; hd < end_head; hd++) { 415 p = (uchar_t *)fbuf; 416 for (i = 1; i <= spt; i++) { 417 *p++ = (uchar_t)cyl; 418 *p++ = (uchar_t)hd; 419 *p++ = (uchar_t)i; /* sector # */ 420 *p++ = (sec_size == 1024) ? 3 : 2; 421 } 422 /* 423 * ASSUME the fd driver is going to set drive-select 424 * bits in the second command byte 425 */ 426 fdr_form.fdr_cmd[1] = hd << 2; 427 fdr_form.fdr_cmd[2] = (sec_size == 1024) ? 3 : 2; 428 fdr_form.fdr_cmd[3] = spt; 429 fdr_form.fdr_cmd[4] = gap; 430 fdr_form.fdr_nbytes = 4 * spt; 431 fdr_form.fdr_addr = (char *)fbuf; 432 433 if (ioctl(fd, FDRAW, &fdr_form) < 0) { 434 435 436 (void) fprintf(stderr, 437 gettext( 438 "format of cyl %d head %d failed\n"), 439 cyl, hd); 440 441 /* restore the default characteristics */ 442 restore_default_chars(fd, save_fdchar, 443 save_allmap); 444 return (-1); 445 } 446 if (fdr_form.fdr_result[0] & 0xC0) { 447 if (fdr_form.fdr_result[1] & 0x02) { 448 (void) fprintf(stderr, gettext( 449 /*CSTYLED*/ 450 "diskette is write protected\n")); 451 452 /* 453 * restore the default 454 * characteristics 455 */ 456 restore_default_chars(fd, save_fdchar, 457 save_allmap); 458 return (-1); 459 } 460 (void) fprintf(stderr, 461 gettext( 462 "format of cyl %d head %d failed\n"), 463 cyl, hd); 464 465 /* restore the default characteristics */ 466 restore_default_chars(fd, save_fdchar, 467 save_allmap); 468 return (-1); 469 } 470 471 } 472 473 /* 474 * do a quick verify 475 */ 476 if (llseek(fd, cyl * cyl_size, 0) != cyl * cyl_size) { 477 PERROR(" bad seek to format verify, "); 478 /* restore the default characteristics */ 479 restore_default_chars(fd, save_fdchar, 480 save_allmap); 481 return (-1); 482 } 483 if (fdchar.fdc_nhead == end_head) { 484 if (read(fd, obuf, cyl_size) != cyl_size) { 485 PERROR("Could not read format data"); 486 /* restore the default characteristics */ 487 restore_default_chars(fd, save_fdchar, 488 save_allmap); 489 return (-1); 490 } 491 } 492 } 493 if (llseek(fd, (off_t)0, 0) != 0) { 494 PERROR("seek to blk 0 failed"); 495 /* restore the default characteristics */ 496 restore_default_chars(fd, save_fdchar, save_allmap); 497 return (-1); 498 } 499 return (0); 500 } 501 502 503 /* 504 * Restore the default characteristics of the floppy diskette. 505 * Fdformat changes the characteristics in the process of formatting. 506 * If fdformat fails while in the process of doing the format, fdformat 507 * should clean up after itself and reset the driver back to the original 508 * state. 509 */ 510 511 static void 512 restore_default_chars(int32_t fd, 513 struct fd_char save_fdchar, 514 struct dk_allmap save_allmap) 515 { 516 517 518 /* 519 * When this function is called, fdformat is failing anyways, 520 * so the errors are not processed. 521 */ 522 523 (void) ioctl(fd, FDIOSCHAR, &save_fdchar); 524 525 (void) ioctl(fd, DKIOCSAPART, &save_allmap); 526 527 /* 528 * Before looking at the diskette's characteristics, format_floppy() 529 * sets the x86 floppy driver to the default characteristics. 530 * restore drive to default geometry and 531 * characteristics. This ioctl isn't implemented on 532 * sparc. 533 */ 534 (void) ioctl(fd, FDDEFGEOCHAR, NULL); 535 536 } 537 538 int32_t 539 _m_media_format(rmedia_handle_t *handle, void *ip) { 540 struct format_track ft; 541 542 /* Check for valid handle */ 543 if (handle == NULL) { 544 DPRINTF("Null Handle\n"); 545 errno = EINVAL; 546 return (-1); 547 } 548 if (handle->sm_signature != (int32_t)LIBSMEDIA_SIGNATURE) { 549 DPRINTF("Invalid signature in handle.\n"); 550 DPRINTF2( 551 "Signature expected=0x%x, found=0x%x\n", 552 LIBSMEDIA_SIGNATURE, handle->sm_signature); 553 errno = EINVAL; 554 return (-1); 555 } 556 if (handle->sm_fd < 0) { 557 DPRINTF("Invalid file handle.\n"); 558 errno = EINVAL; 559 return (-1); 560 } 561 DPRINTF("Format floppy called \n"); 562 ft.track_no = (-1); 563 ft.head = (-1); 564 ft.flag = ((struct format_flags *)ip)->flavor; 565 return (format_floppy(handle->sm_fd, &ft)); 566 567 } 568 569 int32_t 570 _m_media_format_track(rmedia_handle_t *handle, void *ip) 571 { 572 573 /* Check for valid handle */ 574 if (handle == NULL) { 575 DPRINTF("Null Handle\n"); 576 errno = EINVAL; 577 return (-1); 578 } 579 if (handle->sm_signature != (int32_t)LIBSMEDIA_SIGNATURE) { 580 DPRINTF("Invalid signature in handle.\n"); 581 DPRINTF2( 582 "Signature expected=0x%x, found=0x%x\n", 583 LIBSMEDIA_SIGNATURE, handle->sm_signature); 584 errno = EINVAL; 585 return (-1); 586 } 587 if (handle->sm_fd < 0) { 588 DPRINTF("Invalid file handle.\n"); 589 errno = EINVAL; 590 return (-1); 591 } 592 #ifdef DEBUG 593 if (ip != NULL) { 594 struct format_track *ft = (struct format_track *)ip; 595 DPRINTF2("Format track %d head %d\n", ft->track_no, ft->head); 596 } 597 #endif /* DEBUG */ 598 return (format_floppy(handle->sm_fd, ip)); 599 } 600