Beispiel #1
0
void
get_read_write_speeds(int fd, int *read_speed, int *write_speed,
    intlist_t **speeds, int *n_speeds, intlist_t **speeds_mem)
{
	int page_len;
	uchar_t	p[254];
	int n; /* number of write speed performance descriptor blocks */

	*read_speed = *write_speed = 0;
	*speeds = *speeds_mem = NULL;

	if (!get_mode_page(fd, 0x2A, 0, sizeof (p), p, &page_len)) {
		return;
	}

	if (page_len > 8) {
		*read_speed = GET16(&p[8]);
	}
	if (page_len > 18) {
		*write_speed = GET16(&p[18]);
	}
	if (page_len < 28) {
		printf("MMC-2\n");
		return;
	} else {
		printf("MMC-3\n");
	}

	*write_speed = GET16(&p[28]);

	if (page_len < 30) {
		return;
	}

	/* retrieve speed list */
	n = GET16(&p[30]);
	n = min(n, (sizeof (p) - 32) / 4);

	get_write_speeds(&p[32], n, speeds, n_speeds, speeds_mem);

	if (*speeds != NULL) {
		*write_speed = max(*write_speed, (*speeds)[0].val);
	}
}
Beispiel #2
0
/*
 * Get current Read or Write Speed from Mode Page 0x2a.
 *
 * Use the size of the Page to determine which Multimedia Command
 * set (MMC) is present.  Based on the MMC version, get the
 * specified Read/Write Speed.
 *
 * Note that some MMC versions do not necessarily support a
 * (current) Read or Write Speed.  As a result, this function
 * _can_ return a value of zero.
 *
 * The newer standards (reserve and) mark the field(s) as Obsolete,
 * yet many vendors populate the Obsolete fields with valid values
 * (assumedly for backward compatibility).  This is important, as
 * a command like GET PERFORMANCE cannot return _the_ speed; it can
 * only return a Logical-Block-Address-dependent (LBA) speed.  Such
 * values can vary widely between the innermost and outermost Track.
 * Mode Page 0x2a is the best solution identifying "the current
 * (nominal) speed".
 */
static uint16_t
cd_speed_get(cd_device *dev, int cmd)
{
	uchar_t		*mp2a;
	uint16_t	rate = 0;
	int		offset;
	uint_t		buflen = 254;

	/*
	 * Allocate a buffer acceptably larger than any nominal
	 * Page for Page Code 0x2A.
	 */
	mp2a = (uchar_t *)my_zalloc(buflen);
	if (get_mode_page(dev->d_fd, 0x2A, 0, buflen, mp2a) == 0)
		goto end;

	/* Determine MMC version based on 'Page Length' field */
	switch (mp2a[1]) {
	case 0x14:  /* MMC-1 */
		if (debug)
			(void) printf("Mode Page 2A: MMC-1\n");

		offset = (cmd == GET_READ_SPEED) ? 14 : 20;
		rate = read_scsi16(&mp2a[offset]);
		break;


	case 0x18: /* MMC-2 */
		if (debug)
			(void) printf("Mode Page 2A: MMC-2;"
			    " Read and Write Speeds are "
			    "obsolete\n");

		/* see if "Obsolete" values are valid: */
		offset = (cmd == GET_READ_SPEED) ? 14 : 20;
		rate = read_scsi16(&mp2a[offset]);
		break;

	default: /* MMC-3 or newer */
		if (debug)
			(void) printf("Mode Page 2A: MMC-3 or"
			    " newer; Read Speed is obsolete.\n");

		if (cmd == GET_READ_SPEED) {
			/* this is Obsolete, but try it */
			offset = 14;
			rate = read_scsi16(&mp2a[offset]);
		} else {
			/* Write Speed is not obsolete */
			offset = 28;
			rate = read_scsi16(&mp2a[offset]);

			if (rate == 0) {
				/*
				 * then try an Obsolete field
				 * (but this shouldn't happen!)
				 */
				offset = 20;
				rate = read_scsi16(&mp2a[offset]);
			}
		}
		break;
	}
end:
	free(mp2a);

	if (debug)
		(void) printf("cd_speed_get: %s Speed is "
		    "%uX\n", (cmd == GET_READ_SPEED) ?
		    "Read" : "Write", cdrw_bandwidth_to_x(rate));
	return (rate);
}
Beispiel #3
0
/*
 * Set page code 5 for TAO mode.
 */
int
prepare_for_write(cd_device *dev, int track_mode, int test_write,
    int keep_disc_open)
{
	uchar_t *buf;
	int no_err;
	int reset_device;

	if ((write_mode == DAO_MODE) && keep_disc_open) {
		(void) printf(gettext(
		    "Multi-session is not supported on DVD media\n"));
		exit(1);
	}

	if ((write_mode == DAO_MODE) && debug) {
		(void) printf("Preparing to write in DAO\n");
	}

	(void) start_stop(dev->d_fd, 1);
	/* Some drives do not support this command but still do it */
	(void) rezero_unit(dev->d_fd);

	buf = (uchar_t *)my_zalloc(64);

	no_err = get_mode_page(dev->d_fd, 5, 0, 64, buf);
	if (no_err)
		no_err = ((buf[1] + 2) > 64) ? 0 : 1;
	/*
	 * If the device is already in simulation mode and again a
	 * simulation is requested, then set the device in non-simulation
	 * 1st and then take it to simulation mode. This will flush any
	 * previous fake state in the drive.
	 */
	if (no_err && test_write && (buf[2] & 0x10)) {
		reset_device = 1;
	} else {
		reset_device = 0;
	}
	if (no_err != 0) {
		buf[0] &= 0x3f;

		/* set TAO or DAO writing mode */
		buf[2] = (write_mode == TAO_MODE)?1:2;

		/* set simulation flag */
		if (test_write && (!reset_device)) {
			buf[2] |= 0x10;
		} else {
			buf[2] &= ~0x10;
		}

		/* Turn on HW buffer underrun protection (BUFE) */
		if (!test_write) {
			buf[2] |= 0x40;
		}

		/* set track mode type */
		if (device_type == CD_RW) {
			buf[3] = track_mode & 0x0f;	/* ctrl nibble */
		} else {
			buf[3] = 5;	/* always 5 for DVD */
		}

		if (keep_disc_open) {
			buf[3] |= 0xc0;		/* Allow more sessions */
		}

		/* Select track type (audio or data) */
		if (track_mode == TRACK_MODE_DATA) {
			buf[4] = 8;		/* 2048 byte sector */
		} else {
			buf[4] = 0;		/* 2352 byte sector */
		}
		buf[7] = buf[8] = 0;

		/* Need to clear these fields for setting into DAO */
		if (write_mode == DAO_MODE)
			buf[5] = buf[15] = 0;

		/* print out mode for detailed log */
		if (debug && verbose) {
			int i;

			(void) printf("setting = [ ");
			for (i = 0; i < 15; i++)
				(void) printf("0x%x ", buf[i]);
			(void) printf("]\n");
		}

		no_err = set_mode_page(dev->d_fd, buf);

		if (no_err && reset_device) {
			/* Turn the test write bit back on */
			buf[2] |= 0x10;
			no_err = set_mode_page(dev->d_fd, buf);
		}

		/*
		 * Since BUFE is the only optional flag we are
		 * setting we will try to turn it off if the command
		 * fails.
		 */
		if (!no_err) {
			/*
			 * Some old drives may not support HW
			 * buffer underrun protection, try again
			 * after turning it off.
			 */
			if (debug)
				(void) printf("Turning off BUFE\n");
			buf[2] &= ~0x40;
			no_err = set_mode_page(dev->d_fd, buf);
		}
	}

	free(buf);
	return (no_err);
}