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
format_floppy(int32_t fd,void * ip)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
restore_default_chars(int32_t fd,struct fd_char save_fdchar,struct dk_allmap save_allmap)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
_m_media_format(rmedia_handle_t * handle,void * ip)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
_m_media_format_track(rmedia_handle_t * handle,void * ip)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