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)
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
*/
......@@ -706,11 +735,8 @@ static int cdrom_open_write(struct cdrom_device_info *cdi)
ret = cdrom_mrw_open_write(cdi);
else if (CDROM_CAN(CDC_DVD_RAM))
ret = cdrom_dvdram_open_write(cdi);
/*
* needs to really check whether media is writeable
*/
else if (CDROM_CAN(CDC_MO_DRIVE))
ret = 0;
ret = mo_open_write(cdi);
return ret;
}
......
......@@ -294,10 +294,12 @@
* 4.60 Dec 17, 2003 - Add mt rainier support
* - Bump timeout for packet commands, matches sr
* - 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/module.h>
......@@ -818,6 +820,14 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
do_end_request = 1;
} else if (sense_key == ILLEGAL_REQUEST ||
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
request or data protect error.*/
ide_dump_status (drive, "command error", stat);
......@@ -1211,6 +1221,9 @@ static int cdrom_read_from_buffer (ide_drive_t *drive)
{
struct cdrom_info *info = drive->driver_data;
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. */
if (info->buffer == NULL) return 0;
......@@ -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
paranoid and check. */
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",
drive->name, (long)rq->sector);
cdrom_end_request(drive, 0);
......@@ -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)
{
struct request *rq = HWGROUP(drive)->rq;
int nsect, sector, nframes, frame, nskip;
unsigned short sectors_per_frame;
int nskip;
/* Number of sectors to transfer. */
nsect = rq->nr_sectors;
/* Starting sector. */
sector = rq->sector;
sectors_per_frame = queue_hardsect_size(drive->queue) >> SECTOR_BITS;
/* If the requested sector doesn't start on a cdrom block boundary,
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)
of the buffer, it will mean that we're to skip a number
of sectors equal to the amount by which CURRENT_NR_SECTORS
is larger than the buffer size. */
nskip = (sector % SECTORS_PER_FRAME);
nskip = rq->sector & (sectors_per_frame - 1);
if (nskip > 0) {
/* Sanity check... */
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",
drive->name, rq->current_nr_sectors);
cdrom_end_request(drive, 0);
return ide_stopped;
}
sector -= nskip;
nsect += 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 */
rq->timeout = ATAPI_WAIT_PC;
......@@ -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)
{
struct request *rq = HWGROUP(drive)->rq;
int sector, frame, nskip;
int frame = rq->sector;
sector = rq->sector;
nskip = (sector % SECTORS_PER_FRAME);
if (nskip > 0)
sector -= nskip;
frame = sector / SECTORS_PER_FRAME;
sector_div(frame, queue_hardsect_size(drive->queue) >> SECTOR_BITS);
memset(rq->cmd, 0, sizeof(rq->cmd));
rq->cmd[0] = GPCMD_SEEK;
......@@ -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 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
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)
info->nsectors_buffered = 0;
/* use dma, if possible. */
if (drive->using_dma && (rq->sector % SECTORS_PER_FRAME == 0) &&
(rq->nr_sectors % SECTORS_PER_FRAME == 0))
info->dma = 1;
else
info->dma = drive->using_dma;
if ((rq->sector & (sectors_per_frame - 1)) ||
(rq->nr_sectors & (sectors_per_frame - 1)))
info->dma = 0;
info->cmd = READ;
......@@ -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)
{
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);
return ide_stopped;
}
......@@ -1970,11 +1977,11 @@ static ide_startstop_t cdrom_start_write(ide_drive_t *drive, struct request *rq)
info->nsectors_buffered = 0;
/* 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->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);
}
......@@ -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,
unsigned long *sectors_per_frame,
struct request_sense *sense)
{
struct {
......@@ -2227,8 +2235,11 @@ static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity,
req.data_len = sizeof(capbuf);
stat = cdrom_queue_packet_command(drive, &req);
if (stat == 0)
if (stat == 0) {
*capacity = 1 + be32_to_cpu(capbuf.lba);
*sectors_per_frame =
be32_to_cpu(capbuf.blocklen) >> SECTOR_BITS;
}
return stat;
}
......@@ -2270,6 +2281,7 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense)
struct atapi_toc_entry ent;
} ms_tmp;
long last_written;
unsigned long sectors_per_frame = SECTORS_PER_FRAME;
if (toc == NULL) {
/* Try to allocate space. */
......@@ -2289,12 +2301,15 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense)
if (CDROM_STATE_FLAGS(drive)->toc_valid)
return 0;
/* Try to get the total cdrom capacity. */
stat = cdrom_read_capacity(drive, &toc->capacity, sense);
/* Try to get the total cdrom capacity and sector size. */
stat = cdrom_read_capacity(drive, &toc->capacity, &sectors_per_frame,
sense);
if (stat)
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. */
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)
stat = cdrom_get_last_written(cdi, &last_written);
if (!stat && 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. */
......@@ -3306,12 +3321,12 @@ int ide_cdrom_setup (ide_drive_t *drive)
static
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 capacity * SECTORS_PER_FRAME;
return capacity * sectors_per_frame;
}
static
......
......@@ -496,6 +496,7 @@ struct cdrom_generic_command
#define GPCMD_GET_MEDIA_STATUS 0xda
/* Mode page codes for mode sense/set */
#define GPMODE_VENDOR_PAGE 0x00
#define GPMODE_R_W_ERROR_PAGE 0x01
#define GPMODE_WRITE_PARMS_PAGE 0x05
#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