You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5328 lines
149 KiB

16 years ago
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
/* Copyright (c) 2004 - 2006 Derek Foreman, Ben Jansens
Copyright (c) 2006 - 2014 Thomas Schmitt <scdbackup@gmx.net>
Provided under GPL version 2 or later.
*/
#ifdef HAVE_CONFIG_H
#include "../config.h"
#endif
/* ts A61009 */
/* #include <a ssert.h> */
16 years ago
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/time.h>
16 years ago
#include <pthread.h>
#include <ctype.h>
16 years ago
#include "error.h"
#include "sector.h"
#include "libburn.h"
#include "transport.h"
#include "mmc.h"
#include "spc.h"
#include "drive.h"
#include "debug.h"
#include "toc.h"
#include "structure.h"
#include "options.h"
#include "util.h"
#include "init.h"
16 years ago
/* ts A70223 : in init.c */
extern int burn_support_untested_profiles;
static int mmc_get_configuration_al(struct burn_drive *d, int *alloc_len);
#ifdef Libburn_log_in_and_out_streaM
/* <<< ts A61031 */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#endif /* Libburn_log_in_and_out_streaM */
/* ts A61005 */
#include "libdax_msgs.h"
extern struct libdax_msgs *libdax_messenger;
/* ts A61219 : Based on knowlege from dvd+rw-tools-7.0 and mmc5r03c.pdf */
#define Libburn_support_dvd_plus_rW 1
/* ts A61229 */
#define Libburn_support_dvd_minusrw_overW 1
/* ts A70112 */
/* ts A80410 : applies to BD-RE too */
#define Libburn_support_dvd_raM 1
/* ts A70129 */
#define Libburn_support_dvd_r_seQ 1
/* ts A70306 */
#define Libburn_support_dvd_plus_R 1
/* ts A70509 : handling 0x41 as read-only type */
#define Libburn_support_bd_r_readonlY 1
/* ts A81208 */
#define Libburn_support_bd_plus_r_srM 1
/* ts A80410 : <<< Dangerous experiment: Pretend that DVD-RAM is BD-RE
# define Libburn_dvd_ram_as_bd_rE yes
*/
/* ts A80509 : <<< Experiment: pretend that DVD-ROM and CD-ROM are other media
like BD-ROM (0x40), BD-R seq (0x41), BD-R random (0x42)
# define Libburn_rom_as_profilE 0x40
*/
/* ts A80425 : Prevents command FORMAT UNIT for DVD-RAM or BD-RE.
Useful only to test the selection of format descriptors without
actually formatting the media.
# define Libburn_do_not_format_dvd_ram_or_bd_rE 1
*/
/* ts A90603 : Simulate the command restrictions of an old MMC-1 drive
# define Libisofs_simulate_old_mmc1_drivE 1
*/
/* DVD/BD progress report:
ts A61219 : It seems to work with a used (i.e. thoroughly formatted) DVD+RW.
Error messages of class DEBUG appear because of inability to
read TOC or track info. Nevertheless, the written images verify.
ts A61220 : Burned to a virgin DVD+RW by help of new mmc_format_unit()
(did not test wether it would work without). Burned to a
not completely formatted DVD+RW. (Had worked before without
mmc_format_unit() but i did not exceed the formatted range
as reported by dvd+rw-mediainfo.)
ts A61221 : Speed setting now works for both of my drives. The according
functions in dvd+rw-tools are a bit intimidating to the reader.
I hope it is possible to leave much of this to the drive.
And if it fails ... well, it's only speed setting. :))
ts A61229 : Burned to several DVD-RW formatted to mode Restricted Overwrite
by dvd+rw-format. Needs Libburn_support_dvd_minusrw_overW.
ts A61230 : Other than growisofs, libburn does not send a mode page 5 for
such DVD-RW (which the MMC-5 standard does deprecate) and it
really seems to work without such a page.
ts A70101 : Formatted DVD-RW media. Success is varying with media, but
dvd+rw-format does not do better with the same media.
ts A70112 : Support for writing to DVD-RAM.
ts A70130 : Burned a first non-multi sequential DVD-RW. Feature 0021h
Incremental Recording vanishes after that and media thus gets
not recognized as suitable any more.
After a run with -multi another disc still offers 0021h .
dvd+rw-mediainfo shows two tracks. The second, an afio archive
is readable by afio. Third and forth veryfy too. Suddenly
dvd+rw-mediainfo sees lba 0 with track 2. But #2 still verifies
if one knows its address.
ts A70203 : DVD-RW need to get blanked fully. Then feature 0021h persists.
Meanwhile Incremental streaming is supported like CD TAO:
with unpredicted size, multi-track, multi-session.
ts A70205 : Beginning to implement DVD-R[W] DAO : single track and session,
size prediction mandatory.
ts A70208 : Finally made tests with DVD-R. Worked exactly as new DVD-RW.
ts A70306 : Implemented DVD+R (always -multi for now)
ts A70330 : Allowed finalizing of DVD+R.
ts A80228 : Made DVD+R/DL support official after nightmorph reported success
in http://libburnia-project.org/ticket/13
ts A80416 : drive->do_stream_recording brings DVD-RAM to full nominal
writing speed at cost of no defect management.
ts A80416 : Giulio Orsero reports success with BD-RE writing. With
drive->do_stream_recording it does full nominal speed.
ts A80506 : Giulio Orsero reports success with BD-RE formatting.
BD-RE is now an officially supported profile.
ts A81209 : The first two sessions have been written to BD-R SRM
(auto formatted without Defect Management).
ts A90107 : BD-R is now supported media type
*/
/* ts A70519 : With MMC commands of data direction FROM_DRIVE:
Made struct command.dxfer_len equal to Allocation Length
of MMC commands. Made sure that not more bytes are allowed
for transfer than there are available.
*/
/* ts A70711 Trying to keep writing from clogging the SCSI driver due to
full buffer at burner drive: 0=waiting disabled, 1=enabled
These are only defaults which can be overwritten by
burn_drive_set_buffer_waiting()
*/
#define Libburn_wait_for_buffer_freE 0
#define Libburn_wait_for_buffer_min_useC 10000
#define Libburn_wait_for_buffer_max_useC 100000
#define Libburn_wait_for_buffer_tio_seC 120
#define Libburn_wait_for_buffer_min_perC 65
#define Libburn_wait_for_buffer_max_perC 95
/* ts B31107 The minimum values to be applied if maximum read speed is
requested. Some drives tell only the currently set speed and
thus cannot be made faster by using the highest told value.
(The fractions get added or subtracted to yield an integer
number on the safe side of the intended limit.)
*/
#define Libburn_cd_max_read_speeD (52 * 150)
#define Libburn_dvd_max_read_speeD (24 * 1385)
#define Libburn_bd_max_read_speeD (20 * 4495.625 + 0.5)
/* ts B31114 The maximum values for minimum speed
*/
#define Libburn_cd_min_read_speeD ( 1 * 150)
#define Libburn_dvd_min_read_speeD ( 1 * 1385)
#define Libburn_bd_min_read_speeD ( 1 * 4495.625 - 0.625)
static unsigned char MMC_GET_MSINFO[] =
{ 0x43, 0, 1, 0, 0, 0, 0, 16, 0, 0 };
16 years ago
static unsigned char MMC_GET_TOC[] = { 0x43, 2, 2, 0, 0, 0, 0, 16, 0, 0 };
static unsigned char MMC_GET_TOC_FMT0[] = { 0x43, 0, 0, 0, 0, 0, 0, 16, 0, 0 };
16 years ago
static unsigned char MMC_GET_ATIP[] = { 0x43, 2, 4, 0, 0, 0, 0, 16, 0, 0 };
static unsigned char MMC_GET_LEADTEXT[] = { 0x43, 2, 5, 0, 0, 0, 0, 4, 0, 0 };
16 years ago
static unsigned char MMC_GET_DISC_INFO[] =
{ 0x51, 0, 0, 0, 0, 0, 0, 16, 0, 0 };
static unsigned char MMC_READ_CD[] = { 0xBE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static unsigned char MMC_BLANK[] = { 0xA1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
16 years ago
static unsigned char MMC_SEND_OPC[] = { 0x54, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static unsigned char MMC_SET_SPEED[] =
{ 0xBB, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static unsigned char MMC_WRITE_12[] =
{ 0xAA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static unsigned char MMC_WRITE_10[] = { 0x2A, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
/* ts A61201 : inserted 0, before 16, */
16 years ago
static unsigned char MMC_GET_CONFIGURATION[] =
{ 0x46, 0, 0, 0, 0, 0, 0, 16, 0, 0 };
16 years ago
static unsigned char MMC_SYNC_CACHE[] = { 0x35, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static unsigned char MMC_GET_EVENT[] = { 0x4A, 1, 0, 0, 0x7e, 0, 0, 0, 8, 0 };
16 years ago
static unsigned char MMC_CLOSE[] = { 0x5B, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static unsigned char MMC_TRACK_INFO[] = { 0x52, 0, 0, 0, 0, 0, 0, 16, 0, 0 };
16 years ago
static unsigned char MMC_SEND_CUE_SHEET[] =
{ 0x5D, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
/* ts A61023 : get size and free space of drive buffer */
static unsigned char MMC_READ_BUFFER_CAPACITY[] =
{ 0x5C, 0, 0, 0, 0, 0, 0, 16, 0, 0 };
/* ts A61219 : format DVD+RW (and various others) */
static unsigned char MMC_FORMAT_UNIT[] = { 0x04, 0x11, 0, 0, 0, 0 };
/* ts A61221 :
To set speed for DVD media (0xBB is for CD but works on my LG GSA drive) */
static unsigned char MMC_SET_STREAMING[] =
{ 0xB6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
/* ts A61225 :
To obtain write speed descriptors (command can do other things too) */
static unsigned char MMC_GET_PERFORMANCE[] =
{ 0xAC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
/* ts A70108 : To obtain info about drive and media formatting opportunities */
static unsigned char MMC_READ_FORMAT_CAPACITIES[] =
{ 0x23, 0, 0, 0, 0, 0, 0, 0, 0, 0};
/* ts A70205 : To describe the layout of a DVD-R[W] DAO session */
static unsigned char MMC_RESERVE_TRACK[] =
{ 0x53, 0, 0, 0, 0, 0, 0, 0, 0, 0};
/* ts A70812 : Read data sectors (for types with 2048 bytes/sector only) */
static unsigned char MMC_READ_10[] =
{ 0x28, 0, 0, 0, 0, 0, 0, 0, 0, 0};
/* ts A81210 : Determine the upper limit of readable data size */
static unsigned char MMC_READ_CAPACITY[] =
{ 0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0};
/* ts A90903 : Obtain media type specific information. E.g. manufacturer.
*/
static unsigned char MMC_READ_DISC_STRUCTURE[] =
{ 0xAD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
/* ts B21125 : An alternatvie to BEh READ CD
*/
static unsigned char MMC_READ_CD_MSF[] =
{ 0xB9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static int mmc_function_spy_do_tell = 0;
int mmc_function_spy(struct burn_drive *d, char * text)
{
if (mmc_function_spy_do_tell)
fprintf(stderr,"libburn: experimental: mmc_function_spy: %s\n",
text);
if (d == NULL)
return 1;
if (d->drive_role != 1) {
char msg[4096];
sprintf(msg, "Emulated drive caught in SCSI adapter \"%s\"",
text);
libdax_msgs_submit(libdax_messenger, d->global_index,
0x0002014c,
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
msg, 0, 0);
d->cancel = 1;
return 0;
}
return 1;
}
int mmc_function_spy_ctrl(int do_tell)
{
mmc_function_spy_do_tell= !!do_tell;
return 1;
}
/* ts A70201 */
int mmc_four_char_to_int(unsigned char *data)
{
return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
}
/* ts A70201 */
int mmc_int_to_four_char(unsigned char *data, int num)
{
data[0] = (num >> 24) & 0xff;
data[1] = (num >> 16) & 0xff;
data[2] = (num >> 8) & 0xff;
data[3] = num & 0xff;
return 1;
}
static int mmc_start_for_bit0 = 0;
/* @param flag bit0= the calling function should need no START UNIT.
(Handling depends on mmc_start_for_bit0)
*/
int mmc_start_if_needed(struct burn_drive *d, int flag)
{
if (!d->is_stopped)
return 2;
if ((flag & 1) && !mmc_start_for_bit0)
return 2;
d->start_unit(d);
d->is_stopped = 0;
return 1;
}
int mmc_send_cue_sheet(struct burn_drive *d, struct cue_sheet *s)
16 years ago
{
struct buffer *buf = NULL;
struct command *c;
16 years ago
c = &(d->casual_command);
mmc_start_if_needed(d, 0);
if (mmc_function_spy(d, "mmc_send_cue_sheet") <= 0)
return 0;
BURN_ALLOC_MEM_VOID(buf, struct buffer, 1);
scsi_init_command(c, MMC_SEND_CUE_SHEET, sizeof(MMC_SEND_CUE_SHEET));
c->retry = 1;
c->page = buf;
c->page->bytes = s->count * 8;
c->page->sectors = 0;
c->opcode[6] = (c->page->bytes >> 16) & 0xFF;
c->opcode[7] = (c->page->bytes >> 8) & 0xFF;
c->opcode[8] = c->page->bytes & 0xFF;
c->dir = TO_DRIVE;
memcpy(c->page->data, s->data, c->page->bytes);
d->issue_command(d, c);
ex:;
BURN_FREE_MEM(buf);
if (c->error) {
d->cancel = 1;
scsi_notify_error(d, c, c->sense, 18, 2);
}
return !c->error;
16 years ago
}
/* ts A70205 : Announce size of a DVD-R[W] DAO session.
@param size The size in bytes to be announced to the drive.
It will get rounded up to align to 32 KiB.
*/
int mmc_reserve_track(struct burn_drive *d, off_t size)
{
struct command *c;
int lba;
char msg[80];
c = &(d->casual_command);
mmc_start_if_needed(d, 0);
if (mmc_function_spy(d, "mmc_reserve_track") <= 0)
return 0;
scsi_init_command(c, MMC_RESERVE_TRACK, sizeof(MMC_RESERVE_TRACK));
c->retry = 1;
lba = size / 2048;
if (size % 2048)
lba++;
mmc_int_to_four_char(c->opcode+5, lba);
sprintf(msg, "reserving track of %d blocks", lba);
libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
msg, 0, 0);
c->page = NULL;
c->dir = NO_TRANSFER;
c->timeout = Libburn_mmc_reserve_timeouT;
d->issue_command(d, c);
if (c->error) {
d->cancel = 1;
scsi_notify_error(d, c, c->sense, 18, 2);
}
return !c->error;
}
/* ts A70201 :
Common track info fetcher for mmc_get_nwa() and mmc_fake_toc()
*/
int mmc_read_track_info(struct burn_drive *d, int trackno, struct buffer *buf,
int alloc_len)
{
struct command *c;
c = &(d->casual_command);
mmc_start_if_needed(d, 1);
if (mmc_function_spy(d, "mmc_read_track_info") <= 0)
return 0;
scsi_init_command(c, MMC_TRACK_INFO, sizeof(MMC_TRACK_INFO));
c->dxfer_len = alloc_len;
c->opcode[7] = (c->dxfer_len >> 8) & 0xff;
c->opcode[8] = c->dxfer_len & 0xff;
c->retry = 1;
c->opcode[1] = 1;
if(trackno<=0) {
if (d->current_profile == 0x1a || d->current_profile == 0x13 ||
d->current_profile == 0x12 || d->current_profile == 0x42 ||
d->current_profile == 0x43)
/* DVD+RW , DVD-RW restricted overwrite , DVD-RAM
BD-R random recording, BD-RE */
trackno = 1;
else if (d->current_profile == 0x10 ||
d->current_profile == 0x11 ||
d->current_profile == 0x14 ||
d->current_profile == 0x15 ||
d->current_profile == 0x40 ||
d->current_profile == 0x41)
/* DVD-ROM , DVD-R[W] Sequential ,
BD-ROM , BD-R sequential */
trackno = d->last_track_no;
else /* mmc5r03c.pdf: valid only for CD, DVD+R, DVD+R DL */
trackno = 0xFF;
}
mmc_int_to_four_char(c->opcode + 2, trackno);
c->page = buf;
memset(buf->data, 0, BUFFER_SIZE);
c->dir = FROM_DRIVE;
d->issue_command(d, c);
if (c->error)
return 0;
return 1;
}
/* ts A61110 : added parameters trackno, lba, nwa. Redefined return value.
@return 1=nwa is valid , 0=nwa is not valid , -1=error */
/* ts A70201 : outsourced 52h READ TRACK INFO command */
int mmc_get_nwa(struct burn_drive *d, int trackno, int *lba, int *nwa)
16 years ago
{
struct buffer *buf = NULL;
int ret, num, alloc_len = 20, err;
unsigned char *data;
char *msg = NULL;
16 years ago
if (trackno <= 0)
d->next_track_damaged = 0;
mmc_start_if_needed(d, 1);
if (mmc_function_spy(d, "mmc_get_nwa") <= 0)
{ret = -1; goto ex;}
/* ts B00327 : Avoid to inquire unsuitable media states */
if (d->status != BURN_DISC_BLANK && d->status != BURN_DISC_APPENDABLE)
{ret = 0; goto ex;}
BURN_ALLOC_MEM(buf, struct buffer, 1);
ret = mmc_read_track_info(d, trackno, buf, alloc_len);
if (ret <= 0)
goto ex;
data = buf->data;
*lba = mmc_four_char_to_int(data + 8);
*nwa = mmc_four_char_to_int(data + 12);
num = mmc_four_char_to_int(data + 16);
/* Pioneer BD-RW BDR-205 and LITE-ON LTR-48125S return -150 as *nwa
of blank media */
if (*nwa < *lba && d->status == BURN_DISC_BLANK)
*nwa = *lba;
#ifdef Libburn_pioneer_dvr_216d_load_mode5
/* >>> memorize track mode : data[6] & 0xf */;
#endif
{ static int fake_damage = 0; /* bit0= damage on , bit1= NWA_V off */
if (fake_damage & 1)
data[5] |= 32; /* Damage bit */
if (fake_damage & 2)
data[7] &= ~1;
}
BURN_ALLOC_MEM(msg, char, 160);
if (trackno > 0)
sprintf(msg, "Track number %d: ", trackno);
else
sprintf(msg, "Upcomming track: ");
if (d->current_profile == 0x1a || d->current_profile == 0x13 ||
d->current_profile == 0x12 || d->current_profile == 0x43) {
/* overwriteable */
*lba = *nwa = num = 0;
} else if (data[5] & 32) { /* ts B10534 : MMC-5 6.27.3.7 Damage Bit */
if (!(data[7] & 1)) { /* NWA_V is set to zero */
/* "not closed due to an incomplete write" */
strcat(msg, "Damaged, not closed and not writable");
err= 0x00020185;
} else {
/* "may be recorded further in an incremental manner"*/
strcat(msg, "Damaged and not closed");
err= 0x00020186;
}
libdax_msgs_submit(libdax_messenger, d->global_index, err,
LIBDAX_MSGS_SEV_WARNING, LIBDAX_MSGS_PRIO_HIGH,
msg, 0, 0);
if (trackno <= 0)
d->next_track_damaged |= ((!(data[7] & 1)) << 1) | 1;
{ret = 0; goto ex;}
} else if (!(data[7] & 1)) {
/* ts A61106 : MMC-1 Table 142 : NWA_V = NWA Valid Flag */
strcat(msg, "No Next-Writable-Address");
libdax_msgs_submit(libdax_messenger, d->global_index,
0x00020184,
LIBDAX_MSGS_SEV_WARNING, LIBDAX_MSGS_PRIO_HIGH,
msg, 0, 0);
if (trackno <= 0)
d->next_track_damaged |= 2;
{ret = 0; goto ex;}
}
if (num > 0) {
burn_drive_set_media_capacity_remaining(d,
((off_t) num) * ((off_t) 2048));
d->media_lba_limit = *nwa + num;
} else
d->media_lba_limit = 0;
/*
fprintf(stderr, "LIBBURN_DEBUG: media_lba_limit= %d\n",
d->media_lba_limit);
*/
ret = 1;
ex:
BURN_FREE_MEM(buf);
BURN_FREE_MEM(msg);
return ret;
16 years ago
}
/* ts A61009 : function is obviously unused. */
/* void mmc_close_disc(struct burn_drive *d, struct burn_write_opts *o) */
void mmc_close_disc(struct burn_write_opts *o)
16 years ago
{
struct burn_drive *d = o->drive;
if (mmc_function_spy(d, "mmc_close_disc") <= 0)
return;
libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
"HOW THAT ? mmc_close_disc() was called", 0, 0);
/* ts A61009 : made impossible by removing redundant parameter d */
/* a ssert(o->drive == d); */
16 years ago
o->multi = 0;
spc_select_write_params(d, NULL, 0, o);
16 years ago
mmc_close(d, 1, 0);
}
/* ts A61009 : function is obviously unused. */
/* void mmc_close_session(struct burn_drive *d, struct burn_write_opts *o) */
void mmc_close_session(struct burn_write_opts *o)
16 years ago
{
struct burn_drive *d = o->drive;
if (mmc_function_spy(d, "mmc_close_session") <= 0)
return;
libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
"HOW THAT ? mmc_close_session() was called", 0, 0);
/* ts A61009 : made impossible by removing redundant parameter d */
/* a ssert(o->drive == d); */
16 years ago
o->multi = 3;
spc_select_write_params(d, NULL, 0, o);
16 years ago
mmc_close(d, 1, 0);
}
/* ts A70227 : extended meaning of session to address all possible values
of 5Bh CLOSE TRACK SESSION to address any Close Function.
@param session contains the two high bits of Close Function
@param track if not 0: sets the lowest bit of Close Function
*/
16 years ago
void mmc_close(struct burn_drive *d, int session, int track)
{
struct command *c;
char msg[256];
int key, asc, ascq;
16 years ago
c = &(d->casual_command);
if (mmc_function_spy(d, "mmc_close") <= 0)
return;
scsi_init_command(c, MMC_CLOSE, sizeof(MMC_CLOSE));
c->retry = 1;
c->opcode[1] |= 1; /* ts A70918 : Immed */
/* (ts A61030 : shifted !!session rather than or-ing plain session ) */
c->opcode[2] = ((session & 3) << 1) | !!track;
c->opcode[4] = track >> 8;
c->opcode[5] = track & 0xFF;
c->page = NULL;
c->dir = NO_TRANSFER;
c->timeout = Libburn_mmc_close_timeouT;
d->issue_command(d, c);
/* ts A70918 : Immed : wait for drive to complete command */
if (c->error) {
sprintf(msg, "Failed to close %s (%d)",
session > 1 ? "disc" : session > 0 ? "session" : "track",
((session & 3) << 1) | !!track);
sprintf(msg + strlen(msg), ". SCSI error : ");
scsi_error_msg(d, c->sense, 14, msg + strlen(msg),
&key, &asc, &ascq);
libdax_msgs_submit(libdax_messenger, d->global_index,
0x0002017e,
LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
msg, 0, 0);
d->cancel = 1;
return;
}
if (spc_wait_unit_attention(d, 3600, "CLOSE TRACK SESSION", 0) <= 0)
d->cancel = 1;
16 years ago
}
void mmc_get_event(struct burn_drive *d)
{
struct buffer *buf = NULL;
struct command *c;
int alloc_len = 8, len, evt_code, loops = 0;
unsigned char *evt;
16 years ago
c = &(d->casual_command);
BURN_ALLOC_MEM_VOID(buf, struct buffer, 1);
if (mmc_function_spy(d, "mmc_get_event") <= 0)
goto ex;
again:;
scsi_init_command(c, MMC_GET_EVENT, sizeof(MMC_GET_EVENT));
c->dxfer_len = 8;
/* >>> have a burn_drive element for Notification Class */;
c->opcode[4] = 0x7e;
c->opcode[7] = (c->dxfer_len >> 8) & 0xff;
c->opcode[8] = c->dxfer_len & 0xff;
c->retry = 1;
c->page = buf;
c->page->bytes = 0;
c->page->sectors = 0;
c->dir = FROM_DRIVE;
d->issue_command(d, c);
if (c->error)
goto ex;
evt = c->page->data;
len = ((evt[0] << 8) | evt[1]) + 2;
if (len < 8)
goto ex;
/* >>> memorize evt[3] in burn_drive element for Notification Class */;
if (evt[3] == 0) /* No event */
goto ex;
evt_code = evt[4] & 0xf;
if (evt_code == 0) /* No change */
goto ex;
switch (evt[2] & 7) {
case 0: /* no events supported */
goto ex;
case 1: /* Operational change */
if (((evt[6] << 8) | evt[7])) {