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