xref: /titanic_50/usr/src/cmd/cdrw/mmc.c (revision bdfc6d18da790deeec2e0eb09c625902defe2498)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/types.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
33 
34 #include "transport.h"
35 #include "mmc.h"
36 #include "util.h"
37 #include "main.h"
38 
39 int
40 test_unit_ready(int fd)
41 {
42 	struct uscsi_cmd *scmd;
43 
44 	scmd = get_uscsi_cmd();
45 	scmd->uscsi_flags = USCSI_SILENT;
46 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
47 	/* give length of cdb structure */
48 	scmd->uscsi_cdblen = 6;
49 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
50 		return (0);
51 	return (1);
52 }
53 
54 int
55 inquiry(int fd, uchar_t *inq)
56 {
57 	struct uscsi_cmd *scmd;
58 
59 	scmd = get_uscsi_cmd();
60 	scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
61 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
62 	scmd->uscsi_cdb[0] = INQUIRY_CMD;
63 	scmd->uscsi_cdb[4] = INQUIRY_DATA_LENGTH;
64 	scmd->uscsi_cdblen = 6;
65 	scmd->uscsi_bufaddr = (char *)inq;
66 	scmd->uscsi_buflen = INQUIRY_DATA_LENGTH;
67 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
68 		return (0);
69 	return (1);
70 }
71 
72 int
73 read_capacity(int fd, uchar_t *capbuf)
74 {
75 	struct uscsi_cmd *scmd;
76 
77 	scmd = get_uscsi_cmd();
78 	scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
79 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
80 	scmd->uscsi_cdb[0] = READ_CAP_CMD;
81 	scmd->uscsi_cdblen = 10;
82 	scmd->uscsi_bufaddr = (char *)capbuf;
83 	scmd->uscsi_buflen = 8;
84 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
85 		return (0);
86 	return (1);
87 }
88 
89 int
90 mode_sense(int fd, uchar_t pc, int dbd, int page_len, uchar_t *buffer)
91 {
92 	struct uscsi_cmd *scmd;
93 
94 	scmd = get_uscsi_cmd();
95 	scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
96 	scmd->uscsi_buflen = page_len;
97 	scmd->uscsi_bufaddr = (char *)buffer;
98 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
99 	scmd->uscsi_cdblen = 0xa;
100 	scmd->uscsi_cdb[0] = MODE_SENSE_10_CMD;
101 	if (dbd) {
102 		/* don't return any block descriptors */
103 		scmd->uscsi_cdb[1] = 0x8;
104 	}
105 	/* the page code we want */
106 	scmd->uscsi_cdb[2] = pc;
107 	/* allocation length */
108 	scmd->uscsi_cdb[7] = (page_len >> 8) & 0xff;
109 	scmd->uscsi_cdb[8] = page_len & 0xff;
110 
111 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
112 		return (0);
113 	return (1);
114 }
115 
116 int
117 mode_select(int fd, int page_len, uchar_t *buffer)
118 {
119 	struct uscsi_cmd *scmd;
120 
121 	scmd = get_uscsi_cmd();
122 	scmd->uscsi_flags = USCSI_WRITE|USCSI_SILENT;
123 	scmd->uscsi_buflen = page_len;
124 	scmd->uscsi_bufaddr = (char *)buffer;
125 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
126 	scmd->uscsi_cdblen = 0xa;
127 
128 	/* mode select (10) command */
129 	scmd->uscsi_cdb[0] = MODE_SELECT_10_CMD;
130 	scmd->uscsi_cdb[1] = 0x10;
131 
132 	/* parameter list length */
133 	scmd->uscsi_cdb[7] = (page_len >> 8) & 0xff;
134 	scmd->uscsi_cdb[8] = page_len & 0xff;
135 
136 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
137 		return (0);
138 	return (1);
139 }
140 
141 int
142 read_track_info(int fd, int trackno, uchar_t *ti)
143 {
144 	struct uscsi_cmd *scmd;
145 
146 	scmd = get_uscsi_cmd();
147 	scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
148 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
149 	scmd->uscsi_cdb[0] = READ_TRACK_CMD;
150 
151 	/* tell device we are giving it a track number */
152 	scmd->uscsi_cdb[1] = 1;
153 
154 	/* track number to read */
155 	if (trackno == -1)
156 		if (device_type == CD_RW) {
157 			((uchar_t *)scmd->uscsi_cdb)[5] = 0xff;
158 		} else {
159 			/* only 1 track is allowed on DVD media */
160 			scmd->uscsi_cdb[1] = 0;
161 			((uchar_t *)scmd->uscsi_cdb)[5] = 0;
162 		}
163 	else
164 		scmd->uscsi_cdb[5] = (uchar_t)trackno;
165 
166 	scmd->uscsi_cdb[8] = TRACK_INFO_SIZE;
167 	scmd->uscsi_cdblen = 10;
168 	scmd->uscsi_bufaddr = (char *)ti;
169 	scmd->uscsi_buflen = TRACK_INFO_SIZE;
170 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
171 		return (0);
172 	return (1);
173 }
174 
175 int
176 read_toc(int fd, int format, int trackno, int buflen, uchar_t *buf)
177 {
178 	struct uscsi_cmd *scmd;
179 
180 	scmd = get_uscsi_cmd();
181 	scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
182 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
183 	scmd->uscsi_cdb[0] = READ_TOC_CMD;
184 	scmd->uscsi_cdb[2] = format & 0xf;
185 	scmd->uscsi_cdb[6] = trackno;
186 	scmd->uscsi_cdb[8] = buflen & 0xff;
187 	scmd->uscsi_cdb[7] = (buflen >> 8) & 0xff;
188 	scmd->uscsi_cdblen = 10;
189 	scmd->uscsi_bufaddr = (char *)buf;
190 	scmd->uscsi_buflen = buflen;
191 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
192 		return (0);
193 
194 	/* Fix for old SONY drives */
195 	if ((format == 0) && (buflen == 4) && (buf[0] == 0) && (buf[1] == 2)) {
196 		uint16_t toc_size;
197 
198 		toc_size = (((uint16_t)(buf[3] + 1)) * 8) + 2;
199 		load_scsi16(buf, toc_size);
200 	}
201 	return (1);
202 }
203 
204 int
205 read_header(int fd, uint32_t lba, uchar_t *buf)
206 {
207 	struct uscsi_cmd *scmd;
208 
209 	scmd = get_uscsi_cmd();
210 	scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
211 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
212 	scmd->uscsi_cdb[0] = READ_HDR_CMD;
213 
214 	/* Logical block address */
215 	load_scsi32(&scmd->uscsi_cdb[2], lba);
216 
217 	/* allocation length */
218 	scmd->uscsi_cdb[8] = 8;
219 	scmd->uscsi_cdblen = 10;
220 	scmd->uscsi_bufaddr = (char *)buf;
221 	scmd->uscsi_buflen = 8;
222 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
223 		return (0);
224 	return (1);
225 }
226 
227 int
228 read_disc_info(int fd, uchar_t *di)
229 {
230 	struct uscsi_cmd *scmd;
231 
232 	scmd = get_uscsi_cmd();
233 	scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
234 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
235 	scmd->uscsi_cdb[0] = READ_INFO_CMD;
236 	scmd->uscsi_cdb[8] = DISC_INFO_BLOCK_SIZE;
237 	scmd->uscsi_cdblen = 10;
238 	scmd->uscsi_bufaddr = (char *)di;
239 	scmd->uscsi_buflen = DISC_INFO_BLOCK_SIZE;
240 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
241 		return (0);
242 	return (1);
243 }
244 
245 int
246 get_configuration(int fd, uint16_t feature, int bufsize, uchar_t *buf)
247 {
248 	struct uscsi_cmd *scmd;
249 
250 	scmd = get_uscsi_cmd();
251 	scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
252 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
253 	scmd->uscsi_cdb[0] = GET_CONFIG_CMD;
254 	if (feature == 0)
255 		scmd->uscsi_cdb[1] = 0x2;
256 	else
257 		scmd->uscsi_cdb[1] = 0x1;
258 	scmd->uscsi_cdb[1] = 0x2;
259 	scmd->uscsi_cdb[2] = (feature >> 8) & 0xff;
260 	scmd->uscsi_cdb[3] = feature & 0xff;
261 	scmd->uscsi_cdb[7] = (bufsize >> 8) & 0xff;
262 	scmd->uscsi_cdb[8] = bufsize & 0xff;
263 	scmd->uscsi_cdblen = 10;
264 	scmd->uscsi_bufaddr = (char *)buf;
265 	scmd->uscsi_buflen = bufsize;
266 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
267 		return (0);
268 	return (1);
269 }
270 
271 int
272 read10(int fd, uint32_t start_blk, uint16_t nblk, uchar_t *buf,
273 	uint32_t bufsize)
274 {
275 	struct uscsi_cmd *scmd;
276 
277 	scmd = get_uscsi_cmd();
278 	scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
279 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
280 	scmd->uscsi_cdb[0] = READ_10_CMD;
281 	load_scsi32(&scmd->uscsi_cdb[2], start_blk);
282 	scmd->uscsi_cdb[8] = nblk & 0xff;
283 	scmd->uscsi_cdb[7] = (nblk >> 8) & 0xff;
284 	scmd->uscsi_cdblen = 10;
285 	scmd->uscsi_bufaddr = (char *)buf;
286 	scmd->uscsi_buflen = bufsize;
287 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
288 		return (0);
289 	return (1);
290 }
291 
292 int
293 write10(int fd, uint32_t start_blk, uint16_t nblk, uchar_t *buf,
294 	uint32_t bufsize)
295 {
296 	struct uscsi_cmd *scmd;
297 
298 	scmd = get_uscsi_cmd();
299 	scmd->uscsi_flags = USCSI_WRITE|USCSI_SILENT;
300 	/*
301 	 * Some DVD drives take longer to write than
302 	 * the standard time, since they tend to generate
303 	 * the media TOC on the fly when the cache is full
304 	 */
305 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT * 3;
306 	scmd->uscsi_cdb[0] = WRITE_10_CMD;
307 	load_scsi32(&scmd->uscsi_cdb[2], start_blk);
308 	scmd->uscsi_cdb[8] = nblk & 0xff;
309 	scmd->uscsi_cdb[7] = (nblk >> 8) & 0xff;
310 	scmd->uscsi_cdblen = 10;
311 	scmd->uscsi_bufaddr = (char *)buf;
312 	scmd->uscsi_buflen = bufsize;
313 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
314 		return (0);
315 	return (1);
316 }
317 
318 int
319 close_track(int fd, int trackno, int close_session, int immediate)
320 {
321 	struct uscsi_cmd *scmd;
322 
323 	scmd = get_uscsi_cmd();
324 	scmd->uscsi_flags = USCSI_SILENT;
325 	scmd->uscsi_cdb[0] = CLOSE_TRACK_CMD;
326 	if (immediate) {
327 		scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
328 		scmd->uscsi_cdb[1] = 1;
329 	} else {
330 		scmd->uscsi_timeout = 240;
331 	}
332 	if ((close_session) || (device_type == DVD_PLUS) ||
333 	    (device_type == DVD_PLUS_W)) {
334 		/* close the session */
335 		scmd->uscsi_cdb[2] = 2;
336 
337 	} else {
338 		/* Close the track but leave session open */
339 		scmd->uscsi_cdb[2] = 1;
340 		scmd->uscsi_cdb[5] = trackno & 0xff;
341 	}
342 
343 	/*
344 	 * DVD+R media are already formatted, we are using
345 	 * a special case to notify that drive to close
346 	 * track/session and null-fill the remaining space.
347 	 */
348 	if (device_type == DVD_PLUS) {
349 		scmd->uscsi_cdb[5] = 1; /* only 1 track */
350 
351 		if (close_session) {
352 			scmd->uscsi_cdb[2] = 6; /* session */
353 		} else {
354 			scmd->uscsi_cdb[2] = 1; /* track */
355 		}
356 	}
357 
358 	scmd->uscsi_cdblen = 10;
359 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
360 		return (0);
361 	return (1);
362 }
363 
364 int
365 blank_disc(int fd, int type, int immediate)
366 {
367 	struct uscsi_cmd *scmd;
368 
369 	scmd = get_uscsi_cmd();
370 	scmd->uscsi_flags = USCSI_SILENT;
371 
372 	if (immediate) {
373 		scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
374 		scmd->uscsi_cdb[1] = 0x10;
375 	} else {
376 		scmd->uscsi_timeout = 0x12c0;
377 	}
378 	((uchar_t *)scmd->uscsi_cdb)[0] = BLANK_CMD;
379 
380 	/* tell it to blank the last session or all of the disk */
381 	scmd->uscsi_cdb[1] |= type & 0x07;
382 	scmd->uscsi_cdblen = 12;
383 
384 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
385 		return (0);
386 	return (1);
387 }
388 
389 int
390 read_cd(int fd, uint32_t start_blk, uint16_t nblk, uchar_t sector_type,
391 	uchar_t *buf, uint32_t bufsize)
392 {
393 	struct uscsi_cmd *scmd;
394 
395 	scmd = get_uscsi_cmd();
396 	scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
397 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
398 	((uchar_t *)scmd->uscsi_cdb)[0] = READ_CD_CMD;
399 	scmd->uscsi_cdb[1] = (sector_type & 0x7) << 2;
400 	scmd->uscsi_cdb[5] = start_blk & 0xff;
401 	scmd->uscsi_cdb[4] = (start_blk >> 8) & 0xff;
402 	scmd->uscsi_cdb[3] = (start_blk >> 16) & 0xff;
403 	scmd->uscsi_cdb[2] = (start_blk >> 24) & 0xff;
404 	scmd->uscsi_cdb[8] = nblk & 0xff;
405 	scmd->uscsi_cdb[7] = (nblk >> 8) & 0xff;
406 	scmd->uscsi_cdb[9] = 0x10;
407 	scmd->uscsi_cdblen = 12;
408 	scmd->uscsi_bufaddr = (char *)buf;
409 	scmd->uscsi_buflen = bufsize;
410 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
411 		return (0);
412 	return (1);
413 }
414 
415 int
416 load_unload(int fd, int load)
417 {
418 	struct uscsi_cmd *scmd;
419 
420 	scmd = get_uscsi_cmd();
421 	scmd->uscsi_flags = USCSI_SILENT;
422 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
423 	scmd->uscsi_cdb[0] = START_STOP_CMD;
424 	if (load == 0) {
425 		/* unload medium */
426 		scmd->uscsi_cdb[4] = 2;
427 	} else {
428 		/* load medium */
429 		scmd->uscsi_cdb[4] = 3;
430 	}
431 	scmd->uscsi_cdblen = 6;
432 
433 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
434 		return (0);
435 	return (1);
436 }
437 
438 int
439 prevent_allow_mr(int fd, int op)
440 {
441 	struct uscsi_cmd *scmd;
442 
443 	scmd = get_uscsi_cmd();
444 	scmd->uscsi_flags = USCSI_SILENT;
445 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
446 	scmd->uscsi_cdb[0] = PREVENT_ALLOW_CMD;
447 	if (!op) {	/* prevent */
448 		scmd->uscsi_cdb[4] = 1;
449 	}
450 	scmd->uscsi_cdblen = 6;
451 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
452 		return (0);
453 	return (1);
454 }
455 
456 int
457 set_cd_speed(int fd, uint16_t read_speed, uint16_t write_speed)
458 {
459 	struct uscsi_cmd *scmd;
460 
461 	scmd = get_uscsi_cmd();
462 	scmd->uscsi_flags = USCSI_SILENT;
463 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
464 	scmd->uscsi_cdblen = 0xc;
465 	((uchar_t *)scmd->uscsi_cdb)[0] = SET_CD_SPEED;
466 	scmd->uscsi_cdb[2] = (read_speed >> 8) & 0xff;
467 	scmd->uscsi_cdb[3] = read_speed & 0xff;
468 	scmd->uscsi_cdb[4] = (write_speed >> 8) & 0xff;
469 	scmd->uscsi_cdb[5] = write_speed & 0xff;
470 
471 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
472 		return (0);
473 	return (1);
474 }
475 
476 int
477 get_performance(int fd, int get_write_performance, uchar_t *perf)
478 {
479 	struct uscsi_cmd *scmd;
480 
481 	scmd = get_uscsi_cmd();
482 	scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
483 	scmd->uscsi_buflen = GET_PERF_DATA_LEN;
484 	scmd->uscsi_bufaddr = (char *)perf;
485 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
486 	scmd->uscsi_cdblen = 0xc;
487 	((uchar_t *)scmd->uscsi_cdb)[0] = GET_PERFORMANCE_CMD;
488 	scmd->uscsi_cdb[1] = 0x10;
489 	if (get_write_performance)
490 		scmd->uscsi_cdb[1] |= 4;
491 	scmd->uscsi_cdb[9] = 2;
492 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
493 		return (0);
494 	return (1);
495 }
496 
497 int
498 set_streaming(int fd, uchar_t *buf)
499 {
500 	struct uscsi_cmd *scmd;
501 
502 	scmd = get_uscsi_cmd();
503 	scmd->uscsi_flags = USCSI_WRITE|USCSI_SILENT;
504 	scmd->uscsi_buflen = SET_STREAM_DATA_LEN;
505 	scmd->uscsi_bufaddr = (char *)buf;
506 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
507 	scmd->uscsi_cdblen = 0xc;
508 	((uchar_t *)scmd->uscsi_cdb)[0] = STREAM_CMD;
509 	scmd->uscsi_cdb[10] = SET_STREAM_DATA_LEN;
510 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
511 		return (0);
512 	return (1);
513 }
514 
515 int
516 rezero_unit(int fd)
517 {
518 	struct uscsi_cmd *scmd;
519 
520 	scmd = get_uscsi_cmd();
521 	scmd->uscsi_flags = USCSI_SILENT;
522 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
523 	scmd->uscsi_cdblen = 0x6;
524 	scmd->uscsi_cdb[0] = REZERO_UNIT_CMD;
525 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
526 		return (0);
527 	return (1);
528 }
529 
530 int
531 start_stop(int fd, int start)
532 {
533 	struct uscsi_cmd *scmd;
534 
535 	scmd = get_uscsi_cmd();
536 	scmd->uscsi_flags = USCSI_SILENT;
537 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
538 	scmd->uscsi_cdblen = 0x6;
539 	scmd->uscsi_cdb[0] = START_STOP_CMD;
540 	if (start) {
541 		scmd->uscsi_cdb[4] = 1;
542 	}
543 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
544 		return (0);
545 	return (1);
546 }
547 
548 int
549 flush_cache(int fd)
550 {
551 	struct uscsi_cmd *scmd;
552 
553 	scmd = get_uscsi_cmd();
554 	scmd->uscsi_flags = USCSI_SILENT;
555 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
556 	scmd->uscsi_cdblen = 10;
557 	scmd->uscsi_cdb[0] = SYNC_CACHE_CMD;
558 	if (device_type != CD_RW) {
559 		scmd->uscsi_cdb[1] = 0x2; /* Immediate */
560 	}
561 
562 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
563 		return (0);
564 	return (1);
565 }
566 
567 /*
568  * used for DVD- to reserve the size we want to write.
569  * This is used by the drive to generate a TOC.
570  */
571 int
572 set_reservation(int fd, ulong_t size)
573 {
574 	struct uscsi_cmd *scmd;
575 
576 	scmd = get_uscsi_cmd();
577 	scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
578 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
579 	scmd->uscsi_cdb[0] = SET_RESERVATION_CMD;
580 	scmd->uscsi_cdblen = 10;
581 	scmd->uscsi_cdb[5] = (uchar_t)(size >> 24);
582 	scmd->uscsi_cdb[6] = (uchar_t)(size >> 16);
583 	scmd->uscsi_cdb[7] = (uchar_t)(size >> 8);
584 	scmd->uscsi_cdb[8] = (uchar_t)size;
585 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
586 		return (0);
587 	return (1);
588 }
589 
590 /*
591  * Used for DVD+RW media to prepare the disk to write.
592  * It will also be used for packet mode writing when
593  * it becomes supported.
594  */
595 int
596 format_media(int fd)
597 {
598 	struct uscsi_cmd *scmd;
599 	uchar_t buf[20];
600 
601 	(void) memset(buf, 0, 20);
602 	scmd = get_uscsi_cmd();
603 	scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
604 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
605 
606 	scmd->uscsi_cdblen = 12;
607 	scmd->uscsi_cdb[0] = READ_FORMAT_CAP_CMD;
608 	scmd->uscsi_cdb[8] = 0x14; /* buffer length */
609 	scmd->uscsi_buflen = 20;
610 	scmd->uscsi_bufaddr = (char *)buf;
611 
612 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
613 		return (0);
614 
615 	/* RE-use cap structure */
616 
617 	scmd->uscsi_flags = USCSI_WRITE|USCSI_SILENT;
618 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
619 	scmd->uscsi_cdblen = 6;
620 	scmd->uscsi_cdb[0] = FORMAT_UNIT_CMD;
621 	/* full format */
622 	scmd->uscsi_cdb[1] = 0x11;
623 	scmd->uscsi_buflen = 12;
624 	buf[1] = 0x82; /* immediate and FOV */
625 	buf[3] = 8;	/* descriptor length */
626 	buf[8] = 0x98;	/* type = 26 DVD+RW format */
627 	buf[10] = 0;
628 
629 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
630 		return (0);
631 	return (1);
632 }
633 
634 
635 /*
636  * Prefered method of reading the media size. This is
637  * the only supported method on several newer drives.
638  */
639 uint32_t
640 read_format_capacity(int fd, uint_t *bsize)
641 {
642 	struct uscsi_cmd *scmd;
643 	uint32_t filesize;
644 	char buf[20];
645 
646 	scmd = get_uscsi_cmd();
647 	scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
648 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
649 	scmd->uscsi_cdblen = 12;
650 	scmd->uscsi_cdb[0] = READ_FORMAT_CAP_CMD;
651 	scmd->uscsi_cdb[8] = 0x14;
652 	scmd->uscsi_buflen = 20;
653 	scmd->uscsi_bufaddr = buf;
654 
655 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
656 		return (0);
657 
658 	filesize =  (uint32_t)(((uchar_t)buf[4] << 24) +
659 	    ((uchar_t)buf[5] << 16) + ((uchar_t)buf[6] << 8) + (uchar_t)buf[7]);
660 
661 	*bsize = (uint16_t)(((uchar_t)buf[10] << 8) + (uchar_t)buf[11]);
662 
663 	return (filesize);
664 }
665