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