[SCSI] use scatter lists for all block pc requests and simplify hw handlers

Original From: Mike Christie <michaelc@cs.wisc.edu>

Add scsi_execute_req() as a replacement for scsi_wait_req()

Fixed up various pieces (added REQ_SPECIAL and caught req use after
free)

Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
This commit is contained in:
James Bottomley 2005-06-15 18:48:29 -05:00
Родитель 8e6401187e
Коммит 392160335c
3 изменённых файлов: 102 добавлений и 64 удалений

Просмотреть файл

@ -246,7 +246,7 @@ void scsi_wait_req(struct scsi_request *sreq, const void *cmnd, void *buffer,
unsigned bufflen, int timeout, int retries) unsigned bufflen, int timeout, int retries)
{ {
DECLARE_COMPLETION(wait); DECLARE_COMPLETION(wait);
int write = sreq->sr_data_direction == DMA_TO_DEVICE; int write = (sreq->sr_data_direction == DMA_TO_DEVICE);
struct request *req; struct request *req;
req = blk_get_request(sreq->sr_device->request_queue, write, req = blk_get_request(sreq->sr_device->request_queue, write,
@ -281,6 +281,55 @@ void scsi_wait_req(struct scsi_request *sreq, const void *cmnd, void *buffer,
EXPORT_SYMBOL(scsi_wait_req); EXPORT_SYMBOL(scsi_wait_req);
/**
* scsi_execute_req - insert request and wait for the result
* @sdev: scsi device
* @cmd: scsi command
* @data_direction: data direction
* @buffer: data buffer
* @bufflen: len of buffer
* @sense: optional sense buffer
* @timeout: request timeout in seconds
* @retries: number of times to retry request
*
* scsi_execute_req returns the req->errors value which is the
* the scsi_cmnd result field.
**/
int scsi_execute_req(struct scsi_device *sdev, unsigned char *cmd,
int data_direction, void *buffer, unsigned bufflen,
unsigned char *sense, int timeout, int retries)
{
struct request *req;
int write = (data_direction == DMA_TO_DEVICE);
int ret = DRIVER_ERROR << 24;
req = blk_get_request(sdev->request_queue, write, __GFP_WAIT);
if (bufflen && blk_rq_map_kern(sdev->request_queue, req,
buffer, bufflen, __GFP_WAIT))
goto out;
req->cmd_len = COMMAND_SIZE(cmd[0]);
memcpy(req->cmd, cmd, req->cmd_len);
req->sense = sense;
req->sense_len = 0;
req->timeout = timeout;
req->flags |= REQ_BLOCK_PC | REQ_SPECIAL;
/*
* head injection *required* here otherwise quiesce won't work
*/
blk_execute_rq(req->q, NULL, req, 1);
ret = req->errors;
out:
blk_put_request(req);
return ret;
}
EXPORT_SYMBOL(scsi_execute_req);
/* /*
* Function: scsi_init_cmd_errh() * Function: scsi_init_cmd_errh()
* *

Просмотреть файл

@ -111,15 +111,14 @@ MODULE_PARM_DESC(inq_timeout,
/** /**
* scsi_unlock_floptical - unlock device via a special MODE SENSE command * scsi_unlock_floptical - unlock device via a special MODE SENSE command
* @sreq: used to send the command * @sdev: scsi device to send command to
* @result: area to store the result of the MODE SENSE * @result: area to store the result of the MODE SENSE
* *
* Description: * Description:
* Send a vendor specific MODE SENSE (not a MODE SELECT) command using * Send a vendor specific MODE SENSE (not a MODE SELECT) command.
* @sreq to unlock a device, storing the (unused) results into result.
* Called for BLIST_KEY devices. * Called for BLIST_KEY devices.
**/ **/
static void scsi_unlock_floptical(struct scsi_request *sreq, static void scsi_unlock_floptical(struct scsi_device *sdev,
unsigned char *result) unsigned char *result)
{ {
unsigned char scsi_cmd[MAX_COMMAND_SIZE]; unsigned char scsi_cmd[MAX_COMMAND_SIZE];
@ -129,11 +128,10 @@ static void scsi_unlock_floptical(struct scsi_request *sreq,
scsi_cmd[1] = 0; scsi_cmd[1] = 0;
scsi_cmd[2] = 0x2e; scsi_cmd[2] = 0x2e;
scsi_cmd[3] = 0; scsi_cmd[3] = 0;
scsi_cmd[4] = 0x2a; /* size */ scsi_cmd[4] = 0x2a; /* size */
scsi_cmd[5] = 0; scsi_cmd[5] = 0;
sreq->sr_cmd_len = 0; scsi_execute_req(sdev, scsi_cmd, DMA_FROM_DEVICE, result, 0x2a, NULL,
sreq->sr_data_direction = DMA_FROM_DEVICE; SCSI_TIMEOUT, 3);
scsi_wait_req(sreq, scsi_cmd, result, 0x2a /* size */, SCSI_TIMEOUT, 3);
} }
/** /**
@ -433,26 +431,26 @@ void scsi_target_reap(struct scsi_target *starget)
/** /**
* scsi_probe_lun - probe a single LUN using a SCSI INQUIRY * scsi_probe_lun - probe a single LUN using a SCSI INQUIRY
* @sreq: used to send the INQUIRY * @sdev: scsi_device to probe
* @inq_result: area to store the INQUIRY result * @inq_result: area to store the INQUIRY result
* @result_len: len of inq_result
* @bflags: store any bflags found here * @bflags: store any bflags found here
* *
* Description: * Description:
* Probe the lun associated with @sreq using a standard SCSI INQUIRY; * Probe the lun associated with @req using a standard SCSI INQUIRY;
* *
* If the INQUIRY is successful, sreq->sr_result is zero and: the * If the INQUIRY is successful, zero is returned and the
* INQUIRY data is in @inq_result; the scsi_level and INQUIRY length * INQUIRY data is in @inq_result; the scsi_level and INQUIRY length
* are copied to the Scsi_Device at @sreq->sr_device (sdev); * are copied to the Scsi_Device any flags value is stored in *@bflags.
* any flags value is stored in *@bflags.
**/ **/
static void scsi_probe_lun(struct scsi_request *sreq, char *inq_result, static int scsi_probe_lun(struct scsi_device *sdev, char *inq_result,
int *bflags) int result_len, int *bflags)
{ {
struct scsi_device *sdev = sreq->sr_device; /* a bit ugly */ char sense[SCSI_SENSE_BUFFERSIZE];
unsigned char scsi_cmd[MAX_COMMAND_SIZE]; unsigned char scsi_cmd[MAX_COMMAND_SIZE];
int first_inquiry_len, try_inquiry_len, next_inquiry_len; int first_inquiry_len, try_inquiry_len, next_inquiry_len;
int response_len = 0; int response_len = 0;
int pass, count; int pass, count, result;
struct scsi_sense_hdr sshdr; struct scsi_sense_hdr sshdr;
*bflags = 0; *bflags = 0;
@ -475,28 +473,28 @@ static void scsi_probe_lun(struct scsi_request *sreq, char *inq_result,
memset(scsi_cmd, 0, 6); memset(scsi_cmd, 0, 6);
scsi_cmd[0] = INQUIRY; scsi_cmd[0] = INQUIRY;
scsi_cmd[4] = (unsigned char) try_inquiry_len; scsi_cmd[4] = (unsigned char) try_inquiry_len;
sreq->sr_cmd_len = 0;
sreq->sr_data_direction = DMA_FROM_DEVICE;
memset(sense, 0, sizeof(sense));
memset(inq_result, 0, try_inquiry_len); memset(inq_result, 0, try_inquiry_len);
scsi_wait_req(sreq, (void *) scsi_cmd, (void *) inq_result,
try_inquiry_len, result = scsi_execute_req(sdev, scsi_cmd, DMA_FROM_DEVICE,
HZ/2 + HZ*scsi_inq_timeout, 3); inq_result, try_inquiry_len, sense,
HZ / 2 + HZ * scsi_inq_timeout, 3);
SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO "scsi scan: INQUIRY %s " SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO "scsi scan: INQUIRY %s "
"with code 0x%x\n", "with code 0x%x\n",
sreq->sr_result ? "failed" : "successful", result ? "failed" : "successful", result));
sreq->sr_result));
if (sreq->sr_result) { if (result) {
/* /*
* not-ready to ready transition [asc/ascq=0x28/0x0] * not-ready to ready transition [asc/ascq=0x28/0x0]
* or power-on, reset [asc/ascq=0x29/0x0], continue. * or power-on, reset [asc/ascq=0x29/0x0], continue.
* INQUIRY should not yield UNIT_ATTENTION * INQUIRY should not yield UNIT_ATTENTION
* but many buggy devices do so anyway. * but many buggy devices do so anyway.
*/ */
if ((driver_byte(sreq->sr_result) & DRIVER_SENSE) && if ((driver_byte(result) & DRIVER_SENSE) &&
scsi_request_normalize_sense(sreq, &sshdr)) { scsi_normalize_sense(sense, sizeof(sense),
&sshdr)) {
if ((sshdr.sense_key == UNIT_ATTENTION) && if ((sshdr.sense_key == UNIT_ATTENTION) &&
((sshdr.asc == 0x28) || ((sshdr.asc == 0x28) ||
(sshdr.asc == 0x29)) && (sshdr.asc == 0x29)) &&
@ -507,7 +505,7 @@ static void scsi_probe_lun(struct scsi_request *sreq, char *inq_result,
break; break;
} }
if (sreq->sr_result == 0) { if (result == 0) {
response_len = (unsigned char) inq_result[4] + 5; response_len = (unsigned char) inq_result[4] + 5;
if (response_len > 255) if (response_len > 255)
response_len = first_inquiry_len; /* sanity */ response_len = first_inquiry_len; /* sanity */
@ -556,8 +554,8 @@ static void scsi_probe_lun(struct scsi_request *sreq, char *inq_result,
/* If the last transfer attempt got an error, assume the /* If the last transfer attempt got an error, assume the
* peripheral doesn't exist or is dead. */ * peripheral doesn't exist or is dead. */
if (sreq->sr_result) if (result)
return; return -EIO;
/* Don't report any more data than the device says is valid */ /* Don't report any more data than the device says is valid */
sdev->inquiry_len = min(try_inquiry_len, response_len); sdev->inquiry_len = min(try_inquiry_len, response_len);
@ -593,7 +591,7 @@ static void scsi_probe_lun(struct scsi_request *sreq, char *inq_result,
(sdev->scsi_level == 1 && (inq_result[3] & 0x0f) == 1)) (sdev->scsi_level == 1 && (inq_result[3] & 0x0f) == 1))
sdev->scsi_level++; sdev->scsi_level++;
return; return 0;
} }
/** /**
@ -800,9 +798,8 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget,
void *hostdata) void *hostdata)
{ {
struct scsi_device *sdev; struct scsi_device *sdev;
struct scsi_request *sreq;
unsigned char *result; unsigned char *result;
int bflags, res = SCSI_SCAN_NO_RESPONSE; int bflags, res = SCSI_SCAN_NO_RESPONSE, result_len = 256;
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
/* /*
@ -831,16 +828,13 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget,
sdev = scsi_alloc_sdev(starget, lun, hostdata); sdev = scsi_alloc_sdev(starget, lun, hostdata);
if (!sdev) if (!sdev)
goto out; goto out;
sreq = scsi_allocate_request(sdev, GFP_ATOMIC);
if (!sreq) result = kmalloc(result_len, GFP_ATOMIC |
goto out_free_sdev;
result = kmalloc(256, GFP_ATOMIC |
((shost->unchecked_isa_dma) ? __GFP_DMA : 0)); ((shost->unchecked_isa_dma) ? __GFP_DMA : 0));
if (!result) if (!result)
goto out_free_sreq; goto out_free_sdev;
scsi_probe_lun(sreq, result, &bflags); if (scsi_probe_lun(sdev, result, result_len, &bflags))
if (sreq->sr_result)
goto out_free_result; goto out_free_result;
/* /*
@ -868,7 +862,7 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget,
if (res == SCSI_SCAN_LUN_PRESENT) { if (res == SCSI_SCAN_LUN_PRESENT) {
if (bflags & BLIST_KEY) { if (bflags & BLIST_KEY) {
sdev->lockable = 0; sdev->lockable = 0;
scsi_unlock_floptical(sreq, result); scsi_unlock_floptical(sdev, result);
} }
if (bflagsp) if (bflagsp)
*bflagsp = bflags; *bflagsp = bflags;
@ -876,8 +870,6 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget,
out_free_result: out_free_result:
kfree(result); kfree(result);
out_free_sreq:
scsi_release_request(sreq);
out_free_sdev: out_free_sdev:
if (res == SCSI_SCAN_LUN_PRESENT) { if (res == SCSI_SCAN_LUN_PRESENT) {
if (sdevp) { if (sdevp) {
@ -1065,13 +1057,14 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags,
int rescan) int rescan)
{ {
char devname[64]; char devname[64];
char sense[SCSI_SENSE_BUFFERSIZE];
unsigned char scsi_cmd[MAX_COMMAND_SIZE]; unsigned char scsi_cmd[MAX_COMMAND_SIZE];
unsigned int length; unsigned int length;
unsigned int lun; unsigned int lun;
unsigned int num_luns; unsigned int num_luns;
unsigned int retries; unsigned int retries;
int result;
struct scsi_lun *lunp, *lun_data; struct scsi_lun *lunp, *lun_data;
struct scsi_request *sreq;
u8 *data; u8 *data;
struct scsi_sense_hdr sshdr; struct scsi_sense_hdr sshdr;
struct scsi_target *starget = scsi_target(sdev); struct scsi_target *starget = scsi_target(sdev);
@ -1089,10 +1082,6 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags,
if (bflags & BLIST_NOLUN) if (bflags & BLIST_NOLUN)
return 0; return 0;
sreq = scsi_allocate_request(sdev, GFP_ATOMIC);
if (!sreq)
goto out;
sprintf(devname, "host %d channel %d id %d", sprintf(devname, "host %d channel %d id %d",
sdev->host->host_no, sdev->channel, sdev->id); sdev->host->host_no, sdev->channel, sdev->id);
@ -1110,7 +1099,7 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags,
lun_data = kmalloc(length, GFP_ATOMIC | lun_data = kmalloc(length, GFP_ATOMIC |
(sdev->host->unchecked_isa_dma ? __GFP_DMA : 0)); (sdev->host->unchecked_isa_dma ? __GFP_DMA : 0));
if (!lun_data) if (!lun_data)
goto out_release_request; goto out;
scsi_cmd[0] = REPORT_LUNS; scsi_cmd[0] = REPORT_LUNS;
@ -1129,8 +1118,6 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags,
scsi_cmd[10] = 0; /* reserved */ scsi_cmd[10] = 0; /* reserved */
scsi_cmd[11] = 0; /* control */ scsi_cmd[11] = 0; /* control */
sreq->sr_cmd_len = 0;
sreq->sr_data_direction = DMA_FROM_DEVICE;
/* /*
* We can get a UNIT ATTENTION, for example a power on/reset, so * We can get a UNIT ATTENTION, for example a power on/reset, so
@ -1146,29 +1133,30 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags,
SCSI_LOG_SCAN_BUS(3, printk (KERN_INFO "scsi scan: Sending" SCSI_LOG_SCAN_BUS(3, printk (KERN_INFO "scsi scan: Sending"
" REPORT LUNS to %s (try %d)\n", devname, " REPORT LUNS to %s (try %d)\n", devname,
retries)); retries));
scsi_wait_req(sreq, scsi_cmd, lun_data, length,
SCSI_TIMEOUT + 4*HZ, 3); memset(sense, 0, sizeof(sense));
result = scsi_execute_req(sdev, scsi_cmd, DMA_FROM_DEVICE,
lun_data, length, sense,
SCSI_TIMEOUT + 4 * HZ, 3);
SCSI_LOG_SCAN_BUS(3, printk (KERN_INFO "scsi scan: REPORT LUNS" SCSI_LOG_SCAN_BUS(3, printk (KERN_INFO "scsi scan: REPORT LUNS"
" %s (try %d) result 0x%x\n", sreq->sr_result " %s (try %d) result 0x%x\n", result
? "failed" : "successful", retries, ? "failed" : "successful", retries, result));
sreq->sr_result)); if (result == 0)
if (sreq->sr_result == 0)
break; break;
else if (scsi_request_normalize_sense(sreq, &sshdr)) { else if (scsi_normalize_sense(sense, sizeof(sense), &sshdr)) {
if (sshdr.sense_key != UNIT_ATTENTION) if (sshdr.sense_key != UNIT_ATTENTION)
break; break;
} }
} }
if (sreq->sr_result) { if (result) {
/* /*
* The device probably does not support a REPORT LUN command * The device probably does not support a REPORT LUN command
*/ */
kfree(lun_data); kfree(lun_data);
scsi_release_request(sreq);
return 1; return 1;
} }
scsi_release_request(sreq);
/* /*
* Get the length from the first four bytes of lun_data. * Get the length from the first four bytes of lun_data.
@ -1242,8 +1230,6 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags,
kfree(lun_data); kfree(lun_data);
return 0; return 0;
out_release_request:
scsi_release_request(sreq);
out: out:
/* /*
* We are out of memory, don't try scanning any further. * We are out of memory, don't try scanning any further.

Просмотреть файл

@ -54,6 +54,9 @@ extern void scsi_do_req(struct scsi_request *, const void *cmnd,
void *buffer, unsigned bufflen, void *buffer, unsigned bufflen,
void (*done) (struct scsi_cmnd *), void (*done) (struct scsi_cmnd *),
int timeout, int retries); int timeout, int retries);
extern int scsi_execute_req(struct scsi_device *sdev, unsigned char *cmd,
int data_direction, void *buffer, unsigned bufflen,
unsigned char *sense, int timeout, int retries);
struct scsi_mode_data { struct scsi_mode_data {
__u32 length; __u32 length;