xref: /titanic_51/usr/src/cmd/cdrw/misc_scsi.c (revision fa9e4066f08beec538e775443c5be79dd423fcab)
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 <string.h>
32 #include <stdio.h>
33 #include <sys/dkio.h>
34 #include <unistd.h>
35 #include <errno.h>
36 #include <libintl.h>
37 #include <sys/time.h>
38 
39 #include "mmc.h"
40 #include "util.h"
41 #include "misc_scsi.h"
42 #include "transport.h"
43 #include "main.h"
44 #include "toshiba.h"
45 #include "msgs.h"
46 
47 uint32_t
48 read_scsi32(void *addr)
49 {
50 	uchar_t *ad = (uchar_t *)addr;
51 	uint32_t ret;
52 
53 	ret = ((((uint32_t)ad[0]) << 24) | (((uint32_t)ad[1]) << 16) |
54 	    (((uint32_t)ad[2]) << 8) | ad[3]);
55 	return (ret);
56 }
57 
58 uint16_t
59 read_scsi16(void *addr)
60 {
61 	uchar_t *ad = (uchar_t *)addr;
62 	uint16_t ret;
63 
64 	ret = ((((uint16_t)ad[0]) << 8) | ad[1]);
65 	return (ret);
66 }
67 
68 void
69 load_scsi32(void *addr, uint32_t v)
70 {
71 	uchar_t *ad = (uchar_t *)addr;
72 
73 	ad[0] = (uchar_t)(v >> 24);
74 	ad[1] = (uchar_t)(v >> 16);
75 	ad[2] = (uchar_t)(v >> 8);
76 	ad[3] = (uchar_t)v;
77 }
78 
79 void
80 load_scsi16(void *addr, uint16_t v)
81 {
82 	uchar_t *ad = (uchar_t *)addr;
83 	ad[0] = (uchar_t)(v >> 8);
84 	ad[1] = (uchar_t)v;
85 }
86 /*
87  * will get the mode page only i.e. will strip off the header.
88  */
89 int
90 get_mode_page(int fd, int page_no, int pc, int buf_len, uchar_t *buffer)
91 {
92 	int ret;
93 	uchar_t byte2, *buf;
94 	uint_t header_len, page_len, copy_cnt;
95 
96 	byte2 = (uchar_t)(((pc << 6) & 0xC0) | (page_no & 0x3f));
97 	buf = (uchar_t *)my_zalloc(256);
98 
99 	/* Ask 254 bytes only to make our IDE driver happy */
100 	ret = mode_sense(fd, byte2, 1, 254, buf);
101 	if (ret == 0) {
102 		free(buf);
103 		return (0);
104 	}
105 
106 	header_len = 8 + read_scsi16(&buf[6]);
107 	page_len = buf[header_len + 1] + 2;
108 
109 	copy_cnt = (page_len > buf_len) ? buf_len : page_len;
110 	(void) memcpy(buffer, &buf[header_len], copy_cnt);
111 	free(buf);
112 
113 	return (1);
114 }
115 
116 /*
117  * will take care of adding mode header and any extra bytes at the end.
118  */
119 int
120 set_mode_page(int fd, uchar_t *buffer)
121 {
122 	int ret;
123 	uchar_t *buf;
124 	uint_t total, p_len;
125 
126 	p_len = buffer[1] + 2;
127 	total = p_len + 8;
128 	buf = (uchar_t *)my_zalloc(total);
129 
130 	(void) memcpy(&buf[8], buffer, p_len);
131 	if (debug) {
132 		int i;
133 
134 		(void) printf("MODE: [");
135 		for (i = 0; i < p_len; i++) {
136 			(void) printf("0x%02x ", (uchar_t)buffer[i]);
137 		}
138 
139 		(void) printf("]\n");
140 	}
141 	ret = mode_select(fd, total, buf);
142 	free(buf);
143 
144 	return (ret);
145 }
146 
147 /*
148  * Builds track information database for track trackno. If trackno is
149  * -1, builds the database for next blank track.
150  */
151 int
152 build_track_info(cd_device *dev, int trackno, struct track_info *t_info)
153 {
154 	uchar_t *ti;
155 	uchar_t toc[20];		/* 2 entries + 4 byte header */
156 	int ret;
157 
158 	(void) memset(t_info, 0, sizeof (*t_info));
159 	/* 1st try READ TRACK INFORMATION */
160 	ti = (uchar_t *)my_zalloc(TRACK_INFO_SIZE);
161 	t_info->ti_track_no = trackno;
162 
163 	/* Gererate faked information for writing to DVD */
164 	if (device_type != CD_RW) {
165 		uint_t bsize;
166 
167 		t_info->ti_flags = 0x3000;
168 		t_info->ti_track_no = 1;
169 		t_info->ti_session_no = 1;
170 		t_info->ti_track_mode = 0x4;
171 		t_info->ti_data_mode = 1;
172 		t_info->ti_start_address = 0;
173 
174 		/* only 1 track on DVD make it max size */
175 		t_info->ti_track_size = read_format_capacity(target->d_fd,
176 		    &bsize);
177 		if (t_info->ti_track_size < MAX_CD_BLKS) {
178 			t_info->ti_track_size = MAX_DVD_BLKS;
179 		}
180 
181 		t_info->ti_nwa = 0;
182 		t_info->ti_lra = 0;
183 		t_info->ti_packet_size = 0x10;
184 		t_info->ti_free_blocks = 0;
185 	}
186 
187 	if (read_track_info(dev->d_fd, trackno, ti)) {
188 
189 		if (debug)
190 			(void) printf("using read_track_info for TOC \n");
191 
192 		t_info->ti_track_no = ti[2];
193 		t_info->ti_session_no = ti[3];
194 		t_info->ti_flags = (ti[6] >> 4) & 0xf;
195 		t_info->ti_flags |= (uint32_t)(ti[5] & 0xf0);
196 		t_info->ti_flags |= (uint32_t)(ti[7]) << 8;
197 		t_info->ti_flags |= TI_SESSION_NO_VALID | TI_FREE_BLOCKS_VALID;
198 		t_info->ti_track_mode = ti[5] & 0xf;
199 		if ((ti[6] & 0xf) == 0xf)
200 			t_info->ti_data_mode = 0xff;
201 		else
202 			t_info->ti_data_mode = ti[6] & 0xf;
203 		t_info->ti_start_address = read_scsi32(&ti[8]);
204 		t_info->ti_nwa = read_scsi32(&ti[12]);
205 		t_info->ti_free_blocks = read_scsi32(&ti[16]);
206 		t_info->ti_packet_size = read_scsi32(&ti[20]);
207 		t_info->ti_track_size = read_scsi32(&ti[24]);
208 		t_info->ti_lra = read_scsi32(&ti[28]);
209 		free(ti);
210 		return (1);
211 	}
212 	/* READ TRACK INFORMATION not supported, try other options */
213 	free(ti);
214 	/*
215 	 * We can get info for next blank track if READ TRACK INFO is not
216 	 * supported.
217 	 */
218 	if (trackno == -1)
219 		return (0);
220 
221 	if (debug)
222 		(void) printf("using READ_TOC for TOC\n");
223 
224 	/* Try Read TOC */
225 	if (!read_toc(dev->d_fd, 0, trackno, 20, toc)) {
226 		return (0);
227 	}
228 	t_info->ti_start_address = read_scsi32(&toc[8]);
229 	t_info->ti_track_mode = toc[5] & 0xf;
230 	t_info->ti_track_size = read_scsi32(&toc[16]) - read_scsi32(&toc[8]);
231 	t_info->ti_data_mode = get_data_mode(dev->d_fd, read_scsi32(&toc[8]));
232 
233 	/* Numbers for audio tracks are always in 2K chunks */
234 	if ((dev->d_blksize == 512) && ((t_info->ti_track_mode & 4) == 0)) {
235 		t_info->ti_start_address /= 4;
236 		t_info->ti_track_size /= 4;
237 	}
238 
239 	/* Now find out the session thing */
240 	ret = read_toc(dev->d_fd, 1, trackno, 12, toc);
241 
242 	/*
243 	 * Make sure that the call succeeds and returns the requested
244 	 * TOC size correctly.
245 	 */
246 
247 	if ((ret == 0) || (toc[1] != 0x0a)) {
248 
249 		/* For ATAPI drives or old Toshiba drives */
250 		ret = read_toc_as_per_8020(dev->d_fd, 1, trackno, 12, toc);
251 	}
252 	/* If this goes through well TOC length will always be 0x0a */
253 	if (ret && (toc[1] == 0x0a)) {
254 		if (trackno >= toc[6]) {
255 			t_info->ti_session_no = toc[3];
256 			t_info->ti_flags |= TI_SESSION_NO_VALID;
257 		}
258 		/*
259 		 * This might be the last track of this session. If so,
260 		 * exclude the leadout and next lead in.
261 		 */
262 		if (trackno == (toc[6] - 1)) {
263 			/*
264 			 * 1.5 Min leadout + 1 min. leadin + 2 sec. pre-gap.
265 			 * For 2nd+ leadout it will be 0.5 min. But currently
266 			 * there is no direct way. And it will not happen
267 			 * for any normal case.
268 			 *
269 			 * 75 frames/sec, 60 sec/min, so leadin gap is
270 			 * ((1.5 +1)*60 + 2)*75 = 11400 frames (blocks)
271 			 */
272 			t_info->ti_track_size -= 11400;
273 		}
274 	}
275 	return (1);
276 }
277 
278 uchar_t
279 get_data_mode(int fd, uint32_t lba)
280 {
281 	int ret;
282 	uchar_t *buf;
283 	uchar_t mode;
284 
285 	buf = (uchar_t *)my_zalloc(8);
286 	ret = read_header(fd, lba, buf);
287 	if (ret == 0)
288 		mode = 0xff;
289 	else
290 		mode = buf[0];
291 	free(buf);
292 	return (mode);
293 }
294 
295 /*
296  * Set page code 5 for TAO mode.
297  */
298 int
299 prepare_for_write(cd_device *dev, int track_mode, int test_write,
300     int keep_disc_open)
301 {
302 	uchar_t *buf;
303 	int no_err;
304 	int reset_device;
305 
306 	if ((write_mode == DAO_MODE) && keep_disc_open) {
307 		(void) printf(gettext(
308 		    "Multi-session is not supported on DVD media\n"));
309 		exit(1);
310 	}
311 
312 	if ((write_mode == DAO_MODE) && debug) {
313 		(void) printf("Preparing to write in DAO\n");
314 	}
315 
316 	(void) start_stop(dev->d_fd, 1);
317 	/* Some drives do not support this command but still do it */
318 	(void) rezero_unit(dev->d_fd);
319 
320 	buf = (uchar_t *)my_zalloc(64);
321 
322 	no_err = get_mode_page(dev->d_fd, 5, 0, 64, buf);
323 	if (no_err)
324 		no_err = ((buf[1] + 2) > 64) ? 0 : 1;
325 	/*
326 	 * If the device is already in simulation mode and again a
327 	 * simulation is requested, then set the device in non-simulation
328 	 * 1st and then take it to simulation mode. This will flush any
329 	 * previous fake state in the drive.
330 	 */
331 	if (no_err && test_write && (buf[2] & 0x10)) {
332 		reset_device = 1;
333 	} else {
334 		reset_device = 0;
335 	}
336 	if (no_err != 0) {
337 		buf[0] &= 0x3f;
338 
339 		/* set TAO or DAO writing mode */
340 		buf[2] = (write_mode == TAO_MODE)?1:2;
341 
342 		/* set simulation flag */
343 		if (test_write && (!reset_device)) {
344 			buf[2] |= 0x10;
345 		} else {
346 			buf[2] &= ~0x10;
347 		}
348 
349 		/* Turn on HW buffer underrun protection (BUFE) */
350 		if (!test_write) {
351 			buf[2] |= 0x40;
352 		}
353 
354 		/* set track mode type */
355 		if (device_type == CD_RW) {
356 			buf[3] = track_mode & 0x0f;	/* ctrl nibble */
357 		} else {
358 			buf[3] = 5;	/* always 5 for DVD */
359 		}
360 
361 		if (keep_disc_open) {
362 			buf[3] |= 0xc0;		/* Allow more sessions */
363 		}
364 
365 		/* Select track type (audio or data) */
366 		if (track_mode == TRACK_MODE_DATA) {
367 			buf[4] = 8;		/* 2048 byte sector */
368 		} else {
369 			buf[4] = 0;		/* 2352 byte sector */
370 		}
371 		buf[7] = buf[8] = 0;
372 
373 		/* Need to clear these fields for setting into DAO */
374 		if (write_mode == DAO_MODE)
375 			buf[5] = buf[15] = 0;
376 
377 		/* print out mode for detailed log */
378 		if (debug && verbose) {
379 			int i;
380 
381 			(void) printf("setting = [ ");
382 			for (i = 0; i < 15; i++)
383 				(void) printf("0x%x ", buf[i]);
384 			(void) printf("]\n");
385 		}
386 
387 		no_err = set_mode_page(dev->d_fd, buf);
388 
389 		if (no_err && reset_device) {
390 			/* Turn the test write bit back on */
391 			buf[2] |= 0x10;
392 			no_err = set_mode_page(dev->d_fd, buf);
393 		}
394 
395 		/*
396 		 * Since BUFE is the only optional flag we are
397 		 * setting we will try to turn it off if the command
398 		 * fails.
399 		 */
400 		if (!no_err) {
401 			/*
402 			 * Some old drives may not support HW
403 			 * buffer underrun protection, try again
404 			 * after turning it off.
405 			 */
406 			if (debug)
407 				(void) printf("Turning off BUFE\n");
408 			buf[2] &= ~0x40;
409 			no_err = set_mode_page(dev->d_fd, buf);
410 		}
411 	}
412 
413 	free(buf);
414 	return (no_err);
415 }
416 
417 /*
418  * Close session. This will write TOC.
419  */
420 int
421 finalize(cd_device *dev)
422 {
423 	uchar_t *di;
424 	int count, ret, err;
425 	int immediate;
426 	int finalize_max;
427 
428 	/*
429 	 * For ATAPI devices we will use the immediate mode and will
430 	 * poll the command for completion so that this command may
431 	 * not hog the channel. But for SCSI, we will use the treditional
432 	 * way of issuing the command with a large enough timeout. This
433 	 * is done because immediate mode was designed for ATAPI and some
434 	 * SCSI RW drives might not be even tested with it.
435 	 */
436 	if ((dev->d_inq[2] & 7) != 0) {
437 		/* SCSI device */
438 		immediate = 0;
439 	} else {
440 		/* non-SCSI (e.g ATAPI) device */
441 		immediate = 1;
442 	}
443 
444 	/* We need to close track before close session */
445 	if (device_type == DVD_PLUS) {
446 		if (!close_track(dev->d_fd, 0, 0, immediate))
447 			return (0);
448 	}
449 
450 	if (!close_track(dev->d_fd, 0, 1, immediate)) {
451 		/*
452 		 * For DVD-RW close track is not well defined
453 		 * some drives dont like it, others want us
454 		 * to close track before closing the session.
455 		 * NOTE that for MMC specification it is not mandatory
456 		 * to support close track.
457 		 */
458 		if (device_type == DVD_MINUS) {
459 			if (!close_track(dev->d_fd, 1, 0, immediate)) {
460 				return (0);
461 			} else {
462 				/* command is already done */
463 				if (!immediate)
464 					return (1);
465 			}
466 		} else {
467 			return (0);
468 		}
469 	} else {
470 		if (!immediate)
471 			return (1);
472 	}
473 	if (immediate) {
474 		(void) sleep(10);
475 
476 		di = (uchar_t *)my_zalloc(DISC_INFO_BLOCK_SIZE);
477 		err = 0;
478 
479 		if (device_type == CD_RW) {
480 			/* Finalization should not take more than 6 minutes */
481 			finalize_max = FINALIZE_TIMEOUT;
482 		} else {
483 			/* some DVD-RW drives take longer than 6 minutes */
484 			finalize_max = FINALIZE_TIMEOUT*2;
485 		}
486 
487 		for (count = 0; count < finalize_max; count++) {
488 			ret = read_disc_info(dev->d_fd, di);
489 			if (ret != 0)
490 				break;
491 			if (uscsi_status != 2)
492 				err = 1;
493 			if (SENSE_KEY(rqbuf) == 2) {
494 				/* not ready but not becoming ready */
495 				if (ASC(rqbuf) != 4)
496 					err = 1;
497 			} else if (SENSE_KEY(rqbuf) == 5) {
498 				/* illegal mode for this track */
499 				if (ASC(rqbuf) != 0x64)
500 					err = 1;
501 			} else {
502 				err = 1;
503 			}
504 			if (err == 1) {
505 				if (debug) {
506 					(void) printf("Finalization failed\n");
507 					(void) printf("%x %x %x %x\n",
508 					    uscsi_status, SENSE_KEY(rqbuf),
509 					    ASC(rqbuf), ASCQ(rqbuf));
510 				}
511 				free(di);
512 				return (0);
513 			}
514 			if (uscsi_status == 2) {
515 				int i;
516 				/* illegal field in command packet */
517 				if (ASC(rqbuf) == 0x24) {
518 					/* print it out! */
519 					(void) printf("\n");
520 					for (i = 0; i < 18; i++)
521 						(void) printf("%x ",
522 						    (unsigned)(rqbuf[i]));
523 					(void) printf("\n");
524 				}
525 			}
526 			(void) sleep(5);
527 		}
528 		free(di);
529 	}
530 	return (ret);
531 }
532 
533 /*
534  * Find out media capacity.
535  */
536 int
537 get_last_possible_lba(cd_device *dev)
538 {
539 	uchar_t *di;
540 	int cap;
541 
542 	di = (uchar_t *)my_zalloc(DISC_INFO_BLOCK_SIZE);
543 	if (!read_disc_info(dev->d_fd, di)) {
544 		free(di);
545 		return (0);
546 	}
547 	if ((di[21] != 0) && (di[21] != 0xff)) {
548 		cap = ((di[21] * 60) + di[22]) * 75;
549 	} else {
550 		cap = 0;
551 	}
552 
553 	free(di);
554 	return (cap);
555 }
556 
557 int
558 read_audio_through_read_cd(cd_device *dev, uint_t start_lba, uint_t nblks,
559     uchar_t *buf)
560 {
561 	int retry;
562 	int ret;
563 
564 	for (retry = 0; retry < 3; retry++) {
565 		ret = read_cd(dev->d_fd, (uint32_t)start_lba, (uint16_t)nblks,
566 		    1, buf, (uint32_t)(nblks * 2352));
567 		if (ret)
568 			break;
569 	}
570 	return (ret);
571 }
572 
573 int
574 eject_media(cd_device *dev)
575 {
576 	if (vol_running) {
577 		/* If there is a media, try using DKIOCEJECT 1st */
578 		if (check_device(dev, CHECK_NO_MEDIA) == 0) {
579 			if (ioctl(dev->d_fd, DKIOCEJECT, 0) == 0) {
580 				return (1);
581 			}
582 		}
583 	}
584 	if (load_unload(dev->d_fd, 0) == 0) {
585 		/* if eject fails */
586 		if ((uscsi_status == 2) && (ASC(rqbuf) == 0x53)) {
587 			/*
588 			 * check that eject is not blocked on the device
589 			 */
590 			if (!prevent_allow_mr(dev->d_fd, 1))
591 				return (0);
592 			return (load_unload(dev->d_fd, 0));
593 		}
594 		return (0);
595 	}
596 	return (1);
597 }
598 
599 /*
600  * Get CD speed from Page code 2A. since GET PERFORMANCE is not supported
601  * (which is already checked before) this mode page *will* have the speed.
602  */
603 static uint16_t
604 i_cd_speed_read(cd_device *dev, int cmd)
605 {
606 	uchar_t *mp2a;
607 	uint16_t rate;
608 
609 	mp2a = (uchar_t *)my_zalloc(PAGE_CODE_2A_SIZE);
610 	if (get_mode_page(dev->d_fd, 0x2A, 0, PAGE_CODE_2A_SIZE,
611 	    mp2a) == 0) {
612 		rate = 0;
613 	} else {
614 		if (cmd == GET_READ_SPEED) {
615 			rate = ((uint16_t)mp2a[14] << 8) | mp2a[15];
616 		} else {
617 			rate = ((uint16_t)mp2a[20] << 8) | mp2a[21];
618 		}
619 	}
620 	free(mp2a);
621 	return (rate);
622 }
623 
624 /*
625  * CD speed related functions (ioctl style) for drives which do not support
626  * real time streaming.
627  */
628 int
629 cd_speed_ctrl(cd_device *dev, int cmd, int speed)
630 {
631 	uint16_t rate;
632 
633 	if ((cmd == GET_READ_SPEED) || (cmd == GET_WRITE_SPEED))
634 		return (XFER_RATE_TO_SPEED(i_cd_speed_read(dev, cmd)));
635 	if (cmd == SET_READ_SPEED) {
636 		rate = i_cd_speed_read(dev, GET_WRITE_SPEED);
637 		return (set_cd_speed(dev->d_fd, SPEED_TO_XFER_RATE(speed),
638 		    rate));
639 	}
640 	if (cmd == SET_WRITE_SPEED) {
641 		rate = i_cd_speed_read(dev, GET_READ_SPEED);
642 		return (set_cd_speed(dev->d_fd, rate,
643 		    SPEED_TO_XFER_RATE(speed)));
644 	}
645 	return (0);
646 }
647 
648 /*
649  * cd speed related functions for drives which support RT-streaming
650  */
651 int
652 rt_streaming_ctrl(cd_device *dev, int cmd, int speed)
653 {
654 	uchar_t *perf, *str;
655 	int write_perf;
656 	int ret;
657 	uint16_t perf_got;
658 
659 	write_perf = 0;
660 	if ((cmd == GET_WRITE_SPEED) || (cmd == SET_READ_SPEED))
661 		write_perf = 1;
662 	perf = (uchar_t *)my_zalloc(GET_PERF_DATA_LEN);
663 	if (!get_performance(dev->d_fd, write_perf, perf)) {
664 		ret = 0;
665 		goto end_rsc;
666 	}
667 	perf_got = (uint16_t)read_scsi32(&perf[20]);
668 	if ((cmd == GET_READ_SPEED) || (cmd == GET_WRITE_SPEED)) {
669 		ret = XFER_RATE_TO_SPEED(perf_got);
670 		goto end_rsc;
671 	}
672 	str = (uchar_t *)my_zalloc(SET_STREAM_DATA_LEN);
673 	(void) memcpy(&str[8], &perf[16], 4);
674 	load_scsi32(&str[16], 1000);
675 	load_scsi32(&str[24], 1000);
676 	if (cmd == SET_WRITE_SPEED) {
677 		load_scsi32(&str[12], (uint32_t)perf_got);
678 		load_scsi32(&str[20], (uint32_t)SPEED_TO_XFER_RATE(speed));
679 	} else {
680 		load_scsi32(&str[20], (uint32_t)perf_got);
681 		load_scsi32(&str[12], (uint32_t)SPEED_TO_XFER_RATE(speed));
682 	}
683 	ret = set_streaming(dev->d_fd, str);
684 	free(str);
685 
686 	/* If rt_speed_ctrl fails for any reason use cd_speed_ctrl */
687 	if (ret == 0) {
688 		if (debug)
689 			(void) printf(" real time speed control"
690 			    " failed, using CD speed control\n");
691 
692 		dev->d_speed_ctrl = cd_speed_ctrl;
693 		ret = dev->d_speed_ctrl(dev, cmd, speed);
694 	}
695 
696 end_rsc:
697 	free(perf);
698 	return (ret);
699 }
700 
701 /*
702  * Initialize device for track-at-once mode of writing. All of the data will
703  * need to be written to the track without interruption.
704  * This initialized TAO by setting page code 5 and speed.
705  */
706 void
707 write_init(int mode)
708 {
709 	(void) printf(gettext("Initializing device"));
710 	if (simulation)
711 		(void) printf(gettext("(Simulation mode)"));
712 	print_n_flush("...");
713 
714 	get_media_type(target->d_fd);
715 
716 	/* DVD- requires DAO mode */
717 	if (device_type == DVD_MINUS) {
718 		write_mode = DAO_MODE;
719 	}
720 
721 	/* For debug, print out device config information */
722 	if (debug) {
723 		int i;
724 		uchar_t cap[80];
725 
726 		if (get_configuration(target->d_fd, 0, 80, cap))
727 			(void) printf("Drive profile = ");
728 			for (i = 10; i < 70; i += 8)
729 				(void) printf(" 0x%x", cap[i]);
730 			(void) printf("\n");
731 	}
732 
733 	/* DVD+ and DVD- have no support for AUDIO, bail out */
734 	if ((mode == TRACK_MODE_AUDIO) && (device_type != CD_RW)) {
735 		err_msg(gettext("Audio mode is only supported for CD media\n"));
736 		exit(1);
737 	}
738 
739 	if (!prepare_for_write(target, mode, simulation, keep_disc_open)) {
740 		/* l10n_NOTE : 'failed' as in Initializing device...failed  */
741 		(void) printf(gettext("failed.\n"));
742 		err_msg(gettext("Cannot initialize device for write\n"));
743 		exit(1);
744 	}
745 	/* l10n_NOTE : 'done' as in "Initializing device...done"  */
746 	(void) printf(gettext("done.\n"));
747 
748 	/* if speed change option was used (-p) then try to set the speed */
749 	if (requested_speed != 0) {
750 		if (verbose)
751 			(void) printf(gettext("Trying to set speed to %dX.\n"),
752 			    requested_speed);
753 		if (target->d_speed_ctrl(target, SET_WRITE_SPEED,
754 		    requested_speed) == 0) {
755 			err_msg(gettext("Unable to set speed.\n"));
756 			exit(1);
757 		}
758 		if (verbose) {
759 			int speed;
760 			speed = target->d_speed_ctrl(target,
761 			    GET_WRITE_SPEED, 0);
762 			if (speed == requested_speed) {
763 				(void) printf(gettext("Speed set to %dX.\n"),
764 				    speed);
765 			} else {
766 				(void) printf(
767 				gettext("Speed set to closest approximation "
768 				    "of %dX allowed by device (%dX).\n"),
769 				    requested_speed, speed);
770 			}
771 		}
772 	}
773 }
774 
775 void
776 write_fini(void)
777 {
778 	print_n_flush(gettext("Finalizing (Can take several minutes)..."));
779 	/* Some drives don't like this while in test write mode */
780 	if (!simulation) {
781 		if (!finalize(target)) {
782 			/*
783 			 * It is possible that the drive is busy writing the
784 			 * buffered portion. So do not get upset yet.
785 			 */
786 			(void) sleep(10);
787 			if (!finalize(target)) {
788 				if (debug) {
789 					(void) printf("status %x, %x/%x/%x\n",
790 					    uscsi_status, SENSE_KEY(rqbuf),
791 					    ASC(rqbuf), ASCQ(rqbuf));
792 				}
793 
794 				if ((device_type == DVD_MINUS) &&
795 				    (SENSE_KEY(rqbuf) == 5)) {
796 
797 					if (verbose) {
798 						(void) printf(
799 						    "skipping finalizing\n");
800 					}
801 				} else {
802 
803 			/* l10n_NOTE : 'failed' as in finishing up...failed  */
804 					(void) printf(gettext("failed.\n"));
805 
806 					err_msg(gettext(
807 					    "Could not finalize the disc.\n"));
808 					exit(1);
809 				}
810 
811 
812 			}
813 		}
814 		if (vol_running) {
815 			(void) eject_media(target);
816 		}
817 	} else if (check_device(target, CHECK_MEDIA_IS_NOT_BLANK)) {
818 		/*
819 		 * Some drives such as the pioneer A04 will retain a
820 		 * ghost TOC after a simulation write is done. The
821 		 * media will actually be blank, but the drive will
822 		 * report a TOC. There is currently no other way to
823 		 * re-initialize the media other than ejecting or
824 		 * to ask the drive to clear the leadout. The laser
825 		 * is currently off so nothing is written to the
826 		 * media (on a good behaving drive).
827 		 * NOTE that a device reset does not work to make
828 		 * the drive re-initialize the media.
829 		 */
830 
831 		if (!vol_running) {
832 			blanking_type = "clear";
833 			blank();
834 		}
835 
836 	}
837 	/* l10n_NOTE : 'done' as in "Finishing up...done"  */
838 	(void) printf(gettext("done.\n"));
839 }
840