1 /* $NetBSD: mmcformat.c,v 1.9 2023/04/04 20:28:01 rillig Exp $ */
2
3 /*
4 * Copyright (c) 2006, 2008 Reinoud Zandijk
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 */
28
29 #include <sys/cdefs.h>
30 __RCSID("$NetBSD: mmcformat.c,v 1.9 2023/04/04 20:28:01 rillig Exp $");
31
32 #include <sys/types.h>
33 #include <sys/time.h>
34 #include <assert.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <inttypes.h>
38 #include <limits.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <strings.h>
43 #include <unistd.h>
44
45 #include "uscsilib.h"
46
47
48 /* globals */
49 static struct uscsi_dev dev;
50 extern int scsilib_verbose;
51
52 /* #define DEBUG(a) {a;} */
53 #define DEBUG(a) ;
54
55
56 static uint64_t
getmtime(void)57 getmtime(void)
58 {
59 struct timeval tp;
60
61 gettimeofday(&tp, NULL);
62 return (uint64_t) 1000000 * tp.tv_sec + tp.tv_usec;
63 }
64
65
66 static void
print_eta(uint32_t progress,uint64_t now,uint64_t start_time)67 print_eta(uint32_t progress, uint64_t now, uint64_t start_time)
68 {
69 int hours, minutes, seconds;
70 uint64_t tbusy, ttot_est, eta;
71
72 if (progress == 0) {
73 printf(" ETA --:--:--");
74 return;
75 }
76 tbusy = now - start_time;
77 ttot_est = (tbusy * 0x10000) / progress;
78 eta = (ttot_est - tbusy) / 1000000;
79
80 hours = (int) (eta/3600);
81 minutes = (int) (eta/60) % 60;
82 seconds = (int) eta % 60;
83 printf(" ETA %02d:%02d:%02d", hours, minutes, seconds);
84 }
85
86
87 static void
uscsi_waitop(struct uscsi_dev * mydev)88 uscsi_waitop(struct uscsi_dev *mydev)
89 {
90 scsicmd cmd;
91 struct uscsi_sense sense;
92 uint64_t start_time;
93 uint32_t progress;
94 uint8_t buffer[256];
95 int asc, ascq;
96 int cnt = 0;
97
98 bzero(cmd, SCSI_CMD_LEN);
99 bzero(buffer, sizeof(buffer));
100
101 /*
102 * not be to impatient... give the drive some time to start or it
103 * might break off
104 */
105
106 start_time = getmtime();
107 sleep(10);
108
109 progress = 0;
110 while (progress < 0x10000) {
111 /* we need a command that is NOT going to stop the formatting */
112 bzero(cmd, SCSI_CMD_LEN);
113 cmd[0] = 0; /* test unit ready */
114 uscsi_command(SCSI_READCMD, mydev,
115 cmd, 6, buffer, 0, 10000, &sense);
116
117 /*
118 * asc may be `not-ready' or `no-sense'. ascq for format in
119 * progress is 4 too
120 */
121 asc = sense.asc;
122 ascq = sense.ascq;
123 if (((asc == 0) && (ascq == 4)) || (asc == 4)) {
124 /* drive not ready : operation/format in progress */
125 if (sense.skey_valid) {
126 progress = sense.sense_key;
127 } else {
128 /* finished */
129 progress = 0x10000;
130 }
131 }
132 /* check if drive is ready again, ifso break out loop */
133 if ((asc == 0) && (ascq == 0)) {
134 progress = 0x10000;
135 }
136
137 printf("%3d %% ", (100 * progress / 0x10000));
138 printf("%c", "|/-\\" [cnt++ %4]); /* twirl */
139
140 /* print ETA */
141 print_eta(progress, getmtime(), start_time);
142
143 fflush(stdout);
144 sleep(1);
145 printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
146 fflush(stdout);
147 }
148 printf("\n");
149
150 return;
151 }
152
153
154 static char const *
print_mmc_profile(int profile)155 print_mmc_profile(int profile)
156 {
157 static char scrap[100];
158
159 switch (profile) {
160 case 0x00 : return "Unknown[0] profile";
161 case 0x01 : return "Non removable disc";
162 case 0x02 : return "Removable disc";
163 case 0x03 : return "Magneto Optical with sector erase";
164 case 0x04 : return "Magneto Optical write once";
165 case 0x05 : return "Advance Storage Magneto Optical";
166 case 0x08 : return "CD-ROM";
167 case 0x09 : return "CD-R recordable";
168 case 0x0a : return "CD-RW rewritable";
169 case 0x10 : return "DVD-ROM";
170 case 0x11 : return "DVD-R sequential";
171 case 0x12 : return "DVD-RAM rewritable";
172 case 0x13 : return "DVD-RW restricted overwrite";
173 case 0x14 : return "DVD-RW sequential";
174 case 0x1a : return "DVD+RW rewritable";
175 case 0x1b : return "DVD+R recordable";
176 case 0x20 : return "DDCD readonly";
177 case 0x21 : return "DDCD-R recordable";
178 case 0x22 : return "DDCD-RW rewritable";
179 case 0x2b : return "DVD+R double layer";
180 case 0x40 : return "BD-ROM";
181 case 0x41 : return "BD-R Sequential Recording (SRM)";
182 case 0x42 : return "BD-R Random Recording (RRM)";
183 case 0x43 : return "BD-RE rewritable";
184 }
185 sprintf(scrap, "Reserved profile 0x%02x", profile);
186 return scrap;
187 }
188
189
190 static int
uscsi_get_mmc_profile(struct uscsi_dev * mydev,int * mmc_profile)191 uscsi_get_mmc_profile(struct uscsi_dev *mydev, int *mmc_profile)
192 {
193 scsicmd cmd;
194 uint8_t buf[32];
195 int error;
196
197 *mmc_profile = 0;
198
199 bzero(cmd, SCSI_CMD_LEN);
200 cmd[ 0] = 0x46; /* Get configuration */
201 cmd[ 8] = 32; /* just a small buffer size */
202 cmd[ 9] = 0; /* control */
203 error = uscsi_command(SCSI_READCMD, mydev, cmd, 10, buf, 32, 30000, NULL);
204 if (!error) {
205 *mmc_profile = buf[7] | (buf[6] << 8);
206 }
207
208 return error;
209 }
210
211
212 static int
uscsi_set_packet_parameters(struct uscsi_dev * mydev,int blockingnr)213 uscsi_set_packet_parameters(struct uscsi_dev *mydev, int blockingnr)
214 {
215 scsicmd cmd;
216 int val_len;
217 uint8_t res[10000], *pos;
218 int error;
219
220 /* Set up CD/DVD recording parameters */
221 DEBUG(printf("Setting device's recording parameters\n"));
222
223 val_len = 0x32+2+8;
224 bzero(res, val_len);
225
226 pos = res + 8;
227
228 bzero(cmd, SCSI_CMD_LEN);
229 pos[ 0] = 0x05; /* page code 5 : cd writing */
230 pos[ 1] = 0x32; /* length in bytes */
231 pos[ 2] = 0; /* write type 0 : packet/incremental */
232
233 /* next session OK, data packet, rec. incr. fixed packets */
234 pos[ 3] = (3<<6) | 32 | 5;
235 pos[ 4] = 10; /* ISO mode 2; XA form 1 */
236 pos[ 8] = 0x20; /* CD-ROM XA disc or DDCD disc */
237 pos[10] = (blockingnr >> 24) & 0xff; /* MSB packet size */
238 pos[11] = (blockingnr >> 16) & 0xff;
239 pos[12] = (blockingnr >> 8) & 0xff;
240 pos[13] = (blockingnr ) & 0xff; /* LSB packet size */
241
242 bzero(cmd, SCSI_CMD_LEN);
243 cmd[0] = 0x55; /* MODE SELECT (10) */
244 cmd[1] = 16; /* PF format */
245 cmd[7] = val_len >> 8; /* length of blob */
246 cmd[8] = val_len & 0xff;
247 cmd[9] = 0; /* control */
248
249 error = uscsi_command(SCSI_WRITECMD, mydev,
250 cmd, 10, res, val_len, 30000, NULL);
251 if (error) {
252 perror("While WRTITING parameter page 5");
253 return error;
254 }
255
256 /* flag OK */
257 return 0;
258 }
259
260
261 static int
get_format_capabilities(struct uscsi_dev * mydev,uint8_t * buf,uint32_t * len)262 get_format_capabilities(struct uscsi_dev *mydev, uint8_t *buf, uint32_t *len)
263 {
264 scsicmd cmd;
265 int list_length;
266 int trans_len;
267 size_t buf_len = 512;
268 int error;
269
270 assert(*len >= buf_len);
271 bzero(buf, buf_len);
272
273 trans_len = 12; /* only fixed header first */
274 bzero(cmd, SCSI_CMD_LEN);
275 cmd[0] = 0x23; /* Read format capabilities */
276 cmd[7] = trans_len >> 8; /* MSB allocation length */
277 cmd[8] = trans_len & 0xff; /* LSB allocation length */
278 cmd[9] = 0; /* control */
279 error = uscsi_command(SCSI_READCMD, mydev,
280 cmd, 10, buf, trans_len, 30000, NULL);
281 if (error) {
282 fprintf(stderr, "While reading format capabilities : %s\n",
283 strerror(error));
284 return error;
285 }
286
287 list_length = buf[ 3];
288
289 if (list_length % 8) {
290 printf( "\t\tWarning: violating SCSI spec,"
291 "capacity list length ought to be multiple of 8\n");
292 printf("\t\tInterpreting as including header of 4 bytes\n");
293 assert(list_length % 8 == 4);
294 list_length -= 4;
295 }
296
297 /* read in full capacity list */
298 trans_len = 12 + list_length; /* complete structure */
299 bzero(cmd, SCSI_CMD_LEN);
300 cmd[0] = 0x23; /* Read format capabilities */
301 cmd[7] = trans_len >> 8; /* MSB allocation length */
302 cmd[8] = trans_len & 0xff; /* LSB allocation length */
303 cmd[9] = 0; /* control */
304 error = uscsi_command(SCSI_READCMD, mydev,
305 cmd, 10, buf, trans_len, 30000, NULL);
306 if (error) {
307 fprintf(stderr, "While reading format capabilities : %s\n",
308 strerror(error));
309 return error;
310 }
311
312 *len = list_length;
313 return 0;
314 }
315
316
317 static void
print_format(int format_tp,uint32_t num_blks,uint32_t param,int dscr_type,int verbose,int * supported)318 print_format(int format_tp, uint32_t num_blks, uint32_t param,
319 int dscr_type, int verbose, int *supported)
320 {
321 char const *format_str, *nblks_str, *param_str, *user_spec;
322
323 format_str = nblks_str = param_str = "reserved";
324 user_spec = "";
325 *supported = 1;
326
327 switch (format_tp) {
328 case 0x00 :
329 format_str = "full format capacity";
330 nblks_str = "sectors";
331 param_str = "block length in bytes";
332 user_spec = "'-F [-b blockingnr]'";
333 break;
334 case 0x01 :
335 format_str = "spare area expansion";
336 nblks_str = "extension in blocks";
337 param_str = "block length in bytes";
338 user_spec = "'-S'";
339 break;
340 /* 0x02 - 0x03 reserved */
341 case 0x04 :
342 format_str = "variable length zone'd format";
343 nblks_str = "zone length";
344 param_str = "zone number";
345 *supported = 0;
346 break;
347 case 0x05 :
348 format_str = "fixed length zone'd format";
349 nblks_str = "zone length";
350 param_str = "last zone number";
351 *supported = 0;
352 break;
353 /* 0x06 - 0x0f reserved */
354 case 0x10 :
355 format_str = "CD-RW/DVD-RW full packet format";
356 nblks_str = "addressable blocks";
357 param_str = "fixed packet size/ECC blocksize in sectors";
358 user_spec = "'-F -p [-b blockingnr]'";
359 break;
360 case 0x11 :
361 format_str = "CD-RW/DVD-RW grow session";
362 nblks_str = "addressable blocks";
363 param_str = "fixed packet size/ECC blocksize in sectors";
364 user_spec = "'-G'";
365 break;
366 case 0x12 :
367 format_str = "CD-RW/DVD-RW add session";
368 nblks_str = "addressable blocks";
369 param_str = "maximum fixed packet size/ECC blocksize "
370 "in sectors";
371 *supported = 0;
372 break;
373 case 0x13 :
374 format_str = "DVD-RW max growth of last complete session";
375 nblks_str = "addressable blocks";
376 param_str = "ECC blocksize in sectors";
377 user_spec = "'-G'";
378 break;
379 case 0x14 :
380 format_str = "DVD-RW quick grow last session";
381 nblks_str = "addressable blocks";
382 param_str = "ECC blocksize in sectors";
383 *supported = 0;
384 break;
385 case 0x15 :
386 format_str = "DVD-RW quick full format";
387 nblks_str = "addressable blocks";
388 param_str = "ECC blocksize in sectors";
389 *supported = 0;
390 break;
391 /* 0x16 - 0x23 reserved */
392 case 0x24 :
393 format_str = "background MRW format";
394 nblks_str = "Defect Management Area blocks";
395 param_str = "not used";
396 user_spec = "'[-R] [-s] [-w] -F -M [-b blockingnr]'";
397 break;
398 /* 0x25 reserved */
399 case 0x26 :
400 format_str = "background DVD+RW full format";
401 nblks_str = "sectors";
402 param_str = "not used";
403 user_spec = "'[-R] [-w] -F'";
404 break;
405 /* 0x27 - 0x2f reserved */
406 case 0x30 :
407 format_str = "BD-RE full format with spare area";
408 nblks_str = "blocks";
409 param_str = "total spare area size in clusters";
410 user_spec = "'[-s] -F'";
411 break;
412 case 0x31 :
413 format_str = "BD-RE full format without spare area";
414 nblks_str = "blocks";
415 param_str = "block length in bytes";
416 user_spec = "'-F'";
417 break;
418 /* 0x32 - 0x3f reserved */
419 default :
420 break;
421 }
422
423 if (verbose) {
424 printf("\n\tFormat type 0x%02x : %s\n", format_tp, format_str);
425
426 switch (dscr_type) {
427 case 1 :
428 printf( "\t\tUnformatted media,"
429 "maximum formatted capacity\n");
430 break;
431 case 2 :
432 printf( "\t\tFormatted media,"
433 "current formatted capacity\n");
434 break;
435 case 3 :
436 printf( "\t\tNo media present or incomplete session, "
437 "maximum formatted capacity\n");
438 break;
439 default :
440 printf("\t\tUnspecified descriptor type\n");
441 break;
442 }
443
444 printf("\t\tNumber of blocks : %12d\t(%s)\n",
445 num_blks, nblks_str);
446 printf("\t\tParameter : %12d\t(%s)\n",
447 param, param_str);
448
449 if (format_tp == 0x24) {
450 printf( "\t\tExpert select : "
451 "'-X 0x%02x:0xffffff:0' or "
452 "'-X 0x%02x:0xffff0000:0'\n",
453 format_tp, format_tp);
454 } else {
455 printf( "\t\tExpert select : "
456 "'-X 0x%02x:%d:%d'\n",
457 format_tp, num_blks, param);
458 }
459 if (*supported) {
460 printf("\t\tmmc_format arg : %s\n", user_spec);
461 } else {
462 printf("\t\t** not supported **\n");
463 }
464 }
465 }
466
467
468 static void
process_format_caps(uint8_t * buf,int list_length,int verbose,uint8_t * allow,uint32_t * blks,uint32_t * params)469 process_format_caps(uint8_t *buf, int list_length, int verbose,
470 uint8_t *allow, uint32_t *blks, uint32_t *params)
471 {
472 uint32_t num_blks, param;
473 uint8_t *fcd;
474 int dscr_type, format_tp;
475 int supported;
476
477 bzero(allow, 255);
478 bzero(blks, 255*4);
479 bzero(params, 255*4);
480
481 fcd = buf + 4;
482 list_length -= 4; /* strip header */
483
484 if (verbose)
485 printf("\tCurrent/max capacity followed by additional capacity,"
486 "reported length of %d bytes (8/entry)\n", list_length);
487
488 while (list_length > 0) {
489 num_blks = fcd[ 3] | (fcd[ 2] << 8) |
490 (fcd[ 1] << 16) | (fcd[ 0] << 24);
491 dscr_type = fcd[ 4] & 3;
492 format_tp = fcd[ 4] >> 2;
493 param = fcd[ 7] | (fcd[ 6] << 8) | (fcd[ 5] << 16);
494
495 print_format(format_tp, num_blks, param, dscr_type, verbose,
496 &supported);
497
498 allow[format_tp] = 1; /* TODO = supported? */
499 blks[format_tp] = num_blks;
500 params[format_tp] = param;
501
502 fcd += 8;
503 list_length-=8;
504 }
505 }
506
507
508
509 /* format a CD-RW disc */
510 /* old style format 7 */
511 static int
uscsi_format_cdrw_mode7(struct uscsi_dev * mydev,uint32_t blocks)512 uscsi_format_cdrw_mode7(struct uscsi_dev *mydev, uint32_t blocks)
513 {
514 scsicmd cmd;
515 struct uscsi_sense sense;
516 uint8_t buffer[16];
517 int error;
518
519 if (blocks % 32) {
520 blocks -= blocks % 32;
521 }
522
523 bzero(cmd, SCSI_CMD_LEN);
524 bzero(buffer, sizeof(buffer));
525
526 cmd[0] = 0x04; /* format unit */
527 cmd[1] = 0x17; /* parameter list format 7 follows */
528 cmd[5] = 0; /* control */
529
530 /* format list header */
531 buffer[ 0] = 0; /* reserved */
532 buffer[ 1] = 0x80 | 0x02; /* Valid info, immediate return */
533 buffer[ 2] = 0; /* MSB format descriptor length */
534 buffer[ 3] = 8; /* LSB ... */
535
536 /*
537 * for CD-RW the initialisation pattern bit is reserved, but there IS
538 * one
539 */
540
541 buffer[ 4] = 0; /* no header */
542 buffer[ 5] = 0; /* default pattern */
543 buffer[ 6] = 0; /* pattern length MSB */
544 buffer[ 7] = 0; /* pattern length LSB */
545
546 /* 8 bytes of format descriptor */
547 /* (s)ession bit 1<<7, (g)row bit 1<<6 */
548 /* SG action */
549 /* 00 format disc with number of user data blocks */
550 /* 10 create new session with number of data blocks */
551 /* x1 grow session to be number of data blocks */
552
553 buffer[ 8] = 0x00; /* session and grow bits (7 and 6) */
554 buffer[ 9] = 0; /* reserved */
555 buffer[10] = 0; /* reserved */
556 buffer[11] = 0; /* reserved */
557 buffer[12] = (blocks >> 24) & 0xff; /* blocks MSB */
558 buffer[13] = (blocks >> 16) & 0xff;
559 buffer[14] = (blocks >> 8) & 0xff;
560 buffer[15] = (blocks ) & 0xff; /* blocks LSB */
561
562 /* this will take a while .... */
563 error = uscsi_command(SCSI_WRITECMD, mydev,
564 cmd, 6, buffer, sizeof(buffer), UINT_MAX, &sense);
565 if (error)
566 return error;
567
568 uscsi_waitop(mydev);
569 return 0;
570 }
571
572
573 static int
uscsi_format_disc(struct uscsi_dev * mydev,int immed,int format_type,uint32_t blocks,uint32_t param,int certification,int cmplist)574 uscsi_format_disc(struct uscsi_dev *mydev, int immed, int format_type,
575 uint32_t blocks, uint32_t param, int certification, int cmplist)
576 {
577 scsicmd cmd;
578 struct uscsi_sense sense;
579 uint8_t buffer[16], fmt_flags;
580 int error;
581
582 fmt_flags = 0x80; /* valid info flag */
583 if (immed)
584 fmt_flags |= 2;
585 if (certification == 0)
586 fmt_flags |= 32;
587
588 if (cmplist)
589 cmplist = 8;
590
591 #if 0
592 if (mmc_profile != 0x43) {
593 /* certification specifier only valid for BD-RE */
594 certification = 0;
595 }
596 #endif
597
598 bzero(cmd, SCSI_CMD_LEN);
599 bzero(buffer, sizeof(buffer));
600
601 cmd[0] = 0x04; /* format unit */
602 cmd[1] = 0x11 | cmplist; /* parameter list format 1 follows */
603 cmd[5] = 0; /* control */
604
605 /* format list header */
606 buffer[ 0] = 0; /* reserved */
607 buffer[ 1] = 0x80 | fmt_flags; /* Valid info, flags follow */
608 buffer[ 2] = 0; /* MSB format descriptor length */
609 buffer[ 3] = 8; /* LSB ... */
610
611 /* 8 bytes of format descriptor */
612 buffer[ 4] = (blocks >> 24) & 0xff; /* blocks MSB */
613 buffer[ 5] = (blocks >> 16) & 0xff;
614 buffer[ 6] = (blocks >> 8) & 0xff;
615 buffer[ 7] = (blocks ) & 0xff; /* blocks LSB */
616 buffer[ 8] = (format_type << 2) | certification;
617 buffer[ 9] = (param >> 16) & 0xff; /* parameter MSB */
618 buffer[10] = (param >> 8) & 0xff; /* packet size */
619 buffer[11] = (param ) & 0xff; /* parameter LSB */
620
621 /* this will take a while .... */
622 error = uscsi_command(SCSI_WRITECMD, mydev,
623 cmd, 6, buffer, 12, UINT_MAX, &sense);
624 if (error)
625 return error;
626
627 if (immed)
628 uscsi_waitop(mydev);
629
630 return 0;
631 }
632
633
634 static int
uscsi_blank_disc(struct uscsi_dev * mydev)635 uscsi_blank_disc(struct uscsi_dev *mydev)
636 {
637 scsicmd cmd;
638 int error;
639
640 /* XXX check if the device can blank! */
641
642
643 /* blank disc */
644 bzero(cmd, SCSI_CMD_LEN);
645 cmd[ 0] = 0xA1; /* blank */
646 cmd[ 1] = 16; /* Immediate, blank complete */
647 cmd[11] = 0; /* control */
648
649 /* this will take a while .... */
650 error = uscsi_command(SCSI_WRITECMD, mydev,
651 cmd, 12, NULL, 0, UINT_MAX, NULL);
652 if (error)
653 return error;
654
655 uscsi_waitop(mydev);
656 return 0;
657 }
658
659
660 static int
usage(char * program)661 usage(char *program)
662 {
663 fprintf(stderr, "\n");
664 fprintf(stderr, "Usage: %s [options] devicename\n", program);
665 fprintf(stderr,
666 "-B blank cd-rw disc before formatting\n"
667 "-F format cd-rw disc\n"
668 "-O CD-RW formatting 'old-style' for old CD-RW drives\n"
669 "-M select MRW format\n"
670 "-R restart MRW & DVD+RW format\n"
671 "-G grow last CD-RW/DVD-RW session\n"
672 "-S grow spare space DVD-RAM/BD-RE\n"
673 "-s format DVD+MRW/BD-RE with extra spare space\n"
674 "-w wait until completion of background format\n"
675 "-p explicitly set packet format\n"
676 "-c num media certification for DVD-RAM/BD-RE : "
677 "0 no, 1 full, 2 quick\n"
678 "-r recompile defect list for DVD-RAM (cmplist)\n"
679 "-h -H -I help/inquiry formats\n"
680 "-X format expert format selector form 'fmt:blks:param' with -c\n"
681 "-b blockingnr in sectors (for CD-RW)\n"
682 "-D verbose SCSI command errors\n"
683 );
684 return 1;
685 }
686
687
688 int
main(int argc,char * argv[])689 main(int argc, char *argv[])
690 {
691 struct uscsi_addr saddr;
692 uint32_t blks[256], params[256];
693 uint32_t format_type, format_blks, format_param, blockingnr;
694 uint8_t allow[256];
695 uint8_t caps[512];
696 uint32_t caps_len = sizeof(caps);
697 char *progname;
698 int blank, format, mrw, background;
699 int inquiry, spare, oldtimer;
700 int expert;
701 int restart_format, grow_session, grow_spare, packet_wr;
702 int mmc_profile, flag, error, display_usage;
703 int certification, cmplist;
704 int wait_until_finished;
705 progname = strdup(argv[0]);
706 if (argc == 1) {
707 return usage(progname);
708 }
709
710 blank = 0;
711 format = 0;
712 mrw = 0;
713 restart_format = 0;
714 grow_session = 0;
715 grow_spare = 0;
716 wait_until_finished = 0;
717 packet_wr = 0;
718 certification = 1;
719 cmplist = 0;
720 inquiry = 0;
721 spare = 0;
722 inquiry = 0;
723 oldtimer = 0;
724 expert = 0;
725 display_usage = 0;
726 blockingnr = 32;
727 uscsilib_verbose = 0;
728 while ((flag = getopt(argc, argv, "BFMRGSwpsc:rhHIX:Ob:D")) != -1) {
729 switch (flag) {
730 case 'B' :
731 blank = 1;
732 break;
733 case 'F' :
734 format = 1;
735 break;
736 case 'M' :
737 mrw = 1;
738 break;
739 case 'R' :
740 restart_format = 1;
741 break;
742 case 'G' :
743 grow_session = 1;
744 break;
745 case 'S' :
746 grow_spare = 1;
747 break;
748 case 'w' :
749 wait_until_finished = 1;
750 break;
751 case 'p' :
752 packet_wr = 1;
753 break;
754 case 's' :
755 spare = 1;
756 break;
757 case 'c' :
758 certification = atoi(optarg);
759 break;
760 case 'r' :
761 cmplist = 1;
762 break;
763 case 'h' :
764 case 'H' :
765 display_usage = 1;
766 break;
767 case 'I' :
768 inquiry = 1;
769 break;
770 case 'X' :
771 /* TODO parse expert mode string */
772 printf("-X not implemented yet\n");
773 expert = 1;
774 exit(1);
775 break;
776 case 'O' :
777 /* oldtimer CD-RW format */
778 oldtimer = 1;
779 format = 1;
780 break;
781 case 'b' :
782 blockingnr = atoi(optarg);
783 break;
784 case 'D' :
785 uscsilib_verbose = 1;
786 break;
787 default :
788 return usage(progname);
789 }
790 }
791 argv += optind;
792 argc -= optind;
793
794 if (!blank && !format && !grow_session && !grow_spare &&
795 !expert && !inquiry && !display_usage) {
796 fprintf(stderr, "%s : at least one of -B, -F, -G, -h, -H -S, "
797 "-X or -I needs to be specified\n\n", progname);
798 return usage(progname);
799 }
800
801 if (format + grow_session + grow_spare + expert > 1) {
802 fprintf(stderr, "%s : at most one of -F, -G, -S or -X "
803 "needs to be specified\n\n", progname);
804 return usage(progname);
805 }
806
807 if (argc != 1) return usage(progname);
808
809 /* Open the device */
810 dev.dev_name = strdup(*argv);
811 printf("Opening device %s\n", dev.dev_name);
812 error = uscsi_open(&dev);
813 if (error) {
814 fprintf(stderr, "Device failed to open : %s\n",
815 strerror(error));
816 exit(1);
817 }
818
819 error = uscsi_check_for_scsi(&dev);
820 if (error) {
821 fprintf(stderr, "sorry, not a SCSI/ATAPI device : %s\n",
822 strerror(error));
823 exit(1);
824 }
825
826 error = uscsi_identify(&dev, &saddr);
827 if (error) {
828 fprintf(stderr, "SCSI/ATAPI identify returned : %s\n",
829 strerror(error));
830 exit(1);
831 }
832
833 printf("\nDevice identifies itself as : ");
834
835 if (saddr.type == USCSI_TYPE_SCSI) {
836 printf("SCSI busnum = %d, target = %d, lun = %d\n",
837 saddr.addr.scsi.scbus, saddr.addr.scsi.target,
838 saddr.addr.scsi.lun);
839 } else {
840 printf("ATAPI busnum = %d, drive = %d\n",
841 saddr.addr.atapi.atbus, saddr.addr.atapi.drive);
842 }
843
844 printf("\n");
845
846 /* get MMC profile */
847 error = uscsi_get_mmc_profile(&dev, &mmc_profile);
848 if (error) {
849 fprintf(stderr,
850 "Can't get the disc's MMC profile because of :"
851 " %s\n", strerror(error));
852 fprintf(stderr, "aborting\n");
853 uscsi_close(&dev);
854 return 1;
855 }
856
857 /* blank disc section */
858 if (blank) {
859 printf("\nBlanking disc.... "); fflush(stdout);
860 error = uscsi_blank_disc(&dev);
861
862 if (error) {
863 printf("fail\n"); fflush(stdout);
864 fprintf(stderr,
865 "Blanking failed because of : %s\n",
866 strerror(error));
867 uscsi_close(&dev);
868
869 return 1;
870 } else {
871 printf("success!\n\n");
872 }
873 }
874
875 /* re-get MMC profile */
876 error = uscsi_get_mmc_profile(&dev, &mmc_profile);
877 if (error) {
878 fprintf(stderr,
879 "Can't get the disc's MMC profile because of : %s\n",
880 strerror(error));
881 fprintf(stderr, "aborting\n");
882 uscsi_close(&dev);
883 return 1;
884 }
885
886 error = get_format_capabilities(&dev, caps, &caps_len);
887 if (error)
888 exit(1);
889
890 process_format_caps(caps, caps_len, inquiry, allow, blks, params);
891
892 format_type = 0;
893 /* expert format section */
894 if (expert) {
895 }
896
897 if (!format && !grow_spare && !grow_session) {
898 /* we're done */
899 if (display_usage)
900 usage(progname);
901 uscsi_close(&dev);
902 exit(0);
903 }
904
905 /* normal format section */
906 if (format) {
907 /* get current mmc profile of disc */
908
909 if (oldtimer && mmc_profile != 0x0a) {
910 printf("Oldtimer flag only defined for CD-RW; "
911 "ignored\n");
912 }
913
914 switch (mmc_profile) {
915 case 0x12 : /* DVD-RAM */
916 format_type = 0x00;
917 break;
918 case 0x0a : /* CD-RW */
919 format_type = mrw ? 0x24 : 0x10;
920 packet_wr = 1;
921 break;
922 case 0x13 : /* DVD-RW restricted overwrite */
923 case 0x14 : /* DVD-RW sequential */
924 format_type = 0x10;
925 /*
926 * Some drives suddenly stop supporting this format
927 * type when packet_wr = 1
928 */
929 packet_wr = 0;
930 break;
931 case 0x1a : /* DVD+RW */
932 format_type = mrw ? 0x24 : 0x26;
933 break;
934 case 0x43 : /* BD-RE */
935 format_type = spare ? 0x30 : 0x31;
936 break;
937 default :
938 fprintf(stderr, "Can't format discs of type %s\n",
939 print_mmc_profile(mmc_profile));
940 uscsi_close(&dev);
941 exit(1);
942 }
943 }
944
945 if (grow_spare) {
946 switch (mmc_profile) {
947 case 0x12 : /* DVD-RAM */
948 case 0x43 : /* BD-RE */
949 format_type = 0x01;
950 break;
951 default :
952 fprintf(stderr,
953 "Can't grow spare area for discs of type %s\n",
954 print_mmc_profile(mmc_profile));
955 uscsi_close(&dev);
956 exit(1);
957 }
958 }
959
960 if (grow_session) {
961 switch (mmc_profile) {
962 case 0x0a : /* CD-RW */
963 format_type = 0x11;
964 break;
965 case 0x13 : /* DVD-RW restricted overwrite */
966 case 0x14 : /* DVD-RW sequential ? */
967 format_type = 0x13;
968 break;
969 default :
970 uscsi_close(&dev);
971 fprintf(stderr,
972 "Can't grow session for discs of type %s\n",
973 print_mmc_profile(mmc_profile));
974 exit(1);
975 }
976 }
977
978 /* check if format type is allowed */
979 format_blks = blks[format_type];
980 format_param = params[format_type];
981 if (!allow[format_type]) {
982 if (!inquiry)
983 process_format_caps(caps, caps_len, 1, allow,
984 blks, params);
985
986 printf("\n");
987 fflush(stdout);
988 fprintf(stderr,
989 "Drive indicates it can't format with deduced format "
990 "type 0x%02x\n", format_type);
991 uscsi_close(&dev);
992 exit(1);
993 }
994
995 if (restart_format && !((mmc_profile == 0x1a) || (format_type == 0x24)))
996 {
997 fprintf(stderr,
998 "Format restarting only for MRW formats or DVD+RW "
999 "formats\n");
1000 uscsi_close(&dev);
1001 exit(1);
1002 }
1003
1004 if (restart_format && !wait_until_finished) {
1005 printf( "Warning : format restarting without waiting for it be "
1006 "finished is prolly not handy\n");
1007 }
1008
1009 /* explicitly select packet write just in case */
1010 if (packet_wr) {
1011 printf("Explicitly setting packet type and blocking number\n");
1012 error = uscsi_set_packet_parameters(&dev, blockingnr);
1013 if (error) {
1014 fprintf(stderr,
1015 "Can't set packet writing and blocking number: "
1016 "%s\n", strerror(error));
1017 uscsi_close(&dev);
1018 exit(1);
1019 }
1020 }
1021
1022 /* determine if formatting is done in the background */
1023 background = 0;
1024 if (format_type == 0x24) background = 1;
1025 if (format_type == 0x26) background = 1;
1026
1027 /* special case format type 0x24 : MRW */
1028 if (format_type == 0x24) {
1029 format_blks = spare ? 0xffff0000 : 0xffffffff;
1030 format_param = restart_format;
1031 }
1032 /* special case format type 0x26 : DVD+RW */
1033 if (format_type == 0x26) {
1034 format_param = restart_format;
1035 }
1036
1037 /* verbose to the user */
1038 DEBUG(
1039 printf("Actual format selected: "
1040 "format_type 0x%02x, blks %d, param %d, "
1041 "certification %d, cmplist %d\n",
1042 format_type, format_blks, format_param,
1043 certification, cmplist);
1044 );
1045 printf("\nFormatting.... "); fflush(stdout);
1046
1047 /* formatting time! */
1048 if (oldtimer) {
1049 error = uscsi_format_cdrw_mode7(&dev, format_blks);
1050 background = 0;
1051 } else {
1052 error = uscsi_format_disc(&dev, !background, format_type,
1053 format_blks, format_param, certification,
1054 cmplist);
1055 }
1056
1057 /* what now? */
1058 if (error) {
1059 printf("fail\n"); fflush(stdout);
1060 fprintf(stderr, "Formatting failed because of : %s\n",
1061 strerror(error));
1062 } else {
1063 if (background) {
1064 printf("background formatting in progress\n");
1065 if (wait_until_finished) {
1066 printf("Waiting for completion ... ");
1067 uscsi_waitop(&dev);
1068 }
1069 /* explicitly do NOT close disc ... (for now) */
1070 return 0;
1071 } else {
1072 printf("success!\n\n");
1073 }
1074 }
1075
1076 /* finish up */
1077 uscsi_close(&dev);
1078
1079 return error;
1080 }
1081