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
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.
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]
23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
34 #include <sys/types.h>
44 #include "transport.h"
45 #include "misc_scsi.h"
51 static struct iobuf tio_iobs
[NIOBS
];
52 static uchar_t tio_synch_initialized
, tio_abort
, tio_done
;
54 static mutex_t tio_mutex
;
55 static cond_t tio_cond
;
56 static int tio_fd
, tio_trackno
;
57 static int tio_got_ctrl_c
;
60 * Progress call back data.
62 static mutex_t pcb_mutex
;
63 static cond_t pcb_cond
;
64 static uchar_t pcb_user_abort
, pcb_done
, pcb_synch_initialized
;
65 static int64_t pcb_completed_io_size
;
66 static int (*pcb_cb
)(int64_t, int64_t);
67 static int64_t pcb_arg
;
73 for (i
= 0; i
< NIOBS
; i
++) {
74 if (tio_iobs
[i
].iob_buf
) {
75 free(tio_iobs
[i
].iob_buf
);
76 tio_iobs
[i
].iob_buf
= NULL
;
79 if (tio_synch_initialized
== 1) {
80 (void) mutex_destroy(&tio_mutex
);
81 (void) cond_destroy(&tio_cond
);
82 tio_synch_initialized
= 0;
84 tio_abort
= tio_done
= 0;
88 init_tio_data(int bsize
)
92 (void) memset(tio_iobs
, 0, sizeof (tio_iobs
));
93 for (i
= 0; i
< NIOBS
; i
++) {
94 tio_iobs
[i
].iob_buf
= (uchar_t
*)my_zalloc(bsize
);
95 tio_iobs
[i
].iob_total_size
= bsize
;
96 tio_iobs
[i
].iob_state
= IOBS_EMPTY
;
98 (void) mutex_init(&tio_mutex
, USYNC_THREAD
, 0);
99 (void) cond_init(&tio_cond
, USYNC_THREAD
, 0);
100 tio_synch_initialized
= 1;
101 tio_abort
= tio_done
= 0;
108 (void) mutex_init(&pcb_mutex
, USYNC_THREAD
, 0);
109 (void) cond_init(&pcb_cond
, USYNC_THREAD
, 0);
110 pcb_user_abort
= pcb_done
= 0;
111 pcb_completed_io_size
= 0;
112 pcb_synch_initialized
= 1;
118 if (pcb_synch_initialized
== 1) {
119 (void) mutex_destroy(&pcb_mutex
);
120 (void) cond_destroy(&pcb_cond
);
121 pcb_synch_initialized
= 0;
123 pcb_user_abort
= pcb_done
= 0;
124 pcb_completed_io_size
= 0;
129 write_to_cd(void *arg
)
135 (void) mutex_lock(&tio_mutex
);
136 while ((tio_iobs
[i
].iob_state
!= IOBS_READY
) &&
138 /* Wait for buffer to become ready */
139 (void) cond_wait(&tio_cond
, &tio_mutex
);
141 if (tio_abort
== 1) {
142 /* Do a flush cache before aborting */
143 (void) flush_cache(tio_fd
);
144 (void) mutex_unlock(&tio_mutex
);
147 tio_iobs
[i
].iob_state
= IOBS_UNDER_DEVICE_IO
;
149 /* If no more data, then close the track */
150 if (tio_iobs
[i
].iob_data_size
== 0) {
153 /* Some drives misbehave if flush_cache is not done */
154 (void) flush_cache(tio_fd
);
156 if (write_mode
== TAO_MODE
) {
157 /* Its important to try hard to close track */
161 for (; retry
> 0; retry
--) {
163 /* OK to hold mutex when close_track */
164 if (close_track(tio_fd
,
172 /* Some drives don't allow close track in test write */
173 if ((retry
== 0) && (simulation
== 0)) {
181 (void) cond_broadcast(&tio_cond
);
182 (void) mutex_unlock(&tio_mutex
);
186 (void) mutex_unlock(&tio_mutex
);
188 if (!write10(tio_fd
, tio_iobs
[i
].iob_start_blk
,
189 tio_iobs
[i
].iob_nblks
, tio_iobs
[i
].iob_buf
,
190 tio_iobs
[i
].iob_data_size
)) {
193 (void) mutex_lock(&tio_mutex
);
198 (void) cond_broadcast(&tio_cond
);
199 (void) mutex_unlock(&tio_mutex
);
203 (void) mutex_lock(&tio_mutex
);
204 tio_iobs
[i
].iob_state
= IOBS_EMPTY
;
205 (void) cond_broadcast(&tio_cond
);
206 (void) mutex_unlock(&tio_mutex
);
216 progress_callback(void *arg
)
221 (void) mutex_lock(&pcb_mutex
);
223 (void) cond_wait(&pcb_cond
, &pcb_mutex
);
226 (void) mutex_unlock(&pcb_mutex
);
227 if (tio_got_ctrl_c
) {
228 pcb_cb(pcb_arg
, 0xFFFFFFFF);
232 (void) mutex_unlock(&pcb_mutex
);
233 ret
= pcb_cb(pcb_arg
, pcb_completed_io_size
);
235 (void) mutex_lock(&pcb_mutex
);
236 pcb_user_abort
= (uchar_t
)ret
;
237 (void) mutex_unlock(&pcb_mutex
);
245 trackio_sig_handler(int i
)
247 /* Dont need mutex as it is only modified here */
249 (void) signal(SIGINT
, trackio_sig_handler
);
253 write_track(cd_device
*dev
, struct track_info
*ti
, bstreamhandle h
,
254 int (*cb
)(int64_t, int64_t), int64_t arg
, struct trackio_error
*te
)
256 int blksize
, i
, sz_read
, rem
;
258 thread_t tio_thread
, pc_thread
;
259 int write_cd_thr_created
;
260 int progress_callback_thr_created
;
261 int signal_handler_installed
;
263 void (*ohandler
)(int);
265 write_cd_thr_created
= progress_callback_thr_created
= 0;
266 signal_handler_installed
= retval
= 0;
268 if (ti
->ti_track_mode
& 4)
269 blksize
= DATA_TRACK_BLKSIZE
;
271 blksize
= AUDIO_TRACK_BLKSIZE
;
273 /* Initialize buffers */
274 init_tio_data(NBLKS_PER_BUF
*blksize
);
276 /* Fill in all buffers before starting */
277 start_b
= ti
->ti_start_address
;
280 * Start filling initial buffer to ensure that there is plenty of
281 * data when writing begins.
283 for (i
= 0; i
< NIOBS
; i
++) {
284 sz_read
= h
->bstr_read(h
, tio_iobs
[i
].iob_buf
,
285 tio_iobs
[i
].iob_total_size
);
289 * We need to read the source file into the buffer and make
290 * sure that the data in the buffer is a multiple of the
291 * blocksize (data or audio blocksize). iob_total_size is a
292 * multiple of the blocksize so this case should only be
293 * encountered at EOF or from piped input.
295 while ((rem
= (sz_read
% blksize
)) != 0) {
299 * rem contains the amount of data past the previous
300 * block boundry. we need to subtract it from the
301 * blocksize to get the amount needed to reach the
302 * next block boundry.
305 if ((sz_read
+ (blksize
- rem
)) >
306 tio_iobs
[i
].iob_total_size
) {
309 * This should not occur, but we are trying to
310 * write past the end of the buffer. return
318 * Try to continue reading in case the data is being
321 ret
= h
->bstr_read(h
, &tio_iobs
[i
].iob_buf
[sz_read
],
330 * No more data. We need to make sure that we are
331 * aligned with the blocksize. so pad the rest of
337 (void) memset(&tio_iobs
[i
].iob_buf
[sz_read
],
345 /* reading the source failed, clean up and return */
346 te
->err_type
= TRACKIO_ERR_SYSTEM
;
347 te
->te_errno
= errno
;
348 goto write_track_failed
;
351 tio_iobs
[i
].iob_start_blk
= start_b
;
352 tio_iobs
[i
].iob_nblks
= (sz_read
/blksize
);
353 start_b
+= tio_iobs
[i
].iob_nblks
;
354 tio_iobs
[i
].iob_data_size
= sz_read
;
355 tio_iobs
[i
].iob_state
= IOBS_READY
;
361 tio_trackno
= ti
->ti_track_no
;
363 /* Install signal handler for CTRL-C */
364 ohandler
= signal(SIGINT
, trackio_sig_handler
);
366 signal_handler_installed
= 1;
369 /* Create thread which will issue commands to write to device */
370 if (thr_create(0, 0, write_to_cd
, NULL
,
371 THR_BOUND
| THR_NEW_LWP
, &tio_thread
) != 0) {
372 te
->err_type
= TRACKIO_ERR_SYSTEM
;
373 te
->te_errno
= errno
;
374 goto write_track_failed
;
376 write_cd_thr_created
= 1;
378 /* If caller specified a callback, create a thread to do callbacks */
383 if (thr_create(0, 0, progress_callback
, NULL
,
384 THR_BOUND
| THR_NEW_LWP
, &pc_thread
) != 0) {
385 te
->err_type
= TRACKIO_ERR_SYSTEM
;
386 te
->te_errno
= errno
;
387 goto write_track_failed
;
389 progress_callback_thr_created
= 1;
393 while (sz_read
!= 0) {
394 (void) mutex_lock(&tio_mutex
);
395 while ((tio_iobs
[i
].iob_state
!= IOBS_EMPTY
) &&
396 (tio_errno
== 0) && (pcb_user_abort
== 0)) {
398 /* Do callbacks only if there is nothing else to do */
400 (void) mutex_lock(&pcb_mutex
);
401 (void) cond_broadcast(&pcb_cond
);
402 (void) mutex_unlock(&pcb_mutex
);
405 /* If user requested abort, bail out */
406 if (pcb_user_abort
|| tio_got_ctrl_c
) {
409 (void) cond_wait(&tio_cond
, &tio_mutex
);
411 if (pcb_user_abort
|| tio_got_ctrl_c
) {
412 (void) mutex_unlock(&tio_mutex
);
413 te
->err_type
= TRACKIO_ERR_USER_ABORT
;
414 goto write_track_failed
;
417 * We've got a transport error, stop writing, save all
418 * of the error information and clean up the threads.
420 if (tio_errno
!= 0) {
421 (void) mutex_unlock(&tio_mutex
);
422 te
->err_type
= TRACKIO_ERR_TRANSPORT
;
423 te
->te_errno
= tio_errno
;
424 te
->status
= uscsi_status
;
425 if (uscsi_status
== 2) {
426 te
->key
= SENSE_KEY(rqbuf
) & 0xf;
427 te
->asc
= ASC(rqbuf
);
428 te
->ascq
= ASCQ(rqbuf
);
430 goto write_track_failed
;
432 pcb_completed_io_size
+= tio_iobs
[i
].iob_data_size
;
433 tio_iobs
[i
].iob_state
= IOBS_UNDER_FILE_IO
;
434 (void) mutex_unlock(&tio_mutex
);
436 sz_read
= h
->bstr_read(h
, tio_iobs
[i
].iob_buf
,
437 tio_iobs
[i
].iob_total_size
);
440 * We need to read the source file into the buffer and make
441 * sure that the data in the buffer is a multiple of the
442 * blocksize (data or audio blocksize). this case should only
443 * be encountered at EOF or from piped input.
446 while ((rem
= (sz_read
% blksize
)) != 0) {
451 * This should not occur, we are trying to write
452 * past the end of the buffer, return error.
455 if ((sz_read
+ (blksize
- rem
)) >
456 tio_iobs
[i
].iob_total_size
) {
463 * Try to continue reading in case the data is being
467 ret
= h
->bstr_read(h
, &tio_iobs
[i
].iob_buf
[sz_read
],
476 * No more data. We need to make sure that we are
477 * aligned with the blocksize. so pad the rest of
483 * rem contains the amount of data past the
484 * previous block boundry. we need to subtract
485 * it from the blocksize to get the amount
486 * needed to reach the next block boundry.
489 (void) memset(&tio_iobs
[i
].iob_buf
[sz_read
],
495 te
->err_type
= TRACKIO_ERR_SYSTEM
;
496 te
->te_errno
= errno
;
497 goto write_track_failed
;
499 (void) mutex_lock(&tio_mutex
);
500 tio_iobs
[i
].iob_start_blk
= start_b
;
501 tio_iobs
[i
].iob_nblks
= (sz_read
/blksize
);
502 start_b
+= tio_iobs
[i
].iob_nblks
;
503 tio_iobs
[i
].iob_data_size
= sz_read
;
504 tio_iobs
[i
].iob_state
= IOBS_READY
;
505 (void) cond_broadcast(&tio_cond
);
506 (void) mutex_unlock(&tio_mutex
);
511 (void) mutex_lock(&tio_mutex
);
512 while ((tio_errno
== 0) && (tio_done
== 0)) {
514 /* Wait for track IO to complete */
515 (void) cond_wait(&tio_cond
, &tio_mutex
);
516 if (tio_errno
!= 0) {
517 te
->err_type
= TRACKIO_ERR_TRANSPORT
;
518 te
->te_errno
= tio_errno
;
519 te
->status
= uscsi_status
;
520 if (uscsi_status
== 2) {
521 te
->key
= SENSE_KEY(rqbuf
) & 0xf;
522 te
->asc
= ASC(rqbuf
);
523 te
->ascq
= ASCQ(rqbuf
);
525 (void) mutex_unlock(&tio_mutex
);
526 goto write_track_failed
;
529 while (tio_iobs
[i
].iob_state
== IOBS_EMPTY
) {
530 (void) mutex_lock(&pcb_mutex
);
531 pcb_completed_io_size
+=
532 tio_iobs
[i
].iob_data_size
;
533 (void) cond_broadcast(&pcb_cond
);
534 (void) mutex_unlock(&pcb_mutex
);
541 (void) mutex_unlock(&tio_mutex
);
544 if (progress_callback_thr_created
) {
545 if (thr_kill(pc_thread
, 0) == 0) {
546 (void) mutex_lock(&pcb_mutex
);
549 (void) cond_broadcast(&pcb_cond
);
550 (void) mutex_unlock(&pcb_mutex
);
551 (void) thr_join(pc_thread
, NULL
, NULL
);
554 if (write_cd_thr_created
) {
555 if (thr_kill(tio_thread
, 0) == 0) {
556 (void) mutex_lock(&tio_mutex
);
558 (void) cond_broadcast(&tio_cond
);
559 (void) mutex_unlock(&tio_mutex
);
560 (void) thr_join(tio_thread
, NULL
, NULL
);
564 if (signal_handler_installed
) {
565 (void) signal(SIGINT
, ohandler
);