diff --git a/sys/cam/scsi/scsi_cd.c b/sys/cam/scsi/scsi_cd.c index a7af9babbb24..3984f776104f 100644 --- a/sys/cam/scsi/scsi_cd.c +++ b/sys/cam/scsi/scsi_cd.c @@ -56,6 +56,7 @@ #include #include #include +#include #include #include #include @@ -230,6 +231,8 @@ static int cdplaytracks(struct cam_periph *periph, static int cdpause(struct cam_periph *periph, u_int32_t go); static int cdstopunit(struct cam_periph *periph, u_int32_t eject); static int cdstartunit(struct cam_periph *periph); +static int cdsetspeed(struct cam_periph *periph, + u_int32_t rdspeed, u_int32_t wrspeed); static int cdreportkey(struct cam_periph *periph, struct dvd_authinfo *authinfo); static int cdsendkey(struct cam_periph *periph, @@ -2379,6 +2382,12 @@ cdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td) /* return (cd_reset(periph)); */ error = ENOTTY; break; + case CDRIOCREADSPEED: + error = cdsetspeed(periph, *(u_int32_t *)addr, CDR_MAX_SPEED); + break; + case CDRIOCWRITESPEED: + error = cdsetspeed(periph, CDR_MAX_SPEED, *(u_int32_t *)addr); + break; case DVDIOCSENDKEY: case DVDIOCREPORTKEY: { struct dvd_authinfo *authinfo; @@ -2955,6 +2964,44 @@ cdstopunit(struct cam_periph *periph, u_int32_t eject) return(error); } +static int +cdsetspeed(struct cam_periph *periph, u_int32_t rdspeed, u_int32_t wrspeed) +{ + struct scsi_set_speed *scsi_cmd; + struct ccb_scsiio *csio; + union ccb *ccb; + int error; + + error = 0; + ccb = cdgetccb(periph, /* priority */ 1); + csio = &ccb->csio; + + cam_fill_csio(csio, + /* retries */ 1, + /* cbfcnp */ cddone, + /* flags */ CAM_DIR_NONE, + /* tag_action */ MSG_SIMPLE_Q_TAG, + /* data_ptr */ NULL, + /* dxfer_len */ 0, + /* sense_len */ SSD_FULL_SIZE, + sizeof(struct scsi_set_speed), + /* timeout */ 50000); + + scsi_cmd = (struct scsi_set_speed *)&csio->cdb_io.cdb_bytes; + bzero(scsi_cmd, sizeof(*scsi_cmd)); + + scsi_cmd->opcode = SET_CD_SPEED; + scsi_ulto2b(rdspeed, scsi_cmd->readspeed); + scsi_ulto2b(wrspeed, scsi_cmd->writespeed); + + error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO, + /*sense_flags*/SF_RETRY_UA); + + xpt_release_ccb(ccb); + + return(error); +} + static int cdreportkey(struct cam_periph *periph, struct dvd_authinfo *authinfo) { diff --git a/sys/cam/scsi/scsi_cd.h b/sys/cam/scsi/scsi_cd.h index fc521197425b..f24213965a8d 100644 --- a/sys/cam/scsi/scsi_cd.h +++ b/sys/cam/scsi/scsi_cd.h @@ -169,6 +169,16 @@ struct scsi_read_cd_capacity u_int8_t control; }; +struct scsi_set_speed +{ + u_int8_t opcode; + u_int8_t byte2; + u_int8_t readspeed[2]; + u_int8_t writespeed[2]; + u_int8_t reserved[5]; + u_int8_t control; +}; + struct scsi_report_key { u_int8_t opcode; @@ -251,6 +261,7 @@ struct scsi_read_dvd_structure #define PLAY_12 0xa5 /* cdrom pause in 'play audio' mode */ #define PLAY_TRACK_REL_BIG 0xa9 /* cdrom play track/index mode */ #define READ_DVD_STRUCTURE 0xad /* read dvd structure */ +#define SET_CD_SPEED 0xbb /* set c/dvd speed */ struct scsi_report_key_data_header { diff --git a/sys/dev/ata/atapi-cd.c b/sys/dev/ata/atapi-cd.c index 6e91ef7e904d..d3bcd60dbced 100644 --- a/sys/dev/ata/atapi-cd.c +++ b/sys/dev/ata/atapi-cd.c @@ -1021,11 +1021,11 @@ acdioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td) break; case CDRIOCREADSPEED: - error = acd_set_speed(cdp, 177 * (*(int *)addr), -1); + error = acd_set_speed(cdp, *(int *)addr, CDR_MAX_SPEED); break; case CDRIOCWRITESPEED: - error = acd_set_speed(cdp, -1, 177 * (*(int *)addr)); + error = acd_set_speed(cdp, CDR_MAX_SPEED, *(int *)addr); break; case CDRIOCGETBLOCKSIZE: diff --git a/sys/sys/cdrio.h b/sys/sys/cdrio.h index 77cb1be59313..b664a585af15 100644 --- a/sys/sys/cdrio.h +++ b/sys/sys/cdrio.h @@ -129,6 +129,7 @@ struct cdr_format_params { #define CDRIOCFIXATE _IOW('c', 106, int) #define CDRIOCREADSPEED _IOW('c', 107, int) #define CDRIOCWRITESPEED _IOW('c', 108, int) +#define CDR_MAX_SPEED 0xffff #define CDRIOCGETBLOCKSIZE _IOR('c', 109, int) #define CDRIOCSETBLOCKSIZE _IOW('c', 110, int) #define CDRIOCGETPROGRESS _IOR('c', 111, int) diff --git a/usr.sbin/burncd/burncd.8 b/usr.sbin/burncd/burncd.8 index 47dc84f0455c..520ed9a2c925 100644 --- a/usr.sbin/burncd/burncd.8 +++ b/usr.sbin/burncd/burncd.8 @@ -69,6 +69,7 @@ quiet, do not print progress messages. .It Fl s Ar speed set the speed of the burner device. Defaults to 1. +Specify "max" to use the drive's fastest speed. .It Fl t test write, do not actually write on the media. .It Fl v diff --git a/usr.sbin/burncd/burncd.c b/usr.sbin/burncd/burncd.c index 1d3d2fd540ca..9f3738ef566b 100644 --- a/usr.sbin/burncd/burncd.c +++ b/usr.sbin/burncd/burncd.c @@ -116,7 +116,10 @@ main(int argc, char **argv) break; case 's': - speed = atoi(optarg); + if (strcasecmp("max", optarg) == 0) + speed = CDR_MAX_SPEED; + else + speed = atoi(optarg); if (speed <= 0) errx(EX_USAGE, "Invalid speed: %s", optarg); break; diff --git a/usr.sbin/cdcontrol/cdcontrol.1 b/usr.sbin/cdcontrol/cdcontrol.1 index 3f986fe4e6e7..94214f944844 100644 --- a/usr.sbin/cdcontrol/cdcontrol.1 +++ b/usr.sbin/cdcontrol/cdcontrol.1 @@ -164,9 +164,9 @@ Set minute-second-frame ioctl mode (default). .It Ic set Cm lba Set LBA ioctl mode. .It Ic speed Ar s -Set the highest speed that the drive should use. -The speed is a multiple of the single speed. -This command is currently only supported on ATAPI drives. +Set the highest speed that the drive should use for reading data. +The units are multiples of a single speed CDROM (150 KB/s). +Specify "max" to use the drive's fastest speed. .It Ic quit Quit the program. .El diff --git a/usr.sbin/cdcontrol/cdcontrol.c b/usr.sbin/cdcontrol/cdcontrol.c index f497c5240aa2..5dd058599b73 100644 --- a/usr.sbin/cdcontrol/cdcontrol.c +++ b/usr.sbin/cdcontrol/cdcontrol.c @@ -282,7 +282,6 @@ int run (int cmd, char *arg) { long speed; int l, r, rc; - char *ep; switch (cmd) { @@ -435,9 +434,11 @@ int run (int cmd, char *arg) return (0); errno = 0; - speed = strtol(arg, &ep, 10); - if (*ep || ep == arg || speed <= 0 || speed > INT_MAX || - errno != 0) { + if (strcasecmp("max", arg) == 0) + speed = CDR_MAX_SPEED; + else + speed = strtol(arg, NULL, 10) * 177; + if (speed <= 0 || speed > INT_MAX) { warnx("invalid command arguments %s", arg); return (0); }