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