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