patch-1.3.48 linux/drivers/block/ide-tape.h
Next file: linux/drivers/block/ide.c
Previous file: linux/drivers/block/ide-tape.c
Back to the patch index
Back to the overall index
- Lines: 354
- Date:
Sun Dec 17 11:17:19 1995
- Orig file:
v1.3.47/linux/drivers/block/ide-tape.h
- Orig date:
Mon Dec 11 15:42:01 1995
diff -u --recursive --new-file v1.3.47/linux/drivers/block/ide-tape.h linux/drivers/block/ide-tape.h
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide-tape.h Version 1.0 - ALPHA Dec 3, 1995
+ * linux/drivers/block/ide-tape.h Version 1.1 - ALPHA Dec 14, 1995
*
* Copyright (C) 1995 Gadi Oxman <tgud@tochnapc2.technion.ac.il>
*/
@@ -19,6 +19,63 @@
/**************************** Tunable parameters *****************************/
/*
+ * This is probably the most important configuration option.
+ *
+ * Pipelined operation mode has the potential to maximize the
+ * performance of the driver and thus to saturate the throughput
+ * to the maximum value supported by the tape. Currently, pipelined
+ * mode is supported only on writes.
+ *
+ * In pipelined mode we are servicing requests without blocking the
+ * user backup program. For example, on a write request, we will add it
+ * to the pipeline and return without waiting for it to complete. The
+ * user program will then have enough time to prepare the next blocks
+ * while the tape is still busy working on the previous requests.
+ *
+ * Pipelined (write) operation mode is enabled by default, but since
+ * it has a few downfalls as well (Use of additional memory and deferred
+ * error code to the application), you may wish to disable it.
+ * Further explanation of pipelined mode is available in ide-tape.c .
+ */
+
+#define IDETAPE_PIPELINE 1
+
+/*
+ * Pipelined mode parameters.
+ *
+ * We try to use the minimum number of stages which is enough to
+ * keep the tape constantly streaming. To accomplish that, we implement
+ * a feedback loop around the maximum number of stages:
+ *
+ * We start from MIN maximum stages (we will not even use MIN stages
+ * if we don't need them), increment it by RATE*(MAX-MIN)
+ * whenever we sense that the pipeline is empty, until we reach
+ * the optimum value or until we reach MAX.
+ */
+
+#define IDETAPE_MIN_PIPELINE_STAGES 100
+#define IDETAPE_MAX_PIPELINE_STAGES 200
+#define IDETAPE_INCREASE_STAGES_RATE 0.2
+
+/*
+ * It seems that dynamically allocating buffers of about 32KB
+ * each is doomed to fail, unless we are in or very near the
+ * initialization stage. Take care when changing this value, as it
+ * is now optimized with the design of kmalloc, so that we will not
+ * allocate parts of a page. Setting the size to 512 bytes, for example,
+ * would cause kmalloc to allocate for us 1024 bytes, and to
+ * unnecessarily waste double amount of memory.
+ */
+
+#if PAGE_SIZE == 4096
+ #define IDETAPE_ALLOCATION_BLOCK 500
+#elif PAGE_SIZE == 8192
+ #define IDETAPE_ALLOCATION_BLOCK 496
+#else /* ??? Not defined by linux/mm/kmalloc.c */
+ #define IDETAPE_ALLOCATION_BLOCK 512
+#endif
+
+/*
* Setting IDETAPE_DEBUG to 1 will:
*
* 1. Generally log all driver actions.
@@ -45,15 +102,6 @@
#define IDETAPE_MAX_PC_RETRIES 2
/*
- * In case the tape is not at the requested block, we re-position the
- * tape. Repeat the procedure for IDETAPE_LOCATE_RETRIES times before
- * we give up and abort the request. Note that this should not usually
- * happen when using only the character device interface.
- */
-
-#define IDETAPE_LOCATE_RETRIES 1
-
-/*
* With each packet command, we allocate a buffer of
* IDETAPE_TEMP_BUFFER_SIZE bytes. This is used for several packet
* commands (Not for READ/WRITE commands).
@@ -80,70 +128,56 @@
* the handling of a specific request.
*
* Follows a worse case calculation of the required storage, with a
- * large safety margin. Hopefully. :-)
+ * large safety margin.
*/
-#define IDETAPE_PC_STACK 10+\
- IDETAPE_MAX_PC_RETRIES+\
- 3*IDETAPE_LOCATE_RETRIES*IDETAPE_MAX_PC_RETRIES
-/*
- * Media access packet command (like the LOCATE command) have immediate
- * status with a delayed (and usually long) execution. The tape doesn't
- * issue an interrupt when the command is actually complete (so that the
- * bus is freed to use the other IDE device on the same interface), so we
- * must for poll for this event.
- *
- * We set a timer with polling frequency of 1/IDETAPE_DSC_MEDIA_ACCESS_FREQUENCY
- * in this case. We also poll for DSC *before* read/write commands. At
- * this time the DSC role is changed and instead of signalling command
- * completion, it will signal buffer availability. Since read/write
- * commands are fast in comparision to media access commands, the polling
- * frequency here should be much higher.
- *
- * We will insist of reading DSC=1 for IDETAPE_DSC_COUNT times in a row,
- * to accommodate for random fluctuations in the sampling of DSC.
- * We will also set IDETAPE_DSC_POLLING_FREQUENCY to a rather low
- * frequency which besides freeing the CPU and the bus will let
- * random fluctuations a time to settle down.
+#define IDETAPE_PC_STACK 20+IDETAPE_MAX_PC_RETRIES
+
+/*
+ * DSC polling parameters.
*
+ * Polling for DSC (a single bit in the status register) is a very
+ * important function in ide-tape. There are two cases in which we
+ * poll for DSC:
+ *
+ * 1. Before a read/write packet command, to ensure that we
+ * can transfer data from/to the tape's data buffers, without
+ * causing an actual media access. In case the tape is not
+ * ready yet, we take out our request from the device
+ * request queue, so that ide.c will service requests from
+ * the other device on the same interface meanwhile.
+ *
+ * The polling frequency is 1/IDETAPE_DSC_READ_WRITE_FREQUENCY,
+ * and it should be relatively fast. The default is a period
+ * of 50 msec.
+ *
+ * 2. After the successful initialization of a "media access
+ * packet command", which is a command which can take a long
+ * time to complete (it can be several seconds or even an hour).
+ *
+ * Again, we postpone our request in the middle to free the bus
+ * for the other device. The polling frequency here should be
+ * lower than the read/write frequency since those media access
+ * commands are slow. We start from a "fast" frequency -
+ * IDETAPE_DSC_FAST_MEDIA_ACCESS_FREQUENCY (one second), and
+ * if we don't receive DSC after IDETAPE_FAST_SLOW_THRESHOLD
+ * (5 minutes), we switch it to a lower frequency -
+ * IDETAPE_DSC_SLOW_MEDIA_ACCESS_FREQUENCY (1 minute).
+ *
* We also set a timeout for the timer, in case something goes wrong.
* The timeout should be longer then the maximum execution time of a
* tape operation. I still have to measure exactly how much time does
* it take to space over a far filemark, etc. It seemed that 15 minutes
* was way too low, so I am meanwhile setting it to a rather large
- * timeout - 2 Hours.
+ * timeout - 2 Hours ...
*
- * Once we pass a threshold, the polling frequency will change to
- * a slow frequency: On relatively fast operations, there is a point
- * in polling fast, but if we sense that the operation is taking too
- * much time, we will poll at a lower frequency.
*/
+#define IDETAPE_DSC_READ_WRITE_FREQUENCY 5*HZ/100 /* 50 msec */
#define IDETAPE_DSC_FAST_MEDIA_ACCESS_FREQUENCY 1*HZ /* 1 second */
#define IDETAPE_FAST_SLOW_THRESHOLD 5*60*HZ /* 5 minutes */
#define IDETAPE_DSC_SLOW_MEDIA_ACCESS_FREQUENCY 60*HZ /* 1 minute */
-#define IDETAPE_DSC_READ_WRITE_FREQUENCY HZ/20 /* 50 msec */
#define IDETAPE_DSC_TIMEOUT 2*60*60*HZ /* 2 hours */
-#define IDETAPE_DSC_COUNT 1 /* Assume no DSC fluctuations */
-
-/*
- * As explained in many places through the code, we provide both a block
- * device and a character device interface to the tape. The block device
- * interface is needed for compatibility with ide.c. The character device
- * interface is the higher level of the driver, and passes requests
- * to the lower part of the driver which interfaces with ide.c.
- * Using the block device interface, we can bypass this high level
- * of the driver, talking directly with the lower level part.
- *
- * It is intended that the character device interface will be used by
- * the user. To prevent mistakes in this regard, opening of the block
- * device interface will be refused if ALLOW_OPENING_BLOCK_DEVICE is 0.
- *
- * Do not change the following parameter unless you are developing
- * the driver itself.
- */
-
-#define IDETAPE_ALLOW_OPENING_BLOCK_DEVICE 0
/*************************** End of tunable parameters ***********************/
@@ -226,6 +260,30 @@
} idetape_capabilities_page_t;
/*
+ * A pipeline stage contains several small buffers of type
+ * idetape_buffer_head_t. This is necessary since dynamical allocation
+ * of large (32 KB or so) continuous memory blocks will usually fail.
+ */
+
+typedef struct idetape_buffer_head_s {
+ char *data; /* Pointer to data (512 bytes by default) */
+ struct idetape_buffer_head_s *next;
+} idetape_buffer_head_t;
+
+/*
+ * A pipeline stage.
+ *
+ * In a pipeline stage we have a request, pointer to a list of small
+ * buffers, and pointers to the near stages.
+ */
+
+typedef struct idetape_pipeline_stage_s {
+ struct request rq; /* The correspoding request */
+ idetape_buffer_head_t *bh; /* The data buffers */
+ struct idetape_pipeline_stage_s *next,*prev; /* Pointers to the next and previous stages */
+} idetape_pipeline_stage_t;
+
+/*
* Most of our global data which we need to save even as we leave the
* driver due to an interrupt or a timer event is stored in a variable
* of type tape_info, defined below.
@@ -268,9 +326,9 @@
* another ide block device which receives requests and completes
* them.
*
- * However, our requests usually don't originate in the buffer
- * cache but rather in ide-tape.c itself. Here we provide safe
- * storage for such requests.
+ * However, our requests don't originate in the buffer cache but
+ * rather in ide-tape.c itself. Here we provide safe storage for
+ * such requests.
*/
struct request rq_stack [IDETAPE_PC_STACK];
@@ -279,31 +337,37 @@
/*
* While polling for DSC we use postponed_rq to postpone the
* current request so that ide.c will be able to service
- * pending requests on the other device.
+ * pending requests on the other device. Note that at most
+ * we will have only one DSC (usually data transfer) request
+ * in the device request queue. Additional request can be
+ * queued in our internal pipeline, but they will be visible
+ * to ide.c only one at a time.
*/
struct request *postponed_rq;
- byte dsc_count;
- unsigned long dsc_polling_start;
+
+ /*
+ * DSC polling variables.
+ */
+
+ byte dsc_count; /* We received DSC dsc_count times in a row */
+ unsigned long dsc_polling_start; /* The time in which we started polling for DSC */
struct timer_list dsc_timer; /* Timer used to poll for dsc */
- unsigned long dsc_polling_frequency;
+ unsigned long dsc_polling_frequency; /* The current polling frequency */
unsigned long dsc_timeout; /* Maximum waiting time */
- byte dsc_received;
+ byte dsc_received; /* Set when we receive DSC */
+ byte request_status;
+ byte request_dsc_callback;
+ byte last_status; /* Contents of the tape status register */
+ /* before the current request (saved for us */
+ /* by ide.c) */
/* Position information */
byte partition_num; /* Currently not used */
unsigned long block_address; /* Current block */
byte block_address_valid; /* 0 When the tape position is unknown */
/* (To the tape or to us) */
- unsigned long locate_to; /* We want to reach this block, as a part */
- /* of handling the current request */
- byte locate_retries; /* Each time, increase locate_retries */
-
- unsigned long last_written_block; /* Once writing started, we don't allow read */
- byte last_written_valid; /* access beyond the last written block */
- /* ??? Should I remove this ? */
-
/* Last error information */
byte sense_key,asc,ascq;
@@ -311,17 +375,60 @@
/* Character device operation */
unsigned char last_dt_was_write; /* Last character device data transfer was a write */
- byte busy; /* Device already opened */
+ byte busy; /* Device already opened */
/* Device information */
- unsigned short tape_block_size;
- idetape_capabilities_page_t capabilities; /* Capabilities and Mechanical Page */
+ unsigned short tape_block_size; /* Usually 512 or 1024 bytes */
+ idetape_capabilities_page_t capabilities; /* Copy of the tape's Capabilities and Mechanical Page */
- /* Data buffer */
+ /*
+ * Active data transfer request parameters.
+ *
+ * At most, there is only one ide-tape originated data transfer
+ * request in the device request queue. This allows ide.c to
+ * easily service requests from the other device when we
+ * postpone our active request. In the pipelined operation
+ * mode, we use our internal pipeline structure to hold
+ * more data requests.
+ *
+ * The data buffer size is chosen based on the tape's
+ * recommendation.
+ */
- char *data_buffer;
+ struct request *active_data_request; /* Pointer to the request which is waiting in the device request queue */
+ char *data_buffer; /* The correspoding data buffer (for read/write requests) */
+ int data_buffer_size; /* Data buffer size (chosen based on the tape's recommendation */
+ char *temp_data_buffer; /* Temporary buffer for user <-> kernel space data transfer */
+ /*
+ * Pipeline parameters.
+ *
+ * To accomplish non-pipelined mode, we simply set the following
+ * variables to zero (or NULL, where appropriate).
+ */
+
+ int current_number_of_stages; /* Number of currently used stages */
+ int max_number_of_stages; /* We will not allocate more than this number of stages */
+ idetape_pipeline_stage_t *first_stage; /* Will be serviced after the currently active request */
+ idetape_pipeline_stage_t *last_stage; /* New write requests will be added to the pipeline here */
+ int pipeline_was_full_once; /* Set at the first time we fill the pipeline since the tape was opened */
+ int error_in_pipeline_stage; /* Set when an error was detected in one of the pipeline stages */
+ int pipeline_locked; /* Against race conditions ... */
+
} idetape_tape_t;
+
+#define POLL_HWIF_TAPE_DRIVE \
+ if (hwif->tape_drive != NULL) { \
+ if (hwif->tape_drive->tape.request_status) { \
+ OUT_BYTE(hwif->tape_drive->select.all,IDE_SELECT_REG); \
+ hwif->tape_drive->tape.last_status=GET_STAT(); \
+ hwif->tape_drive->tape.request_status=0; \
+ } \
+ if (hwif->tape_drive->tape.request_dsc_callback) { \
+ hwif->tape_drive->tape.request_dsc_callback=0; \
+ idetape_put_back_postponed_request(hwif->tape_drive); \
+ } \
+ }
#endif /* IDETAPE_H */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this