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