xref: /illumos-gate/usr/src/cmd/cdrw/mmc.c (revision 43d18f1c320355e93c47399bea0b2e022fe06364)
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 2005 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 /* Get information about the Logical Unit's capabilities */
246 int
247 get_configuration(int fd, uint16_t feature, int bufsize, uchar_t *buf)
248 {
249 	struct uscsi_cmd *scmd;
250 
251 	scmd = get_uscsi_cmd();
252 	scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
253 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
254 
255 	/* Set OPERATION CODE in CDB */
256 	scmd->uscsi_cdb[0] = GET_CONFIG_CMD;
257 
258 	/*
259 	 * Set RT field in CDB, currently need at most one
260 	 * Feature Descriptor
261 	 */
262 	scmd->uscsi_cdb[1] = 0x2;
263 
264 	/* Set Starting Feature Number in CDB */
265 	scmd->uscsi_cdb[2] = (feature >> 8) & 0xff;
266 	scmd->uscsi_cdb[3] = feature & 0xff;
267 
268 	/* Set Allocation Length in CDB */
269 	scmd->uscsi_cdb[7] = (bufsize >> 8) & 0xff;
270 	scmd->uscsi_cdb[8] = bufsize & 0xff;
271 
272 	scmd->uscsi_cdblen = 10;
273 	scmd->uscsi_bufaddr = (char *)buf;
274 	scmd->uscsi_buflen = bufsize;
275 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
276 		return (0);
277 	return (1);
278 }
279 
280 int
281 read10(int fd, uint32_t start_blk, uint16_t nblk, uchar_t *buf,
282 	uint32_t bufsize)
283 {
284 	struct uscsi_cmd *scmd;
285 
286 	scmd = get_uscsi_cmd();
287 	scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
288 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
289 	scmd->uscsi_cdb[0] = READ_10_CMD;
290 	load_scsi32(&scmd->uscsi_cdb[2], start_blk);
291 	scmd->uscsi_cdb[8] = nblk & 0xff;
292 	scmd->uscsi_cdb[7] = (nblk >> 8) & 0xff;
293 	scmd->uscsi_cdblen = 10;
294 	scmd->uscsi_bufaddr = (char *)buf;
295 	scmd->uscsi_buflen = bufsize;
296 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
297 		return (0);
298 	return (1);
299 }
300 
301 int
302 write10(int fd, uint32_t start_blk, uint16_t nblk, uchar_t *buf,
303 	uint32_t bufsize)
304 {
305 	struct uscsi_cmd *scmd;
306 
307 	scmd = get_uscsi_cmd();
308 	scmd->uscsi_flags = USCSI_WRITE|USCSI_SILENT;
309 	/*
310 	 * Some DVD drives take longer to write than
311 	 * the standard time, since they tend to generate
312 	 * the media TOC on the fly when the cache is full
313 	 */
314 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT * 3;
315 	scmd->uscsi_cdb[0] = WRITE_10_CMD;
316 	load_scsi32(&scmd->uscsi_cdb[2], start_blk);
317 	scmd->uscsi_cdb[8] = nblk & 0xff;
318 	scmd->uscsi_cdb[7] = (nblk >> 8) & 0xff;
319 	scmd->uscsi_cdblen = 10;
320 	scmd->uscsi_bufaddr = (char *)buf;
321 	scmd->uscsi_buflen = bufsize;
322 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
323 		return (0);
324 	return (1);
325 }
326 
327 int
328 close_track(int fd, int trackno, int close_session, int immediate)
329 {
330 	struct uscsi_cmd *scmd;
331 
332 	scmd = get_uscsi_cmd();
333 	scmd->uscsi_flags = USCSI_SILENT;
334 	scmd->uscsi_cdb[0] = CLOSE_TRACK_CMD;
335 	if (immediate) {
336 		scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
337 		scmd->uscsi_cdb[1] = 1;
338 	} else {
339 		scmd->uscsi_timeout = 240;
340 	}
341 	if ((close_session) || (device_type == DVD_PLUS) ||
342 	    (device_type == DVD_PLUS_W)) {
343 		/* close the session */
344 		scmd->uscsi_cdb[2] = 2;
345 
346 	} else {
347 		/* Close the track but leave session open */
348 		scmd->uscsi_cdb[2] = 1;
349 		scmd->uscsi_cdb[5] = trackno & 0xff;
350 	}
351 
352 	/*
353 	 * DVD+R media are already formatted, we are using
354 	 * a special case to notify that drive to close
355 	 * track/session and null-fill the remaining space.
356 	 */
357 	if (device_type == DVD_PLUS) {
358 		scmd->uscsi_cdb[5] = 1; /* only 1 track */
359 
360 		if (close_session) {
361 			scmd->uscsi_cdb[2] = 6; /* session */
362 		} else {
363 			scmd->uscsi_cdb[2] = 1; /* track */
364 		}
365 	}
366 
367 	scmd->uscsi_cdblen = 10;
368 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
369 		return (0);
370 	return (1);
371 }
372 
373 int
374 blank_disc(int fd, int type, int immediate)
375 {
376 	struct uscsi_cmd *scmd;
377 
378 	scmd = get_uscsi_cmd();
379 	scmd->uscsi_flags = USCSI_SILENT;
380 
381 	if (immediate) {
382 		scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
383 		scmd->uscsi_cdb[1] = 0x10;
384 	} else {
385 		scmd->uscsi_timeout = 0x12c0;
386 	}
387 	((uchar_t *)scmd->uscsi_cdb)[0] = BLANK_CMD;
388 
389 	/* tell it to blank the last session or all of the disk */
390 	scmd->uscsi_cdb[1] |= type & 0x07;
391 	scmd->uscsi_cdblen = 12;
392 
393 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
394 		return (0);
395 	return (1);
396 }
397 
398 int
399 read_cd(int fd, uint32_t start_blk, uint16_t nblk, uchar_t sector_type,
400 	uchar_t *buf, uint32_t bufsize)
401 {
402 	struct uscsi_cmd *scmd;
403 
404 	scmd = get_uscsi_cmd();
405 	scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
406 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
407 	((uchar_t *)scmd->uscsi_cdb)[0] = READ_CD_CMD;
408 	scmd->uscsi_cdb[1] = (sector_type & 0x7) << 2;
409 	scmd->uscsi_cdb[5] = start_blk & 0xff;
410 	scmd->uscsi_cdb[4] = (start_blk >> 8) & 0xff;
411 	scmd->uscsi_cdb[3] = (start_blk >> 16) & 0xff;
412 	scmd->uscsi_cdb[2] = (start_blk >> 24) & 0xff;
413 	scmd->uscsi_cdb[8] = nblk & 0xff;
414 	scmd->uscsi_cdb[7] = (nblk >> 8) & 0xff;
415 	scmd->uscsi_cdb[9] = 0x10;
416 	scmd->uscsi_cdblen = 12;
417 	scmd->uscsi_bufaddr = (char *)buf;
418 	scmd->uscsi_buflen = bufsize;
419 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
420 		return (0);
421 	return (1);
422 }
423 
424 int
425 load_unload(int fd, int load)
426 {
427 	struct uscsi_cmd *scmd;
428 
429 	scmd = get_uscsi_cmd();
430 	scmd->uscsi_flags = USCSI_SILENT;
431 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
432 	scmd->uscsi_cdb[0] = START_STOP_CMD;
433 	if (load == 0) {
434 		/* unload medium */
435 		scmd->uscsi_cdb[4] = 2;
436 	} else {
437 		/* load medium */
438 		scmd->uscsi_cdb[4] = 3;
439 	}
440 	scmd->uscsi_cdblen = 6;
441 
442 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
443 		return (0);
444 	return (1);
445 }
446 
447 int
448 prevent_allow_mr(int fd, int op)
449 {
450 	struct uscsi_cmd *scmd;
451 
452 	scmd = get_uscsi_cmd();
453 	scmd->uscsi_flags = USCSI_SILENT;
454 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
455 	scmd->uscsi_cdb[0] = PREVENT_ALLOW_CMD;
456 	if (!op) {	/* prevent */
457 		scmd->uscsi_cdb[4] = 1;
458 	}
459 	scmd->uscsi_cdblen = 6;
460 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
461 		return (0);
462 	return (1);
463 }
464 
465 int
466 set_cd_speed(int fd, uint16_t read_speed, uint16_t write_speed)
467 {
468 	struct uscsi_cmd *scmd;
469 
470 	scmd = get_uscsi_cmd();
471 	scmd->uscsi_flags = USCSI_SILENT;
472 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
473 	scmd->uscsi_cdblen = 0xc;
474 	((uchar_t *)scmd->uscsi_cdb)[0] = SET_CD_SPEED;
475 	scmd->uscsi_cdb[2] = (read_speed >> 8) & 0xff;
476 	scmd->uscsi_cdb[3] = read_speed & 0xff;
477 	scmd->uscsi_cdb[4] = (write_speed >> 8) & 0xff;
478 	scmd->uscsi_cdb[5] = write_speed & 0xff;
479 
480 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
481 		return (0);
482 	return (1);
483 }
484 
485 int
486 get_performance(int fd, int get_write_performance, uchar_t *perf)
487 {
488 	struct uscsi_cmd *scmd;
489 
490 	scmd = get_uscsi_cmd();
491 	scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
492 	scmd->uscsi_buflen = GET_PERF_DATA_LEN;
493 	scmd->uscsi_bufaddr = (char *)perf;
494 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
495 	scmd->uscsi_cdblen = 0xc;
496 	((uchar_t *)scmd->uscsi_cdb)[0] = GET_PERFORMANCE_CMD;
497 	scmd->uscsi_cdb[1] = 0x10;
498 	if (get_write_performance)
499 		scmd->uscsi_cdb[1] |= 4;
500 	scmd->uscsi_cdb[9] = 2;
501 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
502 		return (0);
503 	return (1);
504 }
505 
506 int
507 set_streaming(int fd, uchar_t *buf)
508 {
509 	struct uscsi_cmd *scmd;
510 
511 	scmd = get_uscsi_cmd();
512 	scmd->uscsi_flags = USCSI_WRITE|USCSI_SILENT;
513 	scmd->uscsi_buflen = SET_STREAM_DATA_LEN;
514 	scmd->uscsi_bufaddr = (char *)buf;
515 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
516 	scmd->uscsi_cdblen = 0xc;
517 	((uchar_t *)scmd->uscsi_cdb)[0] = STREAM_CMD;
518 	scmd->uscsi_cdb[10] = SET_STREAM_DATA_LEN;
519 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
520 		return (0);
521 	return (1);
522 }
523 
524 int
525 rezero_unit(int fd)
526 {
527 	struct uscsi_cmd *scmd;
528 
529 	scmd = get_uscsi_cmd();
530 	scmd->uscsi_flags = USCSI_SILENT;
531 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
532 	scmd->uscsi_cdblen = 0x6;
533 	scmd->uscsi_cdb[0] = REZERO_UNIT_CMD;
534 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
535 		return (0);
536 	return (1);
537 }
538 
539 int
540 start_stop(int fd, int start)
541 {
542 	struct uscsi_cmd *scmd;
543 
544 	scmd = get_uscsi_cmd();
545 	scmd->uscsi_flags = USCSI_SILENT;
546 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
547 	scmd->uscsi_cdblen = 0x6;
548 	scmd->uscsi_cdb[0] = START_STOP_CMD;
549 	if (start) {
550 		scmd->uscsi_cdb[4] = 1;
551 	}
552 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
553 		return (0);
554 	return (1);
555 }
556 
557 int
558 flush_cache(int fd)
559 {
560 	struct uscsi_cmd *scmd;
561 
562 	scmd = get_uscsi_cmd();
563 	scmd->uscsi_flags = USCSI_SILENT;
564 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
565 	scmd->uscsi_cdblen = 10;
566 	scmd->uscsi_cdb[0] = SYNC_CACHE_CMD;
567 	if (device_type != CD_RW) {
568 		scmd->uscsi_cdb[1] = 0x2; /* Immediate */
569 	}
570 
571 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
572 		return (0);
573 	return (1);
574 }
575 
576 /*
577  * used for DVD- to reserve the size we want to write.
578  * This is used by the drive to generate a TOC.
579  */
580 int
581 set_reservation(int fd, ulong_t size)
582 {
583 	struct uscsi_cmd *scmd;
584 
585 	scmd = get_uscsi_cmd();
586 	scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
587 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
588 	scmd->uscsi_cdb[0] = SET_RESERVATION_CMD;
589 	scmd->uscsi_cdblen = 10;
590 	scmd->uscsi_cdb[5] = (uchar_t)(size >> 24);
591 	scmd->uscsi_cdb[6] = (uchar_t)(size >> 16);
592 	scmd->uscsi_cdb[7] = (uchar_t)(size >> 8);
593 	scmd->uscsi_cdb[8] = (uchar_t)size;
594 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
595 		return (0);
596 	return (1);
597 }
598 
599 /*
600  * Used for DVD+RW media to prepare the disk to write.
601  * It will also be used for packet mode writing when
602  * it becomes supported.
603  */
604 int
605 format_media(int fd)
606 {
607 	struct uscsi_cmd *scmd;
608 	uchar_t buf[20];
609 
610 	(void) memset(buf, 0, 20);
611 	scmd = get_uscsi_cmd();
612 	scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
613 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
614 
615 	scmd->uscsi_cdblen = 12;
616 	scmd->uscsi_cdb[0] = READ_FORMAT_CAP_CMD;
617 	scmd->uscsi_cdb[8] = 0x14; /* buffer length */
618 	scmd->uscsi_buflen = 20;
619 	scmd->uscsi_bufaddr = (char *)buf;
620 
621 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
622 		return (0);
623 
624 	/* RE-use cap structure */
625 
626 	scmd->uscsi_flags = USCSI_WRITE|USCSI_SILENT;
627 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
628 	scmd->uscsi_cdblen = 6;
629 	scmd->uscsi_cdb[0] = FORMAT_UNIT_CMD;
630 	/* full format */
631 	scmd->uscsi_cdb[1] = 0x11;
632 	scmd->uscsi_buflen = 12;
633 	buf[1] = 0x82; /* immediate and FOV */
634 	buf[3] = 8;	/* descriptor length */
635 	buf[8] = 0x98;	/* type = 26 DVD+RW format */
636 	buf[10] = 0;
637 
638 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
639 		return (0);
640 	return (1);
641 }
642 
643 
644 /*
645  * Prefered method of reading the media size. This is
646  * the only supported method on several newer drives.
647  */
648 uint32_t
649 read_format_capacity(int fd, uint_t *bsize)
650 {
651 	struct uscsi_cmd *scmd;
652 	uint32_t filesize;
653 	char buf[20];
654 
655 	scmd = get_uscsi_cmd();
656 	scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
657 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
658 	scmd->uscsi_cdblen = 12;
659 	scmd->uscsi_cdb[0] = READ_FORMAT_CAP_CMD;
660 	scmd->uscsi_cdb[8] = 0x14;
661 	scmd->uscsi_buflen = 20;
662 	scmd->uscsi_bufaddr = buf;
663 
664 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
665 		return (0);
666 
667 	filesize =  (uint32_t)(((uchar_t)buf[4] << 24) +
668 	    ((uchar_t)buf[5] << 16) + ((uchar_t)buf[6] << 8) + (uchar_t)buf[7]);
669 
670 	*bsize = (uint16_t)(((uchar_t)buf[10] << 8) + (uchar_t)buf[11]);
671 
672 	return (filesize);
673 }
674