blob: cec944e1cd64a4d689e536d8ff1b218074acdf2e [file] [log] [blame]
/*
* scsi_merge.c Copyright (C) 1999 Eric Youngdale
*
* SCSI queueing library.
* Initial versions: Eric Youngdale (eric@andante.org).
* Based upon conversations with large numbers
* of people at Linux Expo.
* Support for dynamic DMA mapping: Jakub Jelinek (jakub@redhat.com).
* Support for highmem I/O: Jens Axboe <axboe@suse.de>
*/
/*
* This file contains queue management functions that are used by SCSI.
* We need to ensure that commands do not grow so large that they cannot
* be handled all at once by a host adapter.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/stat.h>
#include <linux/blk.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/smp_lock.h>
#define __KERNEL_SYSCALLS__
#include <linux/unistd.h>
#include <asm/system.h>
#include <asm/irq.h>
#include <asm/dma.h>
#include <asm/io.h>
#include "scsi.h"
#include "hosts.h"
#include "constants.h"
#include <scsi/scsi_ioctl.h>
/*
* Function: scsi_init_io()
*
* Purpose: SCSI I/O initialize function.
*
* Arguments: SCpnt - Command descriptor we wish to initialize
*
* Returns: 1 on success.
*
* Lock status:
*/
int scsi_init_io(Scsi_Cmnd *SCpnt)
{
struct request *req = &SCpnt->request;
struct scatterlist *sgpnt;
int count, gfp_mask;
/*
* First we need to know how many scatter gather segments are needed.
*/
count = req->nr_phys_segments;
/*
* we used to not use scatter-gather for single segment request,
* but now we do (it makes highmem I/O easier to support without
* kmapping pages)
*/
SCpnt->use_sg = count;
gfp_mask = GFP_NOIO;
if (in_interrupt())
gfp_mask &= ~__GFP_WAIT;
/*
* if sg table allocation fails, requeue request later.
*/
sgpnt = scsi_alloc_sgtable(SCpnt, gfp_mask);
if (!sgpnt)
return 0;
SCpnt->request_buffer = (char *) sgpnt;
SCpnt->request_bufflen = req->nr_sectors << 9;
req->buffer = NULL;
/*
* Next, walk the list, and fill in the addresses and sizes of
* each segment.
*/
count = blk_rq_map_sg(req->q, req, SCpnt->request_buffer);
/*
* mapped well, send it off
*/
if (count <= SCpnt->use_sg) {
SCpnt->use_sg = count;
return 1;
}
printk("Incorrect number of segments after building list\n");
printk("counted %d, received %d\n", count, SCpnt->use_sg);
printk("req nr_sec %lu, cur_nr_sec %u\n", req->nr_sectors, req->current_nr_sectors);
/*
* kill it. there should be no leftover blocks in this request
*/
SCpnt = scsi_end_request(SCpnt, 0, req->nr_sectors);
BUG_ON(SCpnt);
return 0;
}
/*
* Function: scsi_initialize_merge_fn()
*
* Purpose: Initialize merge function for a host
*
* Arguments: SHpnt - Host descriptor.
*
* Returns: Nothing.
*
* Lock status:
*
* Notes:
*/
void scsi_initialize_merge_fn(Scsi_Device * SDpnt)
{
struct Scsi_Host *SHpnt = SDpnt->host;
request_queue_t *q = &SDpnt->request_queue;
u64 bounce_limit;
/*
* The generic merging functions work just fine for us.
* Enable highmem I/O, if appropriate.
*/
bounce_limit = BLK_BOUNCE_HIGH;
if (SHpnt->highmem_io && (SDpnt->type == TYPE_DISK)) {
if (!PCI_DMA_BUS_IS_PHYS)
/* Platforms with virtual-DMA translation
* hardware have no practical limit.
*/
bounce_limit = BLK_BOUNCE_ANY;
else if (SHpnt->pci_dev)
bounce_limit = SHpnt->pci_dev->dma_mask;
} else if (SHpnt->unchecked_isa_dma)
bounce_limit = BLK_BOUNCE_ISA;
blk_queue_bounce_limit(q, bounce_limit);
}