patch-2.3.6 linux/drivers/scsi/sg.c
Next file: linux/drivers/sound/dmasound.c
Previous file: linux/drivers/scsi/sd.c
Back to the patch index
Back to the overall index
- Lines: 1161
- Date:
Mon Jun 7 16:26:25 1999
- Orig file:
v2.3.5/linux/drivers/scsi/sg.c
- Orig date:
Sat May 15 23:46:03 1999
diff -u --recursive --new-file v2.3.5/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c
@@ -16,12 +16,10 @@
*
* Borrows code from st driver. Thanks to Alessandro Rubini's "dd" book.
*/
- static char * sg_version_str = "Version: 2.1.32 (990501)";
+ static char * sg_version_str = "Version: 2.1.34 (990603)";
+ static int sg_version_num = 20134; /* 2 digits for each component */
/*
- * D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au)
- * - scatter list logic replaces previous large atomic SG_BIG_BUFF
- * sized allocation. See notes in <scsi/sg.h> include file.
- *
+ * D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes:
* - scsi logging is available via SCSI_LOG_TIMEOUT macros. First
* the kernel/module needs to be built with CONFIG_SCSI_LOGGING
* (otherwise the macros compile to empty statements), then do
@@ -34,13 +32,27 @@
* Should use hlcomplete but it is too "noisy" (sd uses it).
*
* - This driver obtains memory (heap) for the low-level driver to
- * transfer/dma to and from. It is obtained from up to 4 sources:
- * - 1 SG_SCATTER_SZ sized buffer on open() (per fd)
- * [could be less if SG_SCATTER_SZ bytes not available]
- * - obtain heap as required on write()s (get_free_pages)
+ * transfer/dma to and from. It is obtained from up to 3 sources:
+ * - obtain heap via get_free_pages()
* - obtain heap from the shared scsi dma pool
* - obtain heap from kernel directly (kmalloc) [last choice]
- * the 'alt_address' field in the scatter_list structure and the
+ * Each open() attempts to obtain a "reserve" buffer of
+ * SG_DEF_RESERVED_SIZE bytes (or 0 bytes if opened O_RDONLY). The
+ * amount actually obtained [which could be 0 bytes] can be found from
+ * the SG_GET_RESERVED_SIZE ioctl(). This reserved buffer size can
+ * be changed by calling the SG_SET_RESERVED_SIZE ioctl(). Since this
+ * is an ambit claim, it should be followed by a SG_GET_RESERVED_SIZE
+ * ioctl() to find out how much was actually obtained.
+ * A subsequent write() to this file descriptor will use the
+ * reserved buffer unless:
+ * - it is already in use (eg during command queuing)
+ * - or the write() needs a buffer size larger than the
+ * reserved size
+ * In these cases the write() will attempt to get the required memory
+ * for the duration of this request but, if memory is low, it may
+ * fail with ENOMEM.
+ *
+ * - The 'alt_address' field in the scatter_list structure and the
* related 'mem_src' indicate the source of the heap allocation.
*
*/
@@ -67,11 +79,11 @@
#include <scsi/sg.h>
-int sg_big_buff = SG_SCATTER_SZ; /* sg_big_buff is ro through sysctl */
+int sg_big_buff = SG_DEF_RESERVED_SIZE; /* sg_big_buff is ro through sysctl */
/* N.B. This global is here to keep existing software happy. It now holds
- the size of the "first buffer" of the most recent sucessful sg_open().
+ the size of the reserve buffer of the most recent sucessful sg_open().
Only available when 'sg' compiled into kernel (rather than a module).
- This should probably be deprecated (use SG_GET_RESERVED_SIZE instead). */
+ This is deprecated (use SG_GET_RESERVED_SIZE ioctl() instead). */
#define SG_SECTOR_SZ 512
#define SG_SECTOR_MSK (SG_SECTOR_SZ - 1)
@@ -89,7 +101,6 @@
static int sg_num_page = 0;
#endif
-#define SG_HEAP_FB 0 /* heap obtained at open() (one buffer per fd) */
#define SG_HEAP_PAGE 1 /* heap from kernel via get_free_pages() */
#define SG_HEAP_KMAL 2 /* heap from kernel via kmalloc() */
#define SG_HEAP_POOL 3 /* heap from scsi dma pool (mid-level) */
@@ -112,9 +123,9 @@
{
unsigned short use_sg; /* Number of pieces of scatter-gather */
unsigned short sglist_len; /* size of malloc'd scatter-gather list */
- unsigned bufflen; /* Size of data buffer */
+ unsigned bufflen; /* Size of (aggregate) data buffer */
unsigned b_malloc_len; /* actual len malloc'ed in buffer */
- void * buffer; /* Data buffer or scatter list (12 bytes) */
+ void * buffer; /* Data buffer or scatter list,12 bytes each*/
char mem_src; /* heap whereabouts of 'buffer' */
} Sg_scatter_hold; /* 20 bytes long on i386 */
@@ -126,10 +137,10 @@
Scsi_Cmnd * my_cmdp; /* NULL -> ready to read, else id */
struct sg_request * nextrp; /* NULL -> tail request (slist) */
struct sg_fd * parentfp; /* NULL -> not in use */
- Sg_scatter_hold data; /* hold buffers, perhaps scatter list */
- struct sg_header header; /* scsi command+info <include/sg.h> */
- char fb_used; /* 1 -> using fst_buf, normally 0 (used) */
-} Sg_request; /* around 72 bytes long on i386 */
+ Sg_scatter_hold data; /* hold buffer, perhaps scatter list */
+ struct sg_header header; /* scsi command+info, see <scsi/sg.h> */
+ char res_used; /* 1 -> using reserve buffer, 0 -> not ... */
+} Sg_request; /* 72 bytes long on i386 */
typedef struct sg_fd /* holds the state of a file descriptor */
{
@@ -137,41 +148,52 @@
struct sg_device * parentdp; /* owning device */
wait_queue_head_t read_wait; /* queue read until command done */
int timeout; /* defaults to SG_DEFAULT_TIMEOUT */
- char * fst_buf; /* try to grab SG_SCATTER_SZ sized buffer on open */
- int fb_size; /* actual size of allocated fst_buf */
- Sg_request * headrp; /* head of request slist, NULL->empty */
+ Sg_scatter_hold reserve; /* buffer held for this file descriptor */
+ unsigned save_scat_len; /* original length of trunc. scat. element */
+ Sg_request * headrp; /* head of request slist, NULL->empty */
struct fasync_struct * async_qp; /* used by asynchronous notification */
Sg_request req_arr[SG_MAX_QUEUE]; /* used as singly-linked list */
- char low_dma; /* as in parent but possible overridden to 1 */
+ char low_dma; /* as in parent but possibly overridden to 1 */
char force_packid; /* 1 -> pack_id input to read(), 0 -> ignored */
char closed; /* 1 -> fd closed but request(s) outstanding */
- char my_mem_src; /* heap whereabouts of this sg_fb object */
+ char my_mem_src; /* heap whereabouts of this Sg_fd object */
char cmd_q; /* 1 -> allow command queuing, 0 -> don't */
char underrun_flag; /* 1 -> flag underruns, 0 -> don't, 2 -> test */
-} Sg_fd; /* around 1192 bytes long on i386 */
+ char next_cmd_len; /* 0 -> automatic (def), >0 -> use on next write() */
+} Sg_fd; /* 1208 bytes long on i386 */
typedef struct sg_device /* holds the state of each scsi generic device */
{
Scsi_Device * device;
- wait_queue_head_t generic_wait;/* queue open if O_EXCL on prev. open */
+ wait_queue_head_t o_excl_wait; /* queue open() when O_EXCL in use */
int sg_tablesize; /* adapter's max scatter-gather table size */
Sg_fd * headfp; /* first open fd belonging to this device */
kdev_t i_rdev; /* holds device major+minor number */
char exclude; /* opened for exclusive access */
char sgdebug; /* 0->off, 1->sense, 9->dump dev, 10-> all devs */
- unsigned char merge_fd; /* 0->sequencing per fd (def) else fd count */
-} Sg_device; /* around 24 bytes long on i386 */
+ unsigned char merge_fd; /* 0->sequencing per fd, else fd count */
+} Sg_device; /* 24 bytes long on i386 */
static int sg_fasync(int fd, struct file * filp, int mode);
static void sg_command_done(Scsi_Cmnd * SCpnt);
-static int sg_sc_build(Sg_request * srp, int max_buff_size,
- const char * inp, int num_write_xfer);
-static int sg_sc_undo_rem(Sg_request * srp, char * outp,
- int num_read_xfer);
-static char * sg_malloc(Sg_request * srp, int size, int * retSzp,
+static int sg_start_req(Sg_request * srp, int max_buff_size,
+ const char * inp, int num_write_xfer);
+static void sg_finish_rem_req(Sg_request * srp, char * outp,
+ int num_read_xfer);
+static int sg_build_scat(Sg_scatter_hold * schp, int buff_size,
+ const Sg_fd * sfp);
+static void sg_write_xfer(Sg_scatter_hold * schp, const char * inp,
+ int num_write_xfer);
+static void sg_remove_scat(Sg_scatter_hold * schp);
+static void sg_read_xfer(Sg_scatter_hold * schp, char * outp,
+ int num_read_xfer);
+static void sg_build_reserve(Sg_fd * sfp, int req_size);
+static void sg_link_reserve(Sg_fd * sfp, Sg_request * srp, int size);
+static void sg_unlink_reserve(Sg_fd * sfp, Sg_request * srp);
+static char * sg_malloc(const Sg_fd * sfp, int size, int * retSzp,
int * mem_srcp);
-static void sg_free(Sg_request * srp, char * buff, int size, int mem_src);
+static void sg_free(char * buff, int size, int mem_src);
static char * sg_low_malloc(int rqSz, int lowDma, int mem_src,
int * retSzp);
static void sg_low_free(char * buff, int size, int mem_src);
@@ -180,7 +202,7 @@
static Sg_request * sg_get_request(const Sg_fd * sfp, int pack_id);
static Sg_request * sg_add_request(Sg_fd * sfp);
static int sg_remove_request(Sg_fd * sfp, const Sg_request * srp);
-static int sg_fb_in_use(const Sg_fd * sfp);
+static int sg_res_in_use(const Sg_fd * sfp);
static void sg_clr_scpnt(Scsi_Cmnd * SCpnt);
static void sg_shorten_timeout(Scsi_Cmnd * scpnt);
static void sg_debug(const Sg_device * sdp, const Sg_fd * sfp, int part_of);
@@ -197,6 +219,7 @@
int flags = filp->f_flags;
Sg_device * sdp;
Sg_fd * sfp;
+ int res;
if ((NULL == sg_dev_arr) || (dev < 0) || (dev >= sg_template.dev_max))
return -ENXIO;
@@ -207,38 +230,35 @@
printk("sg_open: inode maj=%d, min=%d sdp maj=%d, min=%d\n",
MAJOR(inode->i_rdev), MINOR(inode->i_rdev),
MAJOR(sdp->i_rdev), MINOR(sdp->i_rdev));
+ /* If we are in the middle of error recovery, don't let anyone
+ * else try and use this device. Also, if error recovery fails, it
+ * may try and take the device offline, in which case all further
+ * access to the device is prohibited. */
if(! scsi_block_when_processing_errors(sdp->device))
return -ENXIO;
-/* if (O_RDWR != (flags & O_ACCMODE)) */
-/* return -EACCES; May just want to get to a ioctl, so remove */
SCSI_LOG_TIMEOUT(3, printk("sg_open: dev=%d, flags=0x%x\n", dev, flags));
- /* If we want exclusive access, then wait until the device is not
- * busy, and then set the flag to prevent anyone else from using it. */
+
if (flags & O_EXCL) {
if (O_RDONLY == (flags & O_ACCMODE))
return -EACCES; /* Can't lock it with read only access */
- while (sdp->headfp) {
- if (flags & O_NONBLOCK)
- return -EBUSY;
- interruptible_sleep_on(&sdp->generic_wait);
- if (signal_pending(current))
- return -ERESTARTSYS;
- }
- sdp->exclude = 1;
- }
- else { /* Wait until nobody has an exclusive open on this device. */
- while (sdp->exclude) {
- if (flags & O_NONBLOCK)
- return -EBUSY;
- interruptible_sleep_on(&sdp->generic_wait);
- if (signal_pending(current))
- return -ERESTARTSYS;
- }
+ if (sdp->headfp && (filp->f_flags & O_NONBLOCK))
+ return -EBUSY;
+ res = 0; /* following is a macro that beats race condition */
+ __wait_event_interruptible(sdp->o_excl_wait,
+ ((sdp->headfp || sdp->exclude) ? 0 : (sdp->exclude = 1)),
+ res);
+ if (res)
+ return res; /* -ERESTARTSYS because signal hit process */
+ }
+ else if (sdp->exclude) { /* some other fd has an exclusive lock on dev */
+ if (filp->f_flags & O_NONBLOCK)
+ return -EBUSY;
+ res = 0; /* following is a macro that beats race condition */
+ __wait_event_interruptible(sdp->o_excl_wait, (! sdp->exclude), res);
+ if (res)
+ return res; /* -ERESTARTSYS because signal hit process */
}
- /* OK, we should have grabbed the device. Mark the thing so
- * that other processes know that we have it, and initialize the
- * state variables to known values. */
if (! sdp->headfp) { /* no existing opens on this device */
sdp->sgdebug = 0;
sdp->sg_tablesize = sdp->device->host->sg_tablesize;
@@ -284,16 +304,14 @@
if(sg_template.module)
__MOD_DEC_USE_COUNT(sg_template.module);
sdp->exclude = 0;
- wake_up_interruptible(&sdp->generic_wait);
+ wake_up_interruptible(&sdp->o_excl_wait);
return 0;
}
-/* Read back the results of a SCSI command which was sent in a prior
- write(). */
static ssize_t sg_read(struct file * filp, char * buf,
size_t count, loff_t *ppos)
{
- int k;
+ int k, res;
Sg_device * sdp;
Sg_fd * sfp;
Sg_request * srp;
@@ -305,13 +323,8 @@
SCSI_LOG_TIMEOUT(3, printk("sg_read: dev=%d, count=%d\n",
MINOR(sdp->i_rdev), (int)count));
- /* If we are in the middle of error recovery, don't let anyone
- * else try and use this device. Also, if error recovery fails, it
- * may try and take the device offline, in which case all further
- * access to the device is prohibited. */
if(! scsi_block_when_processing_errors(sdp->device))
return -ENXIO;
-
if (ppos != &filp->f_pos)
; /* FIXME: Hmm. Seek to the right place, or fail? */
if ((k = verify_area(VERIFY_WRITE, buf, count)))
@@ -319,13 +332,15 @@
if (sfp->force_packid && (count >= size_sg_header))
req_pack_id = shp->pack_id;
srp = sg_get_request(sfp, req_pack_id);
- while(! srp) {
+ if (! srp) { /* now wait on packet to arrive */
if (filp->f_flags & O_NONBLOCK)
return -EAGAIN;
- interruptible_sleep_on(&sfp->read_wait);
- if (signal_pending(current))
- return -ERESTARTSYS;
- srp = sg_get_request(sfp, req_pack_id);
+ res = 0; /* following is a macro that beats race condition */
+ __wait_event_interruptible(sfp->read_wait,
+ (srp = sg_get_request(sfp, req_pack_id)),
+ res);
+ if (res)
+ return res; /* -ERESTARTSYS because signal hit process */
}
if (2 != sfp->underrun_flag)
srp->header.pack_len = srp->header.reply_len; /* Why ????? */
@@ -337,13 +352,13 @@
if (count > srp->header.reply_len)
count = srp->header.reply_len;
if (count > size_sg_header) /* release does copy_to_user */
- sg_sc_undo_rem(srp, buf, count - size_sg_header);
+ sg_finish_rem_req(srp, buf, count - size_sg_header);
else
- sg_sc_undo_rem(srp, NULL, 0);
+ sg_finish_rem_req(srp, NULL, 0);
}
else {
count = (srp->header.result == 0) ? 0 : -EIO;
- sg_sc_undo_rem(srp, NULL, 0);
+ sg_finish_rem_req(srp, NULL, 0);
}
return count;
}
@@ -366,22 +381,15 @@
SCSI_LOG_TIMEOUT(3, printk("sg_write: dev=%d, count=%d\n",
MINOR(sdp->i_rdev), (int)count));
-/* If we are in the middle of error recovery, don't let anyone
- * else try and use this device. Also, if error recovery fails, it
- * may try and take the device offline, in which case all further
- * access to the device is prohibited. */
if(! scsi_block_when_processing_errors(sdp->device) )
return -ENXIO;
-
if (ppos != &filp->f_pos)
; /* FIXME: Hmm. Seek to the right place, or fail? */
if ((k = verify_area(VERIFY_READ, buf, count)))
return k; /* protects following copy_from_user()s + get_user()s */
-/* The minimum scsi command length is 6 bytes. If we get anything
- * less than this, it is clearly bogus. */
if (count < (size_sg_header + 6))
- return -EIO;
+ return -EIO; /* The minimum scsi command length is 6 bytes. */
srp = sg_add_request(sfp);
if (! srp) {
@@ -392,55 +400,54 @@
buf += size_sg_header;
srp->header.pack_len = count;
__get_user(opcode, buf);
- cmd_size = COMMAND_SIZE(opcode);
- if ((opcode >= 0xc0) && srp->header.twelve_byte)
- cmd_size = 12;
+ if (sfp->next_cmd_len > 0) {
+ if (sfp->next_cmd_len > MAX_COMMAND_SIZE) {
+ SCSI_LOG_TIMEOUT(1, printk("sg_write: command length too long\n"));
+ sfp->next_cmd_len = 0;
+ return -EDOM;
+ }
+ cmd_size = sfp->next_cmd_len;
+ sfp->next_cmd_len = 0; /* reset so only this write() effected */
+ }
+ else {
+ cmd_size = COMMAND_SIZE(opcode); /* based on SCSI command group */
+ if ((opcode >= 0xc0) && srp->header.twelve_byte)
+ cmd_size = 12;
+ }
SCSI_LOG_TIMEOUT(4, printk("sg_write: scsi opcode=0x%02x, cmd_size=%d\n",
(int)opcode, cmd_size));
/* Determine buffer size. */
input_size = count - cmd_size;
mxsize = (input_size > srp->header.reply_len) ? input_size :
srp->header.reply_len;
-/* Don't include the command header itself in the size. */
mxsize -= size_sg_header;
input_size -= size_sg_header;
-/* Verify user has actually passed enough bytes for this command. */
if (input_size < 0) {
- sg_sc_undo_rem(srp, NULL, 0);
- return -EIO;
+ sg_remove_request(sfp, srp);
+ return -EIO; /* User did not pass enough bytes for this command. */
}
-
-/* If we cannot allocate the buffer, report an error. */
- if ((k = sg_sc_build(srp, mxsize, buf + cmd_size, input_size))) {
+ if ((k = sg_start_req(srp, mxsize, buf + cmd_size, input_size))) {
SCSI_LOG_TIMEOUT(1, printk("sg_write: build err=%d\n", k));
- sg_sc_undo_rem(srp, NULL, 0);
- return k;
+ sg_finish_rem_req(srp, NULL, 0);
+ return k; /* probably out of space --> ENOMEM */
}
-
/* SCSI_LOG_TIMEOUT(7, printk("sg_write: allocating device\n")); */
-/* Grab a command pointer for the device we want to talk to. If we
- * don't want to block, just return with the appropriate message. */
if (! (SCpnt = scsi_allocate_device(NULL, sdp->device,
!(filp->f_flags & O_NONBLOCK)))) {
- sg_sc_undo_rem(srp, NULL, 0);
- return -EAGAIN;
+ sg_finish_rem_req(srp, NULL, 0);
+ return -EAGAIN; /* No available command blocks at the moment */
}
/* SCSI_LOG_TIMEOUT(7, printk("sg_write: device allocated\n")); */
-
srp->my_cmdp = SCpnt;
SCpnt->request.rq_dev = sdp->i_rdev;
SCpnt->request.rq_status = RQ_ACTIVE;
SCpnt->sense_buffer[0] = 0;
SCpnt->cmd_len = cmd_size;
- /* Now copy the SCSI command from the user's address space. */
__copy_from_user(cmnd, buf, cmd_size);
-
-/* Set the LUN field in the command structure. */
+/* Set the LUN field in the command structure, overriding user input */
cmnd[1]= (cmnd[1] & 0x1f) | (sdp->device->lun << 5);
+
/* SCSI_LOG_TIMEOUT(7, printk("sg_write: do cmd\n")); */
-/* Now pass the actual command down to the low-level driver. We
- * do not do any more here - when the interrupt arrives, we will
- * then do the post-processing. */
spin_lock_irqsave(&io_request_lock, flags);
SCpnt->use_sg = srp->data.use_sg;
SCpnt->sglist_len = srp->data.sglist_len;
@@ -454,6 +461,8 @@
srp->data.sglist_len = 0;
srp->data.bufflen = 0;
srp->data.buffer = NULL;
+/* Now send everything of to mid-level. The next time we hear about this
+ packet is when sg_command_done() is called (ie a callback). */
scsi_do_cmd(SCpnt, (void *)cmnd,
(void *)SCpnt->buffer, mxsize,
sg_command_done, sfp->timeout, SG_DEFAULT_RETRIES);
@@ -475,9 +484,6 @@
return -ENXIO;
SCSI_LOG_TIMEOUT(3, printk("sg_ioctl: dev=%d, cmd=0x%x\n",
MINOR(sdp->i_rdev), (int)cmd_in));
- /* If we are in the middle of error recovery, then don't allow any
- * access to this device. Also, error recovery *may* have taken the
- * device offline, in which case all further access is prohibited. */
if(! scsi_block_when_processing_errors(sdp->device) )
return -ENXIO;
@@ -485,20 +491,18 @@
{
case SG_SET_TIMEOUT:
return get_user(sfp->timeout, (int *)arg);
- case SG_GET_TIMEOUT:
+ case SG_GET_TIMEOUT: /* N.B. User receives timeout as return value */
return sfp->timeout; /* strange ..., for backward compatibility */
case SG_SET_FORCE_LOW_DMA:
result = get_user(val, (int *)arg);
if (result) return result;
if (val) {
- if ((0 == sfp->low_dma) && (0 == sg_fb_in_use(sfp))) {
- sg_low_free(sfp->fst_buf, sfp->fb_size, SG_HEAP_PAGE);
- sfp->fst_buf = sg_low_malloc(SG_SCATTER_SZ, 1,
- SG_HEAP_PAGE, &sfp->fb_size);
- }
sfp->low_dma = 1;
- if (! sfp->fst_buf)
- return -ENOMEM;
+ if ((0 == sfp->low_dma) && (0 == sg_res_in_use(sfp))) {
+ val = (int)sfp->reserve.bufflen;
+ sg_remove_scat(&sfp->reserve);
+ sg_build_reserve(sfp, val);
+ }
}
else
sfp->low_dma = sdp->device->host->unchecked_isa_dma;
@@ -550,15 +554,20 @@
case SG_GET_SG_TABLESIZE:
return put_user(sdp->sg_tablesize, (int *)arg);
case SG_SET_RESERVED_SIZE:
- /* currently ignored, future extension */
if (O_RDWR != (filp->f_flags & O_ACCMODE))
return -EACCES;
result = get_user(val, (int *)arg);
if (result) return result;
- /* logic should go here */
+ if (val != sfp->reserve.bufflen) {
+ if (sg_res_in_use(sfp))
+ return -EBUSY;
+ sg_remove_scat(&sfp->reserve);
+ sg_build_reserve(sfp, val);
+ }
return 0;
case SG_GET_RESERVED_SIZE:
- return put_user(sfp->fb_size, (int *)arg);
+ val = (int)sfp->reserve.bufflen;
+ return put_user(val, (int *)arg);
case SG_GET_MERGE_FD:
return put_user((int)sdp->merge_fd, (int *)arg);
case SG_SET_MERGE_FD:
@@ -587,6 +596,13 @@
return 0;
case SG_GET_UNDERRUN_FLAG:
return put_user((int)sfp->underrun_flag, (int *)arg);
+ case SG_NEXT_CMD_LEN:
+ result = get_user(val, (int *)arg);
+ if (result) return result;
+ sfp->next_cmd_len = (val > 0) ? val : 0;
+ return 0;
+ case SG_GET_VERSION_NUM:
+ return put_user(sg_version_num, (int *)arg);
case SG_EMULATED_HOST:
return put_user(sdp->device->host->hostt->emulated, (int *)arg);
case SCSI_IOCTL_SEND_COMMAND:
@@ -594,8 +610,7 @@
user already has read/write access to the generic device and so
can execute arbitrary SCSI commands. */
if (O_RDWR != (filp->f_flags & O_ACCMODE))
- return -EACCES; /* require write access since these could be
- dangerous */
+ return -EACCES; /* very dangerous things can be done here */
return scsi_ioctl_send_command(sdp->device, (void *)arg);
case SG_SET_DEBUG:
result = get_user(val, (int *)arg);
@@ -613,8 +628,7 @@
return scsi_ioctl(sdp->device, cmd_in, (void *)arg);
default:
if (O_RDWR != (filp->f_flags & O_ACCMODE))
- return -EACCES; /* require write access since these could be
- dangerous */
+ return -EACCES; /* don't know so take safe approach */
return scsi_ioctl(sdp->device, cmd_in, (void *)arg);
}
}
@@ -664,8 +678,7 @@
}
/* This function is called by the interrupt handler when we
- * actually have a command that is complete. Change the
- * flags to indicate that we have a result. */
+ * actually have a command that is complete. */
static void sg_command_done(Scsi_Cmnd * SCpnt)
{
int dev = MINOR(SCpnt->request.rq_dev);
@@ -712,17 +725,16 @@
sg_clr_scpnt(SCpnt);
srp->my_cmdp = NULL;
- SCSI_LOG_TIMEOUT(4,
- printk("sg__done: dev=%d, scsi_stat=%d, res=0x%x\n",
+ SCSI_LOG_TIMEOUT(4, printk("sg__done: dev=%d, scsi_stat=%d, res=0x%x\n",
dev, (int)status_byte(SCpnt->result), (int)SCpnt->result));
-/* See if the command completed normally, or whether something went wrong. */
memcpy(srp->header.sense_buffer, SCpnt->sense_buffer,
sizeof(SCpnt->sense_buffer));
switch (host_byte(SCpnt->result))
- {
+ { /* This setup of 'result' is for backward compatibility and is best
+ ignored by the user who should use target, host + driver status */
case DID_OK:
- case DID_PASSTHROUGH: /* just guessing */
- case DID_SOFT_ERROR: /* just guessing */
+ case DID_PASSTHROUGH:
+ case DID_SOFT_ERROR:
srp->header.result = 0;
break;
case DID_NO_CONNECT:
@@ -738,12 +750,6 @@
srp->header.result = EIO;
break;
case DID_ERROR:
- /* There really should be DID_UNDERRUN and DID_OVERRUN error values,
- * and a means for callers of scsi_do_cmd to indicate whether an
- * underrun or overrun should signal an error. Until that can be
- * implemented, this kludge allows for returning useful error values
- * except in cases that return DID_ERROR that might be due to an
- * underrun. */
if (SCpnt->sense_buffer[0] == 0 &&
status_byte(SCpnt->result) == GOOD)
srp->header.result = 0;
@@ -767,8 +773,6 @@
/* filesystems using this device. */
sdp->device->changed = 1;
}
-
-/* Pick up error and status information */
srp->header.target_status = status_byte(SCpnt->result);
if ((sdp->sgdebug > 0) &&
((CHECK_CONDITION == srp->header.target_status) ||
@@ -784,15 +788,14 @@
SCSI_LOG_TIMEOUT(1,
printk("sg__done: already closed, freeing ...\n"));
/* should check if module is unloaded <<<<<<< */
- sg_sc_undo_rem(srp, NULL, 0);
+ sg_finish_rem_req(srp, NULL, 0);
if (NULL == sfp->headrp) {
SCSI_LOG_TIMEOUT(1,
printk("sg__done: already closed, final cleanup\n"));
sg_remove_sfp(sdp, sfp);
}
}
-/* Now wake up the process that is waiting for the result. */
- /* A. Rubini says this is preferable+faster than wake_up() */
+/* Now wake up any sg_read() that is waiting for this packet. */
wake_up_interruptible(&sfp->read_wait);
if ((sfp->async_qp) && (! closed))
kill_fasync(sfp->async_qp, SIGPOLL);
@@ -873,17 +876,20 @@
printk(" *** Following data belongs to invoking FD ***\n");
else if (! fp->parentdp)
printk(">> Following FD has NULL parent pointer ???\n");
- printk(" FD(%d): timeout=%d, fb_size=%d, cmd_q=%d\n",
- k, fp->timeout, fp->fb_size, (int)fp->cmd_q);
- printk(" low_dma=%d, force_packid=%d, urun_flag=%d, closed=%d\n",
- (int)fp->low_dma, (int)fp->force_packid,
- (int)fp->underrun_flag, (int)fp->closed);
+ printk(" FD(%d): timeout=%d, bufflen=%d, use_sg=%d\n",
+ k, fp->timeout, fp->reserve.bufflen, (int)fp->reserve.use_sg);
+ printk(" low_dma=%d, cmd_q=%d, s_sc_len=%d, f_packid=%d\n",
+ (int)fp->low_dma, (int)fp->cmd_q, (int)fp->save_scat_len,
+ (int)fp->force_packid);
+ printk(" urun_flag=%d, next_cmd_len=%d, closed=%d\n",
+ (int)fp->underrun_flag, (int)fp->next_cmd_len,
+ (int)fp->closed);
srp = fp->headrp;
if (NULL == srp)
printk(" No requests active\n");
while (srp) {
- if (srp->fb_used)
- printk("using 1st buff >> ");
+ if (srp->res_used)
+ printk("reserved buff >> ");
else
printk(" ");
if (srp->my_cmdp)
@@ -988,7 +994,7 @@
SCSI_LOG_TIMEOUT(3, printk("sg_attach: dev=%d \n", k));
sdp->device = scsidp;
- init_waitqueue_head(&sdp->generic_wait);
+ init_waitqueue_head(&sdp->o_excl_wait);
sdp->headfp= NULL;
sdp->exclude = 0;
sdp->merge_fd = 0; /* Cope with SG_DEF_MERGE_FD on open */
@@ -1041,10 +1047,8 @@
}
scsidp->attached--;
sg_template.nr_dev--;
- /*
- * avoid associated device /dev/sg? bying incremented
- * each time module is inserted/removed , <dan@lectra.fr>
- */
+/* avoid associated device /dev/sg? being incremented
+ * each time module is inserted/removed , <dan@lectra.fr> */
sg_template.dev_noticed--;
return;
}
@@ -1099,42 +1103,80 @@
#endif
}
-static int sg_sc_build(Sg_request * srp, int max_buff_size,
- const char * inp, int num_write_xfer)
+static int sg_start_req(Sg_request * srp, int max_buff_size,
+ const char * inp, int num_write_xfer)
+{
+ int res;
+ Sg_fd * sfp = srp->parentfp;
+ Sg_scatter_hold * req_schp = &srp->data;
+ Sg_scatter_hold * rsv_schp = &sfp->reserve;
+
+ SCSI_LOG_TIMEOUT(4, printk("sg_start_req: max_buff_size=%d\n",
+ max_buff_size));
+ if ((! sg_res_in_use(sfp)) && (max_buff_size <= rsv_schp->bufflen)) {
+ sg_link_reserve(sfp, srp, max_buff_size);
+ sg_write_xfer(req_schp, inp, num_write_xfer);
+ }
+ else {
+ res = sg_build_scat(req_schp, max_buff_size, sfp);
+ if (res) {
+ sg_remove_scat(req_schp);
+ return res;
+ }
+ sg_write_xfer(req_schp, inp, num_write_xfer);
+ }
+ return 0;
+}
+
+static void sg_finish_rem_req(Sg_request * srp, char * outp,
+ int num_read_xfer)
+{
+ Sg_fd * sfp = srp->parentfp;
+ Sg_scatter_hold * req_schp = &srp->data;
+
+ SCSI_LOG_TIMEOUT(4, printk("sg_finish_rem_req: res_used=%d\n",
+ (int)srp->res_used));
+ if (num_read_xfer > 0)
+ sg_read_xfer(req_schp, outp, num_read_xfer);
+ if (srp->res_used)
+ sg_unlink_reserve(sfp, srp);
+ else
+ sg_remove_scat(req_schp);
+ sg_remove_request(sfp, srp);
+}
+
+static int sg_build_scat(Sg_scatter_hold * schp, int buff_size,
+ const Sg_fd * sfp)
{
int ret_sz, mem_src;
- int blk_size = max_buff_size;
+ int blk_size = buff_size;
char * p = NULL;
- if ((blk_size < 0) || (! srp))
+ if ((blk_size < 0) || (! sfp))
return -EFAULT;
-
- SCSI_LOG_TIMEOUT(4, printk("sg_sc_build: m_b_s=%d, num_write_xfer=%d\n",
- max_buff_size, num_write_xfer));
if (0 == blk_size)
++blk_size; /* don't know why */
/* round request up to next highest SG_SECTOR_SZ byte boundary */
blk_size = (blk_size + SG_SECTOR_MSK) & (~SG_SECTOR_MSK);
- SCSI_LOG_TIMEOUT(5, printk("sg_sc_build: blk_size=%d\n", blk_size));
-
+ SCSI_LOG_TIMEOUT(4, printk("sg_build_scat: buff_size=%d, blk_size=%d\n",
+ buff_size, blk_size));
if (blk_size <= SG_SCATTER_SZ) {
- mem_src = SG_HEAP_FB;
- p = sg_malloc(srp, blk_size, &ret_sz, &mem_src);
+ mem_src = SG_HEAP_PAGE;
+ p = sg_malloc(sfp, blk_size, &ret_sz, &mem_src);
if (! p)
return -ENOMEM;
if (blk_size == ret_sz) { /* got it on the first attempt */
- srp->data.buffer = p;
- srp->data.bufflen = blk_size;
- srp->data.mem_src = mem_src;
- srp->data.b_malloc_len = blk_size;
- if (inp && (num_write_xfer > 0))
- __copy_from_user(srp->data.buffer, inp, num_write_xfer);
+ schp->use_sg = 0;
+ schp->buffer = p;
+ schp->bufflen = blk_size;
+ schp->mem_src = mem_src;
+ schp->b_malloc_len = blk_size;
return 0;
}
}
else {
mem_src = SG_HEAP_PAGE;
- p = sg_malloc(srp, SG_SCATTER_SZ, &ret_sz, &mem_src);
+ p = sg_malloc(sfp, SG_SCATTER_SZ, &ret_sz, &mem_src);
if (! p)
return -ENOMEM;
}
@@ -1144,23 +1186,23 @@
int k, rem_sz, num, nxt;
int sc_bufflen = PAGE_SIZE;
int mx_sc_elems = (sc_bufflen / sizeof(struct scatterlist)) - 1;
- int sg_tablesize = srp->parentfp->parentdp->sg_tablesize;
+ int sg_tablesize = sfp->parentdp->sg_tablesize;
int first = 1;
k = SG_HEAP_KMAL; /* want to protect mem_src, use k as scratch */
- srp->data.buffer = (struct scatterlist *)sg_malloc(srp,
+ schp->buffer = (struct scatterlist *)sg_malloc(sfp,
sc_bufflen, &num, &k);
- srp->data.mem_src = (char)k;
+ schp->mem_src = (char)k;
/* N.B. ret_sz and mem_src carried into this block ... */
- if (! srp->data.buffer)
+ if (! schp->buffer)
return -ENOMEM;
else if (num != sc_bufflen) {
sc_bufflen = num;
mx_sc_elems = (sc_bufflen / sizeof(struct scatterlist)) - 1;
}
- srp->data.sglist_len = sc_bufflen;
- memset(srp->data.buffer, 0, sc_bufflen);
- for (k = 0, sclp = srp->data.buffer, rem_sz = blk_size, nxt =0;
+ schp->sglist_len = sc_bufflen;
+ memset(schp->buffer, 0, sc_bufflen);
+ for (k = 0, sclp = schp->buffer, rem_sz = blk_size, nxt =0;
(k < sg_tablesize) && (rem_sz > 0) && (k < mx_sc_elems);
++k, rem_sz -= ret_sz, ++sclp) {
if (first)
@@ -1168,7 +1210,7 @@
else {
num = (rem_sz > SG_SCATTER_SZ) ? SG_SCATTER_SZ : rem_sz;
mem_src = SG_HEAP_PAGE;
- p = sg_malloc(srp, num, &ret_sz, &mem_src);
+ p = sg_malloc(sfp, num, &ret_sz, &mem_src);
if (! p)
break;
}
@@ -1176,73 +1218,188 @@
sclp->length = ret_sz;
sclp->alt_address = (char *)(long)mem_src;
- if(inp && (num_write_xfer > 0)) {
- num = (ret_sz > num_write_xfer) ? num_write_xfer : ret_sz;
- __copy_from_user(sclp->address, inp, num);
- num_write_xfer -= num;
- inp += num;
- }
SCSI_LOG_TIMEOUT(5,
- printk("sg_sc_build: k=%d, a=0x%p, len=%d, ms=%d\n",
+ printk("sg_build_build: k=%d, a=0x%p, len=%d, ms=%d\n",
k, sclp->address, ret_sz, mem_src));
} /* end of for loop */
- srp->data.use_sg = k;
+ schp->use_sg = k;
SCSI_LOG_TIMEOUT(5,
- printk("sg_sc_build: use_sg=%d, rem_sz=%d\n", k, rem_sz));
- srp->data.bufflen = blk_size;
+ printk("sg_build_scat: use_sg=%d, rem_sz=%d\n", k, rem_sz));
+ schp->bufflen = blk_size;
if (rem_sz > 0) /* must have failed */
return -ENOMEM;
}
return 0;
}
-static int sg_sc_undo_rem(Sg_request * srp, char * outp,
- int num_read_xfer)
+static void sg_write_xfer(Sg_scatter_hold * schp, const char * inp,
+ int num_write_xfer)
{
- if (! srp)
- return -EFAULT;
- SCSI_LOG_TIMEOUT(4, printk("sg_sc_undo_rem: num_read_xfer=%d\n",
- num_read_xfer));
- if (! outp)
- num_read_xfer = 0;
- if(srp->data.use_sg) {
- int k, num, mem_src;
- struct scatterlist * sclp = (struct scatterlist *)srp->data.buffer;
-
- for (k = 0; (k < srp->data.use_sg) && sclp->address; ++k, ++sclp) {
- if (num_read_xfer > 0) {
- num = (int)sclp->length;
- if (num > num_read_xfer) {
- __copy_to_user(outp, sclp->address, num_read_xfer);
- outp += num_read_xfer;
- num_read_xfer = 0;
- }
- else {
- __copy_to_user(outp, sclp->address, num);
- outp += num;
- num_read_xfer -= num;
- }
+ SCSI_LOG_TIMEOUT(4, printk("sg_write_xfer: num_write_xfer=%d, use_sg=%d\n",
+ num_write_xfer, schp->use_sg));
+ if ((! inp) || (num_write_xfer <= 0))
+ return;
+ if (schp->use_sg > 0) {
+ int k, num;
+ struct scatterlist * sclp = (struct scatterlist *)schp->buffer;
+
+ for (k = 0; (k < schp->use_sg) && sclp->address; ++k, ++sclp) {
+ num = (int)sclp->length;
+ if (num > num_write_xfer) {
+ __copy_from_user(sclp->address, inp, num_write_xfer);
+ break;
}
+ else {
+ __copy_from_user(sclp->address, inp, num);
+ num_write_xfer -= num;
+ if (num_write_xfer <= 0)
+ break;
+ inp += num;
+ }
+ }
+ }
+ else
+ __copy_from_user(schp->buffer, inp, num_write_xfer);
+}
+
+static void sg_remove_scat(Sg_scatter_hold * schp)
+{
+ SCSI_LOG_TIMEOUT(4, printk("sg_remove_scat: use_sg=%d\n", schp->use_sg));
+ if(schp->use_sg > 0) {
+ int k, mem_src;
+ struct scatterlist * sclp = (struct scatterlist *)schp->buffer;
+
+ for (k = 0; (k < schp->use_sg) && sclp->address; ++k, ++sclp) {
mem_src = (int)(long)sclp->alt_address;
SCSI_LOG_TIMEOUT(5,
- printk("sg_sc_undo_rem: k=%d, a=0x%p, len=%d, ms=%d\n",
+ printk("sg_remove_scat: k=%d, a=0x%p, len=%d, ms=%d\n",
k, sclp->address, sclp->length, mem_src));
- sg_free(srp, sclp->address, sclp->length, mem_src);
+ sg_free(sclp->address, sclp->length, mem_src);
+ sclp->address = NULL;
+ sclp->length = 0;
+ }
+ sg_free(schp->buffer, schp->sglist_len, schp->mem_src);
+ }
+ else if (schp->buffer)
+ sg_free(schp->buffer, schp->b_malloc_len, schp->mem_src);
+ schp->buffer = NULL;
+ schp->bufflen = 0;
+ schp->use_sg = 0;
+ schp->sglist_len = 0;
+}
+
+static void sg_read_xfer(Sg_scatter_hold * schp, char * outp,
+ int num_read_xfer)
+{
+ SCSI_LOG_TIMEOUT(4, printk("sg_read_xfer: num_read_xfer=%d\n",
+ num_read_xfer));
+ if ((! outp) || (num_read_xfer <= 0))
+ return;
+ if(schp->use_sg > 0) {
+ int k, num;
+ struct scatterlist * sclp = (struct scatterlist *)schp->buffer;
+
+ for (k = 0; (k < schp->use_sg) && sclp->address; ++k, ++sclp) {
+ num = (int)sclp->length;
+ if (num > num_read_xfer) {
+ __copy_to_user(outp, sclp->address, num_read_xfer);
+ break;
+ }
+ else {
+ __copy_to_user(outp, sclp->address, num);
+ num_read_xfer -= num;
+ if (num_read_xfer <= 0)
+ break;
+ outp += num;
+ }
}
- sg_free(srp, srp->data.buffer, srp->data.sglist_len,
- srp->data.mem_src);
+ }
+ else
+ __copy_to_user(outp, schp->buffer, num_read_xfer);
+}
+
+static void sg_build_reserve(Sg_fd * sfp, int req_size)
+{
+ Sg_scatter_hold * schp = &sfp->reserve;
+
+ SCSI_LOG_TIMEOUT(4, printk("sg_build_reserve: req_size=%d\n", req_size));
+ do {
+ if (req_size < PAGE_SIZE)
+ req_size = PAGE_SIZE;
+ if (0 == sg_build_scat(schp, req_size, sfp))
+ return;
+ else
+ sg_remove_scat(schp);
+ req_size >>= 1; /* divide by 2 */
+ } while (req_size > (PAGE_SIZE / 2));
+}
+
+static void sg_link_reserve(Sg_fd * sfp, Sg_request * srp, int size)
+{
+ Sg_scatter_hold * req_schp = &srp->data;
+ Sg_scatter_hold * rsv_schp = &sfp->reserve;
+
+ SCSI_LOG_TIMEOUT(4, printk("sg_link_reserve: size=%d\n", size));
+ if (rsv_schp->use_sg > 0) {
+ int k, num;
+ int rem = size;
+ struct scatterlist * sclp = (struct scatterlist *)rsv_schp->buffer;
+
+ for (k = 0; k < rsv_schp->use_sg; ++k, ++sclp) {
+ num = (int)sclp->length;
+ if (rem <= num) {
+ sfp->save_scat_len = num;
+ sclp->length = (unsigned)rem;
+ break;
+ }
+ else
+ rem -= num;
+ }
+ if (k < rsv_schp->use_sg) {
+ req_schp->use_sg = k + 1; /* adjust scatter list length */
+ req_schp->bufflen = size;
+ req_schp->sglist_len = rsv_schp->sglist_len;
+ req_schp->buffer = rsv_schp->buffer;
+ req_schp->mem_src = rsv_schp->mem_src;
+ req_schp->b_malloc_len = rsv_schp->b_malloc_len;
+ }
+ else
+ SCSI_LOG_TIMEOUT(1, printk("sg_link_reserve: BAD size\n"));
}
else {
- if (num_read_xfer > 0)
- __copy_to_user(outp, srp->data.buffer, num_read_xfer);
- sg_free(srp, srp->data.buffer, srp->data.b_malloc_len,
- srp->data.mem_src);
- }
- if (0 == sg_remove_request(srp->parentfp, srp)) {
- SCSI_LOG_TIMEOUT(1, printk("sg_sc_undo_rem: srp=0x%p not found\n",
- srp));
+ req_schp->use_sg = 0;
+ req_schp->bufflen = size;
+ req_schp->buffer = rsv_schp->buffer;
+ req_schp->mem_src = rsv_schp->mem_src;
+ req_schp->use_sg = rsv_schp->use_sg;
+ req_schp->b_malloc_len = rsv_schp->b_malloc_len;
}
- return 0;
+ srp->res_used = 1;
+}
+
+static void sg_unlink_reserve(Sg_fd * sfp, Sg_request * srp)
+{
+ Sg_scatter_hold * req_schp = &srp->data;
+ Sg_scatter_hold * rsv_schp = &sfp->reserve;
+
+ SCSI_LOG_TIMEOUT(4, printk("sg_unlink_reserve: req->use_sg=%d\n",
+ (int)req_schp->use_sg));
+ if (rsv_schp->use_sg > 0) {
+ struct scatterlist * sclp = (struct scatterlist *)rsv_schp->buffer;
+
+ if (sfp->save_scat_len > 0)
+ (sclp + (req_schp->use_sg - 1))->length =
+ (unsigned)sfp->save_scat_len;
+ else
+ SCSI_LOG_TIMEOUT(1, printk(
+ "sg_unlink_reserve: BAD save_scat_len\n"));
+ }
+ req_schp->use_sg = 0;
+ req_schp->bufflen = 0;
+ req_schp->buffer = NULL;
+ req_schp->sglist_len = 0;
+ sfp->save_scat_len = 0;
+ srp->res_used = 0;
}
static Sg_request * sg_get_request(const Sg_fd * sfp, int pack_id)
@@ -1292,7 +1449,7 @@
if (resp) {
resp->parentfp = sfp;
resp->nextrp = NULL;
- resp->fb_used = 0;
+ resp->res_used = 0;
memset(&resp->data, 0, sizeof(Sg_scatter_hold));
memset(&resp->header, 0, sizeof(struct sg_header));
resp->my_cmdp = NULL;
@@ -1347,13 +1504,6 @@
sdp->device->host->unchecked_isa_dma : 1;
sfp->cmd_q = SG_DEF_COMMAND_Q;
sfp->underrun_flag = SG_DEF_UNDERRUN_FLAG;
- if (get_reserved)
- sfp->fst_buf = sg_low_malloc(SG_SCATTER_SZ, sfp->low_dma,
- SG_HEAP_PAGE, &sfp->fb_size);
- else
- sfp->fst_buf = NULL;
- if (! sfp->fst_buf)
- sfp->fb_size = 0;
sfp->parentdp = sdp;
if (! sdp->headfp)
sdp->headfp = sfp;
@@ -1363,11 +1513,14 @@
pfp = pfp->nextfp;
pfp->nextfp = sfp;
}
- sg_big_buff = sfp->fb_size; /* show sysctl most recent "fb" size */
SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p, m_s=%d\n",
sfp, (int)sfp->my_mem_src));
- SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: fb_sz=%d, fst_buf=0x%p\n",
- sfp->fb_size, sfp->fst_buf));
+ if (get_reserved) {
+ sg_build_reserve(sfp, SG_DEF_RESERVED_SIZE);
+ sg_big_buff = sfp->reserve.bufflen; /* sysctl shows most recent size */
+ SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: bufflen=%d, use_sg=%d\n",
+ sfp->reserve.bufflen, sfp->reserve.use_sg));
+ }
return sfp;
}
@@ -1388,7 +1541,7 @@
while (srp) {
tsrp = srp->nextrp;
if (! srp->my_cmdp)
- sg_sc_undo_rem(srp, NULL, 0);
+ sg_finish_rem_req(srp, NULL, 0);
else
++dirty;
srp = tsrp;
@@ -1409,12 +1562,12 @@
prev_fp = fp;
}
}
-SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp: fb_sz=%d, fst_buf=0x%p\n",
- sfp->fb_size, sfp->fst_buf));
- sg_low_free(sfp->fst_buf, sfp->fb_size, SG_HEAP_PAGE);
+ if (sfp->reserve.bufflen > 0) {
+SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp: bufflen=%d, use_sg=%d\n",
+ (int)sfp->reserve.bufflen, (int)sfp->reserve.use_sg));
+ sg_remove_scat(&sfp->reserve);
+ }
sfp->parentdp = NULL;
- sfp->fst_buf = NULL;
- sfp->fb_size = 0;
SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp: sfp=0x%p\n", sfp));
sg_low_free((char *)sfp, sizeof(Sg_fd), sfp->my_mem_src);
res = 1;
@@ -1427,12 +1580,12 @@
return res;
}
-static int sg_fb_in_use(const Sg_fd * sfp)
+static int sg_res_in_use(const Sg_fd * sfp)
{
const Sg_request * srp = sfp->headrp;
while (srp) {
- if (srp->fb_used)
+ if (srp->res_used)
return 1;
srp = srp->nextrp;
}
@@ -1511,7 +1664,7 @@
return resp;
}
-static char * sg_malloc(Sg_request * srp, int size, int * retSzp,
+static char * sg_malloc(const Sg_fd * sfp, int size, int * retSzp,
int * mem_srcp)
{
char * resp = NULL;
@@ -1520,26 +1673,16 @@
if (size <= 0)
;
else {
- Sg_fd * sfp = srp->parentfp;
int low_dma = sfp->low_dma;
int l_ms = -1; /* invalid value */
switch (*mem_srcp)
{
case SG_HEAP_PAGE:
- case SG_HEAP_FB:
l_ms = (size < PAGE_SIZE) ? SG_HEAP_POOL : SG_HEAP_PAGE;
resp = sg_low_malloc(size, low_dma, l_ms, 0);
if (resp)
break;
- if ((size <= sfp->fb_size) && (0 == sg_fb_in_use(sfp))) {
- SCSI_LOG_TIMEOUT(6,
- printk("sg_malloc: scsi_malloc failed, get fst_buf\n"));
- resp = sfp->fst_buf;
- srp->fb_used = 1;
- l_ms = SG_HEAP_FB;
- break;
- }
resp = sg_low_malloc(size, low_dma, l_ms, &size);
if (! resp) {
l_ms = (SG_HEAP_POOL == l_ms) ? SG_HEAP_PAGE : SG_HEAP_POOL;
@@ -1595,18 +1738,12 @@
mem_src, buff, size);
}
-static void sg_free(Sg_request * srp, char * buff, int size, int mem_src)
+static void sg_free(char * buff, int size, int mem_src)
{
- Sg_fd * sfp = srp->parentfp;
-
SCSI_LOG_TIMEOUT(6,
printk("sg_free: buff=0x%p, size=%d\n", buff, size));
- if ((! sfp) || (! buff) || (size <= 0))
+ if ((! buff) || (size <= 0))
;
- else if (sfp->fst_buf == buff) {
- srp->fb_used = 0;
- SCSI_LOG_TIMEOUT(6, printk("sg_free: left cause fst_buf\n"));
- }
else
sg_low_free(buff, size, mem_src);
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)