Made portability clarifications
This commit is contained in:
parent
595b877a24
commit
13641fcbae
@ -1 +1 @@
|
|||||||
#define Cdrskin_timestamP "2006.11.15.091329"
|
#define Cdrskin_timestamP "2006.11.15.170927"
|
||||||
|
@ -52,7 +52,7 @@ void burn_drive_free(struct burn_drive *d)
|
|||||||
return;
|
return;
|
||||||
/* ts A60822 : close open fds before forgetting them */
|
/* ts A60822 : close open fds before forgetting them */
|
||||||
if (burn_drive_is_open(d))
|
if (burn_drive_is_open(d))
|
||||||
sg_close_drive(d);
|
d->release(d);
|
||||||
free((void *) d->idata);
|
free((void *) d->idata);
|
||||||
free((void *) d->mdata);
|
free((void *) d->mdata);
|
||||||
if(d->toc_entry != NULL)
|
if(d->toc_entry != NULL)
|
||||||
@ -578,8 +578,10 @@ int burn_drive_scan_sync(struct burn_drive_info *drives[],
|
|||||||
#endif /* 0 */
|
#endif /* 0 */
|
||||||
|
|
||||||
/* refresh the lib's drives */
|
/* refresh the lib's drives */
|
||||||
sg_enumerate();
|
|
||||||
ata_enumerate();
|
/* ts A61115 : formerly sg_enumerate(); ata_enumerate(); */
|
||||||
|
scsi_enumerate_drives();
|
||||||
|
|
||||||
count = burn_drive_count();
|
count = burn_drive_count();
|
||||||
if (count)
|
if (count)
|
||||||
*drives =
|
*drives =
|
||||||
|
541
libburn/sg-freebsd-port.c
Normal file
541
libburn/sg-freebsd-port.c
Normal file
@ -0,0 +1,541 @@
|
|||||||
|
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
||||||
|
|
||||||
|
/*
|
||||||
|
This is the operating system dependent part of libburn. It implements the
|
||||||
|
transport level aspects of SCSI control and command i/o.
|
||||||
|
|
||||||
|
Present implementation: FreeBSD CAM (untested)
|
||||||
|
|
||||||
|
PORTING:
|
||||||
|
|
||||||
|
There are public functions, used by other parts of libburn, which have 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.
|
||||||
|
|
||||||
|
|
||||||
|
Porting hints are marked by the text "PORTING:".
|
||||||
|
Send feedback to libburn-hackers@pykix.org .
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/** PORTING : ------- OS dependent headers and definitions ------ */
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/poll.h>
|
||||||
|
#include <camlib.h>
|
||||||
|
#include <cam/scsi/scsi_message.h>
|
||||||
|
#include <cam/scsi/scsi_pass.h>
|
||||||
|
|
||||||
|
#include <err.h> /* XXX */
|
||||||
|
|
||||||
|
|
||||||
|
/** PORTING : ------ libburn portable headers and definitions ----- */
|
||||||
|
|
||||||
|
#include "transport.h"
|
||||||
|
#include "drive.h"
|
||||||
|
#include "sg.h"
|
||||||
|
#include "spc.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);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
/* ts A61115: Private functions. Port only if needed by public functions */
|
||||||
|
/* (Public functions are listed below) */
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
|
||||||
|
/* Helper function for scsi_give_next_adr() */
|
||||||
|
static int sg_init_enumerator(burn_drive_enumerator_t *idx)
|
||||||
|
{
|
||||||
|
idx->skip_device = 0;
|
||||||
|
|
||||||
|
if ((idx->fd = open(XPT_DEVICE, O_RDWR)) == -1) {
|
||||||
|
warn("couldn't open %s", XPT_DEVICE);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bzero(&(idx->ccb), sizeof(union ccb));
|
||||||
|
|
||||||
|
idx->ccb.ccb_h.path_id = CAM_XPT_PATH_ID;
|
||||||
|
idx->ccb.ccb_h.target_id = CAM_TARGET_WILDCARD;
|
||||||
|
idx->ccb.ccb_h.target_lun = CAM_LUN_WILDCARD;
|
||||||
|
|
||||||
|
idx->ccb.ccb_h.func_code = XPT_DEV_MATCH;
|
||||||
|
idx->bufsize = sizeof(struct dev_match_result) * 100;
|
||||||
|
idx->ccb.cdm.match_buf_len = idx->bufsize;
|
||||||
|
idx->ccb.cdm.matches = (struct dev_match_result *)malloc(idx->bufsize);
|
||||||
|
if (idx->ccb.cdm.matches == NULL) {
|
||||||
|
warnx("can't malloc memory for matches");
|
||||||
|
close(idx->fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
idx->ccb.cdm.num_matches = 0;
|
||||||
|
idx->i = idx->ccb.cdm.num_matches; /* to trigger buffer load */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We fetch all nodes, since we display most of them in the default
|
||||||
|
* case, and all in the verbose case.
|
||||||
|
*/
|
||||||
|
idx->ccb.cdm.num_patterns = 0;
|
||||||
|
idx->ccb.cdm.pattern_buf_len = 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Helper function for scsi_give_next_adr() */
|
||||||
|
static int sg_next_enumeration_buffer(burn_drive_enumerator_t *idx)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* We do the ioctl multiple times if necessary, in case there are
|
||||||
|
* more than 100 nodes in the EDT.
|
||||||
|
*/
|
||||||
|
if (ioctl(idx->fd, CAMIOCOMMAND, &(idx->ccb)) == -1) {
|
||||||
|
warn("error sending CAMIOCOMMAND ioctl");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((idx->ccb.ccb_h.status != CAM_REQ_CMP)
|
||||||
|
|| ((idx->ccb.cdm.status != CAM_DEV_MATCH_LAST)
|
||||||
|
&& (idx->ccb.cdm.status != CAM_DEV_MATCH_MORE))) {
|
||||||
|
warnx("got CAM error %#x, CDM error %d\n",
|
||||||
|
idx->ccb.ccb_h.status, idx->ccb.cdm.status);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int sg_close_drive(struct burn_drive * d)
|
||||||
|
{
|
||||||
|
if (d->cam != NULL) {
|
||||||
|
cam_close_device(d->cam);
|
||||||
|
d->cam = 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 --------------- */
|
||||||
|
|
||||||
|
/* Operating system adapter is CAM */
|
||||||
|
/* Adapter specific handles and data */
|
||||||
|
out.cam = NULL;
|
||||||
|
/* Adapter specific functions */
|
||||||
|
out.grab = sg_grab;
|
||||||
|
out.release = sg_release;
|
||||||
|
out.drive_is_open = sg_drive_is_open;
|
||||||
|
out.issue_command = sg_issue_command;
|
||||||
|
|
||||||
|
/* PORTING: ---------------- end of non portable part ------------ */
|
||||||
|
|
||||||
|
/* Finally register drive and inquire drive information */
|
||||||
|
burn_drive_finish_enum(&out);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ts A61115 */
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
/* 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)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (initialize == 1) {
|
||||||
|
ret = sg_init_enumerator(idx);
|
||||||
|
if (ret<=0)
|
||||||
|
return ret;
|
||||||
|
} else if (initialize == -1) {
|
||||||
|
if(idx->fd != -1)
|
||||||
|
close(idx->fd);
|
||||||
|
idx->fd = -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
try_item:; /* This spaghetti loop keeps the number of tabs small */
|
||||||
|
|
||||||
|
/* Loop content from old scsi_enumerate_drives() */
|
||||||
|
|
||||||
|
while (idx->i >= idx->ccb.cdm.num_matches) {
|
||||||
|
ret = sg_next_enumeration_buffer(idx);
|
||||||
|
if (ret<=0)
|
||||||
|
return -1;
|
||||||
|
if (!((idx->ccb.ccb_h.status == CAM_REQ_CMP)
|
||||||
|
&& (idx->ccb.cdm.status == CAM_DEV_MATCH_MORE)) )
|
||||||
|
return 0;
|
||||||
|
idx->i = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (idx->ccb.cdm.matches[idx->i].type) {
|
||||||
|
case DEV_MATCH_BUS:
|
||||||
|
break;
|
||||||
|
case DEV_MATCH_DEVICE: {
|
||||||
|
struct device_match_result* result;
|
||||||
|
|
||||||
|
result = &(idx->ccb.cdm.matches[i].result.device_result);
|
||||||
|
if (result->flags & DEV_RESULT_UNCONFIGURED)
|
||||||
|
idx->skip_device = 1;
|
||||||
|
else
|
||||||
|
idx->skip_device = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DEV_MATCH_PERIPH: {
|
||||||
|
struct periph_match_result* result;
|
||||||
|
char buf[64];
|
||||||
|
|
||||||
|
result = &(idx->ccb.cdm.matches[i].result.periph_result);
|
||||||
|
if (idx->skip_device ||
|
||||||
|
strcmp(result->periph_name, "pass") == 0)
|
||||||
|
break;
|
||||||
|
snprintf(buf, sizeof (buf), "/dev/%s%d",
|
||||||
|
result->periph_name, result->unit_number);
|
||||||
|
if(adr_size <= strlen(buf)
|
||||||
|
return -1;
|
||||||
|
strcpy(adr, buf);
|
||||||
|
|
||||||
|
/* Found next enumerable address */
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
/* printf(stderr, "unknown match type\n"); */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
(idx->i)++;
|
||||||
|
goto try_item; /* Regular function exit is return 1 above */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** 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;
|
||||||
|
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;
|
||||||
|
enumerate_common(buf, idx.result->path_id, idx.result->path_id,
|
||||||
|
0, idx.result->target_id,
|
||||||
|
idx.result->target_lun);
|
||||||
|
}
|
||||||
|
sg_give_next_adr(&idx, buf, sizeof(buf), -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->cam != 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)
|
||||||
|
{
|
||||||
|
int count;
|
||||||
|
struct cam_device *cam;
|
||||||
|
|
||||||
|
if(d->cam != NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
cam = cam_open_device(d->devname, O_RDWR);
|
||||||
|
if (cam == 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->cam = cam;
|
||||||
|
fcntl(cam->fd, F_SETOWN, getpid());
|
||||||
|
d->released = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** PORTING: Is mainly about the call to sg_close_drive() and wether 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->cam == 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 done = 0;
|
||||||
|
int err;
|
||||||
|
union ccb *ccb;
|
||||||
|
|
||||||
|
if (d->cam == NULL) {
|
||||||
|
c->error = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->error = 0;
|
||||||
|
|
||||||
|
ccb = cam_getccb(d->cam);
|
||||||
|
cam_fill_csio(&ccb->csio,
|
||||||
|
1, /* retries */
|
||||||
|
NULL, /* cbfncp */
|
||||||
|
CAM_DEV_QFRZDIS, /* flags */
|
||||||
|
MSG_SIMPLE_Q_TAG, /* tag_action */
|
||||||
|
NULL, /* data_ptr */
|
||||||
|
0, /* dxfer_len */
|
||||||
|
sizeof (ccb->csio.sense_data), /* sense_len */
|
||||||
|
0, /* cdb_len */
|
||||||
|
30*1000); /* timeout */
|
||||||
|
switch (c->dir) {
|
||||||
|
case TO_DRIVE:
|
||||||
|
ccb->csio.ccb_h.flags |= CAM_DIR_OUT;
|
||||||
|
break;
|
||||||
|
case FROM_DRIVE:
|
||||||
|
ccb->csio.ccb_h.flags |= CAM_DIR_IN;
|
||||||
|
break;
|
||||||
|
case NO_TRANSFER:
|
||||||
|
ccb->csio.ccb_h.flags |= CAM_DIR_NONE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ccb->csio.cdb_len = c->oplen;
|
||||||
|
memcpy(&ccb->csio.cdb_io.cdb_bytes, &c->opcode, c->oplen);
|
||||||
|
|
||||||
|
memset(&ccb->csio.sense_data, 0, sizeof (ccb->csio.sense_data));
|
||||||
|
|
||||||
|
if (c->page) {
|
||||||
|
ccb->csio.data_ptr = c->page->data;
|
||||||
|
if (c->dir == FROM_DRIVE) {
|
||||||
|
ccb->csio.dxfer_len = BUFFER_SIZE;
|
||||||
|
/* touch page so we can use valgrind */
|
||||||
|
memset(c->page->data, 0, BUFFER_SIZE);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* ts A61115: removed a ssert() */
|
||||||
|
if(c->page->bytes <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ccb->csio.dxfer_len = c->page->bytes;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ccb->csio.data_ptr = NULL;
|
||||||
|
ccb->csio.dxfer_len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
err = cam_send_ccb(d->cam, ccb);
|
||||||
|
if (err == -1) {
|
||||||
|
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);
|
||||||
|
cam_freeccb(ccb);
|
||||||
|
sg_close_drive(d);
|
||||||
|
d->released = 1;
|
||||||
|
d->busy = BURN_DRIVE_IDLE;
|
||||||
|
c->error = 1;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* XXX */
|
||||||
|
memcpy(c->sense, &ccb->csio.sense_data, ccb->csio.sense_len);
|
||||||
|
if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
|
||||||
|
if (!c->retry) {
|
||||||
|
c->error = 1;
|
||||||
|
cam_freeccb(ccb);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
switch (scsi_error(d, c->sense, 0)) {
|
||||||
|
case RETRY:
|
||||||
|
done = 0;
|
||||||
|
break;
|
||||||
|
case FAIL:
|
||||||
|
done = 1;
|
||||||
|
c->error = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
done = 1;
|
||||||
|
}
|
||||||
|
} while (!done);
|
||||||
|
cam_freeccb(ccb);
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
burn_drive_enumerator_t idx;
|
||||||
|
int initialize = 1;
|
||||||
|
char buf[64];
|
||||||
|
struct periph_match_result* result;
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
ret = sg_give_next_adr(&idx, buf, sizeof(buf), initialize);
|
||||||
|
initialize = 0;
|
||||||
|
if (ret <= 0)
|
||||||
|
break;
|
||||||
|
if (strcmp(adr, buf) != 0)
|
||||||
|
continue;
|
||||||
|
result = &(idx->ccb.cdm.matches[i].result.periph_result);
|
||||||
|
*bus_no = result->path_id;
|
||||||
|
*host_no = result->path_id;
|
||||||
|
*channel_no = 0;
|
||||||
|
*target_no = result->target_id
|
||||||
|
*lun_no = result->target_lun;
|
||||||
|
sg_give_next_adr(&idx, buf, sizeof(buf), -1);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
sg_give_next_adr(&idx, buf, sizeof(buf), -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;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
@ -1,19 +1,17 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
||||||
|
|
||||||
|
|
||||||
/* >>> ts A61021 : for testing the new arrangement of code
|
|
||||||
please outcomment these defines : */
|
|
||||||
|
|
||||||
/* Keeps alive old enumerate_common(). New version delegates much work
|
/* Revives old enumerate_common(). New version delegates much work
|
||||||
to methods in drive, mmc, spc, and sbc .
|
to methods in drive, mmc, spc, and sbc .
|
||||||
*/
|
*/
|
||||||
#define Scsi_freebsd_make_own_enumeratE 1
|
#define Scsi_freebsd_make_own_enumeratE 1
|
||||||
|
|
||||||
|
|
||||||
/* Keeps alive old sg_enumerate(). New version delegates most work to
|
/* Revives old scsi_enumerate_drives(). New version delegates most work to
|
||||||
sg_give_next_adr().
|
sg_give_next_adr().
|
||||||
*/
|
*/
|
||||||
#define Scsi_freebsd_old_sg_enumeratE 1
|
#define Scsi_freebsd_old_scsi_enumeratE 1
|
||||||
|
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
@ -59,7 +57,7 @@ int burn_drive_is_banned(char *device_address);
|
|||||||
int mmc_function_spy(char * text);
|
int mmc_function_spy(char * text);
|
||||||
|
|
||||||
|
|
||||||
#ifdef Scsi_freebsd_old_sg_enumeratE
|
#ifdef Scsi_freebsd_old_scsi_enumeratE
|
||||||
|
|
||||||
int sg_give_next_adr(burn_drive_enumerator_t *idx,
|
int sg_give_next_adr(burn_drive_enumerator_t *idx,
|
||||||
char adr[], int adr_size, int initialize)
|
char adr[], int adr_size, int initialize)
|
||||||
@ -78,10 +76,11 @@ int sg_obtain_scsi_adr(char *path, int *bus_no, int *host_no, int *channel_no,
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else /* Scsi_freebsd_old_sg_enumeratE */
|
#else /* Scsi_freebsd_old_scsi_enumeratE */
|
||||||
|
|
||||||
/* ts A61021 : Moved most code from sg_enumerate under sg_give_next_adr() */
|
/* ts A61021 : Moved most code from scsi_enumerate_drives under
|
||||||
/* Some helper functions for sg_give_next_adr() */
|
sg_give_next_adr() */
|
||||||
|
/* Some helper functions for scsi_give_next_adr() */
|
||||||
|
|
||||||
static int sg_init_enumerator(burn_drive_enumerator_t *idx)
|
static int sg_init_enumerator(burn_drive_enumerator_t *idx)
|
||||||
{
|
{
|
||||||
@ -172,7 +171,7 @@ int sg_give_next_adr(burn_drive_enumerator_t *idx,
|
|||||||
|
|
||||||
try_item:; /* This spaghetti loop keeps the number of tabs small */
|
try_item:; /* This spaghetti loop keeps the number of tabs small */
|
||||||
|
|
||||||
/* Loop content from old sg_enumerate() */
|
/* Loop content from old scsi_enumerate_drives() */
|
||||||
|
|
||||||
while (idx->i >= idx->ccb.cdm.num_matches) {
|
while (idx->i >= idx->ccb.cdm.num_matches) {
|
||||||
ret = sg_next_enumeration_buffer(idx);
|
ret = sg_next_enumeration_buffer(idx);
|
||||||
@ -277,7 +276,7 @@ int sg_obtain_scsi_adr(char *path, int *bus_no, int *host_no, int *channel_no,
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* ! Scsi_freebsd_old_sg_enumeratE */
|
#endif /* ! Scsi_freebsd_old_scsi_enumeratE */
|
||||||
|
|
||||||
|
|
||||||
int sg_close_drive(struct burn_drive * d)
|
int sg_close_drive(struct burn_drive * d)
|
||||||
@ -294,20 +293,10 @@ int sg_drive_is_open(struct burn_drive * d)
|
|||||||
return (d->cam != NULL);
|
return (d->cam != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int scsi_enumerate_drives(void)
|
||||||
void ata_enumerate(void)
|
|
||||||
{
|
|
||||||
/* ts A61021: Only a dummy function is needed in FreeBSD */
|
|
||||||
/* The difference between sg and ata should be encapsulated
|
|
||||||
in sg-linux.c */
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void sg_enumerate(void)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
#ifdef Scsi_freebsd_old_sg_enumeratE
|
#ifdef Scsi_freebsd_old_scsi_enumeratE
|
||||||
|
|
||||||
union ccb ccb;
|
union ccb ccb;
|
||||||
int bufsize, fd;
|
int bufsize, fd;
|
||||||
@ -404,7 +393,7 @@ void sg_enumerate(void)
|
|||||||
|
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
#else /* Scsi_freebsd_old_sg_enumeratE */
|
#else /* Scsi_freebsd_old_scsi_enumeratE */
|
||||||
|
|
||||||
burn_drive_enumerator_t idx;
|
burn_drive_enumerator_t idx;
|
||||||
int initialize = 1;
|
int initialize = 1;
|
||||||
@ -423,7 +412,7 @@ void sg_enumerate(void)
|
|||||||
}
|
}
|
||||||
sg_give_next_adr(&idx, buf, sizeof(buf), -1);
|
sg_give_next_adr(&idx, buf, sizeof(buf), -1);
|
||||||
|
|
||||||
#endif /* ! Scsi_freebsd_old_sg_enumeratE */
|
#endif /* ! Scsi_freebsd_old_scsi_enumeratE */
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -706,64 +695,3 @@ int sg_issue_command(struct burn_drive *d, struct command *c)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum response scsi_error(struct burn_drive *d, unsigned char *sense,
|
|
||||||
int senselen)
|
|
||||||
{
|
|
||||||
int key, asc, ascq;
|
|
||||||
|
|
||||||
senselen = senselen;
|
|
||||||
key = sense[2];
|
|
||||||
asc = sense[12];
|
|
||||||
ascq = sense[13];
|
|
||||||
|
|
||||||
burn_print(12, "CONDITION: 0x%x 0x%x 0x%x on %s %s\n",
|
|
||||||
key, asc, ascq, d->idata->vendor, d->idata->product);
|
|
||||||
|
|
||||||
switch (asc) {
|
|
||||||
case 0:
|
|
||||||
burn_print(12, "NO ERROR!\n");
|
|
||||||
return RETRY;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
burn_print(1, "not ready\n");
|
|
||||||
return RETRY;
|
|
||||||
case 4:
|
|
||||||
burn_print(1,
|
|
||||||
"logical unit is in the process of becoming ready\n");
|
|
||||||
return RETRY;
|
|
||||||
case 0x20:
|
|
||||||
if (key == 5)
|
|
||||||
burn_print(1, "bad opcode\n");
|
|
||||||
return FAIL;
|
|
||||||
case 0x21:
|
|
||||||
burn_print(1, "invalid address or something\n");
|
|
||||||
return FAIL;
|
|
||||||
case 0x24:
|
|
||||||
if (key == 5)
|
|
||||||
burn_print(1, "invalid field in cdb\n");
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
return FAIL;
|
|
||||||
case 0x26:
|
|
||||||
if (key == 5)
|
|
||||||
burn_print( 1, "invalid field in parameter list\n" );
|
|
||||||
return FAIL;
|
|
||||||
case 0x28:
|
|
||||||
if (key == 6)
|
|
||||||
burn_print(1,
|
|
||||||
"Not ready to ready change, medium may have changed\n");
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
return RETRY;
|
|
||||||
case 0x3A:
|
|
||||||
burn_print(12, "Medium not present in %s %s\n",
|
|
||||||
d->idata->vendor, d->idata->product);
|
|
||||||
|
|
||||||
d->status = BURN_DISC_EMPTY;
|
|
||||||
return FAIL;
|
|
||||||
}
|
|
||||||
burn_print(1, "unknown failure\n");
|
|
||||||
burn_print(1, "key:0x%x, asc:0x%x, ascq:0x%x\n", key, asc, ascq);
|
|
||||||
return FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -1,7 +1,45 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
||||||
|
|
||||||
/* ts A61010 */
|
/*
|
||||||
/* #include <a ssert.h> */
|
This is the operating system dependent part of libburn. It implements the
|
||||||
|
transport level aspects of SCSI control and command i/o.
|
||||||
|
|
||||||
|
Present implementation: Linux SCSI Generic (sg)
|
||||||
|
|
||||||
|
PORTING:
|
||||||
|
|
||||||
|
There are public functions, used by other parts of libburn, which have 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.
|
||||||
|
|
||||||
|
|
||||||
|
Porting hints are marked by the text "PORTING:".
|
||||||
|
Send feedback to libburn-hackers@pykix.org .
|
||||||
|
|
||||||
|
Hint: You should also look into sg-freebsd-port.c, which is a younger and
|
||||||
|
in some aspects more straightforward implementation of this interface.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/** PORTING : ------- OS dependent headers and definitions ------ */
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@ -10,9 +48,6 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
/* #include <m alloc.h> ts A61013 : not in Linux man 3 malloc */
|
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/poll.h>
|
#include <sys/poll.h>
|
||||||
#include <linux/hdreg.h>
|
#include <linux/hdreg.h>
|
||||||
@ -20,6 +55,9 @@
|
|||||||
#include <scsi/sg.h>
|
#include <scsi/sg.h>
|
||||||
#include <scsi/scsi.h>
|
#include <scsi/scsi.h>
|
||||||
|
|
||||||
|
|
||||||
|
/** PORTING : ------ libburn portable headers and definitions ----- */
|
||||||
|
|
||||||
#include "transport.h"
|
#include "transport.h"
|
||||||
#include "drive.h"
|
#include "drive.h"
|
||||||
#include "sg.h"
|
#include "sg.h"
|
||||||
@ -30,20 +68,24 @@
|
|||||||
#include "toc.h"
|
#include "toc.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
/* kludge! glibc headers don't define all the SCSI stuff that we use! */
|
|
||||||
#ifndef SG_GET_ACCESS_COUNT
|
|
||||||
# define SG_GET_ACCESS_COUNT 0x2289
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "libdax_msgs.h"
|
#include "libdax_msgs.h"
|
||||||
extern struct libdax_msgs *libdax_messenger;
|
extern struct libdax_msgs *libdax_messenger;
|
||||||
|
|
||||||
static void enumerate_common(char *fname, int bus_no, int host_no,
|
|
||||||
int channel_no, int target_no, int lun_no);
|
|
||||||
|
|
||||||
/* ts A51221 */
|
/* ts A51221 */
|
||||||
int burn_drive_is_banned(char *device_address);
|
int burn_drive_is_banned(char *device_address);
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
/* PORTING: Private definitions. Port only if needed by public functions. */
|
||||||
|
/* (Public functions are listed below) */
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
|
||||||
|
static void enumerate_common(char *fname, int bus_no, int host_no,
|
||||||
|
int channel_no, int target_no, int lun_no);
|
||||||
|
|
||||||
|
|
||||||
|
/* >>> ts A61115 : this needs mending. A Linux aspect shows up in cdrskin. */
|
||||||
/* ts A60813 : storage objects are in libburn/init.c
|
/* ts A60813 : storage objects are in libburn/init.c
|
||||||
wether to use O_EXCL
|
wether to use O_EXCL
|
||||||
wether to use O_NOBLOCK with open(2) on devices
|
wether to use O_NOBLOCK with open(2) on devices
|
||||||
@ -58,6 +100,12 @@ extern int burn_sg_open_abort_busy;
|
|||||||
int mmc_function_spy(char * text);
|
int mmc_function_spy(char * text);
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
/* PORTING: Private functions. Port only if needed by public functions */
|
||||||
|
/* (Public functions are listed below) */
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
|
||||||
static int sgio_test(int fd)
|
static int sgio_test(int fd)
|
||||||
{
|
{
|
||||||
unsigned char test_ops[] = { 0, 0, 0, 0, 0, 0 };
|
unsigned char test_ops[] = { 0, 0, 0, 0, 0, 0 };
|
||||||
@ -73,45 +121,8 @@ static int sgio_test(int fd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ts A60925 : ticket 74 */
|
|
||||||
int sg_close_drive_fd(char *fname, int driveno, int *fd, int sorry)
|
|
||||||
{
|
|
||||||
int ret, os_errno, sevno= LIBDAX_MSGS_SEV_DEBUG;
|
|
||||||
char msg[4096+100];
|
|
||||||
|
|
||||||
if(*fd < 0)
|
|
||||||
return(0);
|
|
||||||
ret = close(*fd);
|
|
||||||
*fd = -1337;
|
|
||||||
if(ret != -1)
|
|
||||||
return 1;
|
|
||||||
os_errno= errno;
|
|
||||||
|
|
||||||
if (fname != NULL)
|
|
||||||
sprintf(msg, "Encountered error when closing drive '%s'",
|
|
||||||
fname);
|
|
||||||
else
|
|
||||||
sprintf(msg, "Encountered error when closing drive");
|
|
||||||
|
|
||||||
if (sorry)
|
|
||||||
sevno = LIBDAX_MSGS_SEV_SORRY;
|
|
||||||
libdax_msgs_submit(libdax_messenger, driveno, 0x00020002,
|
|
||||||
sevno, LIBDAX_MSGS_PRIO_HIGH, msg, os_errno, 0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sg_drive_is_open(struct burn_drive * d)
|
|
||||||
{
|
|
||||||
/* a bit more detailed case distinction than needed */
|
|
||||||
if (d->fd == -1337)
|
|
||||||
return 0;
|
|
||||||
if (d->fd < 0)
|
|
||||||
return 0;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ts A60924 */
|
/* ts A60924 */
|
||||||
int sg_handle_busy_device(char *fname, int os_errno)
|
static int sg_handle_busy_device(char *fname, int os_errno)
|
||||||
{
|
{
|
||||||
char msg[4096];
|
char msg[4096];
|
||||||
|
|
||||||
@ -135,87 +146,8 @@ int sg_handle_busy_device(char *fname, int os_errno)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ts A60922 ticket 33 */
|
|
||||||
/** Returns the next index number and the next enumerated drive address.
|
|
||||||
@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)
|
|
||||||
{
|
|
||||||
/* sg.h : typedef int burn_drive_enumerator_t; */
|
|
||||||
static int sg_limit = 32, ata_limit = 26;
|
|
||||||
int baseno = 0;
|
|
||||||
|
|
||||||
if (initialize == -1)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (initialize == 1)
|
|
||||||
*idx = -1;
|
|
||||||
(*idx)++;
|
|
||||||
if (*idx >= sg_limit)
|
|
||||||
goto next_ata;
|
|
||||||
if (adr_size < 10)
|
|
||||||
return -1;
|
|
||||||
sprintf(adr, "/dev/sg%d", *idx);
|
|
||||||
return 1;
|
|
||||||
next_ata:;
|
|
||||||
baseno += sg_limit;
|
|
||||||
if (*idx - baseno >= ata_limit)
|
|
||||||
goto next_nothing;
|
|
||||||
if (adr_size < 9)
|
|
||||||
return -1;
|
|
||||||
sprintf(adr, "/dev/hd%c", 'a' + (*idx - baseno));
|
|
||||||
return 1;
|
|
||||||
next_nothing:;
|
|
||||||
baseno += ata_limit;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sg_is_enumerable_adr(char *adr)
|
|
||||||
{
|
|
||||||
char fname[4096];
|
|
||||||
int i, ret = 0, first = 1;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
ret= sg_give_next_adr(&i, fname, sizeof(fname), first);
|
|
||||||
if(ret <= 0)
|
|
||||||
break;
|
|
||||||
first = 0;
|
|
||||||
if (strcmp(adr, fname) == 0)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
}
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A60926 */
|
/* ts A60926 */
|
||||||
int sg_release_siblings(int sibling_fds[], int *sibling_count)
|
static int sg_open_drive_fd(char *fname, int scan_mode)
|
||||||
{
|
|
||||||
int i;
|
|
||||||
char msg[81];
|
|
||||||
|
|
||||||
for(i= 0; i < *sibling_count; i++)
|
|
||||||
sg_close_drive_fd(NULL, -1, &(sibling_fds[i]), 0);
|
|
||||||
if(*sibling_count > 0) {
|
|
||||||
sprintf(msg, "Closed %d O_EXCL scsi siblings", *sibling_count);
|
|
||||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020007,
|
|
||||||
LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH, msg, 0,0);
|
|
||||||
}
|
|
||||||
*sibling_count = 0;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ts A60926 */
|
|
||||||
int sg_open_drive_fd(char *fname, int scan_mode)
|
|
||||||
{
|
{
|
||||||
int open_mode = O_RDWR, fd;
|
int open_mode = O_RDWR, fd;
|
||||||
char msg[81];
|
char msg[81];
|
||||||
@ -266,8 +198,67 @@ int sg_open_drive_fd(char *fname, int scan_mode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ts A60925 : ticket 74 */
|
||||||
|
static int sg_close_drive_fd(char *fname, int driveno, int *fd, int sorry)
|
||||||
|
{
|
||||||
|
int ret, os_errno, sevno= LIBDAX_MSGS_SEV_DEBUG;
|
||||||
|
char msg[4096+100];
|
||||||
|
|
||||||
|
if(*fd < 0)
|
||||||
|
return(0);
|
||||||
|
ret = close(*fd);
|
||||||
|
*fd = -1337;
|
||||||
|
if(ret != -1)
|
||||||
|
return 1;
|
||||||
|
os_errno= errno;
|
||||||
|
|
||||||
|
if (fname != NULL)
|
||||||
|
sprintf(msg, "Encountered error when closing drive '%s'",
|
||||||
|
fname);
|
||||||
|
else
|
||||||
|
sprintf(msg, "Encountered error when closing drive");
|
||||||
|
|
||||||
|
if (sorry)
|
||||||
|
sevno = LIBDAX_MSGS_SEV_SORRY;
|
||||||
|
libdax_msgs_submit(libdax_messenger, driveno, 0x00020002,
|
||||||
|
sevno, LIBDAX_MSGS_PRIO_HIGH, msg, os_errno, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ts A60926 */
|
/* ts A60926 */
|
||||||
int sg_open_scsi_siblings(char *path, int driveno,
|
static int sg_release_siblings(int sibling_fds[], int *sibling_count)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char msg[81];
|
||||||
|
|
||||||
|
for(i= 0; i < *sibling_count; i++)
|
||||||
|
sg_close_drive_fd(NULL, -1, &(sibling_fds[i]), 0);
|
||||||
|
if(*sibling_count > 0) {
|
||||||
|
sprintf(msg, "Closed %d O_EXCL scsi siblings", *sibling_count);
|
||||||
|
libdax_msgs_submit(libdax_messenger, -1, 0x00020007,
|
||||||
|
LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH, msg, 0,0);
|
||||||
|
}
|
||||||
|
*sibling_count = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ts A60926 */
|
||||||
|
static int sg_close_drive(struct burn_drive *d)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!burn_drive_is_open(d))
|
||||||
|
return 0;
|
||||||
|
sg_release_siblings(d->sibling_fds, &(d->sibling_count));
|
||||||
|
ret = sg_close_drive_fd(d->devname, d->global_index, &(d->fd), 0);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ts A60926 */
|
||||||
|
static int sg_open_scsi_siblings(char *path, int driveno,
|
||||||
int sibling_fds[], int *sibling_count,
|
int sibling_fds[], int *sibling_count,
|
||||||
int host_no, int channel_no, int id_no, int lun_no)
|
int host_no, int channel_no, int id_no, int lun_no)
|
||||||
{
|
{
|
||||||
@ -324,19 +315,9 @@ failed:;
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ts A60926 */
|
/** Speciality of Linux: detect non-SCSI ATAPI (EIDE) which will from
|
||||||
int sg_close_drive(struct burn_drive *d)
|
then on used used via generic SCSI as is done with (emulated) SCSI drives */
|
||||||
{
|
static void ata_enumerate(void)
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!burn_drive_is_open(d))
|
|
||||||
return 0;
|
|
||||||
sg_release_siblings(d->sibling_fds, &(d->sibling_count));
|
|
||||||
ret = sg_close_drive_fd(d->devname, d->global_index, &(d->fd), 0);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ata_enumerate(void)
|
|
||||||
{
|
{
|
||||||
struct hd_driveid tm;
|
struct hd_driveid tm;
|
||||||
int i, fd;
|
int i, fd;
|
||||||
@ -372,7 +353,9 @@ void ata_enumerate(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void sg_enumerate(void)
|
|
||||||
|
/** Detects (probably emulated) SCSI drives */
|
||||||
|
static void sg_enumerate(void)
|
||||||
{
|
{
|
||||||
struct sg_scsi_id sid;
|
struct sg_scsi_id sid;
|
||||||
int i, fd, sibling_fds[LIBBURN_SG_MAX_SIBLINGS], sibling_count= 0, ret;
|
int i, fd, sibling_fds[LIBBURN_SG_MAX_SIBLINGS], sibling_count= 0, ret;
|
||||||
@ -428,6 +411,19 @@ void sg_enumerate(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ts A61115 */
|
||||||
|
/* ----------------------------------------------------------------------- */
|
||||||
|
/* 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.
|
||||||
|
*/
|
||||||
/* ts A60923 - A61005 : introduced new SCSI parameters */
|
/* ts A60923 - A61005 : introduced new SCSI parameters */
|
||||||
/* ts A61021 : moved non os-specific code to spc,sbc,mmc,drive */
|
/* ts A61021 : moved non os-specific code to spc,sbc,mmc,drive */
|
||||||
static void enumerate_common(char *fname, int bus_no, int host_no,
|
static void enumerate_common(char *fname, int bus_no, int host_no,
|
||||||
@ -446,6 +442,8 @@ static void enumerate_common(char *fname, int bus_no, int host_no,
|
|||||||
if (ret<=0)
|
if (ret<=0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* PORTING: ------------------- non portable part --------------- */
|
||||||
|
|
||||||
/* Operating system adapter is Linux Generic SCSI (sg) */
|
/* Operating system adapter is Linux Generic SCSI (sg) */
|
||||||
/* Adapter specific handles and data */
|
/* Adapter specific handles and data */
|
||||||
out.fd = -1337;
|
out.fd = -1337;
|
||||||
@ -458,21 +456,122 @@ static void enumerate_common(char *fname, int bus_no, int host_no,
|
|||||||
out.drive_is_open= sg_drive_is_open;
|
out.drive_is_open= sg_drive_is_open;
|
||||||
out.issue_command = sg_issue_command;
|
out.issue_command = sg_issue_command;
|
||||||
|
|
||||||
|
/* PORTING: ---------------- end of non portable part ------------ */
|
||||||
|
|
||||||
/* Finally register drive and inquire drive information */
|
/* Finally register drive and inquire drive information */
|
||||||
burn_drive_finish_enum(&out);
|
burn_drive_finish_enum(&out);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
we use the sg reference count to decide whether we can use the
|
|
||||||
drive or not.
|
|
||||||
if refcount is not one, drive is open somewhere else.
|
|
||||||
|
|
||||||
ts A60813: this test is too late. O_EXCL is the stronger solution.
|
/* ts A61115 */
|
||||||
After all the test was disabled already in icculus.org/burn CVS.
|
/* ------------------------------------------------------------------------ */
|
||||||
|
/* PORTING: Public functions. These MUST be ported. */
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
|
||||||
|
/** PORTING:
|
||||||
|
In this Linux implementation, this function mirrors the enumeration
|
||||||
|
done in sg_enumerate and ata_enumerate(). It would be better to base those
|
||||||
|
functions on this sg_give_next_adr() but the situation is not inviting.
|
||||||
|
*/
|
||||||
|
/* ts A60922 ticket 33 : called from drive.c */
|
||||||
|
/** 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 former.)
|
||||||
|
@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)
|
||||||
|
{
|
||||||
|
/* sg.h : typedef int burn_drive_enumerator_t; */
|
||||||
|
static int sg_limit = 32, ata_limit = 26;
|
||||||
|
int baseno = 0;
|
||||||
|
|
||||||
|
if (initialize == -1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (initialize == 1)
|
||||||
|
*idx = -1;
|
||||||
|
(*idx)++;
|
||||||
|
if (*idx >= sg_limit)
|
||||||
|
goto next_ata;
|
||||||
|
if (adr_size < 10)
|
||||||
|
return -1;
|
||||||
|
sprintf(adr, "/dev/sg%d", *idx);
|
||||||
|
return 1;
|
||||||
|
next_ata:;
|
||||||
|
baseno += sg_limit;
|
||||||
|
if (*idx - baseno >= ata_limit)
|
||||||
|
goto next_nothing;
|
||||||
|
if (adr_size < 9)
|
||||||
|
return -1;
|
||||||
|
sprintf(adr, "/dev/hd%c", 'a' + (*idx - baseno));
|
||||||
|
return 1;
|
||||||
|
next_nothing:;
|
||||||
|
baseno += ata_limit;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Brings all available, not-whitelist-banned, and accessible drives into
|
||||||
|
libburn's list of drives.
|
||||||
|
*/
|
||||||
|
/** PORTING:
|
||||||
|
If not stricken with an incompletely unified situation like in Linux
|
||||||
|
one would rather implement this by a loop calling sg_give_next_adr().
|
||||||
|
If needed with your sg_give_next_adr() results, do a test for existence
|
||||||
|
and accessability. If burn activities are prone to external interference
|
||||||
|
on your system it is also necessary to obtain exclusive access locks on
|
||||||
|
the drives.
|
||||||
|
Hand over each accepted drive to enumerate_common() resp. its replacement
|
||||||
|
within your port.
|
||||||
|
|
||||||
|
See FreeBSD port sketch sg-freebsd-port.c for such an implementation.
|
||||||
|
*/
|
||||||
|
/* ts A61115: replacing call to sg-implementation internals from drive.c */
|
||||||
|
int scsi_enumerate_drives(void)
|
||||||
|
{
|
||||||
|
sg_enumerate();
|
||||||
|
ata_enumerate();
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
/* a bit more detailed case distinction than needed */
|
||||||
|
if (d->fd == -1337)
|
||||||
|
return 0;
|
||||||
|
if (d->fd < 0)
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** 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)
|
int sg_grab(struct burn_drive *d)
|
||||||
{
|
{
|
||||||
int fd, count, os_errno= 0, ret;
|
int fd, os_errno= 0, ret;
|
||||||
|
|
||||||
/* ts A60813 */
|
/* ts A60813 */
|
||||||
int open_mode = O_RDWR;
|
int open_mode = O_RDWR;
|
||||||
@ -495,12 +594,11 @@ int sg_grab(struct burn_drive *d)
|
|||||||
if(burn_sg_open_o_nonblock)
|
if(burn_sg_open_o_nonblock)
|
||||||
open_mode |= O_NONBLOCK;
|
open_mode |= O_NONBLOCK;
|
||||||
|
|
||||||
/* ts A60813
|
/* ts A60813 - A60822
|
||||||
After enumeration the drive fd is probably still open.
|
After enumeration the drive fd is probably still open.
|
||||||
-1337 is the initial value of burn_drive.fd and the value after
|
-1337 is the initial value of burn_drive.fd and the value after
|
||||||
relase of drive. Unclear why not the official error return
|
relase of drive. Unclear why not the official error return
|
||||||
value -1 of open(2) war used. */
|
value -1 of open(2) war used. */
|
||||||
/* ts A60822: was if(d->fd == -1337) { */
|
|
||||||
if(! burn_drive_is_open(d)) {
|
if(! burn_drive_is_open(d)) {
|
||||||
|
|
||||||
/* ts A60821
|
/* ts A60821
|
||||||
@ -523,49 +621,34 @@ int sg_grab(struct burn_drive *d)
|
|||||||
} else
|
} else
|
||||||
fd= d->fd;
|
fd= d->fd;
|
||||||
|
|
||||||
/* ts A61007 : this is redundant */
|
|
||||||
/* a ssert(fd != -1337); */
|
|
||||||
|
|
||||||
if (fd >= 0) {
|
if (fd >= 0) {
|
||||||
|
d->fd = fd;
|
||||||
/* ts A60814:
|
fcntl(fd, F_SETOWN, getpid());
|
||||||
according to my experiments this test would work now ! */
|
d->released = 0;
|
||||||
|
return 1;
|
||||||
/* ts A60926 : this was disabled */
|
|
||||||
/* Tests with growisofs on kernel 2.4.21 yielded that this
|
|
||||||
does not help against blocking on busy drives.
|
|
||||||
*/
|
|
||||||
/* <<< the old dummy */
|
|
||||||
/* er = ioctl(fd, SG_GET_ACCESS_COUNT, &count);*/
|
|
||||||
count = 1;
|
|
||||||
|
|
||||||
if (1 == count) {
|
|
||||||
d->fd = fd;
|
|
||||||
fcntl(fd, F_SETOWN, getpid());
|
|
||||||
d->released = 0;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
drive_is_in_use:;
|
|
||||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
|
||||||
0x00020003,
|
|
||||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
|
||||||
"Could not grab drive - already in use", 0, 0);
|
|
||||||
sg_close_drive(d);
|
|
||||||
d->fd = -1337;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
libdax_msgs_submit(libdax_messenger, d->global_index, 0x00020003,
|
libdax_msgs_submit(libdax_messenger, d->global_index, 0x00020003,
|
||||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||||
"Could not grab drive", os_errno, 0);
|
"Could not grab drive", os_errno, 0);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
drive_is_in_use:;
|
||||||
|
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||||
|
0x00020003,
|
||||||
|
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||||
|
"Could not grab drive - already in use", 0, 0);
|
||||||
|
sg_close_drive(d);
|
||||||
|
d->fd = -1337;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
non zero return means you still have the drive and it's not
|
|
||||||
in a state to be released? (is that even possible?)
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
/** PORTING: Is mainly about the call to sg_close_drive() and wether 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)
|
int sg_release(struct burn_drive *d)
|
||||||
{
|
{
|
||||||
/* ts A60821
|
/* ts A60821
|
||||||
@ -586,6 +669,15 @@ int sg_release(struct burn_drive *d)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** 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 sg_issue_command(struct burn_drive *d, struct command *c)
|
||||||
{
|
{
|
||||||
int done = 0, no_c_page = 0;
|
int done = 0, no_c_page = 0;
|
||||||
@ -596,7 +688,7 @@ int sg_issue_command(struct burn_drive *d, struct command *c)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef Libburn_log_sg_commandS
|
#ifdef Libburn_log_sg_commandS
|
||||||
/* <<< ts A61030 */
|
/* ts A61030 */
|
||||||
static FILE *fp= NULL;
|
static FILE *fp= NULL;
|
||||||
static int fpcount= 0;
|
static int fpcount= 0;
|
||||||
int i;
|
int i;
|
||||||
@ -610,7 +702,7 @@ int sg_issue_command(struct burn_drive *d, struct command *c)
|
|||||||
mmc_function_spy(buf);
|
mmc_function_spy(buf);
|
||||||
|
|
||||||
#ifdef Libburn_log_sg_commandS
|
#ifdef Libburn_log_sg_commandS
|
||||||
/* <<< ts A61030 */
|
/* ts A61030 */
|
||||||
if(fp==NULL) {
|
if(fp==NULL) {
|
||||||
fp= fopen("/tmp/libburn_sg_command_log","a");
|
fp= fopen("/tmp/libburn_sg_command_log","a");
|
||||||
fprintf(fp,"\n-----------------------------------------\n");
|
fprintf(fp,"\n-----------------------------------------\n");
|
||||||
@ -717,7 +809,6 @@ int sg_issue_command(struct burn_drive *d, struct command *c)
|
|||||||
/* ts A61106 */
|
/* ts A61106 */
|
||||||
ex:;
|
ex:;
|
||||||
if (c->error) {
|
if (c->error) {
|
||||||
/* >>> to become d->notify_error() */
|
|
||||||
scsi_notify_error(d, c, s.sbp, s.sb_len_wr, 0);
|
scsi_notify_error(d, c, s.sbp, s.sb_len_wr, 0);
|
||||||
|
|
||||||
#ifdef Libburn_log_sg_commandS
|
#ifdef Libburn_log_sg_commandS
|
||||||
@ -733,111 +824,8 @@ ex:;
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ts A61030 - A61109 */
|
|
||||||
/* @param flag bit0=do report conditions which are considered not an error */
|
|
||||||
int scsi_notify_error(struct burn_drive *d, struct command *c,
|
|
||||||
unsigned char *sense, int senselen, int flag)
|
|
||||||
{
|
|
||||||
int key= -1, asc= -1, ascq= -1, ret;
|
|
||||||
char msg[160];
|
|
||||||
|
|
||||||
if (d->silent_on_scsi_error)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
if (senselen > 2)
|
|
||||||
key = sense[2];
|
|
||||||
if (senselen > 13) {
|
|
||||||
asc = sense[12];
|
|
||||||
ascq = sense[13];
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!(flag & 1)) {
|
|
||||||
/* SPC : TEST UNIT READY command */
|
|
||||||
if (c->opcode[0] == 0)
|
|
||||||
return 1;
|
|
||||||
/* MMC : READ DISC INFORMATION command */
|
|
||||||
if (c->opcode[0] == 0x51)
|
|
||||||
if (key == 0x2 && asc == 0x3A &&
|
|
||||||
ascq>=0 && ascq <= 0x02) /* MEDIUM NOT PRESENT */
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
sprintf(msg,"SCSI error condition on command %2.2Xh :", c->opcode[0]);
|
|
||||||
if (key>=0)
|
|
||||||
sprintf(msg+strlen(msg), " key=%Xh", key);
|
|
||||||
if (asc>=0)
|
|
||||||
sprintf(msg+strlen(msg), " asc=%2.2Xh", asc);
|
|
||||||
if (ascq>=0)
|
|
||||||
sprintf(msg+strlen(msg), " ascq=%2.2Xh", ascq);
|
|
||||||
ret = libdax_msgs_submit(libdax_messenger, d->global_index, 0x0002010f,
|
|
||||||
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH, msg,0,0);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
enum response scsi_error(struct burn_drive *d, unsigned char *sense,
|
|
||||||
int senselen)
|
|
||||||
{
|
|
||||||
int key, asc, ascq;
|
|
||||||
|
|
||||||
senselen = senselen;
|
|
||||||
key = sense[2];
|
|
||||||
asc = sense[12];
|
|
||||||
ascq = sense[13];
|
|
||||||
|
|
||||||
burn_print(12, "CONDITION: 0x%x 0x%x 0x%x on %s %s\n",
|
|
||||||
key, asc, ascq, d->idata->vendor, d->idata->product);
|
|
||||||
|
|
||||||
switch (asc) {
|
|
||||||
case 0:
|
|
||||||
burn_print(12, "NO ERROR!\n");
|
|
||||||
return RETRY;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
burn_print(1, "not ready\n");
|
|
||||||
return RETRY;
|
|
||||||
case 4:
|
|
||||||
burn_print(1,
|
|
||||||
"logical unit is in the process of becoming ready\n");
|
|
||||||
return RETRY;
|
|
||||||
case 0x20:
|
|
||||||
if (key == 5)
|
|
||||||
burn_print(1, "bad opcode\n");
|
|
||||||
return FAIL;
|
|
||||||
case 0x21:
|
|
||||||
burn_print(1, "invalid address or something\n");
|
|
||||||
return FAIL;
|
|
||||||
case 0x24:
|
|
||||||
if (key == 5)
|
|
||||||
burn_print(1, "invalid field in cdb\n");
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
return FAIL;
|
|
||||||
case 0x26:
|
|
||||||
if ( key == 5 )
|
|
||||||
burn_print( 1, "invalid field in parameter list\n" );
|
|
||||||
return FAIL;
|
|
||||||
case 0x28:
|
|
||||||
if (key == 6)
|
|
||||||
burn_print(1,
|
|
||||||
"Not ready to ready change, medium may have changed\n");
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
return RETRY;
|
|
||||||
case 0x3A:
|
|
||||||
burn_print(12, "Medium not present in %s %s\n",
|
|
||||||
d->idata->vendor, d->idata->product);
|
|
||||||
|
|
||||||
d->status = BURN_DISC_EMPTY;
|
|
||||||
return FAIL;
|
|
||||||
}
|
|
||||||
burn_print(1, "unknown failure\n");
|
|
||||||
burn_print(1, "key:0x%x, asc:0x%x, ascq:0x%x\n", key, asc, ascq);
|
|
||||||
return FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ts A60922 */
|
/* ts A60922 */
|
||||||
/** Try to obtain SCSI address parameters.
|
/** Tries to obtain SCSI address parameters.
|
||||||
@return 1 is success , 0 is failure
|
@return 1 is success , 0 is failure
|
||||||
*/
|
*/
|
||||||
int sg_obtain_scsi_adr(char *path, int *bus_no, int *host_no, int *channel_no,
|
int sg_obtain_scsi_adr(char *path, int *bus_no, int *host_no, int *channel_no,
|
||||||
@ -882,3 +870,27 @@ int sg_obtain_scsi_adr(char *path, int *bus_no, int *host_no, int *channel_no,
|
|||||||
#endif
|
#endif
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ts A60922 ticket 33 : called from drive.c */
|
||||||
|
/** Tells wether a text is a persistent address as listed by the enumeration
|
||||||
|
functions.
|
||||||
|
*/
|
||||||
|
int sg_is_enumerable_adr(char *adr)
|
||||||
|
{
|
||||||
|
char fname[4096];
|
||||||
|
int i, ret = 0, first = 1;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
ret= sg_give_next_adr(&i, fname, sizeof(fname), first);
|
||||||
|
if(ret <= 0)
|
||||||
|
break;
|
||||||
|
first = 0;
|
||||||
|
if (strcmp(adr, fname) == 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
35
libburn/sg.h
35
libburn/sg.h
@ -5,20 +5,14 @@
|
|||||||
|
|
||||||
#ifdef __FreeBSD__
|
#ifdef __FreeBSD__
|
||||||
|
|
||||||
/* >>> To hold all state information of BSD device enumeration
|
/* To hold all state information of BSD device enumeration
|
||||||
which are now local in sg_enumerate() . So that sg_give_next_adr()
|
which are now local in sg_enumerate() . So that sg_give_next_adr()
|
||||||
can work in BSD and sg_enumerate() can use it. */
|
can work in BSD and sg_enumerate() can use it. */
|
||||||
struct burn_drive_enumeration_state {
|
struct burn_drive_enumeration_state {
|
||||||
|
|
||||||
#ifdef Scsi_freebsd_old_sg_enumeratE
|
|
||||||
int dummy;
|
|
||||||
#else
|
|
||||||
union ccb ccb;
|
union ccb ccb;
|
||||||
int bufsize, fd;
|
int bufsize, fd;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
int skip_device;
|
int skip_device;
|
||||||
#endif /* ! Scsi_freebsd_old_sg_enumeratE */
|
|
||||||
|
|
||||||
};
|
};
|
||||||
typedef struct burn_drive_enumeration_state burn_drive_enumerator_t;
|
typedef struct burn_drive_enumeration_state burn_drive_enumerator_t;
|
||||||
|
|
||||||
@ -37,11 +31,6 @@ typedef int burn_drive_enumerator_t;
|
|||||||
struct burn_drive;
|
struct burn_drive;
|
||||||
struct command;
|
struct command;
|
||||||
|
|
||||||
enum response
|
|
||||||
{ RETRY, FAIL };
|
|
||||||
|
|
||||||
/* ts A60925 : ticket 74 */
|
|
||||||
int sg_close_drive_fd(char *fname, int driveno, int *fd, int sorry);
|
|
||||||
|
|
||||||
/* ts A60922 ticket 33 */
|
/* ts A60922 ticket 33 */
|
||||||
int sg_give_next_adr(burn_drive_enumerator_t *enm_context,
|
int sg_give_next_adr(burn_drive_enumerator_t *enm_context,
|
||||||
@ -50,23 +39,13 @@ int sg_is_enumerable_adr(char *adr);
|
|||||||
int sg_obtain_scsi_adr(char *path, int *bus_no, int *host_no, int *channel_no,
|
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);
|
||||||
|
|
||||||
/* ts A60926 : ticket 33 ++ */
|
|
||||||
int sg_open_scsi_siblings(char *fname, int driveno,
|
|
||||||
int sibling_fds[], int *sibling_count,
|
|
||||||
int host_no, int channel_no, int id_no, int lun_no);
|
|
||||||
int sg_release_siblings(int sibling_fds[], int *sibling_count);
|
|
||||||
int sg_close_drive(struct burn_drive *d);
|
|
||||||
|
|
||||||
void sg_enumerate(void);
|
|
||||||
void ata_enumerate(void);
|
|
||||||
int sg_grab(struct burn_drive *);
|
int sg_grab(struct burn_drive *);
|
||||||
int sg_release(struct burn_drive *);
|
int sg_release(struct burn_drive *);
|
||||||
int sg_issue_command(struct burn_drive *, struct command *);
|
int sg_issue_command(struct burn_drive *, struct command *);
|
||||||
enum response scsi_error(struct burn_drive *, unsigned char *, int);
|
|
||||||
|
|
||||||
/* ts A61030 */
|
/* ts A61115 : formerly sg_enumerate();ata_enumerate() */
|
||||||
/* @param flag bit0=do also report TEST UNIT READY failures */
|
int scsi_enumerate_drives(void);
|
||||||
int scsi_notify_error(struct burn_drive *, struct command *c,
|
|
||||||
unsigned char *sense, int senselen, int flag);
|
int sg_drive_is_open(struct burn_drive * d);
|
||||||
|
|
||||||
#endif /* __SG */
|
#endif /* __SG */
|
||||||
|
106
libburn/spc.c
106
libburn/spc.c
@ -523,3 +523,109 @@ int burn_scsi_setup_drive(struct burn_drive *d, int bus_no, int host_no,
|
|||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ts A61115 moved from sg-*.c */
|
||||||
|
enum response scsi_error(struct burn_drive *d, unsigned char *sense,
|
||||||
|
int senselen)
|
||||||
|
{
|
||||||
|
int key, asc, ascq;
|
||||||
|
|
||||||
|
senselen = senselen;
|
||||||
|
key = sense[2];
|
||||||
|
asc = sense[12];
|
||||||
|
ascq = sense[13];
|
||||||
|
|
||||||
|
burn_print(12, "CONDITION: 0x%x 0x%x 0x%x on %s %s\n",
|
||||||
|
key, asc, ascq, d->idata->vendor, d->idata->product);
|
||||||
|
|
||||||
|
switch (asc) {
|
||||||
|
case 0:
|
||||||
|
burn_print(12, "NO ERROR!\n");
|
||||||
|
return RETRY;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
burn_print(1, "not ready\n");
|
||||||
|
return RETRY;
|
||||||
|
case 4:
|
||||||
|
burn_print(1,
|
||||||
|
"logical unit is in the process of becoming ready\n");
|
||||||
|
return RETRY;
|
||||||
|
case 0x20:
|
||||||
|
if (key == 5)
|
||||||
|
burn_print(1, "bad opcode\n");
|
||||||
|
return FAIL;
|
||||||
|
case 0x21:
|
||||||
|
burn_print(1, "invalid address or something\n");
|
||||||
|
return FAIL;
|
||||||
|
case 0x24:
|
||||||
|
if (key == 5)
|
||||||
|
burn_print(1, "invalid field in cdb\n");
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
return FAIL;
|
||||||
|
case 0x26:
|
||||||
|
if ( key == 5 )
|
||||||
|
burn_print( 1, "invalid field in parameter list\n" );
|
||||||
|
return FAIL;
|
||||||
|
case 0x28:
|
||||||
|
if (key == 6)
|
||||||
|
burn_print(1,
|
||||||
|
"Not ready to ready change, medium may have changed\n");
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
return RETRY;
|
||||||
|
case 0x3A:
|
||||||
|
burn_print(12, "Medium not present in %s %s\n",
|
||||||
|
d->idata->vendor, d->idata->product);
|
||||||
|
|
||||||
|
d->status = BURN_DISC_EMPTY;
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
burn_print(1, "unknown failure\n");
|
||||||
|
burn_print(1, "key:0x%x, asc:0x%x, ascq:0x%x\n", key, asc, ascq);
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ts A61030 - A61115 */
|
||||||
|
/* @param flag bit0=do report conditions which are considered not an error */
|
||||||
|
int scsi_notify_error(struct burn_drive *d, struct command *c,
|
||||||
|
unsigned char *sense, int senselen, int flag)
|
||||||
|
{
|
||||||
|
int key= -1, asc= -1, ascq= -1, ret;
|
||||||
|
char msg[160];
|
||||||
|
|
||||||
|
if (d->silent_on_scsi_error)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (senselen > 2)
|
||||||
|
key = sense[2];
|
||||||
|
if (senselen > 13) {
|
||||||
|
asc = sense[12];
|
||||||
|
ascq = sense[13];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!(flag & 1)) {
|
||||||
|
/* SPC : TEST UNIT READY command */
|
||||||
|
if (c->opcode[0] == 0)
|
||||||
|
return 1;
|
||||||
|
/* MMC : READ DISC INFORMATION command */
|
||||||
|
if (c->opcode[0] == 0x51)
|
||||||
|
if (key == 0x2 && asc == 0x3A &&
|
||||||
|
ascq>=0 && ascq <= 0x02) /* MEDIUM NOT PRESENT */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sprintf(msg,"SCSI error condition on command %2.2Xh :", c->opcode[0]);
|
||||||
|
if (key>=0)
|
||||||
|
sprintf(msg+strlen(msg), " key=%Xh", key);
|
||||||
|
if (asc>=0)
|
||||||
|
sprintf(msg+strlen(msg), " asc=%2.2Xh", asc);
|
||||||
|
if (ascq>=0)
|
||||||
|
sprintf(msg+strlen(msg), " ascq=%2.2Xh", ascq);
|
||||||
|
ret = libdax_msgs_submit(libdax_messenger, d->global_index, 0x0002010f,
|
||||||
|
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH, msg,0,0);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -33,5 +33,13 @@ int spc_setup_drive(struct burn_drive *d);
|
|||||||
int burn_scsi_setup_drive(struct burn_drive *d, int bus_no, int host_no,
|
int burn_scsi_setup_drive(struct burn_drive *d, int bus_no, int host_no,
|
||||||
int channel_no, int target_no, int lun_no, int flag);
|
int channel_no, int target_no, int lun_no, int flag);
|
||||||
|
|
||||||
|
/* ts A61115 moved from sg-*.h */
|
||||||
|
enum response { RETRY, FAIL };
|
||||||
|
enum response scsi_error(struct burn_drive *, unsigned char *, int);
|
||||||
|
|
||||||
|
/* ts A61030 */
|
||||||
|
/* @param flag bit0=do report conditions which are considered not an error */
|
||||||
|
int scsi_notify_error(struct burn_drive *, struct command *c,
|
||||||
|
unsigned char *sense, int senselen, int flag);
|
||||||
|
|
||||||
#endif /*__SPC*/
|
#endif /*__SPC*/
|
||||||
|
Loading…
Reference in New Issue
Block a user