Experimental SCSI transport adapter via GNU libcdio
This commit is contained in:
parent
e566340261
commit
dd85e37ac8
@ -201,8 +201,10 @@ EXTRA_DIST = \
|
|||||||
cdrskin/cleanup.c \
|
cdrskin/cleanup.c \
|
||||||
libburn/os-freebsd.h \
|
libburn/os-freebsd.h \
|
||||||
libburn/os-linux.h \
|
libburn/os-linux.h \
|
||||||
|
libburn/os-libcdio.h \
|
||||||
libburn/sg-freebsd.c \
|
libburn/sg-freebsd.c \
|
||||||
libburn/sg-linux.c \
|
libburn/sg-linux.c \
|
||||||
|
libburn/sg-libcdio.c \
|
||||||
COPYING \
|
COPYING \
|
||||||
NEWS \
|
NEWS \
|
||||||
ChangeLog \
|
ChangeLog \
|
||||||
|
24
configure.ac
24
configure.ac
@ -206,10 +206,30 @@ else
|
|||||||
LIBBURN_DVD_OBS_64K=
|
LIBBURN_DVD_OBS_64K=
|
||||||
echo "disabled write size default 64 KB on DVD and BD"
|
echo "disabled write size default 64 KB on DVD and BD"
|
||||||
fi
|
fi
|
||||||
dnl Avoid the need for libburn_libburn_la_CFLAGS in Makefile.am (ugly .o names)
|
|
||||||
dnl ### AC_SUBST(LIBBURN_DVD_OBS_64K)
|
|
||||||
CFLAGS="$CFLAGS $LIBBURN_DVD_OBS_64K"
|
CFLAGS="$CFLAGS $LIBBURN_DVD_OBS_64K"
|
||||||
|
|
||||||
|
dnl ts A91218
|
||||||
|
AC_ARG_ENABLE(libcdio,
|
||||||
|
[ --enable-libcdio Enable EXPERIMENTAL use of libcdio as system adapter, default=no],
|
||||||
|
, enable_libcdio=no)
|
||||||
|
if test x$enable_libcdio = xyes; then
|
||||||
|
dnl Check whether there is libcdio-devel and libcdio-runtime.
|
||||||
|
dnl If not, erase this macro
|
||||||
|
LIBCDIO_DEF="-DLibburn_use_libcdiO"
|
||||||
|
dnl The empty yes case obviously causes -lacl to be linked
|
||||||
|
AC_CHECK_HEADER(cdio/cdio.h, AC_CHECK_LIB(cdio, cdio_open, , LIBCDIO_DEF= ), LIBCDIO_DEF= )
|
||||||
|
else
|
||||||
|
LIBCDIO_DEF=
|
||||||
|
fi
|
||||||
|
if test x$LIBCDIO_DEF = x
|
||||||
|
then
|
||||||
|
LIBCDIO_DEF=
|
||||||
|
else
|
||||||
|
echo "enabled EXPERIMENTAL use of libcdio as system adapter"
|
||||||
|
CFLAGS="$CFLAGS $LIBCDIO_DEF"
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
dnl Add compiler-specific flags
|
dnl Add compiler-specific flags
|
||||||
|
|
||||||
|
62
libburn/os-libcdio.h
Normal file
62
libburn/os-libcdio.h
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
|
||||||
|
/* os-dummy.h
|
||||||
|
Operating system specific libburn definitions and declarations. Included
|
||||||
|
by os.h in case of compilation for
|
||||||
|
Unknown POSIX like systems
|
||||||
|
with GNU libcdio MMC transport adapter sg-libcdio.c
|
||||||
|
|
||||||
|
Copyright (C) 2009 Thomas Schmitt <scdbackup@gmx.net>, provided under GPL
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/** List of all signals which shall be caught by signal handlers and trigger
|
||||||
|
a graceful abort of libburn. (See man 7 signal.)
|
||||||
|
*/
|
||||||
|
/* Once as system defined macros */
|
||||||
|
#define BURN_OS_SIGNAL_MACRO_LIST \
|
||||||
|
SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT, \
|
||||||
|
SIGFPE, SIGSEGV, SIGPIPE, SIGALRM, SIGTERM, \
|
||||||
|
SIGUSR1, SIGUSR2, SIGXCPU, SIGTSTP, SIGTTIN, \
|
||||||
|
SIGTTOU
|
||||||
|
|
||||||
|
/* Once as text 1:1 list of strings for messages and interpreters */
|
||||||
|
#define BURN_OS_SIGNAL_NAME_LIST \
|
||||||
|
"SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", "SIGABRT", \
|
||||||
|
"SIGFPE", "SIGSEGV", "SIGPIPE", "SIGALRM", "SIGTERM", \
|
||||||
|
"SIGUSR1", "SIGUSR2", "SIGXCPU", "SIGTSTP", "SIGTTIN", \
|
||||||
|
"SIGTTOU"
|
||||||
|
|
||||||
|
/* The number of above list items */
|
||||||
|
#define BURN_OS_SIGNAL_COUNT 16
|
||||||
|
|
||||||
|
/** To list all signals which shall surely not be caught */
|
||||||
|
#define BURN_OS_NON_SIGNAL_MACRO_LIST \
|
||||||
|
SIGKILL, SIGCHLD, SIGSTOP
|
||||||
|
|
||||||
|
/* The number of above list items */
|
||||||
|
#define BURN_OS_NON_SIGNAL_COUNT 3
|
||||||
|
|
||||||
|
|
||||||
|
/* The maximum size for a (SCSI) i/o transaction */
|
||||||
|
/* Important : MUST be at least 32768 ! */
|
||||||
|
#define BURN_OS_TRANSPORT_BUFFER_SIZE 65536
|
||||||
|
|
||||||
|
|
||||||
|
/* To hold the position of the most recently delivered address from
|
||||||
|
device enumeration.
|
||||||
|
*/
|
||||||
|
struct burn_drive_enumerator_struct {
|
||||||
|
char **ppsz_cd_drives;
|
||||||
|
char **pos;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define BURN_OS_DEFINE_DRIVE_ENUMERATOR_T \
|
||||||
|
typedef struct burn_drive_enumerator_struct burn_drive_enumerator_t;
|
||||||
|
|
||||||
|
|
||||||
|
/* The list of operating system dependent elements in struct burn_drive.
|
||||||
|
Usually they are initialized in sg-*.c:enumerate_common().
|
||||||
|
*/
|
||||||
|
#define BURN_OS_TRANSPORT_DRIVE_ELEMENTS \
|
||||||
|
void *p_cdio; /* actually a pointer to CdIo_t */ \
|
||||||
|
|
10
libburn/os.h
10
libburn/os.h
@ -13,6 +13,15 @@
|
|||||||
Operating system case distinction
|
Operating system case distinction
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef Libburn_use_libcdiO
|
||||||
|
|
||||||
|
|
||||||
|
/* -------------------------- X/Open with GNU libcdio ---------------------- */
|
||||||
|
#include "os-libcdio.h"
|
||||||
|
|
||||||
|
|
||||||
|
#else
|
||||||
#ifdef __FreeBSD__
|
#ifdef __FreeBSD__
|
||||||
|
|
||||||
|
|
||||||
@ -37,6 +46,7 @@
|
|||||||
|
|
||||||
#endif /* ! __linux */
|
#endif /* ! __linux */
|
||||||
#endif /* ! __FreeBSD__ */
|
#endif /* ! __FreeBSD__ */
|
||||||
|
#endif /* ! Libburn_use_libcdiO */
|
||||||
|
|
||||||
|
|
||||||
#endif /* ! BURN_OS_H_INCLUDED */
|
#endif /* ! BURN_OS_H_INCLUDED */
|
||||||
|
@ -323,7 +323,7 @@ try_item:; /* This spaghetti loop keeps the number of tabs small */
|
|||||||
int scsi_enumerate_drives(void)
|
int scsi_enumerate_drives(void)
|
||||||
{
|
{
|
||||||
burn_drive_enumerator_t idx;
|
burn_drive_enumerator_t idx;
|
||||||
int initialize = 1;
|
int initialize = 1, ret;
|
||||||
char buf[64];
|
char buf[64];
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
@ -338,6 +338,7 @@ int scsi_enumerate_drives(void)
|
|||||||
idx.result->target_lun);
|
idx.result->target_lun);
|
||||||
}
|
}
|
||||||
sg_give_next_adr(&idx, buf, sizeof(buf), -1);
|
sg_give_next_adr(&idx, buf, sizeof(buf), -1);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -360,11 +361,12 @@ int sg_drive_is_open(struct burn_drive * d)
|
|||||||
*/
|
*/
|
||||||
int sg_grab(struct burn_drive *d)
|
int sg_grab(struct burn_drive *d)
|
||||||
{
|
{
|
||||||
int count;
|
|
||||||
struct cam_device *cam;
|
struct cam_device *cam;
|
||||||
|
|
||||||
if(d->cam != NULL)
|
if(d->cam != NULL) {
|
||||||
return 0;
|
d->released = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
cam = cam_open_device(d->devname, O_RDWR);
|
cam = cam_open_device(d->devname, O_RDWR);
|
||||||
if (cam == NULL) {
|
if (cam == NULL) {
|
||||||
@ -515,7 +517,7 @@ int sg_obtain_scsi_adr(char *path, int *bus_no, int *host_no, int *channel_no,
|
|||||||
int *target_no, int *lun_no)
|
int *target_no, int *lun_no)
|
||||||
{
|
{
|
||||||
burn_drive_enumerator_t idx;
|
burn_drive_enumerator_t idx;
|
||||||
int initialize = 1;
|
int initialize = 1, ret;
|
||||||
char buf[64];
|
char buf[64];
|
||||||
struct periph_match_result* result;
|
struct periph_match_result* result;
|
||||||
|
|
||||||
@ -524,7 +526,7 @@ int sg_obtain_scsi_adr(char *path, int *bus_no, int *host_no, int *channel_no,
|
|||||||
initialize = 0;
|
initialize = 0;
|
||||||
if (ret <= 0)
|
if (ret <= 0)
|
||||||
break;
|
break;
|
||||||
if (strcmp(adr, buf) != 0)
|
if (strcmp(path, buf) != 0)
|
||||||
continue;
|
continue;
|
||||||
result = &(idx->ccb.cdm.matches[i].result.periph_result);
|
result = &(idx->ccb.cdm.matches[i].result.periph_result);
|
||||||
*bus_no = result->path_id;
|
*bus_no = result->path_id;
|
||||||
@ -546,7 +548,7 @@ int sg_obtain_scsi_adr(char *path, int *bus_no, int *host_no, int *channel_no,
|
|||||||
int sg_is_enumerable_adr(char* adr)
|
int sg_is_enumerable_adr(char* adr)
|
||||||
{
|
{
|
||||||
burn_drive_enumerator_t idx;
|
burn_drive_enumerator_t idx;
|
||||||
int initialize = 1;
|
int initialize = 1, ret;
|
||||||
char buf[64];
|
char buf[64];
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
|
565
libburn/sg-libcdio.c
Normal file
565
libburn/sg-libcdio.c
Normal file
@ -0,0 +1,565 @@
|
|||||||
|
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
This is the main operating system dependent SCSI part of libburn. It implements
|
||||||
|
the transport level aspects of SCSI control and command i/o.
|
||||||
|
|
||||||
|
Present implementation: GNU libcdio , for X/Open compliant operating systems
|
||||||
|
|
||||||
|
|
||||||
|
PORTING:
|
||||||
|
|
||||||
|
Porting libburn typically will consist of adding a new operating system case
|
||||||
|
to the following switcher files:
|
||||||
|
os.h Operating system specific libburn definitions and declarations.
|
||||||
|
sg.c Operating system dependent transport level modules.
|
||||||
|
and of deriving the following system specific files from existing examples:
|
||||||
|
os-*.h Included by os.h. You will need some general system knowledge
|
||||||
|
about signals and knowledge about the storage object needs of your
|
||||||
|
transport level module sg-*.c.
|
||||||
|
|
||||||
|
sg-*.c This source module. You will need special system knowledge about
|
||||||
|
how to detect all potentially available drives, how to open them,
|
||||||
|
eventually how to exclusively reserve them, how to perform
|
||||||
|
SCSI transactions, how to inquire the (pseudo-)SCSI driver.
|
||||||
|
You will not need to care about CD burning, MMC or other high-level
|
||||||
|
SCSI aspects.
|
||||||
|
|
||||||
|
Said sg-*.c operations are defined by a public function interface, which has
|
||||||
|
to be implemented in a way that provides libburn with the desired services:
|
||||||
|
|
||||||
|
sg_give_next_adr() iterates over the set of potentially useful drive
|
||||||
|
address strings.
|
||||||
|
|
||||||
|
scsi_enumerate_drives() brings all available, not-whitelist-banned, and
|
||||||
|
accessible drives into libburn's list of drives.
|
||||||
|
|
||||||
|
sg_drive_is_open() tells wether libburn has the given drive in use.
|
||||||
|
|
||||||
|
sg_grab() opens the drive for SCSI commands and ensures
|
||||||
|
undisturbed access.
|
||||||
|
|
||||||
|
sg_release() closes a drive opened by sg_grab()
|
||||||
|
|
||||||
|
sg_issue_command() sends a SCSI command to the drive, receives reply,
|
||||||
|
and evaluates wether the command succeeded or shall
|
||||||
|
be retried or finally failed.
|
||||||
|
|
||||||
|
sg_obtain_scsi_adr() tries to obtain SCSI address parameters.
|
||||||
|
|
||||||
|
burn_os_stdio_capacity() estimates the emulated media space of stdio-drives.
|
||||||
|
|
||||||
|
burn_os_open_track_src() opens a disk file in a way that allows best
|
||||||
|
throughput with file reading and/or SCSI write command
|
||||||
|
transmission.
|
||||||
|
|
||||||
|
burn_os_alloc_buffer() allocates a memory area that is suitable for file
|
||||||
|
descriptors issued by burn_os_open_track_src().
|
||||||
|
The buffer size may be rounded up for alignment
|
||||||
|
reasons.
|
||||||
|
|
||||||
|
burn_os_free_buffer() delete a buffer obtained by burn_os_alloc_buffer().
|
||||||
|
|
||||||
|
Porting hints are marked by the text "PORTING:".
|
||||||
|
Send feedback to libburn-hackers@pykix.org .
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/** PORTING : ------- OS dependent headers and definitions ------ */
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#ifdef Libburn_os_has_statvfS
|
||||||
|
#include <sys/statvfs.h>
|
||||||
|
#endif /* Libburn_os_has_stavtfS */
|
||||||
|
|
||||||
|
|
||||||
|
#include <cdio/cdio.h>
|
||||||
|
#include <cdio/mmc.h>
|
||||||
|
|
||||||
|
|
||||||
|
/** PORTING : ------ libburn portable headers and definitions ----- */
|
||||||
|
|
||||||
|
#include "transport.h"
|
||||||
|
#include "drive.h"
|
||||||
|
#include "sg.h"
|
||||||
|
#include "spc.h"
|
||||||
|
/* collides with symbols of <cdio/mmc.h>
|
||||||
|
#include "mmc.h"
|
||||||
|
*/
|
||||||
|
#include "sbc.h"
|
||||||
|
#include "debug.h"
|
||||||
|
#include "toc.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#include "libdax_msgs.h"
|
||||||
|
extern struct libdax_msgs *libdax_messenger;
|
||||||
|
|
||||||
|
|
||||||
|
/* is in portable part of libburn */
|
||||||
|
int burn_drive_is_banned(char *device_address);
|
||||||
|
|
||||||
|
|
||||||
|
/* Whether to log SCSI commands:
|
||||||
|
bit0= log in /tmp/libburn_sg_command_log
|
||||||
|
bit1= log to stderr
|
||||||
|
bit2= flush every line
|
||||||
|
*/
|
||||||
|
extern int burn_sg_log_scsi;
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
/* PORTING: Private functions. Port only if needed by public functions */
|
||||||
|
/* (Public functions are listed below) */
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
|
||||||
|
static int sg_close_drive(struct burn_drive * d)
|
||||||
|
{
|
||||||
|
CdIo_t *p_cdio;
|
||||||
|
|
||||||
|
if (d->p_cdio != NULL) {
|
||||||
|
p_cdio = (CdIo_t *) d->p_cdio;
|
||||||
|
cdio_destroy(p_cdio);
|
||||||
|
d->p_cdio = NULL;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------------- */
|
||||||
|
/* PORTING: Private functions which contain publicly needed functionality. */
|
||||||
|
/* Their portable part must be performed. So it is probably best */
|
||||||
|
/* to replace the non-portable part and to call these functions */
|
||||||
|
/* in your port, too. */
|
||||||
|
/* ----------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
/** Wraps a detected drive into libburn structures and hands it over to
|
||||||
|
libburn drive list.
|
||||||
|
*/
|
||||||
|
static void enumerate_common(char *fname, int bus_no, int host_no,
|
||||||
|
int channel_no, int target_no, int lun_no)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct burn_drive out;
|
||||||
|
|
||||||
|
/* General libburn drive setup */
|
||||||
|
burn_setup_drive(&out, fname);
|
||||||
|
|
||||||
|
/* This transport adapter uses SCSI-family commands and models
|
||||||
|
(seems the adapter would know better than its boss, if ever) */
|
||||||
|
ret = burn_scsi_setup_drive(&out, bus_no, host_no, channel_no,
|
||||||
|
target_no, lun_no, 0);
|
||||||
|
if (ret <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* PORTING: ------------------- non portable part --------------- */
|
||||||
|
|
||||||
|
/* Transport adapter is libcdio */
|
||||||
|
/* Adapter specific handles and data */
|
||||||
|
out.p_cdio = NULL;
|
||||||
|
|
||||||
|
/* PORTING: ---------------- end of non portable part ------------ */
|
||||||
|
|
||||||
|
/* Adapter specific functions with standardized names */
|
||||||
|
out.grab = sg_grab;
|
||||||
|
out.release = sg_release;
|
||||||
|
out.drive_is_open = sg_drive_is_open;
|
||||||
|
out.issue_command = sg_issue_command;
|
||||||
|
/* Finally register drive and inquire drive information */
|
||||||
|
burn_drive_finish_enum(&out);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
/* PORTING: Public functions. These MUST be ported. */
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
|
||||||
|
/** Returns the next index number and the next enumerated drive address.
|
||||||
|
The enumeration has to cover all available and accessible drives. It is
|
||||||
|
allowed to return addresses of drives which are not available but under
|
||||||
|
some (even exotic) circumstances could be available. It is on the other
|
||||||
|
hand allowed, only to hand out addresses which can really be used right
|
||||||
|
in the moment of this call. (This implementation chooses the latter.)
|
||||||
|
@param idx An opaque handle. Make no own theories about it.
|
||||||
|
@param adr Takes the reply
|
||||||
|
@param adr_size Gives maximum size of reply including final 0
|
||||||
|
@param initialize 1 = start new,
|
||||||
|
0 = continue, use no other values for now
|
||||||
|
-1 = finish
|
||||||
|
@return 1 = reply is a valid address , 0 = no further address available
|
||||||
|
-1 = severe error (e.g. adr_size too small)
|
||||||
|
*/
|
||||||
|
int sg_give_next_adr(burn_drive_enumerator_t *idx,
|
||||||
|
char adr[], int adr_size, int initialize)
|
||||||
|
{
|
||||||
|
if (initialize == 1) {
|
||||||
|
idx->pos = idx->ppsz_cd_drives =
|
||||||
|
cdio_get_devices(DRIVER_DEVICE);
|
||||||
|
if (idx->ppsz_cd_drives == NULL)
|
||||||
|
return 0;
|
||||||
|
} else if (initialize == -1) {
|
||||||
|
if (*(idx->ppsz_cd_drives) != NULL)
|
||||||
|
cdio_free_device_list(idx->ppsz_cd_drives);
|
||||||
|
idx->ppsz_cd_drives = NULL;
|
||||||
|
}
|
||||||
|
if (idx->pos == NULL)
|
||||||
|
return 0;
|
||||||
|
if (*(idx->pos) == NULL)
|
||||||
|
return 0;
|
||||||
|
if (strlen(*(idx->pos)) >= adr_size)
|
||||||
|
return -1;
|
||||||
|
strcpy(adr, *(idx->pos));
|
||||||
|
(idx->pos)++;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Brings all available, not-whitelist-banned, and accessible drives into
|
||||||
|
libburn's list of drives.
|
||||||
|
*/
|
||||||
|
int scsi_enumerate_drives(void)
|
||||||
|
{
|
||||||
|
burn_drive_enumerator_t idx;
|
||||||
|
int initialize = 1, ret;
|
||||||
|
char buf[64];
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
ret = sg_give_next_adr(&idx, buf, sizeof(buf), initialize);
|
||||||
|
initialize = 0;
|
||||||
|
if (ret <= 0)
|
||||||
|
break;
|
||||||
|
if (burn_drive_is_banned(buf))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* >>> try to obtain bus,host,channel,target,lun */;
|
||||||
|
|
||||||
|
enumerate_common(buf, -1, -1, -1, -1, -1);
|
||||||
|
}
|
||||||
|
sg_give_next_adr(&idx, buf, sizeof(buf), -1);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Tells wether libburn has the given drive in use or exclusively reserved.
|
||||||
|
If it is "open" then libburn will eventually call sg_release() on it when
|
||||||
|
it is time to give up usage resp. reservation.
|
||||||
|
*/
|
||||||
|
/** Published as burn_drive.drive_is_open() */
|
||||||
|
int sg_drive_is_open(struct burn_drive * d)
|
||||||
|
{
|
||||||
|
return (d->p_cdio != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Opens the drive for SCSI commands and - if burn activities are prone
|
||||||
|
to external interference on your system - obtains an exclusive access lock
|
||||||
|
on the drive. (Note: this is not physical tray locking.)
|
||||||
|
A drive that has been opened with sg_grab() will eventually be handed
|
||||||
|
over to sg_release() for closing and unreserving.
|
||||||
|
*/
|
||||||
|
int sg_grab(struct burn_drive *d)
|
||||||
|
{
|
||||||
|
CdIo_t *p_cdio;
|
||||||
|
|
||||||
|
if(d->p_cdio != NULL) {
|
||||||
|
d->released = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
p_cdio = cdio_open(d->devname, DRIVER_DEVICE);
|
||||||
|
|
||||||
|
if (p_cdio == NULL) {
|
||||||
|
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||||
|
0x00020003,
|
||||||
|
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||||
|
"Could not grab drive", 0/*os_errno*/, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
d->p_cdio = p_cdio;
|
||||||
|
d->released = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** PORTING: Is mainly about the call to sg_close_drive() and whether it
|
||||||
|
implements the demanded functionality.
|
||||||
|
*/
|
||||||
|
/** Gives up the drive for SCSI commands and releases eventual access locks.
|
||||||
|
(Note: this is not physical tray locking.)
|
||||||
|
*/
|
||||||
|
int sg_release(struct burn_drive *d)
|
||||||
|
{
|
||||||
|
if (d->p_cdio == NULL) {
|
||||||
|
burn_print(1, "release an ungrabbed drive. die\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
sg_close_drive(d);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Sends a SCSI command to the drive, receives reply and evaluates wether
|
||||||
|
the command succeeded or shall be retried or finally failed.
|
||||||
|
Returned SCSI errors shall not lead to a return value indicating failure.
|
||||||
|
The callers get notified by c->error. An SCSI failure which leads not to
|
||||||
|
a retry shall be notified via scsi_notify_error().
|
||||||
|
The Libburn_log_sg_commandS facility might be of help when problems with
|
||||||
|
a drive have to be examined. It shall stay disabled for normal use.
|
||||||
|
@return: 1 success , <=0 failure
|
||||||
|
*/
|
||||||
|
int sg_issue_command(struct burn_drive *d, struct command *c)
|
||||||
|
{
|
||||||
|
int i_status;
|
||||||
|
unsigned int dxfer_len;
|
||||||
|
static FILE *fp = NULL;
|
||||||
|
mmc_cdb_t cdb = {{0, }};
|
||||||
|
cdio_mmc_direction_t e_direction;
|
||||||
|
CdIo_t *p_cdio;
|
||||||
|
char msg[160];
|
||||||
|
|
||||||
|
c->error = 0;
|
||||||
|
if (d->p_cdio == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
p_cdio = (CdIo_t *) d->p_cdio;
|
||||||
|
if (burn_sg_log_scsi & 1) {
|
||||||
|
if (fp == NULL) {
|
||||||
|
fp= fopen("/tmp/libburn_sg_command_log", "a");
|
||||||
|
fprintf(fp,
|
||||||
|
"\n-----------------------------------------\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (burn_sg_log_scsi & 3)
|
||||||
|
scsi_log_cmd(c,fp,0);
|
||||||
|
|
||||||
|
memcpy(cdb.field, c->opcode, c->oplen);
|
||||||
|
if (c->dir == TO_DRIVE) {
|
||||||
|
dxfer_len = c->page->bytes;
|
||||||
|
e_direction = SCSI_MMC_DATA_WRITE;
|
||||||
|
} else if (c->dir == FROM_DRIVE) {
|
||||||
|
if (c->dxfer_len >= 0)
|
||||||
|
dxfer_len = c->dxfer_len;
|
||||||
|
else
|
||||||
|
dxfer_len = BUFFER_SIZE;
|
||||||
|
e_direction = SCSI_MMC_DATA_READ;
|
||||||
|
/* touch page so we can use valgrind */
|
||||||
|
memset(c->page->data, 0, BUFFER_SIZE);
|
||||||
|
} else {
|
||||||
|
dxfer_len = 0;
|
||||||
|
#ifdef SCSI_MMC_HAS_DIR_NONE
|
||||||
|
e_direction = SCSI_MMC_DATA_NONE;
|
||||||
|
#else
|
||||||
|
e_direction = SCSI_MMC_DATA_READ;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* >>> longer timeout , sg-linux has 200 s */
|
||||||
|
|
||||||
|
/* >>> retry-loop */
|
||||||
|
|
||||||
|
i_status = mmc_run_cmd(p_cdio, 10000, &cdb, e_direction,
|
||||||
|
dxfer_len, c->page->data);
|
||||||
|
|
||||||
|
if (i_status == 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* >>> One would need to get info about the nature of failure
|
||||||
|
SCSI SK,ASC,ASCQ would be nice.
|
||||||
|
One would need to distinguish between drive error and
|
||||||
|
transport error.
|
||||||
|
*/;
|
||||||
|
|
||||||
|
/* This is for failure of the transport mechanism itself:
|
||||||
|
|
||||||
|
libdax_msgs_submit(libdax_messenger,
|
||||||
|
d->global_index, 0x0002010c,
|
||||||
|
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
||||||
|
"Failed to transfer command to drive",
|
||||||
|
errno, 0);
|
||||||
|
sg_close_drive(d);
|
||||||
|
d->released = 1;
|
||||||
|
d->busy = BURN_DRIVE_IDLE;
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* >>> end retry-loop */
|
||||||
|
|
||||||
|
|
||||||
|
if (c->opcode[0] != 0x00) {
|
||||||
|
sprintf(msg, "SCSI command %2.2Xh failed",
|
||||||
|
(unsigned int) c->opcode[0]);
|
||||||
|
libdax_msgs_submit(libdax_messenger,
|
||||||
|
d->global_index, 0x0002010f,
|
||||||
|
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
|
||||||
|
msg, errno, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 2 04 00 LOGICAL UNIT NOT READY, CAUSE NOT REPORTABLE */
|
||||||
|
c->sense[2] = 0x02;
|
||||||
|
c->sense[12] = 0x04;
|
||||||
|
c->sense[13] = 0x00;
|
||||||
|
|
||||||
|
c->error = 1;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Tries to obtain SCSI address parameters.
|
||||||
|
@return 1 is success , 0 is failure
|
||||||
|
*/
|
||||||
|
int sg_obtain_scsi_adr(char *path, int *bus_no, int *host_no, int *channel_no,
|
||||||
|
int *target_no, int *lun_no)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* >>> any chance to get them from libcdio ? */;
|
||||||
|
|
||||||
|
*bus_no = *host_no = *channel_no = *target_no = *lun_no = -1;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Tells wether a text is a persistent address as listed by the enumeration
|
||||||
|
functions.
|
||||||
|
*/
|
||||||
|
int sg_is_enumerable_adr(char* adr)
|
||||||
|
{
|
||||||
|
burn_drive_enumerator_t idx;
|
||||||
|
int initialize = 1, ret;
|
||||||
|
char buf[64];
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
ret = sg_give_next_adr(&idx, buf, sizeof(buf), initialize);
|
||||||
|
initialize = 0;
|
||||||
|
if (ret <= 0)
|
||||||
|
break;
|
||||||
|
if (strcmp(adr, buf) == 0) {
|
||||||
|
sg_give_next_adr(&idx, buf, sizeof(buf), -1);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sg_give_next_adr(&idx, buf, sizeof(buf), -1);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Estimate the potential payload capacity of a file address.
|
||||||
|
@param path The address of the file to be examined. If it does not
|
||||||
|
exist yet, then the directory will be inquired.
|
||||||
|
@param bytes The pointed value gets modified, but only if an estimation is
|
||||||
|
possible.
|
||||||
|
@return -2 = cannot perform necessary operations on file object
|
||||||
|
-1 = neither path nor dirname of path exist
|
||||||
|
0 = could not estimate size capacity of file object
|
||||||
|
1 = estimation has been made, bytes was set
|
||||||
|
*/
|
||||||
|
int burn_os_stdio_capacity(char *path, off_t *bytes)
|
||||||
|
{
|
||||||
|
struct stat stbuf;
|
||||||
|
|
||||||
|
#ifdef Libburn_os_has_statvfS
|
||||||
|
struct statvfs vfsbuf;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
char testpath[4096], *cpt;
|
||||||
|
long blocks;
|
||||||
|
off_t add_size = 0;
|
||||||
|
|
||||||
|
testpath[0] = 0;
|
||||||
|
blocks = *bytes / 512;
|
||||||
|
if (stat(path, &stbuf) == -1) {
|
||||||
|
strcpy(testpath, path);
|
||||||
|
cpt = strrchr(testpath, '/');
|
||||||
|
if(cpt == NULL)
|
||||||
|
strcpy(testpath, ".");
|
||||||
|
else if(cpt == testpath)
|
||||||
|
testpath[1] = 0;
|
||||||
|
else
|
||||||
|
*cpt = 0;
|
||||||
|
if (stat(testpath, &stbuf) == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
#ifdef Libburn_if_this_was_linuX
|
||||||
|
|
||||||
|
} else if(S_ISBLK(stbuf.st_mode)) {
|
||||||
|
fd = open(path, open_mode);
|
||||||
|
if (fd == -1)
|
||||||
|
return -2;
|
||||||
|
ret = ioctl(fd, BLKGETSIZE, &blocks);
|
||||||
|
close(fd);
|
||||||
|
if (ret == -1)
|
||||||
|
return -2;
|
||||||
|
*bytes = ((off_t) blocks) * (off_t) 512;
|
||||||
|
|
||||||
|
#endif /* Libburn_if_this_was_linuX */
|
||||||
|
|
||||||
|
} else if(S_ISREG(stbuf.st_mode)) {
|
||||||
|
add_size = stbuf.st_blocks * (off_t) 512;
|
||||||
|
strcpy(testpath, path);
|
||||||
|
} else
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (testpath[0]) {
|
||||||
|
|
||||||
|
#ifdef Libburn_os_has_statvfS
|
||||||
|
|
||||||
|
if (statvfs(testpath, &vfsbuf) == -1)
|
||||||
|
return -2;
|
||||||
|
*bytes = add_size + ((off_t) vfsbuf.f_bsize) *
|
||||||
|
(off_t) vfsbuf.f_bavail;
|
||||||
|
|
||||||
|
#else /* Libburn_os_has_statvfS */
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
#endif /* ! Libburn_os_has_stavtfS */
|
||||||
|
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ts A91122 : an interface to open(O_DIRECT) or similar OS tricks. */
|
||||||
|
|
||||||
|
#ifdef Libburn_read_o_direcT
|
||||||
|
|
||||||
|
/* No special O_DIRECT-like precautions are implemented here */
|
||||||
|
|
||||||
|
#endif /* Libburn_read_o_direcT */
|
||||||
|
|
||||||
|
|
||||||
|
int burn_os_open_track_src(char *path, int open_flags, int flag)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = open(path, open_flags);
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void *burn_os_alloc_buffer(size_t amount, int flag)
|
||||||
|
{
|
||||||
|
void *buf = NULL;
|
||||||
|
|
||||||
|
buf = calloc(1, amount);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int burn_os_free_buffer(void *buffer, size_t amount, int flag)
|
||||||
|
{
|
||||||
|
if (buffer == NULL)
|
||||||
|
return 0;
|
||||||
|
free(buffer);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
@ -5,6 +5,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef Libburn_use_libcdiO
|
||||||
|
|
||||||
|
#include "sg-libcdio.c"
|
||||||
|
|
||||||
|
#else
|
||||||
#ifdef __FreeBSD__
|
#ifdef __FreeBSD__
|
||||||
|
|
||||||
#include "sg-freebsd.c"
|
#include "sg-freebsd.c"
|
||||||
@ -38,4 +43,5 @@ static int intentional_compiler_warning(void)
|
|||||||
|
|
||||||
#endif /* ! __linux */
|
#endif /* ! __linux */
|
||||||
#endif /* ! __FreeBSD__ */
|
#endif /* ! __FreeBSD__ */
|
||||||
|
#endif /* ! Libburn_use_libcdiO */
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user