patch-2.3.99-pre1 linux/drivers/scsi/st.c
Next file: linux/drivers/scsi/st.h
Previous file: linux/drivers/scsi/sr.c
Back to the patch index
Back to the overall index
- Lines: 1494
- Date:
Mon Mar 13 12:32:22 2000
- Orig file:
v2.3.51/linux/drivers/scsi/st.c
- Orig date:
Thu Mar 2 14:36:23 2000
diff -u --recursive --new-file v2.3.51/linux/drivers/scsi/st.c linux/drivers/scsi/st.c
@@ -6,12 +6,13 @@
Rewritten from Dwayne Forsyth's SCSI tape driver by Kai Makisara.
Contribution and ideas from several people including (in alphabetical
order) Klaus Ehrenfried, Wolfgang Denk, Steve Hirsch, Andreas Koppenh"ofer,
- Michael Leodolter, Eyal Lebedinsky, J"org Weule, and Eric Youngdale.
+ Michael Leodolter, Eyal Lebedinsky, Michael Schaefer, J"org Weule, and
+ Eric Youngdale.
Copyright 1992 - 2000 Kai Makisara
email Kai.Makisara@metla.fi
- Last modified: Tue Feb 29 20:47:03 2000 by makisara@kai.makisara.local
+ Last modified: Mon Mar 13 21:15:29 2000 by makisara@kai.makisara.local
Some small formal changes - aeb, 950809
Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
@@ -125,14 +126,17 @@
24 bits) */
#define SET_DENS_AND_BLK 0x10001
+#define ST_DEV_ARR_LUMP 6
+static rwlock_t st_dev_arr_lock = RW_LOCK_UNLOCKED;
+
static int st_nbr_buffers;
-static ST_buffer **st_buffers;
+static ST_buffer **st_buffers = NULL;
static int st_buffer_size = ST_BUFFER_SIZE;
static int st_write_threshold = ST_WRITE_THRESHOLD;
static int st_max_buffers = ST_MAX_BUFFERS;
static int st_max_sg_segs = ST_MAX_SG;
-static Scsi_Tape *scsi_tapes = NULL;
+static Scsi_Tape **scsi_tapes = NULL;
static int modes_defined = FALSE;
@@ -161,16 +165,14 @@
static int st_compression(Scsi_Tape *, int);
-static int find_partition(struct inode *);
-static int update_partition(struct inode *);
+static int find_partition(Scsi_Tape *);
+static int update_partition(Scsi_Tape *);
-static int st_int_ioctl(struct inode *inode, unsigned int cmd_in,
- unsigned long arg);
+static int st_int_ioctl(Scsi_Tape *, unsigned int, unsigned long);
-
/* Convert the result to success code */
-static int st_chk_result(Scsi_Request * SRpnt)
+static int st_chk_result(Scsi_Tape *STp, Scsi_Request * SRpnt)
{
int dev;
int result = SRpnt->sr_result;
@@ -184,8 +186,10 @@
if (driver_byte(result) & DRIVER_SENSE)
scode = sense[2] & 0x0f;
- else
+ else {
+ sense[0] = 0;
scode = 0;
+ }
dev = TAPE_NR(SRpnt->sr_request.rq_dev);
DEB(
@@ -224,8 +228,8 @@
&& SRpnt->sr_cmnd[0] != WRITE_FILEMARKS
#endif
) {
- scsi_tapes[dev].recover_count++;
- scsi_tapes[dev].mt_status->mt_erreg += (1 << MT_ST_SOFTERR_SHIFT);
+ STp->recover_count++;
+ STp->recover_reg++;
DEB(
if (debugging) {
@@ -236,7 +240,7 @@
else
stp = "ioctl";
printk(ST_DEB_MSG "st%d: Recovered %s error (%d).\n", dev, stp,
- scsi_tapes[dev].recover_count);
+ STp->recover_count);
} ) /* end DEB */
if ((sense[2] & 0xe0) == 0)
@@ -254,7 +258,9 @@
Scsi_Tape *STp;
if ((st_nbr = TAPE_NR(SCpnt->request.rq_dev)) < st_template.nr_dev) {
- STp = &(scsi_tapes[st_nbr]);
+ read_lock(&st_dev_arr_lock);
+ STp = scsi_tapes[st_nbr];
+ read_unlock(&st_dev_arr_lock);
if ((STp->buffer)->writing &&
(SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
(SCpnt->sense_buffer[2] & 0x40)) {
@@ -330,7 +336,7 @@
if (do_wait) {
down(SRpnt->sr_request.sem);
SRpnt->sr_request.sem = NULL;
- (STp->buffer)->syscall_result = st_chk_result(SRpnt);
+ (STp->buffer)->syscall_result = st_chk_result(STp, SRpnt);
}
return SRpnt;
}
@@ -354,7 +360,7 @@
down(&(STp->sem));
(STp->buffer)->last_SRpnt->sr_request.sem = NULL;
- (STp->buffer)->syscall_result = st_chk_result((STp->buffer)->last_SRpnt);
+ (STp->buffer)->syscall_result = st_chk_result(STp, (STp->buffer)->last_SRpnt);
scsi_release_request((STp->buffer)->last_SRpnt);
if (STbuffer->writing < STbuffer->buffer_bytes)
@@ -491,15 +497,12 @@
/* Flush the tape buffer. The tape will be positioned correctly unless
seek_next is true. */
-static int flush_buffer(struct inode *inode, struct file *filp, int seek_next)
+static int flush_buffer(Scsi_Tape *STp, int seek_next)
{
int backspace, result;
- Scsi_Tape *STp;
ST_buffer *STbuffer;
ST_partstat *STps;
- int dev = TAPE_NR(inode->i_rdev);
- STp = &(scsi_tapes[dev]);
STbuffer = STp->buffer;
/*
@@ -538,7 +541,7 @@
}
}
if (!result && backspace > 0)
- result = st_int_ioctl(inode, MTBSR, backspace);
+ result = st_int_ioctl(STp, MTBSR, backspace);
} else if (STps->eof == ST_FM_HIT) {
if (STps->drv_file >= 0)
STps->drv_file++;
@@ -550,11 +553,11 @@
}
/* Set the mode parameters */
-static int set_mode_densblk(struct inode *inode, Scsi_Tape * STp, ST_mode * STm)
+static int set_mode_densblk(Scsi_Tape * STp, ST_mode * STm)
{
int set_it = FALSE;
unsigned long arg;
- int dev = TAPE_NR(inode->i_rdev);
+ int dev = TAPE_NR(STp->devt);
if (!STp->density_changed &&
STm->default_density >= 0 &&
@@ -572,7 +575,7 @@
} else
arg |= STp->block_size;
if (set_it &&
- st_int_ioctl(inode, SET_DENS_AND_BLK, arg)) {
+ st_int_ioctl(STp, SET_DENS_AND_BLK, arg)) {
printk(KERN_WARNING
"st%d: Can't set default block size to %d bytes and density %x.\n",
dev, STm->default_blksize, STm->default_density);
@@ -597,22 +600,26 @@
int dev = TAPE_NR(inode->i_rdev);
int mode = TAPE_MODE(inode->i_rdev);
- if (dev >= st_template.dev_max || !scsi_tapes[dev].device)
+ read_lock(&st_dev_arr_lock);
+ STp = scsi_tapes[dev];
+ if (dev >= st_template.dev_max || STp == NULL) {
+ read_unlock(&st_dev_arr_lock);
return (-ENXIO);
+ }
+ read_unlock(&st_dev_arr_lock);
- if (!scsi_block_when_processing_errors(scsi_tapes[dev].device)) {
+ if (!scsi_block_when_processing_errors(STp->device)) {
return -ENXIO;
}
- STp = &(scsi_tapes[dev]);
if (STp->in_use) {
DEB( printk(ST_DEB_MSG "st%d: Device already in use.\n", dev); )
return (-EBUSY);
}
STp->in_use = 1;
- STp->rew_at_close = (MINOR(inode->i_rdev) & 0x80) == 0;
+ STp->rew_at_close = STp->autorew_dev = (MINOR(inode->i_rdev) & 0x80) == 0;
- if (scsi_tapes[dev].device->host->hostt->module)
- __MOD_INC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
+ if (STp->device->host->hostt->module)
+ __MOD_INC_USE_COUNT(STp->device->host->hostt->module);
if (st_template.module)
__MOD_INC_USE_COUNT(st_template.module);
@@ -626,10 +633,14 @@
/* Allocate a buffer for this user */
need_dma_buffer = STp->restr_dma;
+ read_lock(&st_dev_arr_lock);
for (i = 0; i < st_nbr_buffers; i++)
if (!st_buffers[i]->in_use &&
- (!need_dma_buffer || st_buffers[i]->dma))
+ (!need_dma_buffer || st_buffers[i]->dma)) {
+ STp->buffer = st_buffers[i];
break;
+ }
+ read_unlock(&st_dev_arr_lock);
if (i >= st_nbr_buffers) {
STp->buffer = new_tape_buffer(FALSE, need_dma_buffer);
if (STp->buffer == NULL) {
@@ -637,8 +648,8 @@
retval = (-EBUSY);
goto err_out;
}
- } else
- STp->buffer = st_buffers[i];
+ }
+
(STp->buffer)->in_use = 1;
(STp->buffer)->writing = 0;
(STp->buffer)->syscall_result = 0;
@@ -824,7 +835,7 @@
partition support has been enabled. */
DEBC(printk(ST_DEB_MSG
"st%d: Updating partition number in status.\n", dev));
- if ((STp->partition = find_partition(inode)) < 0) {
+ if ((STp->partition = find_partition(STp)) < 0) {
retval = STp->partition;
goto err_out;
}
@@ -836,11 +847,11 @@
STp->density_changed = STp->blksize_changed = FALSE;
STp->compression_changed = FALSE;
if (!(STm->defaults_for_writes) &&
- (retval = set_mode_densblk(inode, STp, STm)) < 0)
+ (retval = set_mode_densblk(STp, STm)) < 0)
goto err_out;
if (STp->default_drvbuffer != 0xff) {
- if (st_int_ioctl(inode, MTSETDRVBUFFER, STp->default_drvbuffer))
+ if (st_int_ioctl(STp, MTSETDRVBUFFER, STp->default_drvbuffer))
printk(KERN_WARNING
"st%d: Can't set default drive buffering to %d.\n",
dev, STp->default_drvbuffer);
@@ -855,8 +866,8 @@
STp->buffer = NULL;
}
STp->in_use = 0;
- if (scsi_tapes[dev].device->host->hostt->module)
- __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
+ if (STp->device->host->hostt->module)
+ __MOD_DEC_USE_COUNT(STp->device->host->hostt->module);
if (st_template.module)
__MOD_DEC_USE_COUNT(st_template.module);
return retval;
@@ -882,7 +893,9 @@
return 0;
dev = TAPE_NR(devt);
- STp = &(scsi_tapes[dev]);
+ read_lock(&st_dev_arr_lock);
+ STp = scsi_tapes[dev];
+ read_unlock(&st_dev_arr_lock);
STm = &(STp->modes[STp->current_mode]);
STps = &(STp->ps[STp->partition]);
@@ -893,7 +906,7 @@
}
if (STp->can_partitions &&
- (result2 = update_partition(inode)) < 0) {
+ (result2 = update_partition(STp)) < 0) {
DEBC(printk(ST_DEB_MSG
"st%d: update_partition at close failed.\n", dev));
if (result == 0)
@@ -950,7 +963,7 @@
STps = &(STp->ps[STp->partition]);
if (!STm->sysv || STps->rw != ST_READING) {
if (STp->can_bsr)
- result = flush_buffer(inode, filp, 0);
+ result = flush_buffer(STp, 0);
else if (STps->eof == ST_FM_HIT) {
result = cross_eof(STp, FALSE);
if (result) {
@@ -973,7 +986,7 @@
out:
if (STp->rew_at_close) {
- result2 = st_int_ioctl(inode, MTREW, 1);
+ result2 = st_int_ioctl(STp, MTREW, 1);
if (result == 0)
result = result2;
}
@@ -991,10 +1004,12 @@
int dev;
dev = TAPE_NR(devt);
- STp = &(scsi_tapes[dev]);
+ read_lock(&st_dev_arr_lock);
+ STp = scsi_tapes[dev];
+ read_unlock(&st_dev_arr_lock);
if (STp->door_locked == ST_LOCKED_AUTO)
- st_int_ioctl(inode, MTUNLOCK, 0);
+ st_int_ioctl(STp, MTUNLOCK, 0);
if (STp->buffer != NULL) {
normalize_buffer(STp->buffer);
@@ -1002,8 +1017,8 @@
}
STp->in_use = 0;
- if (scsi_tapes[dev].device->host->hostt->module)
- __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
+ if (STp->device->host->hostt->module)
+ __MOD_DEC_USE_COUNT(STp->device->host->hostt->module);
if (st_template.module)
__MOD_DEC_USE_COUNT(st_template.module);
@@ -1028,7 +1043,9 @@
ST_partstat *STps;
int dev = TAPE_NR(inode->i_rdev);
- STp = &(scsi_tapes[dev]);
+ read_lock(&st_dev_arr_lock);
+ STp = scsi_tapes[dev];
+ read_unlock(&st_dev_arr_lock);
/*
* If we are in the middle of error recovery, don't let anyone
@@ -1079,7 +1096,7 @@
}
if (STp->can_partitions &&
- (retval = update_partition(inode)) < 0)
+ (retval = update_partition(STp)) < 0)
return retval;
STps = &(STp->ps[STp->partition]);
@@ -1092,17 +1109,17 @@
return (-EOVERFLOW);
if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED &&
- !st_int_ioctl(inode, MTLOCK, 0))
+ !st_int_ioctl(STp, MTLOCK, 0))
STp->door_locked = ST_LOCKED_AUTO;
if (STps->rw == ST_READING) {
- retval = flush_buffer(inode, filp, 0);
+ retval = flush_buffer(STp, 0);
if (retval)
return retval;
STps->rw = ST_WRITING;
} else if (STps->rw != ST_WRITING &&
STps->drv_file == 0 && STps->drv_block == 0) {
- if ((retval = set_mode_densblk(inode, STp, STm)) < 0)
+ if ((retval = set_mode_densblk(STp, STm)) < 0)
return retval;
if (STm->default_compression != ST_DONT_TOUCH &&
!(STp->compression_changed)) {
@@ -1328,21 +1345,19 @@
/* Read data from the tape. Returns zero in the normal case, one if the
eof status has changed, and the negative error code in case of a
fatal error. Otherwise updates the buffer and the eof state. */
-static long read_tape(struct inode *inode, long count, Scsi_Request ** aSRpnt)
+static long read_tape(Scsi_Tape *STp, long count, Scsi_Request ** aSRpnt)
{
int transfer, blks, bytes;
static unsigned char cmd[MAX_COMMAND_SIZE];
Scsi_Request *SRpnt;
- Scsi_Tape *STp;
ST_mode *STm;
ST_partstat *STps;
- int dev = TAPE_NR(inode->i_rdev);
+ int dev = TAPE_NR(STp->devt);
int retval = 0;
if (count == 0)
return 0;
- STp = &(scsi_tapes[dev]);
STm = &(STp->modes[STp->current_mode]);
STps = &(STp->ps[STp->partition]);
if (STps->eof == ST_FM_HIT)
@@ -1418,7 +1433,7 @@
printk(KERN_NOTICE "st%d: Incorrect block size.\n", dev);
if (STps->drv_block >= 0)
STps->drv_block += blks - transfer + 1;
- st_int_ioctl(inode, MTBSR, 1);
+ st_int_ioctl(STp, MTBSR, 1);
return (-EIO);
}
/* We have some data, deliver it */
@@ -1429,7 +1444,7 @@
dev, count, (STp->buffer)->buffer_bytes));
if (STps->drv_block >= 0)
STps->drv_block += 1;
- if (st_int_ioctl(inode, MTBSR, 1))
+ if (st_int_ioctl(STp, MTBSR, 1))
return (-EIO);
}
} else if (SRpnt->sr_sense_buffer[2] & 0x80) { /* FM overrides EOM */
@@ -1509,7 +1524,9 @@
ST_partstat *STps;
int dev = TAPE_NR(inode->i_rdev);
- STp = &(scsi_tapes[dev]);
+ read_lock(&st_dev_arr_lock);
+ STp = scsi_tapes[dev];
+ read_unlock(&st_dev_arr_lock);
/*
* If we are in the middle of error recovery, don't let anyone
@@ -1542,7 +1559,7 @@
} ) /* end DEB */
if (STp->can_partitions &&
- (total = update_partition(inode)) < 0)
+ (total = update_partition(STp)) < 0)
return total;
if (STp->block_size == 0 &&
@@ -1555,12 +1572,12 @@
return (-EIO); /* Read must be integral number of blocks */
if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED &&
- !st_int_ioctl(inode, MTLOCK, 0))
+ !st_int_ioctl(STp, MTLOCK, 0))
STp->door_locked = ST_LOCKED_AUTO;
STps = &(STp->ps[STp->partition]);
if (STps->rw == ST_WRITING) {
- transfer = flush_buffer(inode, filp, 0);
+ transfer = flush_buffer(STp, 0);
if (transfer)
return transfer;
STps->rw = ST_READING;
@@ -1596,7 +1613,7 @@
/* Get new data if the buffer is empty */
if ((STp->buffer)->buffer_bytes == 0) {
- special = read_tape(inode, count - total, &SRpnt);
+ special = read_tape(STp, count - total, &SRpnt);
if (special < 0) { /* No need to continue read */
if (SRpnt != NULL) {
scsi_release_request(SRpnt);
@@ -1684,15 +1701,13 @@
}
-static int st_set_options(struct inode *inode, long options)
+static int st_set_options(Scsi_Tape *STp, long options)
{
int value;
long code;
- Scsi_Tape *STp;
ST_mode *STm;
- int dev = TAPE_NR(inode->i_rdev);
+ int dev = TAPE_NR(STp->devt);
- STp = &(scsi_tapes[dev]);
STm = &(STp->modes[STp->current_mode]);
if (!STm->defined) {
memcpy(STm, &(STp->modes[0]), sizeof(ST_mode));
@@ -1823,95 +1838,146 @@
return 0;
}
+#define MODE_HEADER_LENGTH 4
+
+/* Mode header and page byte offsets */
+#define MH_OFF_DATA_LENGTH 0
+#define MH_OFF_MEDIUM_TYPE 1
+#define MH_OFF_DEV_SPECIFIC 2
+#define MH_OFF_BDESCS_LENGTH 3
+#define MP_OFF_PAGE_NBR 0
+#define MP_OFF_PAGE_LENGTH 1
+
+/* Mode header and page bit masks */
+#define MH_BIT_WP 0x80
+#define MP_MSK_PAGE_NBR 0x3f
+
+/* Don't return block descriptors */
+#define MODE_SENSE_OMIT_BDESCS 0x08
+
+#define MODE_SELECT_PAGE_FORMAT 0x10
+
+/* Read a mode page into the tape buffer. The block descriptors are included
+ if incl_block_descs is true. */
+static int read_mode_page(Scsi_Tape *STp, int page, int omit_block_descs)
+{
+ unsigned char cmd[MAX_COMMAND_SIZE];
+ Scsi_Request *SRpnt = NULL;
+
+ memset(cmd, 0, MAX_COMMAND_SIZE);
+ cmd[0] = MODE_SENSE;
+ if (omit_block_descs)
+ cmd[1] = MODE_SENSE_OMIT_BDESCS;
+ cmd[2] = page;
+ cmd[4] = 255;
+
+ SRpnt = st_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_READ,
+ STp->timeout, 0, TRUE);
+ if (SRpnt == NULL)
+ return (STp->buffer)->syscall_result;
+
+ scsi_release_request(SRpnt);
+
+ return (STp->buffer)->syscall_result;
+}
+
+
+/* Send the mode page in the tape buffer to the drive. Assumes that the mode data
+ in the buffer is correctly formatted. */
+static int write_mode_page(Scsi_Tape *STp, int page)
+{
+ int pgo;
+ unsigned char cmd[MAX_COMMAND_SIZE];
+ Scsi_Request *SRpnt = NULL;
+
+ memset(cmd, 0, MAX_COMMAND_SIZE);
+ cmd[0] = MODE_SELECT;
+ cmd[1] = MODE_SELECT_PAGE_FORMAT;
+ pgo = MODE_HEADER_LENGTH + (STp->buffer)->b_data[MH_OFF_BDESCS_LENGTH];
+ cmd[4] = pgo + (STp->buffer)->b_data[pgo + MP_OFF_PAGE_LENGTH] + 2;
+
+ /* Clear reserved fields */
+ (STp->buffer)->b_data[MH_OFF_DATA_LENGTH] = 0;
+ (STp->buffer)->b_data[MH_OFF_MEDIUM_TYPE] = 0;
+ (STp->buffer)->b_data[MH_OFF_DEV_SPECIFIC] &= ~MH_BIT_WP;
+ (STp->buffer)->b_data[pgo + MP_OFF_PAGE_NBR] &= MP_MSK_PAGE_NBR;
+
+ SRpnt = st_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_WRITE,
+ STp->timeout, 0, TRUE);
+ if (SRpnt == NULL)
+ return (STp->buffer)->syscall_result;
+
+ scsi_release_request(SRpnt);
+
+ return (STp->buffer)->syscall_result;
+}
+
#define COMPRESSION_PAGE 0x0f
#define COMPRESSION_PAGE_LENGTH 16
-#define MODE_HEADER_LENGTH 4
+#define CP_OFF_DCE_DCC 2
#define DCE_MASK 0x80
#define DCC_MASK 0x40
#define RED_MASK 0x60
-/* Control the compression with mode page 15. Algorithm not changed if zero. */
+/* Control the compression with mode page 15. Algorithm not changed if zero.
+
+ The block descriptors are read and written because Sony SDT-7000 does not
+ work without this (suggestion from Michael Schaefer <Michael.Schaefer@dlr.de>).
+ Including block descriptors should not cause any harm to other drives. */
+
static int st_compression(Scsi_Tape * STp, int state)
{
- int dev;
- unsigned char cmd[MAX_COMMAND_SIZE];
- Scsi_Request *SRpnt = NULL;
+ int retval;
+ int mpoffs; /* Offset to mode page start */
+ unsigned char *b_data = (STp->buffer)->b_data;
+ DEB( int dev = TAPE_NR(STp->devt); )
if (STp->ready != ST_READY)
return (-EIO);
/* Read the current page contents */
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = MODE_SENSE;
- cmd[1] = 8;
- cmd[2] = COMPRESSION_PAGE;
- cmd[4] = COMPRESSION_PAGE_LENGTH + MODE_HEADER_LENGTH;
-
- SRpnt = st_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_READ,
- STp->timeout, 0, TRUE);
- if (SRpnt == NULL)
- return (STp->buffer)->syscall_result;
-
- dev = TAPE_NR(SRpnt->sr_request.rq_dev);
-
- if ((STp->buffer)->syscall_result != 0) {
+ retval = read_mode_page(STp, COMPRESSION_PAGE, FALSE);
+ if (retval) {
DEBC(printk(ST_DEB_MSG "st%d: Compression mode page not supported.\n",
dev));
- scsi_release_request(SRpnt);
- SRpnt = NULL;
return (-EIO);
}
+
+ mpoffs = MODE_HEADER_LENGTH + b_data[MH_OFF_BDESCS_LENGTH];
DEBC(printk(ST_DEB_MSG "st%d: Compression state is %d.\n", dev,
- ((STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] & DCE_MASK ? 1 : 0)));
+ (b_data[mpoffs + CP_OFF_DCE_DCC] & DCE_MASK ? 1 : 0)));
/* Check if compression can be changed */
- if (((STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] & DCC_MASK) == 0) {
+ if ((b_data[mpoffs + 2] & DCC_MASK) == 0) {
DEBC(printk(ST_DEB_MSG "st%d: Compression not supported.\n", dev));
- scsi_release_request(SRpnt);
- SRpnt = NULL;
return (-EIO);
}
/* Do the change */
if (state)
- (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] |= DCE_MASK;
+ b_data[mpoffs + CP_OFF_DCE_DCC] |= DCE_MASK;
else
- (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] &= ~DCE_MASK;
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = MODE_SELECT;
- cmd[1] = 0x10;
- cmd[4] = COMPRESSION_PAGE_LENGTH + MODE_HEADER_LENGTH;
-
- (STp->buffer)->b_data[0] = 0; /* Reserved data length */
- (STp->buffer)->b_data[1] = 0; /* Reserved media type byte */
- (STp->buffer)->b_data[MODE_HEADER_LENGTH] &= 0x3f;
- SRpnt = st_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_WRITE,
- STp->timeout, 0, TRUE);
+ b_data[mpoffs + CP_OFF_DCE_DCC] &= ~DCE_MASK;
- if ((STp->buffer)->syscall_result != 0) {
+ retval = write_mode_page(STp, COMPRESSION_PAGE);
+ if (retval) {
DEBC(printk(ST_DEB_MSG "st%d: Compression change failed.\n", dev));
- scsi_release_request(SRpnt);
- SRpnt = NULL;
return (-EIO);
}
DEBC(printk(ST_DEB_MSG "st%d: Compression state changed to %d.\n",
dev, state));
- scsi_release_request(SRpnt);
- SRpnt = NULL;
STp->compression_changed = TRUE;
return 0;
}
/* Internal ioctl function */
-static int st_int_ioctl(struct inode *inode,
- unsigned int cmd_in, unsigned long arg)
+static int st_int_ioctl(Scsi_Tape *STp, unsigned int cmd_in, unsigned long arg)
{
int timeout;
long ltmp;
@@ -1919,13 +1985,11 @@
int chg_eof = TRUE;
unsigned char cmd[MAX_COMMAND_SIZE];
Scsi_Request *SRpnt;
- Scsi_Tape *STp;
ST_partstat *STps;
int fileno, blkno, at_sm, undone;
int datalen = 0, direction = SCSI_DATA_NONE;
- int dev = TAPE_NR(inode->i_rdev);
+ int dev = TAPE_NR(STp->devt);
- STp = &(scsi_tapes[dev]);
if (STp->ready != ST_READY && cmd_in != MTLOAD) {
if (STp->ready == ST_NO_TAPE)
return (-ENOMEDIUM);
@@ -2120,7 +2184,7 @@
case MTEOM:
if (!STp->fast_mteom) {
/* space to the end of tape */
- ioctl_result = st_int_ioctl(inode, MTFSF, 0x3fff);
+ ioctl_result = st_int_ioctl(STp, MTFSF, 0x3fff);
fileno = STps->drv_file;
if (STps->eof >= ST_EOD_1)
return 0;
@@ -2247,9 +2311,9 @@
STp->door_locked = ST_UNLOCKED;
if (cmd_in == MTBSFM)
- ioctl_result = st_int_ioctl(inode, MTFSF, 1);
+ ioctl_result = st_int_ioctl(STp, MTFSF, 1);
else if (cmd_in == MTFSFM)
- ioctl_result = st_int_ioctl(inode, MTBSF, 1);
+ ioctl_result = st_int_ioctl(STp, MTBSF, 1);
if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) {
STp->block_size = arg & MT_ST_BLKSIZE_MASK;
@@ -2275,7 +2339,7 @@
if (cmd_in == MTOFFL || cmd_in == MTUNLOAD)
STp->rew_at_close = 0;
else if (cmd_in == MTLOAD) {
- STp->rew_at_close = (MINOR(inode->i_rdev) & 0x80) == 0;
+ STp->rew_at_close = STp->autorew_dev;
for (i = 0; i < ST_NBR_PARTITIONS; i++) {
STp->ps[i].rw = ST_IDLE;
STp->ps[i].last_block_valid = FALSE;
@@ -2368,16 +2432,14 @@
/* Get the tape position. If bt == 2, arg points into a kernel space mt_loc
structure. */
-static int get_location(struct inode *inode, unsigned int *block, int *partition,
+static int get_location(Scsi_Tape *STp, unsigned int *block, int *partition,
int logical)
{
- Scsi_Tape *STp;
- int dev = TAPE_NR(inode->i_rdev);
int result;
unsigned char scmd[MAX_COMMAND_SIZE];
Scsi_Request *SRpnt;
+ DEB( int dev = TAPE_NR(STp->devt); )
- STp = &(scsi_tapes[dev]);
if (STp->ready != ST_READY)
return (-EIO);
@@ -2430,19 +2492,17 @@
/* Set the tape block and partition. Negative partition means that only the
block should be set in vendor specific way. */
-static int set_location(struct inode *inode, unsigned int block, int partition,
+static int set_location(Scsi_Tape *STp, unsigned int block, int partition,
int logical)
{
- Scsi_Tape *STp;
ST_partstat *STps;
- int dev = TAPE_NR(inode->i_rdev);
int result, p;
unsigned int blk;
int timeout;
unsigned char scmd[MAX_COMMAND_SIZE];
Scsi_Request *SRpnt;
+ DEB( int dev = TAPE_NR(STp->devt); )
- STp = &(scsi_tapes[dev]);
if (STp->ready != ST_READY)
return (-EIO);
timeout = STp->long_timeout;
@@ -2458,7 +2518,7 @@
partition >= ST_NBR_PARTITIONS)
return (-EINVAL);
if (partition != STp->partition) {
- if (get_location(inode, &blk, &p, 1))
+ if (get_location(STp, &blk, &p, 1))
STps->last_block_valid = FALSE;
else {
STps->last_block_valid = TRUE;
@@ -2508,7 +2568,7 @@
result = (-EIO);
if (STp->can_partitions &&
(STp->device)->scsi_level >= SCSI_2 &&
- (p = find_partition(inode)) >= 0)
+ (p = find_partition(STp)) >= 0)
STp->partition = p;
} else {
if (STp->can_partitions) {
@@ -2535,12 +2595,12 @@
/* Find the current partition number for the drive status. Called from open and
returns either partition number of negative error code. */
-static int find_partition(struct inode *inode)
+static int find_partition(Scsi_Tape *STp)
{
int i, partition;
unsigned int block;
- if ((i = get_location(inode, &block, &partition, 1)) < 0)
+ if ((i = get_location(STp, &block, &partition, 1)) < 0)
return i;
if (partition >= ST_NBR_PARTITIONS)
return (-EIO);
@@ -2549,60 +2609,52 @@
/* Change the partition if necessary */
-static int update_partition(struct inode *inode)
+static int update_partition(Scsi_Tape *STp)
{
- int dev = TAPE_NR(inode->i_rdev);
- Scsi_Tape *STp;
ST_partstat *STps;
- STp = &(scsi_tapes[dev]);
if (STp->partition == STp->new_partition)
return 0;
STps = &(STp->ps[STp->new_partition]);
if (!STps->last_block_valid)
STps->last_block_visited = 0;
- return set_location(inode, STps->last_block_visited, STp->new_partition, 1);
+ return set_location(STp, STps->last_block_visited, STp->new_partition, 1);
}
/* Functions for reading and writing the medium partition mode page. These
seem to work with Wangtek 6200HS and HP C1533A. */
#define PART_PAGE 0x11
-#define PART_PAGE_LENGTH 10
+#define PART_PAGE_FIXED_LENGTH 8
+
+#define PP_OFF_MAX_ADD_PARTS 2
+#define PP_OFF_NBR_ADD_PARTS 3
+#define PP_OFF_FLAGS 4
+#define PP_OFF_PART_UNITS 6
+#define PP_OFF_RESERVED 7
+
+#define PP_BIT_IDP 0x20
+#define PP_MSK_PSUM_MB 0x10
/* Get the number of partitions on the tape. As a side effect reads the
mode page into the tape buffer. */
-static int nbr_partitions(struct inode *inode)
+static int nbr_partitions(Scsi_Tape *STp)
{
- int dev = TAPE_NR(inode->i_rdev), result;
- Scsi_Tape *STp;
- Scsi_Request *SRpnt = NULL;
- unsigned char cmd[MAX_COMMAND_SIZE];
+ int result;
+ DEB( int dev = TAPE_NR(STp->devt) );
- STp = &(scsi_tapes[dev]);
if (STp->ready != ST_READY)
return (-EIO);
- memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
- cmd[0] = MODE_SENSE;
- cmd[1] = 8; /* Page format */
- cmd[2] = PART_PAGE;
- cmd[4] = 200;
-
- SRpnt = st_do_scsi(SRpnt, STp, cmd, 200, SCSI_DATA_READ, STp->timeout,
- MAX_READY_RETRIES, TRUE);
- if (SRpnt == NULL)
- return (STp->buffer)->syscall_result;
-
- scsi_release_request(SRpnt);
- SRpnt = NULL;
+ result = read_mode_page(STp, PART_PAGE, TRUE);
- if ((STp->buffer)->syscall_result != 0) {
+ if (result) {
DEBC(printk(ST_DEB_MSG "st%d: Can't read medium partition page.\n",
dev));
result = (-EIO);
} else {
- result = (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] + 1;
+ result = (STp->buffer)->b_data[MODE_HEADER_LENGTH +
+ PP_OFF_NBR_ADD_PARTS] + 1;
DEBC(printk(ST_DEB_MSG "st%d: Number of partitions %d.\n", dev, result));
}
@@ -2611,62 +2663,69 @@
/* Partition the tape into two partitions if size > 0 or one partition if
- size == 0 */
-static int partition_tape(struct inode *inode, int size)
+ size == 0.
+
+ The block descriptors are read and written because Sony SDT-7000 does not
+ work without this (suggestion from Michael Schaefer <Michael.Schaefer@dlr.de>).
+
+ My HP C1533A drive returns only one partition size field. This is used to
+ set the size of partition 1. There is no size field for the default partition.
+ Michael Schaefer's Sony SDT-7000 returns two descriptors and the second is
+ used to set the size of partition 1 (this is what the SCSI-3 standard specifies).
+ The following algorithm is used to accomodate both drives: if the number of
+ partition size fields is greater than the maximum number of additional partitions
+ in the mode page, the second field is used. Otherwise the first field is used.
+ */
+static int partition_tape(Scsi_Tape *STp, int size)
{
- int dev = TAPE_NR(inode->i_rdev), result;
- int length;
- Scsi_Tape *STp;
- Scsi_Request *SRpnt = NULL;
- unsigned char cmd[MAX_COMMAND_SIZE], *bp;
+ int dev = TAPE_NR(STp->devt), result;
+ int pgo, psd_cnt, psdo;
+ unsigned char *bp;
- if ((result = nbr_partitions(inode)) < 0)
+ result = read_mode_page(STp, PART_PAGE, FALSE);
+ if (result) {
+ DEBC(printk(ST_DEB_MSG "st%d: Can't read partition mode page.\n", dev));
return result;
- STp = &(scsi_tapes[dev]);
-
+ }
/* The mode page is in the buffer. Let's modify it and write it. */
- bp = &((STp->buffer)->b_data[0]);
+ bp = (STp->buffer)->b_data;
+ pgo = MODE_HEADER_LENGTH + bp[MH_OFF_BDESCS_LENGTH];
+ DEBC(printk(ST_DEB_MSG "st%d: Partition page length is %d bytes.\n",
+ dev, bp[pgo + MP_OFF_PAGE_LENGTH] + 2));
+
+ psd_cnt = (bp[pgo + MP_OFF_PAGE_LENGTH] + 2 - PART_PAGE_FIXED_LENGTH) / 2;
+ psdo = pgo + PART_PAGE_FIXED_LENGTH;
+ if (psd_cnt > bp[pgo + PP_OFF_MAX_ADD_PARTS]) {
+ bp[psdo] = bp[psdo + 1] = 0xff; /* Rest of the tape */
+ psdo += 2;
+ }
+ memset(bp + psdo, 0, bp[pgo + PP_OFF_NBR_ADD_PARTS] * 2);
+
+ DEBC(printk("st%d: psd_cnt %d, max.parts %d, nbr_parts %d\n", dev,
+ psd_cnt, bp[pgo + PP_OFF_MAX_ADD_PARTS],
+ bp[pgo + PP_OFF_NBR_ADD_PARTS]));
+
if (size <= 0) {
- length = 8;
- bp[MODE_HEADER_LENGTH + 3] = 0;
+ bp[pgo + PP_OFF_NBR_ADD_PARTS] = 0;
DEBC(printk(ST_DEB_MSG "st%d: Formatting tape with one partition.\n",
dev));
} else {
- length = 10;
- bp[MODE_HEADER_LENGTH + 3] = 1;
- bp[MODE_HEADER_LENGTH + 8] = (size >> 8) & 0xff;
- bp[MODE_HEADER_LENGTH + 9] = size & 0xff;
+ bp[psdo] = (size >> 8) & 0xff;
+ bp[psdo + 1] = size & 0xff;
+ bp[pgo + 3] = 1;
DEBC(printk(ST_DEB_MSG
- "st%d: Formatting tape with two partition (1 = %d MB).\n",
+ "st%d: Formatting tape with two partitions (1 = %d MB).\n",
dev, size));
}
- bp[MODE_HEADER_LENGTH + 6] = 0;
- bp[MODE_HEADER_LENGTH + 7] = 0;
- bp[MODE_HEADER_LENGTH + 4] = 0x30; /* IDP | PSUM = MB */
-
- bp[0] = 0;
- bp[1] = 0;
- bp[MODE_HEADER_LENGTH] &= 0x3f;
- bp[MODE_HEADER_LENGTH + 1] = length - 2;
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = MODE_SELECT;
- cmd[1] = 0x10;
- cmd[4] = length + MODE_HEADER_LENGTH;
-
- SRpnt = st_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_WRITE,
- STp->long_timeout, MAX_READY_RETRIES, TRUE);
- if (SRpnt == NULL)
- return (STp->buffer)->syscall_result;
-
- scsi_release_request(SRpnt);
- SRpnt = NULL;
+ bp[pgo + PP_OFF_PART_UNITS] = 0;
+ bp[pgo + PP_OFF_RESERVED] = 0;
+ bp[pgo + PP_OFF_FLAGS] = PP_BIT_IDP | PP_MSK_PSUM_MB;
- if ((STp->buffer)->syscall_result != 0) {
+ result = write_mode_page(STp, PART_PAGE);
+ if (result) {
printk(KERN_INFO "st%d: Partitioning of tape failed.\n", dev);
result = (-EIO);
- } else
- result = 0;
+ }
return result;
}
@@ -2679,14 +2738,15 @@
{
int i, cmd_nr, cmd_type, bt;
unsigned int blk;
- struct mtop mtc;
- struct mtpos mt_pos;
Scsi_Tape *STp;
ST_mode *STm;
ST_partstat *STps;
int dev = TAPE_NR(inode->i_rdev);
- STp = &(scsi_tapes[dev]);
+ read_lock(&st_dev_arr_lock);
+ STp = scsi_tapes[dev];
+ read_unlock(&st_dev_arr_lock);
+
DEB(
if (debugging && !STp->in_use) {
printk(ST_DEB_MSG "st%d: Incorrect device.\n", dev);
@@ -2709,6 +2769,8 @@
cmd_nr = _IOC_NR(cmd_in);
if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) {
+ struct mtop mtc;
+
if (_IOC_SIZE(cmd_in) != sizeof(mtc))
return (-EINVAL);
@@ -2751,7 +2813,7 @@
mtc.mt_op == MTLOCK || mtc.mt_op == MTLOAD ||
mtc.mt_op == MTCOMPRESSION;
}
- i = flush_buffer(inode, file, i);
+ i = flush_buffer(STp, i);
if (i < 0)
return i;
} else {
@@ -2770,7 +2832,7 @@
STp->device->was_reset = 0;
if (STp->door_locked != ST_UNLOCKED &&
STp->door_locked != ST_LOCK_FAILS) {
- if (st_int_ioctl(inode, MTLOCK, 0)) {
+ if (st_int_ioctl(STp, MTLOCK, 0)) {
printk(KERN_NOTICE
"st%d: Could not relock door after bus reset.\n",
dev);
@@ -2785,18 +2847,18 @@
STps->rw = ST_IDLE; /* Prevent automatic WEOF and fsf */
if (mtc.mt_op == MTOFFL && STp->door_locked != ST_UNLOCKED)
- st_int_ioctl(inode, MTUNLOCK, 0); /* Ignore result! */
+ st_int_ioctl(STp, MTUNLOCK, 0); /* Ignore result! */
if (mtc.mt_op == MTSETDRVBUFFER &&
(mtc.mt_count & MT_ST_OPTIONS) != 0)
- return st_set_options(inode, mtc.mt_count);
+ return st_set_options(STp, mtc.mt_count);
if (mtc.mt_op == MTSETPART) {
if (!STp->can_partitions ||
mtc.mt_count < 0 || mtc.mt_count >= ST_NBR_PARTITIONS)
return (-EINVAL);
if (mtc.mt_count >= STp->nbr_partitions &&
- (STp->nbr_partitions = nbr_partitions(inode)) < 0)
+ (STp->nbr_partitions = nbr_partitions(STp)) < 0)
return (-EIO);
if (mtc.mt_count >= STp->nbr_partitions)
return (-EINVAL);
@@ -2807,8 +2869,8 @@
if (mtc.mt_op == MTMKPART) {
if (!STp->can_partitions)
return (-EINVAL);
- if ((i = st_int_ioctl(inode, MTREW, 0)) < 0 ||
- (i = partition_tape(inode, mtc.mt_count)) < 0)
+ if ((i = st_int_ioctl(STp, MTREW, 0)) < 0 ||
+ (i = partition_tape(STp, mtc.mt_count)) < 0)
return i;
for (i = 0; i < ST_NBR_PARTITIONS; i++) {
STp->ps[i].rw = ST_IDLE;
@@ -2822,93 +2884,97 @@
}
if (mtc.mt_op == MTSEEK) {
- i = set_location(inode, mtc.mt_count, STp->new_partition, 0);
+ i = set_location(STp, mtc.mt_count, STp->new_partition, 0);
if (!STp->can_partitions)
STp->ps[0].rw = ST_IDLE;
return i;
}
if (STp->can_partitions && STp->ready == ST_READY &&
- (i = update_partition(inode)) < 0)
+ (i = update_partition(STp)) < 0)
return i;
if (mtc.mt_op == MTCOMPRESSION)
return st_compression(STp, (mtc.mt_count & 1));
else
- return st_int_ioctl(inode, mtc.mt_op, mtc.mt_count);
+ return st_int_ioctl(STp, mtc.mt_op, mtc.mt_count);
}
if (!STm->defined)
return (-ENXIO);
- if ((i = flush_buffer(inode, file, FALSE)) < 0)
+ if ((i = flush_buffer(STp, FALSE)) < 0)
return i;
if (STp->can_partitions &&
- (i = update_partition(inode)) < 0)
+ (i = update_partition(STp)) < 0)
return i;
if (cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET)) {
+ struct mtget mt_status;
if (_IOC_SIZE(cmd_in) != sizeof(struct mtget))
return (-EINVAL);
- (STp->mt_status)->mt_dsreg =
+ mt_status.mt_type = STp->tape_type;
+ mt_status.mt_dsreg =
((STp->block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK) |
((STp->density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK);
- (STp->mt_status)->mt_blkno = STps->drv_block;
- (STp->mt_status)->mt_fileno = STps->drv_file;
+ mt_status.mt_blkno = STps->drv_block;
+ mt_status.mt_fileno = STps->drv_file;
if (STp->block_size != 0) {
if (STps->rw == ST_WRITING)
- (STp->mt_status)->mt_blkno +=
+ mt_status.mt_blkno +=
(STp->buffer)->buffer_bytes / STp->block_size;
else if (STps->rw == ST_READING)
- (STp->mt_status)->mt_blkno -=
+ mt_status.mt_blkno -=
((STp->buffer)->buffer_bytes +
STp->block_size - 1) / STp->block_size;
}
- (STp->mt_status)->mt_gstat = 0;
+ mt_status.mt_gstat = 0;
if (STp->drv_write_prot)
- (STp->mt_status)->mt_gstat |= GMT_WR_PROT(0xffffffff);
- if ((STp->mt_status)->mt_blkno == 0) {
- if ((STp->mt_status)->mt_fileno == 0)
- (STp->mt_status)->mt_gstat |= GMT_BOT(0xffffffff);
+ mt_status.mt_gstat |= GMT_WR_PROT(0xffffffff);
+ if (mt_status.mt_blkno == 0) {
+ if (mt_status.mt_fileno == 0)
+ mt_status.mt_gstat |= GMT_BOT(0xffffffff);
else
- (STp->mt_status)->mt_gstat |= GMT_EOF(0xffffffff);
+ mt_status.mt_gstat |= GMT_EOF(0xffffffff);
}
- (STp->mt_status)->mt_resid = STp->partition;
+ mt_status.mt_erreg = (STp->recover_reg << MT_ST_SOFTERR_SHIFT);
+ mt_status.mt_resid = STp->partition;
if (STps->eof == ST_EOM_OK || STps->eof == ST_EOM_ERROR)
- (STp->mt_status)->mt_gstat |= GMT_EOT(0xffffffff);
+ mt_status.mt_gstat |= GMT_EOT(0xffffffff);
else if (STps->eof >= ST_EOM_OK)
- (STp->mt_status)->mt_gstat |= GMT_EOD(0xffffffff);
+ mt_status.mt_gstat |= GMT_EOD(0xffffffff);
if (STp->density == 1)
- (STp->mt_status)->mt_gstat |= GMT_D_800(0xffffffff);
+ mt_status.mt_gstat |= GMT_D_800(0xffffffff);
else if (STp->density == 2)
- (STp->mt_status)->mt_gstat |= GMT_D_1600(0xffffffff);
+ mt_status.mt_gstat |= GMT_D_1600(0xffffffff);
else if (STp->density == 3)
- (STp->mt_status)->mt_gstat |= GMT_D_6250(0xffffffff);
+ mt_status.mt_gstat |= GMT_D_6250(0xffffffff);
if (STp->ready == ST_READY)
- (STp->mt_status)->mt_gstat |= GMT_ONLINE(0xffffffff);
+ mt_status.mt_gstat |= GMT_ONLINE(0xffffffff);
if (STp->ready == ST_NO_TAPE)
- (STp->mt_status)->mt_gstat |= GMT_DR_OPEN(0xffffffff);
+ mt_status.mt_gstat |= GMT_DR_OPEN(0xffffffff);
if (STps->at_sm)
- (STp->mt_status)->mt_gstat |= GMT_SM(0xffffffff);
+ mt_status.mt_gstat |= GMT_SM(0xffffffff);
if (STm->do_async_writes ||
(STm->do_buffer_writes && STp->block_size != 0) ||
STp->drv_buffer != 0)
- (STp->mt_status)->mt_gstat |= GMT_IM_REP_EN(0xffffffff);
+ mt_status.mt_gstat |= GMT_IM_REP_EN(0xffffffff);
- i = copy_to_user((char *) arg, (char *) (STp->mt_status),
+ i = copy_to_user((char *) arg, (char *) &(mt_status),
sizeof(struct mtget));
if (i)
return (-EFAULT);
- (STp->mt_status)->mt_erreg = 0; /* Clear after read */
+ STp->recover_reg = 0; /* Clear after read */
return 0;
} /* End of MTIOCGET */
if (cmd_type == _IOC_TYPE(MTIOCPOS) && cmd_nr == _IOC_NR(MTIOCPOS)) {
+ struct mtpos mt_pos;
if (_IOC_SIZE(cmd_in) != sizeof(struct mtpos))
return (-EINVAL);
- if ((i = get_location(inode, &blk, &bt, 0)) < 0)
+ if ((i = get_location(STp, &blk, &bt, 0)) < 0)
return i;
mt_pos.mt_blkno = blk;
i = copy_to_user((char *) arg, (char *) (&mt_pos), sizeof(struct mtpos));
@@ -2920,15 +2986,21 @@
}
-/* Try to allocate a new tape buffer */
+/* Try to allocate a new tape buffer. Calling function must not hold
+ dev_arr_lock. */
static ST_buffer *
new_tape_buffer(int from_initialization, int need_dma)
{
int i, priority, b_size, order, got = 0, segs = 0;
+ unsigned long flags;
ST_buffer *tb;
- if (st_nbr_buffers >= st_template.dev_max)
+ read_lock(&st_dev_arr_lock);
+ if (st_nbr_buffers >= st_template.dev_max) {
+ read_unlock(&st_dev_arr_lock);
return NULL; /* Should never happen */
+ }
+ read_unlock(&st_dev_arr_lock);
if (from_initialization)
priority = GFP_ATOMIC;
@@ -3014,7 +3086,10 @@
tb->dma = need_dma;
tb->buffer_size = got;
tb->writing = 0;
+
+ write_lock_irqsave(&st_dev_arr_lock, flags);
st_buffers[st_nbr_buffers++] = tb;
+ write_unlock_irqrestore(&st_dev_arr_lock, flags);
return tb;
}
@@ -3039,7 +3114,8 @@
priority |= GFP_DMA;
for (b_size = PAGE_SIZE, order=0;
b_size * nbr < new_size - STbuffer->buffer_size;
- order++, b_size *= 2);
+ order++, b_size *= 2)
+ ; /* empty */
for (segs = STbuffer->sg_segs, got = STbuffer->buffer_size;
segs < max_segs && got < new_size;) {
@@ -3080,7 +3156,7 @@
for (i = STbuffer->orig_sg_segs; i < STbuffer->sg_segs; i++) {
for (b_size=PAGE_SIZE, order=0; b_size < STbuffer->sg[i].length;
order++, b_size *= 2)
- ;
+ ; /* empty */
free_pages((unsigned long)(STbuffer->sg[i].address), order);
STbuffer->buffer_size -= STbuffer->sg[i].length;
}
@@ -3239,23 +3315,77 @@
Scsi_Tape *tpnt;
ST_mode *STm;
ST_partstat *STps;
- int i, mode;
+ int i, mode, target_nbr;
+ unsigned long flags = 0;
if (SDp->type != TYPE_TAPE)
return 1;
+ write_lock_irqsave(&st_dev_arr_lock, flags);
if (st_template.nr_dev >= st_template.dev_max) {
- SDp->attached--;
- return 1;
+ Scsi_Tape **tmp_da;
+ ST_buffer **tmp_ba;
+ int tmp_dev_max;
+
+ tmp_dev_max = st_template.nr_dev + ST_DEV_ARR_LUMP;
+ if (tmp_dev_max > ST_MAX_TAPES)
+ tmp_dev_max = ST_MAX_TAPES;
+ if (tmp_dev_max <= st_template.nr_dev) {
+ SDp->attached--;
+ write_unlock_irqrestore(&st_dev_arr_lock, flags);
+ printk(KERN_ERR "st: Too many tape devices (max. %d).\n",
+ ST_MAX_TAPES);
+ return 1;
+ }
+
+ tmp_da = (Scsi_Tape **) kmalloc(tmp_dev_max * sizeof(Scsi_Tape *),
+ GFP_ATOMIC);
+ tmp_ba = (ST_buffer **) kmalloc(tmp_dev_max * sizeof(ST_buffer *),
+ GFP_ATOMIC);
+ if (tmp_da == NULL || tmp_ba == NULL) {
+ if (tmp_da != NULL)
+ kfree(tmp_da);
+ SDp->attached--;
+ write_unlock_irqrestore(&st_dev_arr_lock, flags);
+ printk(KERN_ERR "st: Can't extend device array.\n");
+ return 1;
+ }
+
+ memset(tmp_da, 0, tmp_dev_max * sizeof(Scsi_Tape *));
+ if (scsi_tapes != NULL) {
+ memcpy(tmp_da, scsi_tapes,
+ st_template.dev_max * sizeof(Scsi_Tape *));
+ kfree(scsi_tapes);
+ }
+ scsi_tapes = tmp_da;
+
+ memset(tmp_ba, 0, tmp_dev_max * sizeof(ST_buffer *));
+ if (st_buffers != NULL) {
+ memcpy(tmp_ba, st_buffers,
+ st_template.dev_max * sizeof(ST_buffer *));
+ kfree(st_buffers);
+ }
+ st_buffers = tmp_ba;
+
+ st_template.dev_max = tmp_dev_max;
}
- for (tpnt = scsi_tapes, i = 0; i < st_template.dev_max; i++, tpnt++)
- if (!tpnt->device)
+ for (i = 0; i < st_template.dev_max; i++)
+ if (scsi_tapes[i] == NULL)
break;
-
if (i >= st_template.dev_max)
panic("scsi_devices corrupt (st)");
+ tpnt = (Scsi_Tape *)kmalloc(sizeof(Scsi_Tape), GFP_ATOMIC);
+ if (tpnt == NULL) {
+ SDp->attached--;
+ write_unlock_irqrestore(&st_dev_arr_lock, flags);
+ printk(KERN_ERR "st: Can't allocate device descriptor.\n");
+ return 1;
+ }
+ memset(tpnt, 0, sizeof(Scsi_Tape));
+ scsi_tapes[i] = tpnt;
+
for (mode = 0; mode < ST_NBR_MODES; ++mode) {
char name[8];
static char *formats[ST_NBR_MODES] ={"", "l", "m", "a"};
@@ -3276,11 +3406,11 @@
0, 0, &st_fops, NULL);
}
devfs_register_tape (tpnt->de_r[0]);
- scsi_tapes[i].device = SDp;
+ tpnt->device = SDp;
if (SDp->scsi_level <= 2)
- scsi_tapes[i].mt_status->mt_type = MT_ISSCSI1;
+ tpnt->tape_type = MT_ISSCSI1;
else
- scsi_tapes[i].mt_status->mt_type = MT_ISSCSI2;
+ tpnt->tape_type = MT_ISSCSI2;
tpnt->inited = 0;
tpnt->devt = MKDEV(SCSI_TAPE_MAJOR, i);
@@ -3333,6 +3463,20 @@
tpnt->blksize_changed = FALSE;
st_template.nr_dev++;
+ write_unlock_irqrestore(&st_dev_arr_lock, flags);
+
+ /* See if we need to allocate more static buffers */
+ target_nbr = st_template.nr_dev;
+ if (target_nbr > st_max_buffers)
+ target_nbr = st_max_buffers;
+ for (i=st_nbr_buffers; i < target_nbr; i++)
+ if (!new_tape_buffer(TRUE, TRUE)) {
+ printk(KERN_INFO "st: Unable to allocate new static buffer.\n");
+ break;
+ }
+ /* If the previous allocation fails, we will try again when the buffer is
+ really needed. */
+
return 0;
};
@@ -3354,90 +3498,28 @@
/* Driver initialization (not __init because may be called later) */
static int st_init()
{
- int i, j;
- Scsi_Tape *STp;
- int target_nbr;
+ unsigned long flags;
- if (st_template.dev_noticed == 0)
+ if (st_template.dev_noticed == 0 || st_registered)
return 0;
printk(KERN_INFO "st: bufsize %d, wrt %d, max init. buffers %d, s/g segs %d.\n",
st_buffer_size, st_write_threshold, st_max_buffers, st_max_sg_segs);
+ write_lock_irqsave(&st_dev_arr_lock, flags);
if (!st_registered) {
if (devfs_register_chrdev(SCSI_TAPE_MAJOR, "st", &st_fops)) {
+ write_unlock_irqrestore(&st_dev_arr_lock, flags);
printk(KERN_ERR "Unable to get major %d for SCSI tapes\n",
MAJOR_NR);
return 1;
}
st_registered++;
}
- if (scsi_tapes)
- return 0;
- st_template.dev_max = st_template.dev_noticed + ST_EXTRA_DEVS;
- if (st_template.dev_max < ST_MAX_TAPES)
- st_template.dev_max = ST_MAX_TAPES;
- if (st_template.dev_max > 128 / ST_NBR_MODES)
- printk(KERN_INFO "st: Only %d tapes accessible.\n", 128 / ST_NBR_MODES);
- scsi_tapes =
- (Scsi_Tape *) kmalloc(st_template.dev_max * sizeof(Scsi_Tape),
- GFP_ATOMIC);
- if (scsi_tapes == NULL) {
- printk(KERN_ERR "Unable to allocate descriptors for SCSI tapes.\n");
- devfs_unregister_chrdev(SCSI_TAPE_MAJOR, "st");
- return 1;
- }
-
- DEB(printk(ST_DEB_MSG "st: Buffer size %d bytes, write threshold %d bytes.\n",
- st_buffer_size, st_write_threshold));
-
- memset(scsi_tapes, 0, st_template.dev_max * sizeof(Scsi_Tape));
- for (i = 0; i < st_template.dev_max; ++i) {
- STp = &(scsi_tapes[i]);
- STp->capacity = 0xfffff;
- STp->mt_status = (struct mtget *) kmalloc(sizeof(struct mtget),
- GFP_ATOMIC);
- if (STp->mt_status == NULL) {
- for (j=0; j < i; j++)
- kfree(scsi_tapes[j].mt_status);
- kfree(scsi_tapes);
- devfs_unregister_chrdev(SCSI_TAPE_MAJOR, "st");
- return 1;
- }
- /* Initialize status */
- memset((void *) scsi_tapes[i].mt_status, 0, sizeof(struct mtget));
- }
-
- /* Allocate the buffers */
- st_buffers =
- (ST_buffer **) kmalloc(st_template.dev_max * sizeof(ST_buffer *),
- GFP_ATOMIC);
- if (st_buffers == NULL) {
- printk(KERN_ERR "Unable to allocate tape buffer pointers.\n");
- devfs_unregister_chrdev(SCSI_TAPE_MAJOR, "st");
- for (i=0; i < st_template.dev_max; i++)
- kfree(scsi_tapes[i].mt_status);
- kfree(scsi_tapes);
- unregister_chrdev(SCSI_TAPE_MAJOR, "st");
- return 1;
- }
- target_nbr = st_template.dev_noticed;
- if (target_nbr < ST_EXTRA_DEVS)
- target_nbr = ST_EXTRA_DEVS;
- if (target_nbr > st_max_buffers)
- target_nbr = st_max_buffers;
- for (i = st_nbr_buffers = 0; i < target_nbr; i++) {
- if (!new_tape_buffer(TRUE, TRUE)) {
- if (i == 0) {
- printk(KERN_INFO
- "No tape buffers allocated at initialization.\n");
- break;
- }
- printk(KERN_INFO "Number of tape buffers adjusted.\n");
- break;
- }
- }
+ st_template.dev_max = 0;
+ st_nbr_buffers = 0;
+ write_unlock_irqrestore(&st_dev_arr_lock, flags);
return 0;
}
@@ -3446,9 +3528,12 @@
{
Scsi_Tape *tpnt;
int i, mode;
+ unsigned long flags;
- for (tpnt = scsi_tapes, i = 0; i < st_template.dev_max; i++, tpnt++)
- if (tpnt->device == SDp) {
+ write_lock_irqsave(&st_dev_arr_lock, flags);
+ for (i = 0; i < st_template.dev_max; i++) {
+ tpnt = scsi_tapes[i];
+ if (tpnt != NULL && tpnt->device == SDp) {
tpnt->device = NULL;
for (mode = 0; mode < ST_NBR_MODES; ++mode) {
devfs_unregister (tpnt->de_r[mode]);
@@ -3456,11 +3541,17 @@
devfs_unregister (tpnt->de_n[mode]);
tpnt->de_n[mode] = NULL;
}
+ kfree(tpnt);
+ scsi_tapes[i] = 0;
SDp->attached--;
st_template.nr_dev--;
st_template.dev_noticed--;
+ write_unlock_irqrestore(&st_dev_arr_lock, flags);
return;
}
+ }
+
+ write_unlock_irqrestore(&st_dev_arr_lock, flags);
return;
}
@@ -3484,7 +3575,8 @@
st_registered--;
if (scsi_tapes != NULL) {
for (i=0; i < st_template.dev_max; ++i)
- kfree(scsi_tapes[i].mt_status);
+ if (scsi_tapes[i])
+ kfree(scsi_tapes[i]);
kfree(scsi_tapes);
if (st_buffers != NULL) {
for (i = 0; i < st_nbr_buffers; i++) {
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)