示例#1
0
/*
 * Close session. This will write TOC.
 */
int
finalize(cd_device *dev)
{
	uchar_t *di;
	int count, ret, err;
	int immediate;
	int finalize_max;

	/*
	 * For ATAPI devices we will use the immediate mode and will
	 * poll the command for completion so that this command may
	 * not hog the channel. But for SCSI, we will use the treditional
	 * way of issuing the command with a large enough timeout. This
	 * is done because immediate mode was designed for ATAPI and some
	 * SCSI RW drives might not be even tested with it.
	 */
	if ((dev->d_inq[2] & 7) != 0) {
		/* SCSI device */
		immediate = 0;
	} else {
		/* non-SCSI (e.g ATAPI) device */
		immediate = 1;
	}

	/* We need to close track before close session */
	if (device_type == DVD_PLUS) {
		if (!close_track(dev->d_fd, 0, 0, immediate))
			return (0);
	}

	if (!close_track(dev->d_fd, 0, 1, immediate)) {
		/*
		 * For DAO mode which we use for DVD-RW, the latest MMC
		 * specification does not mention close_track. Some
		 * newer drives will return an ILLEGAL INSTRUCTION
		 * which we will ignore. We have also found a Panasonic
		 * drive which will return a MEDIA ERROR. It is safe
		 * to ignore both errors as this is not needed for
		 * these drives.
		 * This is kept for older drives which had needed
		 * us to issue close_track to flush the cache fully.
		 * once we are certain these drives have cleared the
		 * market, this can be removed.
		 */
		if (device_type == DVD_MINUS) {
			return (0);
		}
	} else {
		if (!immediate)
			return (1);
	}
	if (immediate) {
		(void) sleep(10);

		di = (uchar_t *)my_zalloc(DISC_INFO_BLOCK_SIZE);
		err = 0;

		if (device_type == CD_RW) {
			/* Finalization should not take more than 6 minutes */
			finalize_max = FINALIZE_TIMEOUT;
		} else {
			/* some DVD-RW drives take longer than 6 minutes */
			finalize_max = FINALIZE_TIMEOUT*2;
		}

		for (count = 0; count < finalize_max; count++) {
			ret = read_disc_info(dev->d_fd, di);
			if (ret != 0)
				break;
			if (uscsi_status != 2)
				err = 1;
			if (SENSE_KEY(rqbuf) == 2) {
				/* not ready but not becoming ready */
				if (ASC(rqbuf) != 4)
					err = 1;
			} else if (SENSE_KEY(rqbuf) == 5) {
				/* illegal mode for this track */
				if (ASC(rqbuf) != 0x64)
					err = 1;
			} else {
				err = 1;
			}
			if (err == 1) {
				if (debug) {
					(void) printf("Finalization failed\n");
					(void) printf("%x %x %x %x\n",
					    uscsi_status, SENSE_KEY(rqbuf),
					    ASC(rqbuf), ASCQ(rqbuf));
				}
				free(di);
				return (0);
			}
			if (uscsi_status == 2) {
				int i;
				/* illegal field in command packet */
				if (ASC(rqbuf) == 0x24) {
					/* print it out! */
					(void) printf("\n");
					for (i = 0; i < 18; i++)
						(void) printf("%x ",
						    (unsigned)(rqbuf[i]));
					(void) printf("\n");
				}
			}
			(void) sleep(5);
		}
		free(di);
	}
	return (ret);
}
示例#2
0
void
write_fini(void)
{
	print_n_flush(gettext("Finalizing (Can take several minutes)..."));
	/* Some drives don't like this while in test write mode */
	if (!simulation) {
		if (!finalize(target)) {
			/*
			 * It is possible that the drive is busy writing the
			 * buffered portion. So do not get upset yet.
			 */
			(void) sleep(10);
			if (!finalize(target)) {
				if (debug) {
					(void) printf("status %x, %x/%x/%x\n",
					    uscsi_status, SENSE_KEY(rqbuf),
					    ASC(rqbuf), ASCQ(rqbuf));
				}

				/*
				 * Different vendor drives return different
				 * sense error info for CLOSE SESSION command.
				 * The Panasonic drive that we are using is
				 * one such drive.
				 */
				if (device_type == DVD_MINUS) {
					if (verbose) {
						(void) printf(
						    "skipping finalizing\n");
					}
				} else {

			/* l10n_NOTE : 'failed' as in finishing up...failed  */
					(void) printf(gettext("failed.\n"));

					err_msg(gettext(
					    "Could not finalize the disc.\n"));
					exit(1);
				}


			}
		}
		if (vol_running) {
			(void) eject_media(target);
		}
	} else if (check_device(target, CHECK_MEDIA_IS_NOT_BLANK)) {
		/*
		 * Some drives such as the pioneer A04 will retain a
		 * ghost TOC after a simulation write is done. The
		 * media will actually be blank, but the drive will
		 * report a TOC. There is currently no other way to
		 * re-initialize the media other than ejecting or
		 * to ask the drive to clear the leadout. The laser
		 * is currently off so nothing is written to the
		 * media (on a good behaving drive).
		 * NOTE that a device reset does not work to make
		 * the drive re-initialize the media.
		 */

		blanking_type = "clear_ghost";
		blank();

	}
	/* l10n_NOTE : 'done' as in "Finishing up...done"  */
	(void) printf(gettext("done.\n"));
}
示例#3
0
int
uscsi(int fd, struct uscsi_cmd *scmd)
{
	char		rqbuf[RQLEN];
	int		ret;
	int		i, retries, total_retries;
	int		max_retries = 20;

	scmd->uscsi_flags |= USCSI_RQENABLE;
	scmd->uscsi_rqlen = RQLEN;
	scmd->uscsi_rqbuf = rqbuf;

	for (retries = 0; retries < max_retries; retries++) {
		scmd->uscsi_status = 0;
		memset(rqbuf, 0, RQLEN);

		ret = ioctl(fd, USCSICMD, scmd);

		if ((ret == 0) && (scmd->uscsi_status == 2)) {
			ret = -1;
			errno = EIO;
		}
		if ((ret < 0) && (scmd->uscsi_status == 2)) {
			/*
			 * The drive is not ready to recieve commands but
			 * may be in the process of becoming ready.
			 * sleep for a short time then retry command.
			 * SENSE/ASC = 2/4 : not ready
			 * ASCQ = 0  Not Reportable.
			 * ASCQ = 1  Becoming ready.
			 * ASCQ = 4  FORMAT in progress.
			 * ASCQ = 7  Operation in progress.
			 */
			if ((SENSE_KEY(rqbuf) == 2) && (ASC(rqbuf) == 4) &&
			    ((ASCQ(rqbuf) == 0) || (ASCQ(rqbuf) == 1) ||
			    (ASCQ(rqbuf) == 4)) || (ASCQ(rqbuf) == 7)) {
				total_retries++;
				sleep(1);
				continue;
			}

			/*
			 * Device is not ready to transmit or a device reset
			 * has occurred. wait for a short period of time then
			 * retry the command.
			 */
			if ((SENSE_KEY(rqbuf) == 6) && ((ASC(rqbuf) == 0x28) ||
			    (ASC(rqbuf) == 0x29))) {
				sleep(1);
				total_retries++;
				continue;
			}
			/*
			 * Blank Sense, we don't know what the error is or if
			 * the command succeeded, Hope for the best. Some
			 * drives return blank sense periodically and will
			 * fail if this is removed.
			 */
			if ((SENSE_KEY(rqbuf) == 0) && (ASC(rqbuf) == 0) &&
			    (ASCQ(rqbuf) == 0)) {
				ret = 0;
				break;
			}

			HAL_DEBUG (("cmd: 0x%02x ret:%i status:%02x "
			    " sense: %02x ASC: %02x ASCQ:%02x\n",
			    (uchar_t)scmd->uscsi_cdb[0], ret,
			    scmd->uscsi_status,
			    (uchar_t)SENSE_KEY(rqbuf),
			    (uchar_t)ASC(rqbuf), (uchar_t)ASCQ(rqbuf)));
		}

		break;
	}

	if (retries) {
		HAL_DEBUG (("total retries: %d\n", total_retries));
	}

	return (ret);
}