Commit a9b9b3c5 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] ide-cd mo write protect

From: Jens Axboe <axboe@suse.de>

It's from Pascal Schmidt and adds write protect handling to ide-cd along
with support for non-2kb block sizes.
parent 541f40bd
...@@ -695,6 +695,35 @@ static int cdrom_mrw_open_write(struct cdrom_device_info *cdi) ...@@ -695,6 +695,35 @@ static int cdrom_mrw_open_write(struct cdrom_device_info *cdi)
return ret; return ret;
} }
static int mo_open_write(struct cdrom_device_info *cdi)
{
struct cdrom_generic_command cgc;
char buffer[255];
int ret;
init_cdrom_command(&cgc, &buffer, 4, CGC_DATA_READ);
cgc.quiet = 1;
/*
* obtain write protect information as per
* drivers/scsi/sd.c:sd_read_write_protect_flag
*/
ret = cdrom_mode_sense(cdi, &cgc, GPMODE_ALL_PAGES, 0);
if (ret)
ret = cdrom_mode_sense(cdi, &cgc, GPMODE_VENDOR_PAGE, 0);
if (ret) {
cgc.buflen = 255;
ret = cdrom_mode_sense(cdi, &cgc, GPMODE_ALL_PAGES, 0);
}
/* drive gave us no info, let the user go ahead */
if (ret)
return 0;
return buffer[3] & 0x80;
}
/* /*
* returns 0 for ok to open write, non-0 to disallow * returns 0 for ok to open write, non-0 to disallow
*/ */
...@@ -706,11 +735,8 @@ static int cdrom_open_write(struct cdrom_device_info *cdi) ...@@ -706,11 +735,8 @@ static int cdrom_open_write(struct cdrom_device_info *cdi)
ret = cdrom_mrw_open_write(cdi); ret = cdrom_mrw_open_write(cdi);
else if (CDROM_CAN(CDC_DVD_RAM)) else if (CDROM_CAN(CDC_DVD_RAM))
ret = cdrom_dvdram_open_write(cdi); ret = cdrom_dvdram_open_write(cdi);
/*
* needs to really check whether media is writeable
*/
else if (CDROM_CAN(CDC_MO_DRIVE)) else if (CDROM_CAN(CDC_MO_DRIVE))
ret = 0; ret = mo_open_write(cdi);
return ret; return ret;
} }
......
...@@ -294,10 +294,12 @@ ...@@ -294,10 +294,12 @@
* 4.60 Dec 17, 2003 - Add mt rainier support * 4.60 Dec 17, 2003 - Add mt rainier support
* - Bump timeout for packet commands, matches sr * - Bump timeout for packet commands, matches sr
* - Odd stuff * - Odd stuff
* 4.61 Jan 22, 2004 - support hardware sector sizes other than 2kB,
* Pascal Schmidt <der.eremit@email.de>
* *
*************************************************************************/ *************************************************************************/
#define IDECD_VERSION "4.60" #define IDECD_VERSION "4.61"
#include <linux/config.h> #include <linux/config.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -818,6 +820,14 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret) ...@@ -818,6 +820,14 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
do_end_request = 1; do_end_request = 1;
} else if (sense_key == ILLEGAL_REQUEST || } else if (sense_key == ILLEGAL_REQUEST ||
sense_key == DATA_PROTECT) { sense_key == DATA_PROTECT) {
/*
* check if this was a write protected media
*/
if (rq_data_dir(rq) == WRITE) {
printk("ide-cd: media marked write protected\n");
set_disk_ro(drive->disk, 1);
}
/* No point in retrying after an illegal /* No point in retrying after an illegal
request or data protect error.*/ request or data protect error.*/
ide_dump_status (drive, "command error", stat); ide_dump_status (drive, "command error", stat);
...@@ -1211,6 +1221,9 @@ static int cdrom_read_from_buffer (ide_drive_t *drive) ...@@ -1211,6 +1221,9 @@ static int cdrom_read_from_buffer (ide_drive_t *drive)
{ {
struct cdrom_info *info = drive->driver_data; struct cdrom_info *info = drive->driver_data;
struct request *rq = HWGROUP(drive)->rq; struct request *rq = HWGROUP(drive)->rq;
unsigned short sectors_per_frame;
sectors_per_frame = queue_hardsect_size(drive->queue) >> SECTOR_BITS;
/* Can't do anything if there's no buffer. */ /* Can't do anything if there's no buffer. */
if (info->buffer == NULL) return 0; if (info->buffer == NULL) return 0;
...@@ -1249,7 +1262,7 @@ static int cdrom_read_from_buffer (ide_drive_t *drive) ...@@ -1249,7 +1262,7 @@ static int cdrom_read_from_buffer (ide_drive_t *drive)
will fail. I think that this will never happen, but let's be will fail. I think that this will never happen, but let's be
paranoid and check. */ paranoid and check. */
if (rq->current_nr_sectors < bio_cur_sectors(rq->bio) && if (rq->current_nr_sectors < bio_cur_sectors(rq->bio) &&
(rq->sector % SECTORS_PER_FRAME) != 0) { (rq->sector & (sectors_per_frame - 1))) {
printk("%s: cdrom_read_from_buffer: buffer botch (%ld)\n", printk("%s: cdrom_read_from_buffer: buffer botch (%ld)\n",
drive->name, (long)rq->sector); drive->name, (long)rq->sector);
cdrom_end_request(drive, 0); cdrom_end_request(drive, 0);
...@@ -1268,13 +1281,10 @@ static int cdrom_read_from_buffer (ide_drive_t *drive) ...@@ -1268,13 +1281,10 @@ static int cdrom_read_from_buffer (ide_drive_t *drive)
static ide_startstop_t cdrom_start_read_continuation (ide_drive_t *drive) static ide_startstop_t cdrom_start_read_continuation (ide_drive_t *drive)
{ {
struct request *rq = HWGROUP(drive)->rq; struct request *rq = HWGROUP(drive)->rq;
int nsect, sector, nframes, frame, nskip; unsigned short sectors_per_frame;
int nskip;
/* Number of sectors to transfer. */ sectors_per_frame = queue_hardsect_size(drive->queue) >> SECTOR_BITS;
nsect = rq->nr_sectors;
/* Starting sector. */
sector = rq->sector;
/* If the requested sector doesn't start on a cdrom block boundary, /* If the requested sector doesn't start on a cdrom block boundary,
we must adjust the start of the transfer so that it does, we must adjust the start of the transfer so that it does,
...@@ -1283,31 +1293,19 @@ static ide_startstop_t cdrom_start_read_continuation (ide_drive_t *drive) ...@@ -1283,31 +1293,19 @@ static ide_startstop_t cdrom_start_read_continuation (ide_drive_t *drive)
of the buffer, it will mean that we're to skip a number of the buffer, it will mean that we're to skip a number
of sectors equal to the amount by which CURRENT_NR_SECTORS of sectors equal to the amount by which CURRENT_NR_SECTORS
is larger than the buffer size. */ is larger than the buffer size. */
nskip = (sector % SECTORS_PER_FRAME); nskip = rq->sector & (sectors_per_frame - 1);
if (nskip > 0) { if (nskip > 0) {
/* Sanity check... */ /* Sanity check... */
if (rq->current_nr_sectors != bio_cur_sectors(rq->bio) && if (rq->current_nr_sectors != bio_cur_sectors(rq->bio) &&
(rq->sector % CD_FRAMESIZE != 0)) { (rq->sector & (sectors_per_frame - 1))) {
printk ("%s: cdrom_start_read_continuation: buffer botch (%u)\n", printk ("%s: cdrom_start_read_continuation: buffer botch (%u)\n",
drive->name, rq->current_nr_sectors); drive->name, rq->current_nr_sectors);
cdrom_end_request(drive, 0); cdrom_end_request(drive, 0);
return ide_stopped; return ide_stopped;
} }
sector -= nskip;
nsect += nskip;
rq->current_nr_sectors += nskip; rq->current_nr_sectors += nskip;
} }
/* Convert from sectors to cdrom blocks, rounding up the transfer
length if needed. */
nframes = (nsect + SECTORS_PER_FRAME-1) / SECTORS_PER_FRAME;
frame = sector / SECTORS_PER_FRAME;
/* Largest number of frames was can transfer at once is 64k-1. For
some drives we need to limit this even more. */
nframes = MIN (nframes, (CDROM_CONFIG_FLAGS (drive)->limit_nframes) ?
(65534 / CD_FRAMESIZE) : 65535);
/* Set up the command */ /* Set up the command */
rq->timeout = ATAPI_WAIT_PC; rq->timeout = ATAPI_WAIT_PC;
...@@ -1346,13 +1344,9 @@ static ide_startstop_t cdrom_seek_intr (ide_drive_t *drive) ...@@ -1346,13 +1344,9 @@ static ide_startstop_t cdrom_seek_intr (ide_drive_t *drive)
static ide_startstop_t cdrom_start_seek_continuation (ide_drive_t *drive) static ide_startstop_t cdrom_start_seek_continuation (ide_drive_t *drive)
{ {
struct request *rq = HWGROUP(drive)->rq; struct request *rq = HWGROUP(drive)->rq;
int sector, frame, nskip; int frame = rq->sector;
sector = rq->sector; sector_div(frame, queue_hardsect_size(drive->queue) >> SECTOR_BITS);
nskip = (sector % SECTORS_PER_FRAME);
if (nskip > 0)
sector -= nskip;
frame = sector / SECTORS_PER_FRAME;
memset(rq->cmd, 0, sizeof(rq->cmd)); memset(rq->cmd, 0, sizeof(rq->cmd));
rq->cmd[0] = GPCMD_SEEK; rq->cmd[0] = GPCMD_SEEK;
...@@ -1396,6 +1390,9 @@ static ide_startstop_t cdrom_start_read (ide_drive_t *drive, unsigned int block) ...@@ -1396,6 +1390,9 @@ static ide_startstop_t cdrom_start_read (ide_drive_t *drive, unsigned int block)
{ {
struct cdrom_info *info = drive->driver_data; struct cdrom_info *info = drive->driver_data;
struct request *rq = HWGROUP(drive)->rq; struct request *rq = HWGROUP(drive)->rq;
unsigned short sectors_per_frame;
sectors_per_frame = queue_hardsect_size(drive->queue) >> SECTOR_BITS;
/* We may be retrying this request after an error. Fix up /* We may be retrying this request after an error. Fix up
any weirdness which might be present in the request packet. */ any weirdness which might be present in the request packet. */
...@@ -1411,10 +1408,9 @@ static ide_startstop_t cdrom_start_read (ide_drive_t *drive, unsigned int block) ...@@ -1411,10 +1408,9 @@ static ide_startstop_t cdrom_start_read (ide_drive_t *drive, unsigned int block)
info->nsectors_buffered = 0; info->nsectors_buffered = 0;
/* use dma, if possible. */ /* use dma, if possible. */
if (drive->using_dma && (rq->sector % SECTORS_PER_FRAME == 0) && info->dma = drive->using_dma;
(rq->nr_sectors % SECTORS_PER_FRAME == 0)) if ((rq->sector & (sectors_per_frame - 1)) ||
info->dma = 1; (rq->nr_sectors & (sectors_per_frame - 1)))
else
info->dma = 0; info->dma = 0;
info->cmd = READ; info->cmd = READ;
...@@ -1950,11 +1946,22 @@ static ide_startstop_t cdrom_start_write_cont(ide_drive_t *drive) ...@@ -1950,11 +1946,22 @@ static ide_startstop_t cdrom_start_write_cont(ide_drive_t *drive)
static ide_startstop_t cdrom_start_write(ide_drive_t *drive, struct request *rq) static ide_startstop_t cdrom_start_write(ide_drive_t *drive, struct request *rq)
{ {
struct cdrom_info *info = drive->driver_data; struct cdrom_info *info = drive->driver_data;
struct gendisk *g = drive->disk;
unsigned short sectors_per_frame = queue_hardsect_size(drive->queue) >> SECTOR_BITS;
/* /*
* writes *must* be 2kB frame aligned * writes *must* be hardware frame aligned
*/ */
if ((rq->nr_sectors & 3) || (rq->sector & 3)) { if ((rq->nr_sectors & (sectors_per_frame - 1)) ||
(rq->sector & (sectors_per_frame - 1))) {
cdrom_end_request(drive, 0);
return ide_stopped;
}
/*
* disk has become write protected
*/
if (g->policy) {
cdrom_end_request(drive, 0); cdrom_end_request(drive, 0);
return ide_stopped; return ide_stopped;
} }
...@@ -1970,11 +1977,11 @@ static ide_startstop_t cdrom_start_write(ide_drive_t *drive, struct request *rq) ...@@ -1970,11 +1977,11 @@ static ide_startstop_t cdrom_start_write(ide_drive_t *drive, struct request *rq)
info->nsectors_buffered = 0; info->nsectors_buffered = 0;
/* use dma, if possible. we don't need to check more, since we /* use dma, if possible. we don't need to check more, since we
* know that the transfer is always (at least!) 2KB aligned */ * know that the transfer is always (at least!) frame aligned */
info->dma = drive->using_dma ? 1 : 0; info->dma = drive->using_dma ? 1 : 0;
info->cmd = WRITE; info->cmd = WRITE;
/* Start sending the read request to the drive. */ /* Start sending the write request to the drive. */
return cdrom_start_packet_command(drive, 32768, cdrom_start_write_cont); return cdrom_start_packet_command(drive, 32768, cdrom_start_write_cont);
} }
...@@ -2209,6 +2216,7 @@ static int cdrom_eject(ide_drive_t *drive, int ejectflag, ...@@ -2209,6 +2216,7 @@ static int cdrom_eject(ide_drive_t *drive, int ejectflag,
} }
static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity, static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity,
unsigned long *sectors_per_frame,
struct request_sense *sense) struct request_sense *sense)
{ {
struct { struct {
...@@ -2227,8 +2235,11 @@ static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity, ...@@ -2227,8 +2235,11 @@ static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity,
req.data_len = sizeof(capbuf); req.data_len = sizeof(capbuf);
stat = cdrom_queue_packet_command(drive, &req); stat = cdrom_queue_packet_command(drive, &req);
if (stat == 0) if (stat == 0) {
*capacity = 1 + be32_to_cpu(capbuf.lba); *capacity = 1 + be32_to_cpu(capbuf.lba);
*sectors_per_frame =
be32_to_cpu(capbuf.blocklen) >> SECTOR_BITS;
}
return stat; return stat;
} }
...@@ -2270,6 +2281,7 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense) ...@@ -2270,6 +2281,7 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense)
struct atapi_toc_entry ent; struct atapi_toc_entry ent;
} ms_tmp; } ms_tmp;
long last_written; long last_written;
unsigned long sectors_per_frame = SECTORS_PER_FRAME;
if (toc == NULL) { if (toc == NULL) {
/* Try to allocate space. */ /* Try to allocate space. */
...@@ -2289,12 +2301,15 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense) ...@@ -2289,12 +2301,15 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense)
if (CDROM_STATE_FLAGS(drive)->toc_valid) if (CDROM_STATE_FLAGS(drive)->toc_valid)
return 0; return 0;
/* Try to get the total cdrom capacity. */ /* Try to get the total cdrom capacity and sector size. */
stat = cdrom_read_capacity(drive, &toc->capacity, sense); stat = cdrom_read_capacity(drive, &toc->capacity, &sectors_per_frame,
sense);
if (stat) if (stat)
toc->capacity = 0x1fffff; toc->capacity = 0x1fffff;
set_capacity(drive->disk, toc->capacity * SECTORS_PER_FRAME); set_capacity(drive->disk, toc->capacity * sectors_per_frame);
blk_queue_hardsect_size(drive->queue,
sectors_per_frame << SECTOR_BITS);
/* First read just the header, so we know how long the TOC is. */ /* First read just the header, so we know how long the TOC is. */
stat = cdrom_read_tocentry(drive, 0, 1, 0, (char *) &toc->hdr, stat = cdrom_read_tocentry(drive, 0, 1, 0, (char *) &toc->hdr,
...@@ -2406,7 +2421,7 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense) ...@@ -2406,7 +2421,7 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense)
stat = cdrom_get_last_written(cdi, &last_written); stat = cdrom_get_last_written(cdi, &last_written);
if (!stat && last_written) { if (!stat && last_written) {
toc->capacity = last_written; toc->capacity = last_written;
set_capacity(drive->disk, toc->capacity * SECTORS_PER_FRAME); set_capacity(drive->disk, toc->capacity * sectors_per_frame);
} }
/* Remember that we've read this stuff. */ /* Remember that we've read this stuff. */
...@@ -3306,12 +3321,12 @@ int ide_cdrom_setup (ide_drive_t *drive) ...@@ -3306,12 +3321,12 @@ int ide_cdrom_setup (ide_drive_t *drive)
static static
sector_t ide_cdrom_capacity (ide_drive_t *drive) sector_t ide_cdrom_capacity (ide_drive_t *drive)
{ {
unsigned long capacity; unsigned long capacity, sectors_per_frame;
if (cdrom_read_capacity(drive, &capacity, NULL)) if (cdrom_read_capacity(drive, &capacity, &sectors_per_frame, NULL))
return 0; return 0;
return capacity * SECTORS_PER_FRAME; return capacity * sectors_per_frame;
} }
static static
......
...@@ -496,6 +496,7 @@ struct cdrom_generic_command ...@@ -496,6 +496,7 @@ struct cdrom_generic_command
#define GPCMD_GET_MEDIA_STATUS 0xda #define GPCMD_GET_MEDIA_STATUS 0xda
/* Mode page codes for mode sense/set */ /* Mode page codes for mode sense/set */
#define GPMODE_VENDOR_PAGE 0x00
#define GPMODE_R_W_ERROR_PAGE 0x01 #define GPMODE_R_W_ERROR_PAGE 0x01
#define GPMODE_WRITE_PARMS_PAGE 0x05 #define GPMODE_WRITE_PARMS_PAGE 0x05
#define GPMODE_AUDIO_CTL_PAGE 0x0e #define GPMODE_AUDIO_CTL_PAGE 0x0e
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment