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
)
137 (void) mutex_lock(&tio_mutex
);
138 while ((tio_iobs
[i
].iob_state
!= IOBS_READY
) &&
140 /* Wait for buffer to become ready */
141 (void) cond_wait(&tio_cond
, &tio_mutex
);
143 if (tio_abort
== 1) {
144 /* Do a flush cache before aborting */
145 (void) flush_cache(tio_fd
);
146 (void) mutex_unlock(&tio_mutex
);
149 tio_iobs
[i
].iob_state
= IOBS_UNDER_DEVICE_IO
;
151 /* If no more data, then close the track */
152 if (tio_iobs
[i
].iob_data_size
== 0) {
155 /* Some drives misbehave if flush_cache is not done */
156 (void) flush_cache(tio_fd
);
158 if (write_mode
== TAO_MODE
) {
159 /* Its important to try hard to close track */
163 for (; retry
> 0; retry
--) {
165 /* OK to hold mutex when close_track */
166 if (close_track(tio_fd
,
174 /* Some drives don't allow close track in test write */
175 if ((retry
== 0) && (simulation
== 0)) {
183 (void) cond_broadcast(&tio_cond
);
184 (void) mutex_unlock(&tio_mutex
);
188 (void) mutex_unlock(&tio_mutex
);
190 if (!write10(tio_fd
, tio_iobs
[i
].iob_start_blk
,
191 tio_iobs
[i
].iob_nblks
, tio_iobs
[i
].iob_buf
,
192 tio_iobs
[i
].iob_data_size
)) {
195 (void) mutex_lock(&tio_mutex
);
200 (void) cond_broadcast(&tio_cond
);
201 (void) mutex_unlock(&tio_mutex
);
205 (void) mutex_lock(&tio_mutex
);
206 tio_iobs
[i
].iob_state
= IOBS_EMPTY
;
207 (void) cond_broadcast(&tio_cond
);
208 (void) mutex_unlock(&tio_mutex
);
220 progress_callback(void *arg
)
225 (void) mutex_lock(&pcb_mutex
);
227 (void) cond_wait(&pcb_cond
, &pcb_mutex
);
230 (void) mutex_unlock(&pcb_mutex
);
231 if (tio_got_ctrl_c
) {
232 pcb_cb(pcb_arg
, 0xFFFFFFFF);
236 (void) mutex_unlock(&pcb_mutex
);
237 ret
= pcb_cb(pcb_arg
, pcb_completed_io_size
);
239 (void) mutex_lock(&pcb_mutex
);
240 pcb_user_abort
= (uchar_t
)ret
;
241 (void) mutex_unlock(&pcb_mutex
);
253 trackio_sig_handler(int i
)
255 /* Dont need mutex as it is only modified here */
257 (void) signal(SIGINT
, trackio_sig_handler
);
261 write_track(cd_device
*dev
, struct track_info
*ti
, bstreamhandle h
,
262 int (*cb
)(int64_t, int64_t), int64_t arg
, struct trackio_error
*te
)
264 int blksize
, i
, sz_read
, rem
;
266 thread_t tio_thread
, pc_thread
;
267 int write_cd_thr_created
;
268 int progress_callback_thr_created
;
269 int signal_handler_installed
;
271 void (*ohandler
)(int);
273 write_cd_thr_created
= progress_callback_thr_created
= 0;
274 signal_handler_installed
= retval
= 0;
276 if (ti
->ti_track_mode
& 4)
277 blksize
= DATA_TRACK_BLKSIZE
;
279 blksize
= AUDIO_TRACK_BLKSIZE
;
281 /* Initialize buffers */
282 init_tio_data(NBLKS_PER_BUF
*blksize
);
284 /* Fill in all buffers before starting */
285 start_b
= ti
->ti_start_address
;
288 * Start filling initial buffer to ensure that there is plenty of
289 * data when writing begins.
291 for (i
= 0; i
< NIOBS
; i
++) {
292 sz_read
= h
->bstr_read(h
, tio_iobs
[i
].iob_buf
,
293 tio_iobs
[i
].iob_total_size
);
297 * We need to read the source file into the buffer and make
298 * sure that the data in the buffer is a multiple of the
299 * blocksize (data or audio blocksize). iob_total_size is a
300 * multiple of the blocksize so this case should only be
301 * encountered at EOF or from piped input.
303 while ((rem
= (sz_read
% blksize
)) != 0) {
307 * rem contains the amount of data past the previous
308 * block boundry. we need to subtract it from the
309 * blocksize to get the amount needed to reach the
310 * next block boundry.
313 if ((sz_read
+ (blksize
- rem
)) >
314 tio_iobs
[i
].iob_total_size
) {
317 * This should not occur, but we are trying to
318 * write past the end of the buffer. return
326 * Try to continue reading in case the data is being
329 ret
= h
->bstr_read(h
, &tio_iobs
[i
].iob_buf
[sz_read
],
338 * No more data. We need to make sure that we are
339 * aligned with the blocksize. so pad the rest of
345 (void) memset(&tio_iobs
[i
].iob_buf
[sz_read
],
353 /* reading the source failed, clean up and return */
354 te
->err_type
= TRACKIO_ERR_SYSTEM
;
355 te
->te_errno
= errno
;
356 goto write_track_failed
;
359 tio_iobs
[i
].iob_start_blk
= start_b
;
360 tio_iobs
[i
].iob_nblks
= (sz_read
/blksize
);
361 start_b
+= tio_iobs
[i
].iob_nblks
;
362 tio_iobs
[i
].iob_data_size
= sz_read
;
363 tio_iobs
[i
].iob_state
= IOBS_READY
;
369 tio_trackno
= ti
->ti_track_no
;
371 /* Install signal handler for CTRL-C */
372 ohandler
= signal(SIGINT
, trackio_sig_handler
);
374 signal_handler_installed
= 1;
377 /* Create thread which will issue commands to write to device */
378 if (thr_create(0, 0, write_to_cd
, NULL
,
379 THR_BOUND
| THR_NEW_LWP
, &tio_thread
) != 0) {
380 te
->err_type
= TRACKIO_ERR_SYSTEM
;
381 te
->te_errno
= errno
;
382 goto write_track_failed
;
384 write_cd_thr_created
= 1;
386 /* If caller specified a callback, create a thread to do callbacks */
391 if (thr_create(0, 0, progress_callback
, NULL
,
392 THR_BOUND
| THR_NEW_LWP
, &pc_thread
) != 0) {
393 te
->err_type
= TRACKIO_ERR_SYSTEM
;
394 te
->te_errno
= errno
;
395 goto write_track_failed
;
397 progress_callback_thr_created
= 1;
401 while (sz_read
!= 0) {
402 (void) mutex_lock(&tio_mutex
);
403 while ((tio_iobs
[i
].iob_state
!= IOBS_EMPTY
) &&
404 (tio_errno
== 0) && (pcb_user_abort
== 0)) {
406 /* Do callbacks only if there is nothing else to do */
408 (void) mutex_lock(&pcb_mutex
);
409 (void) cond_broadcast(&pcb_cond
);
410 (void) mutex_unlock(&pcb_mutex
);
413 /* If user requested abort, bail out */
414 if (pcb_user_abort
|| tio_got_ctrl_c
) {
417 (void) cond_wait(&tio_cond
, &tio_mutex
);
419 if (pcb_user_abort
|| tio_got_ctrl_c
) {
420 (void) mutex_unlock(&tio_mutex
);
421 te
->err_type
= TRACKIO_ERR_USER_ABORT
;
422 goto write_track_failed
;
425 * We've got a transport error, stop writing, save all
426 * of the error information and clean up the threads.
428 if (tio_errno
!= 0) {
429 (void) mutex_unlock(&tio_mutex
);
430 te
->err_type
= TRACKIO_ERR_TRANSPORT
;
431 te
->te_errno
= tio_errno
;
432 te
->status
= uscsi_status
;
433 if (uscsi_status
== 2) {
434 te
->key
= SENSE_KEY(rqbuf
) & 0xf;
435 te
->asc
= ASC(rqbuf
);
436 te
->ascq
= ASCQ(rqbuf
);
438 goto write_track_failed
;
440 pcb_completed_io_size
+= tio_iobs
[i
].iob_data_size
;
441 tio_iobs
[i
].iob_state
= IOBS_UNDER_FILE_IO
;
442 (void) mutex_unlock(&tio_mutex
);
444 sz_read
= h
->bstr_read(h
, tio_iobs
[i
].iob_buf
,
445 tio_iobs
[i
].iob_total_size
);
448 * We need to read the source file into the buffer and make
449 * sure that the data in the buffer is a multiple of the
450 * blocksize (data or audio blocksize). this case should only
451 * be encountered at EOF or from piped input.
454 while ((rem
= (sz_read
% blksize
)) != 0) {
459 * This should not occur, we are trying to write
460 * past the end of the buffer, return error.
463 if ((sz_read
+ (blksize
- rem
)) >
464 tio_iobs
[i
].iob_total_size
) {
471 * Try to continue reading in case the data is being
475 ret
= h
->bstr_read(h
, &tio_iobs
[i
].iob_buf
[sz_read
],
484 * No more data. We need to make sure that we are
485 * aligned with the blocksize. so pad the rest of
491 * rem contains the amount of data past the
492 * previous block boundry. we need to subtract
493 * it from the blocksize to get the amount
494 * needed to reach the next block boundry.
497 (void) memset(&tio_iobs
[i
].iob_buf
[sz_read
],
503 te
->err_type
= TRACKIO_ERR_SYSTEM
;
504 te
->te_errno
= errno
;
505 goto write_track_failed
;
507 (void) mutex_lock(&tio_mutex
);
508 tio_iobs
[i
].iob_start_blk
= start_b
;
509 tio_iobs
[i
].iob_nblks
= (sz_read
/blksize
);
510 start_b
+= tio_iobs
[i
].iob_nblks
;
511 tio_iobs
[i
].iob_data_size
= sz_read
;
512 tio_iobs
[i
].iob_state
= IOBS_READY
;
513 (void) cond_broadcast(&tio_cond
);
514 (void) mutex_unlock(&tio_mutex
);
519 (void) mutex_lock(&tio_mutex
);
520 while ((tio_errno
== 0) && (tio_done
== 0)) {
522 /* Wait for track IO to complete */
523 (void) cond_wait(&tio_cond
, &tio_mutex
);
524 if (tio_errno
!= 0) {
525 te
->err_type
= TRACKIO_ERR_TRANSPORT
;
526 te
->te_errno
= tio_errno
;
527 te
->status
= uscsi_status
;
528 if (uscsi_status
== 2) {
529 te
->key
= SENSE_KEY(rqbuf
) & 0xf;
530 te
->asc
= ASC(rqbuf
);
531 te
->ascq
= ASCQ(rqbuf
);
533 (void) mutex_unlock(&tio_mutex
);
534 goto write_track_failed
;
537 while (tio_iobs
[i
].iob_state
== IOBS_EMPTY
) {
538 (void) mutex_lock(&pcb_mutex
);
539 pcb_completed_io_size
+=
540 tio_iobs
[i
].iob_data_size
;
541 (void) cond_broadcast(&pcb_cond
);
542 (void) mutex_unlock(&pcb_mutex
);
549 (void) mutex_unlock(&tio_mutex
);
552 if (progress_callback_thr_created
) {
553 if (thr_kill(pc_thread
, 0) == 0) {
554 (void) mutex_lock(&pcb_mutex
);
557 (void) cond_broadcast(&pcb_cond
);
558 (void) mutex_unlock(&pcb_mutex
);
559 (void) thr_join(pc_thread
, NULL
, NULL
);
562 if (write_cd_thr_created
) {
563 if (thr_kill(tio_thread
, 0) == 0) {
564 (void) mutex_lock(&tio_mutex
);
566 (void) cond_broadcast(&tio_cond
);
567 (void) mutex_unlock(&tio_mutex
);
568 (void) thr_join(tio_thread
, NULL
, NULL
);
572 if (signal_handler_installed
) {
573 (void) signal(SIGINT
, ohandler
);