#include <scsi/scsi_eh.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_ioctl.h>
-#include <scsi/scsi_request.h>
#include <scsi/scsicam.h>
#include "scsi_logging.h"
static void sd_end_flush(request_queue_t *, struct request *);
static int sd_prepare_flush(request_queue_t *, struct request *);
static void sd_read_capacity(struct scsi_disk *sdkp, char *diskname,
- struct scsi_request *SRpnt, unsigned char *buffer);
+ unsigned char *buffer);
static struct scsi_driver sd_template = {
.owner = THIS_MODULE,
return container_of(disk->private_data, struct scsi_disk, driver);
}
-static struct scsi_disk *scsi_disk_get(struct gendisk *disk)
+static struct scsi_disk *__scsi_disk_get(struct gendisk *disk)
{
struct scsi_disk *sdkp = NULL;
+ if (disk->private_data) {
+ sdkp = scsi_disk(disk);
+ if (scsi_device_get(sdkp->device) == 0)
+ kref_get(&sdkp->kref);
+ else
+ sdkp = NULL;
+ }
+ return sdkp;
+}
+
+static struct scsi_disk *scsi_disk_get(struct gendisk *disk)
+{
+ struct scsi_disk *sdkp;
+
down(&sd_ref_sem);
- if (disk->private_data == NULL)
- goto out;
- sdkp = scsi_disk(disk);
- kref_get(&sdkp->kref);
- if (scsi_device_get(sdkp->device))
- goto out_put;
+ sdkp = __scsi_disk_get(disk);
up(&sd_ref_sem);
return sdkp;
+}
- out_put:
- kref_put(&sdkp->kref, scsi_disk_release);
- sdkp = NULL;
- out:
+static struct scsi_disk *scsi_disk_get_from_dev(struct device *dev)
+{
+ struct scsi_disk *sdkp;
+
+ down(&sd_ref_sem);
+ sdkp = dev_get_drvdata(dev);
+ if (sdkp)
+ sdkp = __scsi_disk_get(sdkp->disk);
up(&sd_ref_sem);
return sdkp;
}
return 0;
memcpy(SCpnt->cmnd, rq->cmd, sizeof(SCpnt->cmnd));
+ SCpnt->cmd_len = rq->cmd_len;
if (rq_data_dir(rq) == WRITE)
SCpnt->sc_data_direction = DMA_TO_DEVICE;
else if (rq->data_len)
static int sd_sync_cache(struct scsi_device *sdp)
{
- struct scsi_request *sreq;
int retries, res;
+ struct scsi_sense_hdr sshdr;
if (!scsi_device_online(sdp))
return -ENODEV;
- sreq = scsi_allocate_request(sdp, GFP_KERNEL);
- if (!sreq) {
- printk("FAILED\n No memory for request\n");
- return -ENOMEM;
- }
- sreq->sr_data_direction = DMA_NONE;
for (retries = 3; retries > 0; --retries) {
unsigned char cmd[10] = { 0 };
* Leave the rest of the command zero to indicate
* flush everything.
*/
- scsi_wait_req(sreq, cmd, NULL, 0, SD_TIMEOUT, SD_MAX_RETRIES);
- if (sreq->sr_result == 0)
+ res = scsi_execute_req(sdp, cmd, DMA_NONE, NULL, 0, &sshdr,
+ SD_TIMEOUT, SD_MAX_RETRIES);
+ if (res == 0)
break;
}
- res = sreq->sr_result;
- if (res) {
- printk(KERN_WARNING "FAILED\n status = %x, message = %02x, "
+ if (res) { printk(KERN_WARNING "FAILED\n status = %x, message = %02x, "
"host = %d, driver = %02x\n ",
status_byte(res), msg_byte(res),
host_byte(res), driver_byte(res));
if (driver_byte(res) & DRIVER_SENSE)
- scsi_print_req_sense("sd", sreq);
+ scsi_print_sense_hdr("sd", &sshdr);
}
- scsi_release_request(sreq);
return res;
}
static int sd_issue_flush(struct device *dev, sector_t *error_sector)
{
+ int ret = 0;
struct scsi_device *sdp = to_scsi_device(dev);
- struct scsi_disk *sdkp = dev_get_drvdata(dev);
+ struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev);
if (!sdkp)
return -ENODEV;
- if (!sdkp->WCE)
- return 0;
-
- return sd_sync_cache(sdp);
+ if (sdkp->WCE)
+ ret = sd_sync_cache(sdp);
+ scsi_disk_put(sdkp);
+ return ret;
}
static void sd_end_flush(request_queue_t *q, struct request *flush_rq)
struct scsi_device *sdev = q->queuedata;
struct scsi_disk *sdkp = dev_get_drvdata(&sdev->sdev_gendev);
- if (sdkp->WCE) {
- memset(rq->cmd, 0, sizeof(rq->cmd));
- rq->flags |= REQ_BLOCK_PC | REQ_SOFTBARRIER;
- rq->timeout = SD_TIMEOUT;
- rq->cmd[0] = SYNCHRONIZE_CACHE;
- return 1;
- }
+ if (!sdkp || !sdkp->WCE)
+ return 0;
- return 0;
+ memset(rq->cmd, 0, sizeof(rq->cmd));
+ rq->flags |= REQ_BLOCK_PC | REQ_SOFTBARRIER;
+ rq->timeout = SD_TIMEOUT;
+ rq->cmd[0] = SYNCHRONIZE_CACHE;
+ return 1;
}
static void sd_rescan(struct device *dev)
{
- struct scsi_disk *sdkp = dev_get_drvdata(dev);
- sd_revalidate_disk(sdkp->disk);
+ struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev);
+
+ if (sdkp) {
+ sd_revalidate_disk(sdkp->disk);
+ scsi_disk_put(sdkp);
+ }
}
scsi_io_completion(SCpnt, good_bytes, block_sectors << 9);
}
-static int media_not_present(struct scsi_disk *sdkp, struct scsi_request *srp)
+static int media_not_present(struct scsi_disk *sdkp,
+ struct scsi_sense_hdr *sshdr)
{
- struct scsi_sense_hdr sshdr;
- if (!srp->sr_result)
- return 0;
- if (!(driver_byte(srp->sr_result) & DRIVER_SENSE))
+ if (!scsi_sense_valid(sshdr))
return 0;
/* not invoked for commands that could return deferred errors */
- if (scsi_request_normalize_sense(srp, &sshdr)) {
- if (sshdr.sense_key != NOT_READY &&
- sshdr.sense_key != UNIT_ATTENTION)
- return 0;
- if (sshdr.asc != 0x3A) /* medium not present */
- return 0;
- }
+ if (sshdr->sense_key != NOT_READY &&
+ sshdr->sense_key != UNIT_ATTENTION)
+ return 0;
+ if (sshdr->asc != 0x3A) /* medium not present */
+ return 0;
+
set_media_not_present(sdkp);
return 1;
}
* spinup disk - called only in sd_revalidate_disk()
*/
static void
-sd_spinup_disk(struct scsi_disk *sdkp, char *diskname,
- struct scsi_request *SRpnt, unsigned char *buffer) {
+sd_spinup_disk(struct scsi_disk *sdkp, char *diskname)
+{
unsigned char cmd[10];
- unsigned long spintime_value = 0;
+ unsigned long spintime_expire = 0;
int retries, spintime;
unsigned int the_result;
struct scsi_sense_hdr sshdr;
cmd[0] = TEST_UNIT_READY;
memset((void *) &cmd[1], 0, 9);
- SRpnt->sr_cmd_len = 0;
- memset(SRpnt->sr_sense_buffer, 0,
- SCSI_SENSE_BUFFERSIZE);
- SRpnt->sr_data_direction = DMA_NONE;
+ the_result = scsi_execute_req(sdkp->device, cmd,
+ DMA_NONE, NULL, 0,
+ &sshdr, SD_TIMEOUT,
+ SD_MAX_RETRIES);
- scsi_wait_req (SRpnt, (void *) cmd, (void *) buffer,
- 0/*512*/, SD_TIMEOUT, SD_MAX_RETRIES);
-
- the_result = SRpnt->sr_result;
if (the_result)
- sense_valid = scsi_request_normalize_sense(
- SRpnt, &sshdr);
+ sense_valid = scsi_sense_valid(&sshdr);
retries++;
} while (retries < 3 &&
(!scsi_status_is_good(the_result) ||
* any media in it, don't bother with any of the rest of
* this crap.
*/
- if (media_not_present(sdkp, SRpnt))
+ if (media_not_present(sdkp, &sshdr))
return;
if ((driver_byte(the_result) & DRIVER_SENSE) == 0) {
cmd[1] = 1; /* Return immediately */
memset((void *) &cmd[2], 0, 8);
cmd[4] = 1; /* Start spin cycle */
- SRpnt->sr_cmd_len = 0;
- memset(SRpnt->sr_sense_buffer, 0,
- SCSI_SENSE_BUFFERSIZE);
-
- SRpnt->sr_data_direction = DMA_NONE;
- scsi_wait_req(SRpnt, (void *)cmd,
- (void *) buffer, 0/*512*/,
- SD_TIMEOUT, SD_MAX_RETRIES);
- spintime_value = jiffies;
+ scsi_execute_req(sdkp->device, cmd, DMA_NONE,
+ NULL, 0, &sshdr,
+ SD_TIMEOUT, SD_MAX_RETRIES);
+ spintime_expire = jiffies + 100 * HZ;
+ spintime = 1;
}
- spintime = 1;
/* Wait 1 second for next try */
msleep(1000);
printk(".");
+
+ /*
+ * Wait for USB flash devices with slow firmware.
+ * Yes, this sense key/ASC combination shouldn't
+ * occur here. It's characteristic of these devices.
+ */
+ } else if (sense_valid &&
+ sshdr.sense_key == UNIT_ATTENTION &&
+ sshdr.asc == 0x28) {
+ if (!spintime) {
+ spintime_expire = jiffies + 5 * HZ;
+ spintime = 1;
+ }
+ /* Wait 1 second for next try */
+ msleep(1000);
} else {
/* we don't understand the sense code, so it's
* probably pointless to loop */
if(!spintime) {
printk(KERN_NOTICE "%s: Unit Not Ready, "
"sense:\n", diskname);
- scsi_print_req_sense("", SRpnt);
+ scsi_print_sense_hdr("", &sshdr);
}
break;
}
- } while (spintime &&
- time_after(spintime_value + 100 * HZ, jiffies));
+ } while (spintime && time_before_eq(jiffies, spintime_expire));
if (spintime) {
if (scsi_status_is_good(the_result))
*/
static void
sd_read_capacity(struct scsi_disk *sdkp, char *diskname,
- struct scsi_request *SRpnt, unsigned char *buffer) {
+ unsigned char *buffer)
+{
unsigned char cmd[16];
- struct scsi_device *sdp = sdkp->device;
int the_result, retries;
int sector_size = 0;
int longrc = 0;
struct scsi_sense_hdr sshdr;
int sense_valid = 0;
+ struct scsi_device *sdp = sdkp->device;
repeat:
retries = 3;
memset((void *) buffer, 0, 8);
}
- SRpnt->sr_cmd_len = 0;
- memset(SRpnt->sr_sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
- SRpnt->sr_data_direction = DMA_FROM_DEVICE;
-
- scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer,
- longrc ? 12 : 8, SD_TIMEOUT, SD_MAX_RETRIES);
+ the_result = scsi_execute_req(sdp, cmd, DMA_FROM_DEVICE,
+ buffer, longrc ? 12 : 8, &sshdr,
+ SD_TIMEOUT, SD_MAX_RETRIES);
- if (media_not_present(sdkp, SRpnt))
+ if (media_not_present(sdkp, &sshdr))
return;
- the_result = SRpnt->sr_result;
if (the_result)
- sense_valid = scsi_request_normalize_sense(SRpnt,
- &sshdr);
+ sense_valid = scsi_sense_valid(&sshdr);
retries--;
} while (the_result && retries);
driver_byte(the_result));
if (driver_byte(the_result) & DRIVER_SENSE)
- scsi_print_req_sense("sd", SRpnt);
+ scsi_print_sense_hdr("sd", &sshdr);
else
printk("%s : sense not available. \n", diskname);
* Jacques Gelinas (Jacques@solucorp.qc.ca)
*/
int hard_sector = sector_size;
- sector_t sz = sdkp->capacity * (hard_sector/256);
+ sector_t sz = (sdkp->capacity/2) * (hard_sector/256);
request_queue_t *queue = sdp->request_queue;
- sector_t mb;
+ sector_t mb = sz;
blk_queue_hardsect_size(queue, hard_sector);
/* avoid 64-bit division on 32-bit platforms */
- mb = sz >> 1;
- sector_div(sz, 1250);
+ sector_div(sz, 625);
mb -= sz - 974;
sector_div(mb, 1950);
/* called with buffer of length 512 */
static inline int
-sd_do_mode_sense(struct scsi_request *SRpnt, int dbd, int modepage,
- unsigned char *buffer, int len, struct scsi_mode_data *data)
+sd_do_mode_sense(struct scsi_device *sdp, int dbd, int modepage,
+ unsigned char *buffer, int len, struct scsi_mode_data *data,
+ struct scsi_sense_hdr *sshdr)
{
- return scsi_mode_sense(SRpnt->sr_device, dbd, modepage, buffer, len,
+ return scsi_mode_sense(sdp, dbd, modepage, buffer, len,
SD_TIMEOUT, SD_MAX_RETRIES, data,
- SRpnt->sr_sense_buffer);
+ sshdr);
}
/*
*/
static void
sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname,
- struct scsi_request *SRpnt, unsigned char *buffer) {
+ unsigned char *buffer)
+{
int res;
+ struct scsi_device *sdp = sdkp->device;
struct scsi_mode_data data;
set_disk_ro(sdkp->disk, 0);
- if (sdkp->device->skip_ms_page_3f) {
+ if (sdp->skip_ms_page_3f) {
printk(KERN_NOTICE "%s: assuming Write Enabled\n", diskname);
return;
}
- if (sdkp->device->use_192_bytes_for_3f) {
- res = sd_do_mode_sense(SRpnt, 0, 0x3F, buffer, 192, &data);
+ if (sdp->use_192_bytes_for_3f) {
+ res = sd_do_mode_sense(sdp, 0, 0x3F, buffer, 192, &data, NULL);
} else {
/*
* First attempt: ask for all pages (0x3F), but only 4 bytes.
* We have to start carefully: some devices hang if we ask
* for more than is available.
*/
- res = sd_do_mode_sense(SRpnt, 0, 0x3F, buffer, 4, &data);
+ res = sd_do_mode_sense(sdp, 0, 0x3F, buffer, 4, &data, NULL);
/*
* Second attempt: ask for page 0 When only page 0 is
* CDB.
*/
if (!scsi_status_is_good(res))
- res = sd_do_mode_sense(SRpnt, 0, 0, buffer, 4, &data);
+ res = sd_do_mode_sense(sdp, 0, 0, buffer, 4, &data, NULL);
/*
* Third attempt: ask 255 bytes, as we did earlier.
*/
if (!scsi_status_is_good(res))
- res = sd_do_mode_sense(SRpnt, 0, 0x3F, buffer, 255,
- &data);
+ res = sd_do_mode_sense(sdp, 0, 0x3F, buffer, 255,
+ &data, NULL);
}
if (!scsi_status_is_good(res)) {
*/
static void
sd_read_cache_type(struct scsi_disk *sdkp, char *diskname,
- struct scsi_request *SRpnt, unsigned char *buffer)
+ unsigned char *buffer)
{
int len = 0, res;
+ struct scsi_device *sdp = sdkp->device;
int dbd;
int modepage;
struct scsi_mode_data data;
struct scsi_sense_hdr sshdr;
- if (sdkp->device->skip_ms_page_8)
+ if (sdp->skip_ms_page_8)
goto defaults;
- if (sdkp->device->type == TYPE_RBC) {
+ if (sdp->type == TYPE_RBC) {
modepage = 6;
dbd = 8;
} else {
}
/* cautiously ask */
- res = sd_do_mode_sense(SRpnt, dbd, modepage, buffer, 4, &data);
+ res = sd_do_mode_sense(sdp, dbd, modepage, buffer, 4, &data, &sshdr);
if (!scsi_status_is_good(res))
goto bad_sense;
len += data.header_length + data.block_descriptor_length;
/* Get the data */
- res = sd_do_mode_sense(SRpnt, dbd, modepage, buffer, len, &data);
+ res = sd_do_mode_sense(sdp, dbd, modepage, buffer, len, &data, &sshdr);
if (scsi_status_is_good(res)) {
const char *types[] = {
}
bad_sense:
- if (scsi_request_normalize_sense(SRpnt, &sshdr) &&
+ if (scsi_sense_valid(&sshdr) &&
sshdr.sense_key == ILLEGAL_REQUEST &&
sshdr.asc == 0x24 && sshdr.ascq == 0x0)
printk(KERN_NOTICE "%s: cache data unavailable\n",
{
struct scsi_disk *sdkp = scsi_disk(disk);
struct scsi_device *sdp = sdkp->device;
- struct scsi_request *sreq;
unsigned char *buffer;
SCSI_LOG_HLQUEUE(3, printk("sd_revalidate_disk: disk=%s\n", disk->disk_name));
if (!scsi_device_online(sdp))
goto out;
- sreq = scsi_allocate_request(sdp, GFP_KERNEL);
- if (!sreq) {
- printk(KERN_WARNING "(sd_revalidate_disk:) Request allocation "
- "failure.\n");
- goto out;
- }
-
buffer = kmalloc(512, GFP_KERNEL | __GFP_DMA);
if (!buffer) {
printk(KERN_WARNING "(sd_revalidate_disk:) Memory allocation "
"failure.\n");
- goto out_release_request;
+ goto out;
}
/* defaults, until the device tells us otherwise */
sdkp->WCE = 0;
sdkp->RCD = 0;
- sd_spinup_disk(sdkp, disk->disk_name, sreq, buffer);
+ sd_spinup_disk(sdkp, disk->disk_name);
/*
* Without media there is no reason to ask; moreover, some devices
* react badly if we do.
*/
if (sdkp->media_present) {
- sd_read_capacity(sdkp, disk->disk_name, sreq, buffer);
+ sd_read_capacity(sdkp, disk->disk_name, buffer);
if (sdp->removable)
sd_read_write_protect_flag(sdkp, disk->disk_name,
- sreq, buffer);
- sd_read_cache_type(sdkp, disk->disk_name, sreq, buffer);
+ buffer);
+ sd_read_cache_type(sdkp, disk->disk_name, buffer);
}
set_capacity(disk, sdkp->capacity);
kfree(buffer);
- out_release_request:
- scsi_release_request(sreq);
out:
return 0;
}
if (sdp->type != TYPE_DISK && sdp->type != TYPE_MOD && sdp->type != TYPE_RBC)
goto out;
- SCSI_LOG_HLQUEUE(3, printk("sd_attach: scsi device: <%d,%d,%d,%d>\n",
- sdp->host->host_no, sdp->channel, sdp->id, sdp->lun));
+ SCSI_LOG_HLQUEUE(3, sdev_printk(KERN_INFO, sdp,
+ "sd_attach\n"));
error = -ENOMEM;
sdkp = kmalloc(sizeof(*sdkp), GFP_KERNEL);
if (error)
goto out_put;
+ get_device(&sdp->sdev_gendev);
sdkp->device = sdp;
sdkp->driver = &sd_template;
sdkp->disk = gd;
dev_set_drvdata(dev, sdkp);
add_disk(gd);
- printk(KERN_NOTICE "Attached scsi %sdisk %s at scsi%d, channel %d, "
- "id %d, lun %d\n", sdp->removable ? "removable " : "",
- gd->disk_name, sdp->host->host_no, sdp->channel,
- sdp->id, sdp->lun);
+ sdev_printk(KERN_NOTICE, sdp, "Attached scsi %sdisk %s\n",
+ sdp->removable ? "removable " : "", gd->disk_name);
return 0;
del_gendisk(sdkp->disk);
sd_shutdown(dev);
+
down(&sd_ref_sem);
+ dev_set_drvdata(dev, NULL);
kref_put(&sdkp->kref, scsi_disk_release);
up(&sd_ref_sem);
spin_unlock(&sd_index_lock);
disk->private_data = NULL;
-
put_disk(disk);
+ put_device(&sdkp->device->sdev_gendev);
kfree(sdkp);
}
static void sd_shutdown(struct device *dev)
{
struct scsi_device *sdp = to_scsi_device(dev);
- struct scsi_disk *sdkp = dev_get_drvdata(dev);
+ struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev);
if (!sdkp)
return; /* this can happen */
- if (!sdkp->WCE)
- return;
-
- printk(KERN_NOTICE "Synchronizing SCSI cache for disk %s: \n",
- sdkp->disk->disk_name);
- sd_sync_cache(sdp);
-}
+ if (sdkp->WCE) {
+ printk(KERN_NOTICE "Synchronizing SCSI cache for disk %s: \n",
+ sdkp->disk->disk_name);
+ sd_sync_cache(sdp);
+ }
+ scsi_disk_put(sdkp);
+}
/**
* init_sd - entry point for this driver (both when built in or when