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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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