import less(1)
[unleashed/tickless.git] / usr / src / lib / libsmedia / plugins / floppy / common / f_format.c
blobe6027b2cc4b7f8ad177c59087aff08d4af55adba
1 /*
2 * CDDL HEADER START
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.
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.
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]
20 * CDDL HEADER END
24 * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
28 #pragma ident "%Z%%M% %I% %E% SMI"
31 * f_format.c :
32 * This file contains the format functions for floppy plug-in for
33 * library libsm.so.
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"
52 * extern functions
55 extern void my_perror(char *err_string);
57 * local functions
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)
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;
91 /* for verify buffers */
92 static uchar_t *obuf;
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,
99 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
104 struct fd_raw fdr_form = {
105 0x4D, 0, 2, 0, 0x54, (char)0xA5, 0, 0, 0, 0,
107 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
108 0, /* nbytes */
109 0 /* addr */
112 format_flags = ft->flag;
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);
131 * restore drive to default geometry and characteristics
132 * (probably not implemented on sparc)
134 (void) ioctl(fd, FDDEFGEOCHAR, NULL);
137 if (ioctl(fd, DKIOCINFO, &dkinfo) < 0) {
138 PERROR("DKIOCINFO failed.");
139 exit(3);
143 /* get the default partititon maps */
144 if (ioctl(fd, DKIOCGAPART, &allmap) < 0) {
145 PERROR("DKIOCGAPART failed.");
146 return (-1);
149 /* Save the original default partition maps */
150 save_allmap = allmap;
152 /* find out the characteristics of the default diskette */
153 if (ioctl(fd, FDIOGCHAR, &fdchar) < 0) {
154 PERROR("FDIOGCHAR failed.");
155 return (-1);
158 /* Save the original characteristics of the default diskette */
159 save_fdchar = fdchar;
162 * The user may only format the entire diskette.
163 * formatting partion a or b is not allowed
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;
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);
178 /* find out the geometry of the drive */
179 if (ioctl(fd, DKIOCGGEOM, &fdgeom) < 0) {
180 PERROR("DKIOCGGEOM failed.");
181 return (-1);
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;
193 * set proper density flag in case we're formating to default
194 * characteristics because no density switch was input
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:
207 * default to HD even though High density and
208 * "medium" density both use 500 KB/sec
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
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;
230 gap = 0x54;
231 } else if (D_flag) {
232 transfer_rate = 250;
233 if (drive_size == 5) {
234 if (fdchar.fdc_transfer_rate == 500) {
236 * formatting a 360KB DD diskette in
237 * a 1.2MB drive is not a good idea
239 transfer_rate = 300;
240 fdchar.fdc_steps = 2;
242 num_cyl = 40;
243 gap = 0x50;
244 } else {
245 num_cyl = 80;
246 gap = 0x54;
248 sec_size = 512;
249 spt = 9;
250 } else if (M_flag) {
251 #ifdef sparc
252 transfer_rate = 500;
253 #else
255 * 416.67 KB/sec is the effective transfer rate of a "medium"
256 * density diskette spun at 300 rpm instead of 360 rpm
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;
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.
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);
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);
303 #endif
304 if (num_cyl != fdchar.fdc_ncyl || spt != fdchar.fdc_secptrack ||
305 transfer_rate != fdchar.fdc_transfer_rate) {
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).
313 * The x86 fd driver uses fdc_medium as the diameter
314 * indicator, either 3 or 5. It should not be modified.
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;
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);
330 if (ioctl(fd, DKIOCSAPART, &allmap) < 0) {
331 PERROR("DKIOCSAPART failed");
333 /* restore the default characteristics */
334 restore_default_chars(fd, save_fdchar, save_allmap);
335 return (-1);
339 cyl_size = 2 * sec_size * spt;
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);
348 * for those systems that support this ioctl, they will
349 * return whether or not a diskette is in the drive.
351 if (ioctl(fd, FDGETCHANGE, &chgd) == 0) {
352 if (chgd & FDGC_CURRENT) {
353 (void) fprintf(stderr,
354 gettext("no diskette in drive \n"));
356 /* restore the default characteristics */
357 restore_default_chars(fd, save_fdchar, save_allmap);
358 return (-1);
360 if (chgd & FDGC_CURWPROT) {
361 (void) fprintf(stderr,
362 gettext("Media is write protected\n"));
364 /* restore the default characteristics */
365 restore_default_chars(fd, save_fdchar, save_allmap);
366 return (-1);
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);
376 * do the format, a track at a time
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);
394 for (cyl = start_cyl; cyl < (int32_t)end_cyl; cyl++) {
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.
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);
407 /* restore the default characteristics */
408 restore_default_chars(fd, save_fdchar, save_allmap);
409 return (-1);
412 * Assume that the fd driver has issued a SENSE_INT
413 * command to complete the seek operation.
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;
425 * ASSUME the fd driver is going to set drive-select
426 * bits in the second command byte
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;
435 if (ioctl(fd, FDRAW, &fdr_form) < 0) {
438 (void) fprintf(stderr,
439 gettext(
440 "format of cyl %d head %d failed\n"),
441 cyl, hd);
443 /* restore the default characteristics */
444 restore_default_chars(fd, save_fdchar,
445 save_allmap);
446 return (-1);
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"));
455 * restore the default
456 * characteristics
458 restore_default_chars(fd, save_fdchar,
459 save_allmap);
460 return (-1);
462 (void) fprintf(stderr,
463 gettext(
464 "format of cyl %d head %d failed\n"),
465 cyl, hd);
467 /* restore the default characteristics */
468 restore_default_chars(fd, save_fdchar,
469 save_allmap);
470 return (-1);
476 * do a quick verify
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);
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);
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);
501 return (0);
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.
513 static void
514 restore_default_chars(int32_t fd,
515 struct fd_char save_fdchar,
516 struct dk_allmap save_allmap)
521 * When this function is called, fdformat is failing anyways,
522 * so the errors are not processed.
525 (void) ioctl(fd, FDIOSCHAR, &save_fdchar);
527 (void) ioctl(fd, DKIOCSAPART, &save_allmap);
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.
536 (void) ioctl(fd, FDDEFGEOCHAR, NULL);
540 int32_t
541 _m_media_format(rmedia_handle_t *handle, void *ip) {
542 struct format_track ft;
544 /* Check for valid handle */
545 if (handle == NULL) {
546 DPRINTF("Null Handle\n");
547 errno = EINVAL;
548 return (-1);
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);
558 if (handle->sm_fd < 0) {
559 DPRINTF("Invalid file handle.\n");
560 errno = EINVAL;
561 return (-1);
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));
571 int32_t
572 _m_media_format_track(rmedia_handle_t *handle, void *ip)
575 /* Check for valid handle */
576 if (handle == NULL) {
577 DPRINTF("Null Handle\n");
578 errno = EINVAL;
579 return (-1);
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);
589 if (handle->sm_fd < 0) {
590 DPRINTF("Invalid file handle.\n");
591 errno = EINVAL;
592 return (-1);
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);
599 #endif /* DEBUG */
600 return (format_floppy(handle->sm_fd, ip));