Example #1
0
int sg_release(struct burn_drive *d)
{
	if (mmc_function_spy(d, "sg_release") <= 0)
		return 0;

	if (d->cam == NULL)
		return 0;

	mmc_function_spy(NULL, "sg_release ----------- closing.");

	sg_close_drive(d);
	d->released = 1;
	return 0;
}
Example #2
0
/* @param flag bit0= asynchronous waiting
*/
int sbc_start_unit_flag(struct burn_drive *d, int flag)
{
	struct command *c;
	int ret;

	c = &(d->casual_command);
	if (mmc_function_spy(d, "start_unit") <= 0)
		return 0;

	scsi_init_command(c, SBC_START_UNIT, sizeof(SBC_START_UNIT));
	c->retry = 1;
	if (d->do_no_immed && (flag & 1))
		c->timeout = 1800 * 1000;
	else
		c->opcode[1] |= (flag & 1); /* ts A70918 : Immed */
	c->dir = NO_TRANSFER;
	d->issue_command(d, c);
	if (c->error)
		return 0;
	if (d->do_no_immed || !(flag & 1))
		return 1;
	/* ts A70918 : asynchronous */
	ret = spc_wait_unit_attention(d, 1800, "START UNIT", 0);
	return ret;
}
Example #3
0
/* ts A90824 : Trying to reduce drive noise */
int sbc_stop_unit(struct burn_drive *d)
{
	struct command *c;
	int ret;

	c = &(d->casual_command);
	if (mmc_function_spy(d, "stop_unit") <= 0)
		return 0;

	scsi_init_command(c, SBC_STOP_UNIT, sizeof(SBC_STOP_UNIT));
	c->retry = 0;
	c->opcode[1] |= 1; /* Immed */
	c->dir = NO_TRANSFER;
	d->issue_command(d, c);
	if (c->error)
		return 0;
	ret = spc_wait_unit_attention(d, 1800, "STOP UNIT", 0);
	d->is_stopped = 1;
	return ret;
}
Example #4
0
int sg_grab(struct burn_drive *d)
{
	struct cam_device *cam;
	char path_string[80];

	if (mmc_function_spy(d, "sg_grab") <= 0)
		return 0;

	if (burn_drive_is_open(d)) {
		d->released = 0;
		return 1;
	}

	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", errno, 0);
		return 0;
	}
	d->cam = cam;
	if (burn_sg_open_o_excl & 63)
		if (sg_lock(d, 0) <= 0)
			return 0;
	fcntl(cam->fd, F_SETOWN, getpid());

	cam_path_string(d->cam, path_string, sizeof(path_string));

#ifdef Libburn_ahci_verbouS
	fprintf(stderr, "libburn_EXPERIMENTAL: CAM path = %s\n", path_string);
#endif

	if (strstr(path_string, ":ahcich") != NULL)
		d->is_ahci = 1;
	else
		d->is_ahci = -1;

	d->released = 0;
	return 1;
}
Example #5
0
void sbc_eject(struct burn_drive *d)
{
	struct command *c;

	c = &(d->casual_command);
	if (mmc_function_spy(d, "eject") <= 0)
		return;

	scsi_init_command(c, SBC_UNLOAD, sizeof(SBC_UNLOAD));
	/* c->opcode[1] |= 1; / * ts A70918 : Immed , ts B00109 : revoked */
	c->page = NULL;
	c->dir = NO_TRANSFER;
	d->issue_command(d, c);
	/* ts A70918 : Wait long. A late eject could surprise or hurt user.
	   ts B00109 : Asynchronous eject revoked, as one cannot reliably
	               distinguish out from unready.
	if (c->error)
		return;
	spc_wait_unit_attention(d, 1800, "STOP UNIT (+ EJECT)", 0);
	*/
}
Example #6
0
void sbc_load(struct burn_drive *d)
{
	struct command *c;

	c = &(d->casual_command);
	if (mmc_function_spy(d, "load") <= 0)
		return;

	scsi_init_command(c, SBC_LOAD, sizeof(SBC_LOAD));
	c->retry = 1;

	/* ts A70921 : Had to revoke Immed because of LG GSA-4082B */
	/* c->opcode[1] |= 1; / * ts A70918 : Immed */

	c->dir = NO_TRANSFER;
	c->timeout = Libburn_mmc_load_timeouT;
	d->issue_command(d, c);
	if (c->error)
		return;
	/* ts A70923 : Needed regardless of Immed bit. Was once 1 minute, now
           5 minutes for loading. If this does not suffice then other commands
	   shall fail righteously. */
	spc_wait_unit_attention(d, 300, "waiting after START UNIT (+ LOAD)",0);
}
Example #7
0
int sg_issue_command(struct burn_drive *d, struct command *c)
{
	int done = 0, err, sense_len = 0, ret, ignore_error, i;
	int cam_pass_err_recover = 0, key, asc, ascq, timeout_ms;
	union ccb *ccb;
	static FILE *fp = NULL;
	time_t start_time;

	mmc_function_spy(NULL, "sg_issue_command");

	c->error = 0;
	memset(c->sense, 0, sizeof(c->sense));

	if (d->cam == NULL)
		return 0;
	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);

	c->error = 0;
	if (c->timeout > 0)
		timeout_ms = c->timeout;
	else
		timeout_ms = 200000;

	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 */
				  timeout_ms);                    /* 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;
	}

#ifdef Libburn_for_freebsd_ahcI
	/* ts B00325 : Advise by Alexander Motin */
        /* Runs well on 8-STABLE (23 Mar 2003)
	   But on 8-RELEASE cam_send_ccb() returns non-zero with errno 6
           on eject. Long lasting TEST UNIT READY cycles break with
           errno 16.
        */
#ifdef Libburn_ahci_style_for_alL
	{
#else
	if (d->is_ahci > 0) {
#endif
		ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
		cam_pass_err_recover = 1;
	}
#endif /* Libburn_for_freebsd_ahcI */

	ccb->csio.cdb_len = c->oplen;
	memcpy(&ccb->csio.cdb_io.cdb_bytes, &c->opcode, c->oplen);
	
	if (c->page) {
		ccb->csio.data_ptr  = c->page->data;
		if (c->dir == FROM_DRIVE) {

			/* ts A90430 : Ticket 148 , by jwehle :
			   "On ... FreeBSD 6.4 which has a usb memory reader in
			    addition to a ATAPI DVD burner sg_issue_command
			    will hang while the SCSI bus is being scanned"
			*/
			if (c->dxfer_len >= 0)
				ccb->csio.dxfer_len = c->dxfer_len;
			else
				ccb->csio.dxfer_len = BUFFER_SIZE;

/* touch page so we can use valgrind */
			memset(c->page->data, 0, BUFFER_SIZE);
		} else {
			ccb->csio.dxfer_len = c->page->bytes;
		}
	} else {
		ccb->csio.data_ptr  = NULL;
		ccb->csio.dxfer_len = 0;
	}

	start_time = time(NULL);
	for (i = 0; !done; i++) {

		memset(&ccb->csio.sense_data, 0, sizeof(ccb->csio.sense_data));
		memset(c->sense, 0, sizeof(c->sense));
		err = cam_send_ccb(d->cam, ccb);

		ignore_error = sense_len = 0;
		/* ts B00325 : CAM_AUTOSNS_VALID advised by Alexander Motin */
		if (ccb->ccb_h.status & CAM_AUTOSNS_VALID) {
			/* ts B00110 */
			/* Better curb sense_len */
			sense_len = ccb->csio.sense_len;
			if (sense_len > (int) sizeof(c->sense))
				sense_len = sizeof(c->sense);
			memcpy(c->sense, &ccb->csio.sense_data, sense_len);
			spc_decode_sense(c->sense, sense_len,
							&key, &asc, &ascq);
			if (sense_len >= 14 && cam_pass_err_recover && key)
				ignore_error = 1;
		}

		if (err == -1 && cam_pass_err_recover && ! ignore_error) {

#ifdef Libburn_ahci_verbouS
			fprintf(stderr, "libburn_EXPERIMENTAL: errno = %d . cam_errbuf = '%s'\n", errno, cam_errbuf);
#endif

			if (errno == ENXIO && c->opcode[0] != 0) {
				/* Operations on empty or ejected tray */
				/* MEDIUM NOT PRESENT */

#ifdef Libburn_ahci_verbouS
				fprintf(stderr, "libburn_EXPERIMENTAL: Emulating [2,3A,00] MEDIUM NOT PRESENT\n");
#endif

				c->sense[0] = 0x70; /*Fixed format sense data*/
				c->sense[2] = 0x02;
				c->sense[12] = 0x3A;
				c->sense[13] = 0x00;
				sense_len = 14;
				ignore_error = 1;
			} else if (c->opcode[0] == 0 && 
					(errno == EBUSY || errno == ENXIO)) {
				/* Timeout of TEST UNIT READY loop */
				/* Inquiries while tray is being loaded */
				/*LOGICAL UNIT NOT READY,CAUSE NOT REPORTABLE*/

#ifdef Libburn_ahci_verbouS
				fprintf(stderr, "libburn_EXPERIMENTAL: Emulating [2,04,00] LOGICAL UNIT NOT READY,CAUSE NOT REPORTABLE\n");
#endif

				c->sense[0] = 0x70; /*Fixed format sense data*/
				c->sense[2] = 0x02;
				c->sense[12] = 0x04;
				c->sense[13] = 0x00;
				sense_len = 14;
				ignore_error = 1;
			} else if (errno == EINVAL) {
				/* Inappropriate MODE SENSE */
				/* INVALID FIELD IN CDB */

#ifdef Libburn_ahci_verbouS
				fprintf(stderr, "libburn_EXPERIMENTAL: Emulating [5,24,00] INVALID FIELD IN CDB\n");
#endif

				c->sense[0] = 0x70; /*Fixed format sense data*/
				c->sense[2] = 0x05;
				c->sense[12] = 0x24;
				c->sense[13] = 0x00;
				sense_len = 14;
				ignore_error = 1;
			}
		}

		if (err == -1 && !ignore_error) {
			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;
			c->error = 1;
			{ret = -1; goto ex;}
		}
		/* XXX */

		if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
			if (sense_len < 14) {
				/*LOGICAL UNIT NOT READY,CAUSE NOT REPORTABLE*/

#ifdef Libburn_ahci_verbouS
				fprintf(stderr, "libburn_EXPERIMENTAL: CAM_STATUS= %d .Emulating [2,04,00] LOGICAL UNIT NOT READY,CAUSE NOT REPORTABLE\n", (ccb->ccb_h.status & CAM_STATUS_MASK));
#endif

				c->sense[0] = 0x70; /*Fixed format sense data*/
				c->sense[2] = 0x02;
				c->sense[12] = 0x04;
				c->sense[13] = 0x00;
				done = 1;
			}

			/* >>> Need own duration time measurement.
			       Then remove bit1 from flag.
			*/
			done = scsi_eval_cmd_outcome(d, c, fp, c->sense,
						sense_len, 0, start_time,
						timeout_ms, i,
						2 | !!ignore_error);
			if (d->cancel)
				done = 1;
		} else {
			done = 1;
		}
	} while (!done);
	ret = 1;
ex:;
	cam_freeccb(ccb);
	return ret;
}


/* ts B00115 */
/* Return 1 if the given path leads to a regular file or a device that can be
   seeked, read and eventually written with 2 kB granularity.
*/
int burn_os_is_2k_seekrw(char *path, int flag)
{
        struct stat stbuf;
#ifdef Libburn_DIOCGMEDIASIZE_ISBLK
	int fd, ret;
	off_t add_size;
#else
	char *spt;
	int i, e;
#endif /* ! Libburn_DIOCGMEDIASIZE_ISBLK */

        if (stat(path, &stbuf) == -1)
                return 0;
        if (S_ISREG(stbuf.st_mode))
                return 1;
	if (!S_ISCHR(stbuf.st_mode))
		return 0;

#ifdef Libburn_DIOCGMEDIASIZE_ISBLK

	/* If it throws no error with DIOCGMEDIASIZE then it is a
	   'block device'
	*/
	fd = open(path, O_RDONLY);
	if (fd == -1)
		return 0;
	ret = ioctl(fd, DIOCGMEDIASIZE, &add_size);
	close(fd);

	return (ret != -1);

#else /* Libburn_DIOCGMEDIASIZE_ISBLK */

	spt = strrchr(path, '/');
	if (spt == NULL)
	        spt = path;
	else
	        spt++;
	e = strlen(spt);
	for (i = strlen(spt) - 1; i > 0; i--)
		if (spt[i] >= '0' && spt[i] <= '9')
			e = i;
	if (strncmp(spt, "da", e) == 0) /* SCSI disk. E.g. USB stick. */
		return 1;
	if (strncmp(spt, "cd", e) == 0) /* SCSI CD drive might be writeable. */
		return 1;
	if (strncmp(spt, "ad", e) == 0) /* IDE hard drive */
		return 1;
	if (strncmp(spt, "acd", e) == 0) /* IDE CD drive might be writeable */
		return 1;
	if (strncmp(spt, "fd", e) == 0) /* Floppy disk */
		return 1;
	if (strncmp(spt, "fla", e) == 0) /* Flash drive */
		return 1;
	return 0;

#endif /* ! Libburn_DIOCGMEDIASIZE_ISBLK */

}


/* ts A70909 */
/** 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 This value gets modified 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;
	struct statvfs vfsbuf;
	char *testpath = NULL, *cpt;
	off_t add_size = 0;
	int fd, ret;

	BURN_ALLOC_MEM(testpath, char, 4096);
	testpath[0] = 0;
	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)
			{ret = -1; goto ex;}

#ifdef Libburn_if_this_was_linuX

	} else if(S_ISBLK(stbuf.st_mode)) {
		int open_mode = O_RDWR, fd, ret;
		long blocks;

		blocks = *bytes / 512;
		if(burn_sg_open_o_excl)
			open_mode |= O_EXCL;
		fd = open(path, open_mode);
		if (fd == -1)
			{ret = -2; goto ex;}
		ret = ioctl(fd, BLKGETSIZE, &blocks);
		close(fd);
		if (ret == -1)
			{ret = -2; goto ex;}
		*bytes = ((off_t) blocks) * (off_t) 512;

#endif /* Libburn_if_this_was_linuX */


	} else if(S_ISCHR(stbuf.st_mode)) {
		fd = open(path, O_RDONLY);
		if (fd == -1)
			{ret = -2; goto ex;}
		ret = ioctl(fd, DIOCGMEDIASIZE, &add_size);
		close(fd);
		if (ret == -1)
			{ret = -2; goto ex;}
		*bytes = add_size;
	} else if(S_ISREG(stbuf.st_mode)) {
		add_size = stbuf.st_blocks * (off_t) 512;
		strcpy(testpath, path);
	} else
		{ret = 0; goto ex;}

	if (testpath[0]) {	
		if (statvfs(testpath, &vfsbuf) == -1)
			{ret = -2; goto ex;}
		*bytes = add_size + ((off_t) vfsbuf.f_frsize) *
						(off_t) vfsbuf.f_bavail;
	}
	ret = 1;
ex:
	BURN_FREE_MEM(testpath);
	return ret;
}


/* 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;
}
Example #8
0
/* ts A61021: The old version which mixes SCSI and operating system adapter
*/
static void enumerate_common(char *fname, int bus_no, int host_no,
			     int channel_no, int target_no, int lun_no)
{
	struct burn_drive *t;
	struct burn_drive out;

	/* ts A60923 */
	out.bus_no = bus_no;
	out.host = host_no;
	out.id = target_no;
	out.channel = channel_no;
	out.lun = lun_no;

	out.devname = strdup(fname);

	out.cam = NULL;
	out.lock_fd = -1;
	out.is_ahci = 0;

	out.start_lba= -2000000000;
	out.end_lba= -2000000000;
	out.read_atip = mmc_read_atip;

	out.grab = sg_grab;
	out.release = sg_release;
	out.drive_is_open= sg_drive_is_open;
	out.issue_command = sg_issue_command;
	out.getcaps = spc_getcaps;
	out.released = 1;
	out.status = BURN_DISC_UNREADY;

	out.eject = sbc_eject;
	out.load = sbc_load;
	out.lock = spc_prevent;
	out.unlock = spc_allow;
	out.read_disc_info = spc_sense_write_params;
	out.get_erase_progress = spc_get_erase_progress;
	out.test_unit_ready = spc_test_unit_ready;
	out.probe_write_modes = spc_probe_write_modes;
	out.read_toc = mmc_read_toc;
	out.write = mmc_write;
	out.erase = mmc_erase;
	out.read_cd = mmc_read_cd;
	out.perform_opc = mmc_perform_opc;
	out.set_speed = mmc_set_speed;
	out.send_parameters = spc_select_error_params;
	out.send_write_parameters = spc_select_write_params;
	out.send_cue_sheet = mmc_send_cue_sheet;
	out.sync_cache = mmc_sync_cache;
	out.get_nwa = mmc_get_nwa;
	out.close_disc = mmc_close_disc;
	out.close_session = mmc_close_session;
	out.close_track_session = mmc_close;
	out.read_buffer_capacity = mmc_read_buffer_capacity;
	out.idata = calloc(1, sizeof(struct burn_scsi_inquiry_data));
	out.idata->valid = 0;
	out.mdata = calloc(1, sizeof(struct scsi_mode_data));
	out.mdata->valid = 0;
	if (out.idata == NULL || out.mdata == NULL) {
		libdax_msgs_submit(libdax_messenger, -1, 0x00020108,
			LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
			"Could not allocate new drive object", 0, 0);
		return;
	}
	memset(&out.params, 0, sizeof(struct params));
	t = burn_drive_register(&out);

/* ts A60821
   <<< debug: for tracing calls which might use open drive fds */
	mmc_function_spy(NULL, "enumerate_common : -------- doing grab");

/* try to get the drive info */
	if (t->grab(t)) {
		t->getcaps(t);
		t->unlock(t);
		t->released = 1;
	}

/* ts A60821
   <<< debug: for tracing calls which might use open drive fds */
	mmc_function_spy(NULL, "enumerate_common : ----- would release ");

}