osst.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:172k
- break;
- case OS_WRITE_EOD:
- osst_init_aux(STp, OS_FRAME_TYPE_EOD, STp->frame_seq_number++,
- STp->logical_blk_num, 0, 0);
- break;
- case OS_WRITE_NEW_MARK:
- osst_init_aux(STp, OS_FRAME_TYPE_MARKER, STp->frame_seq_number++,
- STp->logical_blk_num++, 0, blks=1);
- break;
- case OS_WRITE_HEADER:
- osst_init_aux(STp, OS_FRAME_TYPE_HEADER, 0, 0, 0, blks=0);
- break;
- default: /* probably FILLER */
- osst_init_aux(STp, OS_FRAME_TYPE_FILL, 0, 0, 0, 0);
- }
- #if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "osst%d:D: Flushing %d bytes, Transfering %d bytes in %d lblocks.n",
- dev, offset, transfer, blks);
- #endif
- SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, transfer, SCSI_DATA_WRITE,
- STp->timeout, MAX_WRITE_RETRIES, TRUE);
- *aSRpnt = SRpnt;
- if (!SRpnt)
- return (-EBUSY);
- if ((STp->buffer)->syscall_result != 0) {
- #if DEBUG
- printk(OSST_DEB_MSG
- "osst%d:D: write sense [0]=0x%02x [2]=%02x [12]=%02x [13]=%02xn",
- dev, SRpnt->sr_sense_buffer[0], SRpnt->sr_sense_buffer[2],
- SRpnt->sr_sense_buffer[12], SRpnt->sr_sense_buffer[13]);
- #endif
- if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
- (SRpnt->sr_sense_buffer[2] & 0x40) && /* FIXME - SC-30 drive doesn't assert EOM bit */
- (SRpnt->sr_sense_buffer[2] & 0x0f) == NO_SENSE) {
- STp->dirty = 0;
- (STp->buffer)->buffer_bytes = 0;
- result = (-ENOSPC);
- }
- else {
- if (osst_write_error_recovery(STp, aSRpnt, 1)) {
- printk(KERN_ERR "osst%d:E: Error on flush write.n", dev);
- result = (-EIO);
- }
- }
- STps->drv_block = (-1);
- }
- else {
- STp->first_frame_position++;
- STp->dirty = 0;
- (STp->buffer)->buffer_bytes = 0;
- }
- }
- #if DEBUG
- printk(OSST_DEB_MSG "osst%d:D: Exit flush write buffer with code %dn", dev, result);
- #endif
- return result;
- }
- /* Flush the tape buffer. The tape will be positioned correctly unless
- seek_next is true. */
- static int osst_flush_buffer(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int seek_next)
- {
- ST_partstat * STps;
- int backspace = 0, result = 0;
- #if DEBUG
- int dev = TAPE_NR(STp->devt);
- #endif
- /*
- * If there was a bus reset, block further access
- * to this device.
- */
- if( STp->device->was_reset )
- return (-EIO);
- if (STp->ready != ST_READY)
- return 0;
- STps = &(STp->ps[STp->partition]);
- if (STps->rw == ST_WRITING) /* Writing */
- return osst_flush_write_buffer(STp, aSRpnt);
- if (STp->block_size == 0)
- return 0;
- #if DEBUG
- printk(OSST_DEB_MSG "osst%d:D: Reached flush (read) buffern", dev);
- #endif
- if (!STp->can_bsr) {
- backspace = ((STp->buffer)->buffer_bytes + (STp->buffer)->read_pointer) / STp->block_size -
- ((STp->buffer)->read_pointer + STp->block_size - 1 ) / STp->block_size ;
- (STp->buffer)->buffer_bytes = 0;
- (STp->buffer)->read_pointer = 0;
- STp->frame_in_buffer = 0; /* FIXME is this relevant w. OSST? */
- }
- if (!seek_next) {
- if (STps->eof == ST_FM_HIT) {
- result = cross_eof(STp, aSRpnt, FALSE); /* Back over the EOF hit */
- if (!result)
- STps->eof = ST_NOEOF;
- else {
- if (STps->drv_file >= 0)
- STps->drv_file++;
- STps->drv_block = 0;
- }
- }
- if (!result && backspace > 0) /* TODO -- design and run a test case for this */
- result = osst_seek_logical_blk(STp, aSRpnt, STp->logical_blk_num - backspace);
- }
- else if (STps->eof == ST_FM_HIT) {
- if (STps->drv_file >= 0)
- STps->drv_file++;
- STps->drv_block = 0;
- STps->eof = ST_NOEOF;
- }
- return result;
- }
- static int osst_write_frame(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int synchronous)
- {
- unsigned char cmd[MAX_COMMAND_SIZE];
- Scsi_Request * SRpnt;
- int blks;
- #if DEBUG
- int dev = TAPE_NR(STp->devt);
- #endif
- if ((!STp-> raw) && (STp->first_frame_position == 0xbae)) { /* _must_ preserve buffer! */
- #if DEBUG
- printk(OSST_DEB_MSG "osst%d:D: Reaching config partition.n", dev);
- #endif
- if (osst_flush_drive_buffer(STp, aSRpnt) < 0) {
- return (-EIO);
- }
- /* error recovery may have bumped us past the header partition */
- if (osst_get_frame_position(STp, aSRpnt) < 0xbb8) {
- #if DEBUG
- printk(OSST_DEB_MSG "osst%d:D: Skipping over config partition.n", dev);
- #endif
- osst_position_tape_and_confirm(STp, aSRpnt, 0xbb8);
- }
- }
- if (STp->poll)
- osst_wait_frame (STp, aSRpnt, STp->first_frame_position, -50, 60);
- /* TODO: Check for an error ! */
- // osst_build_stats(STp, &SRpnt);
- STp->ps[STp->partition].rw = ST_WRITING;
- STp->write_type = OS_WRITE_DATA;
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = WRITE_6;
- cmd[1] = 1;
- cmd[4] = 1; /* one frame at a time... */
- blks = STp->buffer->buffer_bytes / STp->block_size;
- #if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "osst%d:D: Writing %d blocks to frame %d, lblks %d-%dn", dev, blks,
- STp->frame_seq_number, STp->logical_blk_num - blks, STp->logical_blk_num - 1);
- #endif
- osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->frame_seq_number++,
- STp->logical_blk_num - blks, STp->block_size, blks);
- #if DEBUG
- if (!synchronous)
- STp->write_pending = 1;
- #endif
- SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, SCSI_DATA_WRITE, STp->timeout,
- MAX_WRITE_RETRIES, synchronous);
- if (!SRpnt)
- return (-EBUSY);
- *aSRpnt = SRpnt;
- if (synchronous) {
- if (STp->buffer->syscall_result != 0) {
- #if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "osst%d:D: Error on write:n", dev);
- #endif
- if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
- (SRpnt->sr_sense_buffer[2] & 0x40)) {
- if ((SRpnt->sr_sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW)
- return (-ENOSPC);
- }
- else {
- if (osst_write_error_recovery(STp, aSRpnt, 1))
- return (-EIO);
- }
- }
- else
- STp->first_frame_position++;
- }
- STp->write_count++;
- return 0;
- }
- /* Entry points to osst */
- /* Write command */
- static ssize_t osst_write(struct file * filp, const char * buf, size_t count, loff_t *ppos)
- {
- struct inode *inode = filp->f_dentry->d_inode;
- ssize_t total, retval = 0;
- ssize_t i, do_count, blks, transfer;
- int write_threshold;
- int doing_write = 0;
- const char *b_point;
- Scsi_Request * SRpnt = NULL;
- OS_Scsi_Tape * STp;
- ST_mode * STm;
- ST_partstat * STps;
- int dev = TAPE_NR(inode->i_rdev);
- STp = os_scsi_tapes[dev];
- if (down_interruptible(&STp->lock))
- return (-ERESTARTSYS);
- /*
- * 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(STp->device) ) {
- retval = (-ENXIO);
- goto out;
- }
-
- if (ppos != &filp->f_pos) {
- /* "A request was outside the capabilities of the device." */
- retval = (-ENXIO);
- goto out;
- }
- if (STp->ready != ST_READY) {
- if (STp->ready == ST_NO_TAPE)
- retval = (-ENOMEDIUM);
- else
- retval = (-EIO);
- goto out;
- }
- STm = &(STp->modes[STp->current_mode]);
- if (!STm->defined) {
- retval = (-ENXIO);
- goto out;
- }
- if (count == 0)
- goto out;
- /*
- * If there was a bus reset, block further access
- * to this device.
- */
- if (STp->device->was_reset) {
- retval = (-EIO);
- goto out;
- }
- #if DEBUG
- if (!STp->in_use) {
- printk(OSST_DEB_MSG "osst%d:D: Incorrect device.n", dev);
- retval = (-EIO);
- goto out;
- }
- #endif
- if (STp->write_prot) {
- retval = (-EACCES);
- goto out;
- }
- /* Write must be integral number of blocks */
- if (STp->block_size != 0 && (count % STp->block_size) != 0) {
- printk(KERN_ERR "osst%d:E: Write (%ld bytes) not multiple of tape block size (%d%c).n",
- dev, (unsigned long)count, STp->block_size<1024?
- STp->block_size:STp->block_size/1024, STp->block_size<1024?'b':'k');
- retval = (-EINVAL);
- goto out;
- }
- if (STp->first_frame_position >= STp->capacity - OSST_EOM_RESERVE) {
- printk(KERN_ERR "osst%d:E: Write truncated at EOM early warning (frame %d).n",
- dev, STp->first_frame_position);
- retval = (-ENOSPC);
- goto out;
- }
- STps = &(STp->ps[STp->partition]);
- if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED &&
- !osst_int_ioctl(STp, &SRpnt, MTLOCK, 0))
- STp->door_locked = ST_LOCKED_AUTO;
- if (STps->rw == ST_READING) {
- retval = osst_flush_buffer(STp, &SRpnt, 0);
- if (retval)
- goto out;
- STps->rw = ST_IDLE;
- }
- else if (STps->rw != ST_WRITING) {
- /* Are we totally rewriting this tape? */
- if (!STp->header_ok ||
- (STp->first_frame_position == STp->first_data_ppos && STps->drv_block < 0) ||
- (STps->drv_file == 0 && STps->drv_block == 0)) {
- STp->wrt_pass_cntr++;
- #if DEBUG
- printk(OSST_DEB_MSG "osst%d:D: Allocating next write pass counter: %dn",
- dev, STp->wrt_pass_cntr);
- #endif
- osst_reset_header(STp, &SRpnt);
- STps->drv_file = STps->drv_block = 0;
- }
- /* Do we know where we'll be writing on the tape? */
- else {
- if ((STp->fast_open && osst_verify_position(STp, &SRpnt)) ||
- STps->drv_file < 0 || STps->drv_block < 0) {
- if (STp->first_frame_position == STp->eod_frame_ppos) { /* at EOD */
- STps->drv_file = STp->filemark_cnt;
- STps->drv_block = 0;
- }
- else {
- /* We have no idea where the tape is positioned - give up */
- #if DEBUG
- printk(OSST_DEB_MSG
- "osst%d:D: Cannot write at indeterminate position.n", dev);
- #endif
- retval = (-EIO);
- goto out;
- }
- }
- if ((STps->drv_file + STps->drv_block) > 0 && STps->drv_file < STp->filemark_cnt) {
- STp->filemark_cnt = STps->drv_file;
- STp->last_mark_ppos =
- ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt-1]);
- printk(KERN_WARNING
- "osst%d:W: Overwriting file %d with old write pass counter %dn",
- dev, STps->drv_file, STp->wrt_pass_cntr);
- printk(KERN_WARNING
- "osst%d:W: may lead to stale data being accepted on reading back!n",
- dev);
- #if DEBUG
- printk(OSST_DEB_MSG
- "osst%d:D: resetting filemark count to %d and last mark ppos,lbn to %d,%dn",
- dev, STp->filemark_cnt, STp->last_mark_ppos, STp->last_mark_lbn);
- #endif
- }
- }
- STp->fast_open = FALSE;
- }
- if (!STp->header_ok) {
- #if DEBUG
- printk(OSST_DEB_MSG "osst%d:D: Write cannot proceed without valid headersn", dev);
- #endif
- retval = (-EIO);
- goto out;
- }
- if ((STp->buffer)->writing) {
- if (SRpnt) printk(KERN_ERR "osst%d:A: Not supposed to have SRpnt at line %dn", dev, __LINE__);
- osst_write_behind_check(STp);
- if ((STp->buffer)->syscall_result) {
- #if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "osst%d:D: Async write error (write) %x.n", dev,
- (STp->buffer)->midlevel_result);
- #endif
- if ((STp->buffer)->midlevel_result == INT_MAX)
- STps->eof = ST_EOM_OK;
- else
- STps->eof = ST_EOM_ERROR;
- }
- }
- if (STps->eof == ST_EOM_OK) {
- retval = (-ENOSPC);
- goto out;
- }
- else if (STps->eof == ST_EOM_ERROR) {
- retval = (-EIO);
- goto out;
- }
- /* Check the buffer readability in cases where copy_user might catch
- the problems after some tape movement. */
- if ((copy_from_user(&i, buf, 1) != 0 ||
- copy_from_user(&i, buf + count - 1, 1) != 0)) {
- retval = (-EFAULT);
- goto out;
- }
- if (!STm->do_buffer_writes) {
- write_threshold = 1;
- }
- else
- write_threshold = (STp->buffer)->buffer_blocks * STp->block_size;
- if (!STm->do_async_writes)
- write_threshold--;
- total = count;
- #if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "osst%d:D: Writing %d bytes to file %d block %d lblk %d fseq %d fppos %dn",
- dev, count, STps->drv_file, STps->drv_block,
- STp->logical_blk_num, STp->frame_seq_number, STp->first_frame_position);
- #endif
- b_point = buf;
- while ((STp->buffer)->buffer_bytes + count > write_threshold)
- {
- doing_write = 1;
- do_count = (STp->buffer)->buffer_blocks * STp->block_size -
- (STp->buffer)->buffer_bytes;
- if (do_count > count)
- do_count = count;
- i = append_to_buffer(b_point, STp->buffer, do_count);
- if (i) {
- retval = i;
- goto out;
- }
- blks = do_count / STp->block_size;
- STp->logical_blk_num += blks; /* logical_blk_num is incremented as data is moved from user */
-
- i = osst_write_frame(STp, &SRpnt, TRUE);
- if (i == (-ENOSPC)) {
- transfer = STp->buffer->writing; /* FIXME -- check this logic */
- if (transfer <= do_count) {
- filp->f_pos += do_count - transfer;
- count -= do_count - transfer;
- if (STps->drv_block >= 0) {
- STps->drv_block += (do_count - transfer) / STp->block_size;
- }
- STps->eof = ST_EOM_OK;
- retval = (-ENOSPC); /* EOM within current request */
- #if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "osst%d:D: EOM with %d bytes unwritten.n",
- dev, transfer);
- #endif
- }
- else {
- STps->eof = ST_EOM_ERROR;
- STps->drv_block = (-1); /* Too cautious? */
- retval = (-EIO); /* EOM for old data */
- #if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "osst%d:D: EOM with lost data.n", dev);
- #endif
- }
- }
- else
- retval = i;
-
- if (retval < 0) {
- if (SRpnt != NULL) {
- scsi_release_request(SRpnt);
- SRpnt = NULL;
- }
- STp->buffer->buffer_bytes = 0;
- STp->dirty = 0;
- if (count < total)
- retval = total - count;
- goto out;
- }
- filp->f_pos += do_count;
- b_point += do_count;
- count -= do_count;
- if (STps->drv_block >= 0) {
- STps->drv_block += blks;
- }
- STp->buffer->buffer_bytes = 0;
- STp->dirty = 0;
- } /* end while write threshold exceeded */
- if (count != 0) {
- STp->dirty = 1;
- i = append_to_buffer(b_point, STp->buffer, count);
- if (i) {
- retval = i;
- goto out;
- }
- blks = count / STp->block_size;
- STp->logical_blk_num += blks;
- if (STps->drv_block >= 0) {
- STps->drv_block += blks;
- }
- filp->f_pos += count;
- count = 0;
- }
- if (doing_write && (STp->buffer)->syscall_result != 0) {
- retval = (STp->buffer)->syscall_result;
- goto out;
- }
- if (STm->do_async_writes && ((STp->buffer)->buffer_bytes >= STp->write_threshold)) {
- /* Schedule an asynchronous write */
- (STp->buffer)->writing = ((STp->buffer)->buffer_bytes /
- STp->block_size) * STp->block_size;
- STp->dirty = !((STp->buffer)->writing ==
- (STp->buffer)->buffer_bytes);
- i = osst_write_frame(STp, &SRpnt, FALSE);
- if (i < 0) {
- retval = (-EIO);
- goto out;
- }
- SRpnt = NULL; /* Prevent releasing this request! */
- }
- STps->at_sm &= (total == 0);
- if (total > 0)
- STps->eof = ST_NOEOF;
- retval = total;
- out:
- if (SRpnt != NULL) scsi_release_request(SRpnt);
- up(&STp->lock);
- return retval;
- }
- /* Read command */
- static ssize_t osst_read(struct file * filp, char * buf, size_t count, loff_t *ppos)
- {
- struct inode * inode = filp->f_dentry->d_inode;
- ssize_t total, retval = 0;
- ssize_t i, transfer;
- int special;
- OS_Scsi_Tape * STp;
- ST_mode * STm;
- ST_partstat * STps;
- Scsi_Request *SRpnt = NULL;
- int dev = TAPE_NR(inode->i_rdev);
- STp = os_scsi_tapes[dev];
- if (down_interruptible(&STp->lock))
- return (-ERESTARTSYS);
- /*
- * 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(STp->device) ) {
- retval = (-ENXIO);
- goto out;
- }
-
- if (ppos != &filp->f_pos) {
- /* "A request was outside the capabilities of the device." */
- retval = (-ENXIO);
- goto out;
- }
- if (STp->ready != ST_READY) {
- if (STp->ready == ST_NO_TAPE)
- retval = (-ENOMEDIUM);
- else
- retval = (-EIO);
- goto out;
- }
- STm = &(STp->modes[STp->current_mode]);
- if (!STm->defined) {
- retval = (-ENXIO);
- goto out;
- }
- #if DEBUG
- if (!STp->in_use) {
- printk(OSST_DEB_MSG "osst%d:D: Incorrect device.n", dev);
- retval = (-EIO);
- goto out;
- }
- #endif
- /* Must have initialized medium */
- if (!STp->header_ok) {
- retval = (-EIO);
- goto out;
- }
- if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED &&
- !osst_int_ioctl(STp, &SRpnt, MTLOCK, 0))
- STp->door_locked = ST_LOCKED_AUTO;
- STps = &(STp->ps[STp->partition]);
- if (STps->rw == ST_WRITING) {
- retval = osst_flush_buffer(STp, &SRpnt, 0);
- if (retval)
- goto out;
- STps->rw = ST_IDLE;
- /* FIXME -- this may leave the tape without EOD and up2date headers */
- }
- if ((count % STp->block_size) != 0) {
- printk(KERN_WARNING
- "osst%d:W: Read (%Zd bytes) not multiple of tape block size (%d%c).n", dev, count,
- STp->block_size<1024?STp->block_size:STp->block_size/1024, STp->block_size<1024?'b':'k');
- }
- #if DEBUG
- if (debugging && STps->eof != ST_NOEOF)
- printk(OSST_DEB_MSG "osst%d:D: EOF/EOM flag up (%d). Bytes %dn", dev,
- STps->eof, (STp->buffer)->buffer_bytes);
- #endif
- if ((STp->buffer)->buffer_bytes == 0 &&
- STps->eof >= ST_EOD_1) {
- if (STps->eof < ST_EOD) {
- STps->eof += 1;
- retval = 0;
- goto out;
- }
- retval = (-EIO); /* EOM or Blank Check */
- goto out;
- }
- /* Check the buffer writability before any tape movement. Don't alter
- buffer data. */
- if (copy_from_user(&i, buf, 1) != 0 ||
- copy_to_user (buf, &i, 1) != 0 ||
- copy_from_user(&i, buf + count - 1, 1) != 0 ||
- copy_to_user (buf + count - 1, &i, 1) != 0) {
- retval = (-EFAULT);
- goto out;
- }
- /* Loop until enough data in buffer or a special condition found */
- for (total = 0, special = 0; total < count - STp->block_size + 1 && !special; ) {
- /* Get new data if the buffer is empty */
- if ((STp->buffer)->buffer_bytes == 0) {
- if (STps->eof == ST_FM_HIT)
- break;
- special = osst_get_logical_frame(STp, &SRpnt, STp->frame_seq_number, 0);
- if (special < 0) { /* No need to continue read */
- STp->frame_in_buffer = 0;
- retval = special;
- goto out;
- }
- }
- /* Move the data from driver buffer to user buffer */
- if ((STp->buffer)->buffer_bytes > 0) {
- #if DEBUG
- if (debugging && STps->eof != ST_NOEOF)
- printk(OSST_DEB_MSG "osst%d:D: EOF up (%d). Left %d, needed %d.n", dev,
- STps->eof, (STp->buffer)->buffer_bytes, count - total);
- #endif
- transfer = (((STp->buffer)->buffer_bytes < count - total ?
- (STp->buffer)->buffer_bytes : count - total)/
- STp->block_size) * STp->block_size; /* force multiple of block size */
- i = from_buffer(STp->buffer, buf, transfer);
- if (i) {
- retval = i;
- goto out;
- }
- STp->logical_blk_num += transfer / STp->block_size;
- STps->drv_block += transfer / STp->block_size;
- filp->f_pos += transfer;
- buf += transfer;
- total += transfer;
- }
-
- if ((STp->buffer)->buffer_bytes == 0) {
- #if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "osst%d:D: Finished with frame %dn",
- dev, STp->frame_seq_number);
- #endif
- STp->frame_in_buffer = 0;
- STp->frame_seq_number++; /* frame to look for next time */
- }
- } /* for (total = 0, special = 0; total < count && !special; ) */
- /* Change the eof state if no data from tape or buffer */
- if (total == 0) {
- if (STps->eof == ST_FM_HIT) {
- STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_FM;
- STps->drv_block = 0;
- if (STps->drv_file >= 0)
- STps->drv_file++;
- }
- else if (STps->eof == ST_EOD_1) {
- STps->eof = ST_EOD_2;
- if (STps->drv_block > 0 && STps->drv_file >= 0)
- STps->drv_file++;
- STps->drv_block = 0;
- }
- else if (STps->eof == ST_EOD_2)
- STps->eof = ST_EOD;
- }
- else if (STps->eof == ST_FM)
- STps->eof = ST_NOEOF;
- retval = total;
- out:
- if (SRpnt != NULL) scsi_release_request(SRpnt);
- up(&STp->lock);
- return retval;
- }
- /* Set the driver options */
- static void osst_log_options(OS_Scsi_Tape *STp, ST_mode *STm, int dev)
- {
- printk(KERN_INFO
- "osst%d:I: Mode %d options: buffer writes: %d, async writes: %d, read ahead: %dn",
- dev, STp->current_mode, STm->do_buffer_writes, STm->do_async_writes,
- STm->do_read_ahead);
- printk(KERN_INFO
- "osst%d:I: can bsr: %d, two FMs: %d, fast mteom: %d, auto lock: %d,n",
- dev, STp->can_bsr, STp->two_fm, STp->fast_mteom, STp->do_auto_lock);
- printk(KERN_INFO
- "osst%d:I: defs for wr: %d, no block limits: %d, partitions: %d, s2 log: %dn",
- dev, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions,
- STp->scsi2_logical);
- printk(KERN_INFO
- "osst%d:I: sysv: %dn", dev, STm->sysv);
- #if DEBUG
- printk(KERN_INFO
- "osst%d:D: debugging: %dn",
- dev, debugging);
- #endif
- }
- static int osst_set_options(OS_Scsi_Tape *STp, long options)
- {
- int value;
- long code;
- ST_mode *STm;
- int dev = TAPE_NR(STp->devt);
- STm = &(STp->modes[STp->current_mode]);
- if (!STm->defined) {
- memcpy(STm, &(STp->modes[0]), sizeof(ST_mode));
- modes_defined = TRUE;
- #if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "osst%d:D: Initialized mode %d definition from mode 0n",
- dev, STp->current_mode);
- #endif
- }
- code = options & MT_ST_OPTIONS;
- if (code == MT_ST_BOOLEANS) {
- STm->do_buffer_writes = (options & MT_ST_BUFFER_WRITES) != 0;
- STm->do_async_writes = (options & MT_ST_ASYNC_WRITES) != 0;
- STm->defaults_for_writes = (options & MT_ST_DEF_WRITES) != 0;
- STm->do_read_ahead = (options & MT_ST_READ_AHEAD) != 0;
- STp->two_fm = (options & MT_ST_TWO_FM) != 0;
- STp->fast_mteom = (options & MT_ST_FAST_MTEOM) != 0;
- STp->do_auto_lock = (options & MT_ST_AUTO_LOCK) != 0;
- STp->can_bsr = (options & MT_ST_CAN_BSR) != 0;
- STp->omit_blklims = (options & MT_ST_NO_BLKLIMS) != 0;
- if ((STp->device)->scsi_level >= SCSI_2)
- STp->can_partitions = (options & MT_ST_CAN_PARTITIONS) != 0;
- STp->scsi2_logical = (options & MT_ST_SCSI2LOGICAL) != 0;
- STm->sysv = (options & MT_ST_SYSV) != 0;
- #if DEBUG
- debugging = (options & MT_ST_DEBUGGING) != 0;
- #endif
- osst_log_options(STp, STm, dev);
- }
- else if (code == MT_ST_SETBOOLEANS || code == MT_ST_CLEARBOOLEANS) {
- value = (code == MT_ST_SETBOOLEANS);
- if ((options & MT_ST_BUFFER_WRITES) != 0)
- STm->do_buffer_writes = value;
- if ((options & MT_ST_ASYNC_WRITES) != 0)
- STm->do_async_writes = value;
- if ((options & MT_ST_DEF_WRITES) != 0)
- STm->defaults_for_writes = value;
- if ((options & MT_ST_READ_AHEAD) != 0)
- STm->do_read_ahead = value;
- if ((options & MT_ST_TWO_FM) != 0)
- STp->two_fm = value;
- if ((options & MT_ST_FAST_MTEOM) != 0)
- STp->fast_mteom = value;
- if ((options & MT_ST_AUTO_LOCK) != 0)
- STp->do_auto_lock = value;
- if ((options & MT_ST_CAN_BSR) != 0)
- STp->can_bsr = value;
- if ((options & MT_ST_NO_BLKLIMS) != 0)
- STp->omit_blklims = value;
- if ((STp->device)->scsi_level >= SCSI_2 &&
- (options & MT_ST_CAN_PARTITIONS) != 0)
- STp->can_partitions = value;
- if ((options & MT_ST_SCSI2LOGICAL) != 0)
- STp->scsi2_logical = value;
- if ((options & MT_ST_SYSV) != 0)
- STm->sysv = value;
- #if DEBUG
- if ((options & MT_ST_DEBUGGING) != 0)
- debugging = value;
- #endif
- osst_log_options(STp, STm, dev);
- }
- else if (code == MT_ST_WRITE_THRESHOLD) {
- value = (options & ~MT_ST_OPTIONS) * ST_KILOBYTE;
- if (value < 1 || value > osst_buffer_size) {
- printk(KERN_WARNING "osst%d:W: Write threshold %d too small or too large.n",
- dev, value);
- return (-EIO);
- }
- STp->write_threshold = value;
- printk(KERN_INFO "osst%d:I: Write threshold set to %d bytes.n",
- dev, value);
- }
- else if (code == MT_ST_DEF_BLKSIZE) {
- value = (options & ~MT_ST_OPTIONS);
- if (value == ~MT_ST_OPTIONS) {
- STm->default_blksize = (-1);
- printk(KERN_INFO "osst%d:I: Default block size disabled.n", dev);
- }
- else {
- if (value < 512 || value > OS_DATA_SIZE || OS_DATA_SIZE % value) {
- printk(KERN_WARNING "osst%d:W: Default block size cannot be set to %d.n",
- dev, value);
- return (-EINVAL);
- }
- STm->default_blksize = value;
- printk(KERN_INFO "osst%d:I: Default block size set to %d bytes.n",
- dev, STm->default_blksize);
- }
- }
- else if (code == MT_ST_TIMEOUTS) {
- value = (options & ~MT_ST_OPTIONS);
- if ((value & MT_ST_SET_LONG_TIMEOUT) != 0) {
- STp->long_timeout = (value & ~MT_ST_SET_LONG_TIMEOUT) * HZ;
- printk(KERN_INFO "osst%d:I: Long timeout set to %d seconds.n", dev,
- (value & ~MT_ST_SET_LONG_TIMEOUT));
- }
- else {
- STp->timeout = value * HZ;
- printk(KERN_INFO "osst%d:I: Normal timeout set to %d seconds.n", dev, value);
- }
- }
- else if (code == MT_ST_DEF_OPTIONS) {
- code = (options & ~MT_ST_CLEAR_DEFAULT);
- value = (options & MT_ST_CLEAR_DEFAULT);
- if (code == MT_ST_DEF_DENSITY) {
- if (value == MT_ST_CLEAR_DEFAULT) {
- STm->default_density = (-1);
- printk(KERN_INFO "osst%d:I: Density default disabled.n", dev);
- }
- else {
- STm->default_density = value & 0xff;
- printk(KERN_INFO "osst%d:I: Density default set to %xn",
- dev, STm->default_density);
- }
- }
- else if (code == MT_ST_DEF_DRVBUFFER) {
- if (value == MT_ST_CLEAR_DEFAULT) {
- STp->default_drvbuffer = 0xff;
- printk(KERN_INFO "osst%d:I: Drive buffer default disabled.n", dev);
- }
- else {
- STp->default_drvbuffer = value & 7;
- printk(KERN_INFO "osst%d:I: Drive buffer default set to %xn",
- dev, STp->default_drvbuffer);
- }
- }
- else if (code == MT_ST_DEF_COMPRESSION) {
- if (value == MT_ST_CLEAR_DEFAULT) {
- STm->default_compression = ST_DONT_TOUCH;
- printk(KERN_INFO "osst%d:I: Compression default disabled.n", dev);
- }
- else {
- STm->default_compression = (value & 1 ? ST_YES : ST_NO);
- printk(KERN_INFO "osst%d:I: Compression default set to %xn",
- dev, (value & 1));
- }
- }
- }
- else
- return (-EIO);
- return 0;
- }
- /* Internal ioctl function */
- static int osst_int_ioctl(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned int cmd_in, unsigned long arg)
- {
- int timeout;
- long ltmp;
- int i, ioctl_result;
- int chg_eof = TRUE;
- unsigned char cmd[MAX_COMMAND_SIZE];
- Scsi_Request * SRpnt = * aSRpnt;
- ST_partstat * STps;
- int fileno, blkno, at_sm, frame_seq_numbr, logical_blk_num;
- int datalen = 0, direction = SCSI_DATA_NONE;
- int dev = TAPE_NR(STp->devt);
- if (STp->ready != ST_READY && cmd_in != MTLOAD) {
- if (STp->ready == ST_NO_TAPE)
- return (-ENOMEDIUM);
- else
- return (-EIO);
- }
- timeout = STp->long_timeout;
- STps = &(STp->ps[STp->partition]);
- fileno = STps->drv_file;
- blkno = STps->drv_block;
- at_sm = STps->at_sm;
- frame_seq_numbr = STp->frame_seq_number;
- logical_blk_num = STp->logical_blk_num;
- memset(cmd, 0, MAX_COMMAND_SIZE);
- switch (cmd_in) {
- case MTFSFM:
- chg_eof = FALSE; /* Changed from the FSF after this */
- case MTFSF:
- if (STp->raw)
- return (-EIO);
- if (STp->linux_media)
- ioctl_result = osst_space_over_filemarks_forward_fast(STp, &SRpnt, cmd_in, arg);
- else
- ioctl_result = osst_space_over_filemarks_forward_slow(STp, &SRpnt, cmd_in, arg);
- if (fileno >= 0)
- fileno += arg;
- blkno = 0;
- at_sm &= (arg == 0);
- goto os_bypass;
- case MTBSF:
- chg_eof = FALSE; /* Changed from the FSF after this */
- case MTBSFM:
- if (STp->raw)
- return (-EIO);
- ioctl_result = osst_space_over_filemarks_backward(STp, &SRpnt, cmd_in, arg);
- if (fileno >= 0)
- fileno -= arg;
- blkno = (-1); /* We can't know the block number */
- at_sm &= (arg == 0);
- goto os_bypass;
- case MTFSR:
- case MTBSR:
- #if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "osst%d:D: Skipping %lu blocks %s from logical block %dn",
- dev, arg, cmd_in==MTFSR?"forward":"backward", logical_blk_num);
- #endif
- if (cmd_in == MTFSR) {
- logical_blk_num += arg;
- if (blkno >= 0) blkno += arg;
- }
- else {
- logical_blk_num -= arg;
- if (blkno >= 0) blkno -= arg;
- }
- ioctl_result = osst_seek_logical_blk(STp, &SRpnt, logical_blk_num);
- fileno = STps->drv_file;
- blkno = STps->drv_block;
- at_sm &= (arg == 0);
- goto os_bypass;
- case MTFSS:
- cmd[0] = SPACE;
- cmd[1] = 0x04; /* Space Setmarks */ /* FIXME -- OS can't do this? */
- cmd[2] = (arg >> 16);
- cmd[3] = (arg >> 8);
- cmd[4] = arg;
- #if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "osst%d:D: Spacing tape forward %d setmarks.n", dev,
- cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
- #endif
- if (arg != 0) {
- blkno = fileno = (-1);
- at_sm = 1;
- }
- break;
- case MTBSS:
- cmd[0] = SPACE;
- cmd[1] = 0x04; /* Space Setmarks */ /* FIXME -- OS can't do this? */
- ltmp = (-arg);
- cmd[2] = (ltmp >> 16);
- cmd[3] = (ltmp >> 8);
- cmd[4] = ltmp;
- #if DEBUG
- if (debugging) {
- if (cmd[2] & 0x80)
- ltmp = 0xff000000;
- ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
- printk(OSST_DEB_MSG "osst%d:D: Spacing tape backward %ld setmarks.n",
- dev, (-ltmp));
- }
- #endif
- if (arg != 0) {
- blkno = fileno = (-1);
- at_sm = 1;
- }
- break;
- case MTWEOF:
- if ( STps->rw == ST_WRITING && !(STp->device)->was_reset)
- ioctl_result = osst_flush_write_buffer(STp, &SRpnt);
- else
- ioctl_result = 0;
- #if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "osst%d:D: Writing %ld filemark(s).n", dev, arg);
- #endif
- for (i=0; i<arg; i++)
- ioctl_result |= osst_write_filemark(STp, &SRpnt);
- if (fileno >= 0) fileno += arg;
- if (blkno >= 0) blkno = 0;
- goto os_bypass;
- case MTWSM:
- if (STp->write_prot)
- return (-EACCES);
- if (!STp->raw)
- return 0;
- cmd[0] = WRITE_FILEMARKS; /* FIXME -- need OS version */
- if (cmd_in == MTWSM)
- cmd[1] = 2;
- cmd[2] = (arg >> 16);
- cmd[3] = (arg >> 8);
- cmd[4] = arg;
- timeout = STp->timeout;
- #if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "osst%d:D: Writing %d setmark(s).n", dev,
- cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
- #endif
- if (fileno >= 0)
- fileno += arg;
- blkno = 0;
- at_sm = (cmd_in == MTWSM);
- break;
- case MTOFFL:
- case MTLOAD:
- case MTUNLOAD:
- case MTRETEN:
- cmd[0] = START_STOP;
- cmd[1] = 1; /* Don't wait for completion */
- if (cmd_in == MTLOAD) {
- if (STp->ready == ST_NO_TAPE)
- cmd[4] = 4; /* open tray */
- else
- cmd[4] = 1; /* load */
- }
- if (cmd_in == MTRETEN)
- cmd[4] = 3; /* retension then mount */
- if (cmd_in == MTOFFL)
- cmd[4] = 4; /* rewind then eject */
- timeout = STp->timeout;
- #if DEBUG
- if (debugging) {
- switch (cmd_in) {
- case MTUNLOAD:
- printk(OSST_DEB_MSG "osst%d:D: Unloading tape.n", dev);
- break;
- case MTLOAD:
- printk(OSST_DEB_MSG "osst%d:D: Loading tape.n", dev);
- break;
- case MTRETEN:
- printk(OSST_DEB_MSG "osst%d:D: Retensioning tape.n", dev);
- break;
- case MTOFFL:
- printk(OSST_DEB_MSG "osst%d:D: Ejecting tape.n", dev);
- break;
- }
- }
- #endif
- fileno = blkno = at_sm = frame_seq_numbr = logical_blk_num = 0 ;
- break;
- case MTNOP:
- #if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "osst%d:D: No-op on tape.n", dev);
- #endif
- return 0; /* Should do something ? */
- break;
- case MTEOM:
- #if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "osst%d:D: Spacing to end of recorded medium.n", dev);
- #endif
- osst_set_frame_position(STp, &SRpnt, STp->eod_frame_ppos, 0);
- if (osst_get_logical_frame(STp, &SRpnt, -1, 0) < 0) {
- ioctl_result = -EIO;
- goto os_bypass;
- }
- if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_EOD) {
- #if DEBUG
- printk(OSST_DEB_MSG "osst%d:D: No EOD frame found where expected.n", dev);
- #endif
- ioctl_result = -EIO;
- goto os_bypass;
- }
- ioctl_result = osst_set_frame_position(STp, &SRpnt, STp->eod_frame_ppos, 0);
- fileno = STp->filemark_cnt;
- blkno = at_sm = 0;
- goto os_bypass;
- case MTERASE:
- if (STp->write_prot)
- return (-EACCES);
- ioctl_result = osst_reset_header(STp, &SRpnt);
- i = osst_write_eod(STp, &SRpnt);
- if (i < ioctl_result) ioctl_result = i;
- i = osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos);
- if (i < ioctl_result) ioctl_result = i;
- fileno = blkno = at_sm = 0 ;
- goto os_bypass;
- case MTREW:
- cmd[0] = REZERO_UNIT; /* rewind */
- cmd[1] = 1;
- #if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "osst%d:D: Rewinding tape, Immed=%d.n", dev, cmd[1]);
- #endif
- fileno = blkno = at_sm = frame_seq_numbr = logical_blk_num = 0 ;
- break;
- case MTLOCK:
- chg_eof = FALSE;
- cmd[0] = ALLOW_MEDIUM_REMOVAL;
- cmd[4] = SCSI_REMOVAL_PREVENT;
- #if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "osst%d:D: Locking drive door.n", dev);
- #endif
- break;
- case MTUNLOCK:
- chg_eof = FALSE;
- cmd[0] = ALLOW_MEDIUM_REMOVAL;
- cmd[4] = SCSI_REMOVAL_ALLOW;
- #if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "osst%d:D: Unlocking drive door.n", dev);
- #endif
- break;
- case MTSETBLK: /* Set block length */
- case MTSETDENSITY: /* Set tape density */
- case MTSETDRVBUFFER: /* Set drive buffering */
- case SET_DENS_AND_BLK: /* Set density and block size */
- chg_eof = FALSE;
- if (STp->dirty || (STp->buffer)->buffer_bytes != 0)
- return (-EIO); /* Not allowed if data in buffer */
- if ((cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) &&
- (arg & MT_ST_BLKSIZE_MASK) != 0 &&
- ((arg & MT_ST_BLKSIZE_MASK) < STp->min_block ||
- (arg & MT_ST_BLKSIZE_MASK) > STp->max_block ||
- (arg & MT_ST_BLKSIZE_MASK) > osst_buffer_size)) {
- printk(KERN_WARNING "osst%d:W: Illegal block size.n", dev);
- return (-EINVAL);
- }
- return 0; /* FIXME silently ignore if block size didn't change */
- default:
- return (-ENOSYS);
- }
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, datalen, direction, timeout, MAX_RETRIES, TRUE);
- ioctl_result = (STp->buffer)->syscall_result;
- if (!SRpnt) {
- #if DEBUG
- printk(OSST_DEB_MSG "osst%d:D: Couldn't exec scsi cmd for IOCTLn", dev);
- #endif
- return ioctl_result;
- }
- if (!ioctl_result) { /* SCSI command successful */
- STp->frame_seq_number = frame_seq_numbr;
- STp->logical_blk_num = logical_blk_num;
- }
- os_bypass:
- #if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "osst%d:D: IOCTL (%d) Result=%dn", dev, cmd_in, ioctl_result);
- #endif
- if (!ioctl_result) { /* success */
- if (cmd_in == MTFSFM) {
- fileno--;
- blkno--;
- }
- if (cmd_in == MTBSFM) {
- fileno++;
- blkno++;
- }
- STps->drv_block = blkno;
- STps->drv_file = fileno;
- STps->at_sm = at_sm;
- if (cmd_in == MTLOCK)
- STp->door_locked = ST_LOCKED_EXPLICIT;
- else if (cmd_in == MTUNLOCK)
- STp->door_locked = ST_UNLOCKED;
- if (cmd_in == MTEOM)
- STps->eof = ST_EOD;
- else if (cmd_in == MTFSF)
- STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_FM;
- else if (chg_eof)
- STps->eof = ST_NOEOF;
- 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; FIXME */
- for (i=0; i < ST_NBR_PARTITIONS; i++) {
- STp->ps[i].rw = ST_IDLE;
- STp->ps[i].last_block_valid = FALSE;/* FIXME - where else is this field maintained? */
- }
- STp->partition = 0;
- }
- if (cmd_in == MTREW) {
- ioctl_result = osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos);
- if (ioctl_result > 0)
- ioctl_result = 0;
- }
- } else if (cmd_in == MTBSF || cmd_in == MTBSFM ) {
- if (osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos) < 0)
- STps->drv_file = STps->drv_block = -1;
- else
- STps->drv_file = STps->drv_block = 0;
- STps->eof = ST_NOEOF;
- } else if (cmd_in == MTFSF || cmd_in == MTFSFM) {
- if (osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos) < 0)
- STps->drv_file = STps->drv_block = -1;
- else {
- STps->drv_file = STp->filemark_cnt;
- STps->drv_block = 0;
- }
- STps->eof = ST_EOD;
- } else if (cmd_in == MTBSR || cmd_in == MTFSR || cmd_in == MTWEOF || cmd_in == MTEOM) {
- STps->drv_file = STps->drv_block = (-1);
- STps->eof = ST_NOEOF;
- STp->header_ok = 0;
- } else if (cmd_in == MTERASE) {
- STp->header_ok = 0;
- } else if (SRpnt) { /* SCSI command was not completely successful. */
- if (SRpnt->sr_sense_buffer[2] & 0x40) {
- STps->eof = ST_EOM_OK;
- STps->drv_block = 0;
- }
- if (chg_eof)
- STps->eof = ST_NOEOF;
- if ((SRpnt->sr_sense_buffer[2] & 0x0f) == BLANK_CHECK)
- STps->eof = ST_EOD;
- if (cmd_in == MTLOCK)
- STp->door_locked = ST_LOCK_FAILS;
- if (cmd_in == MTLOAD && osst_wait_for_medium(STp, &SRpnt, 60))
- ioctl_result = osst_wait_ready(STp, &SRpnt, 5 * 60);
- }
- *aSRpnt = SRpnt;
- return ioctl_result;
- }
- /* Open the device */
- static int os_scsi_tape_open(struct inode * inode, struct file * filp)
- {
- unsigned short flags;
- int i, b_size, need_dma_buffer, new_session = FALSE, retval = 0;
- unsigned char cmd[MAX_COMMAND_SIZE];
- Scsi_Request * SRpnt;
- OS_Scsi_Tape * STp;
- ST_mode * STm;
- ST_partstat * STps;
- int dev = TAPE_NR(inode->i_rdev);
- int mode = TAPE_MODE(inode->i_rdev);
- if (dev >= osst_template.dev_max || (STp = os_scsi_tapes[dev]) == NULL || !STp->device)
- return (-ENXIO);
- if( !scsi_block_when_processing_errors(STp->device) ) {
- return -ENXIO;
- }
- if (STp->in_use) {
- #if DEBUG
- printk(OSST_DEB_MSG "osst%d:D: Device already in use.n", dev);
- #endif
- return (-EBUSY);
- }
- STp->in_use = 1;
- STp->rew_at_close = (MINOR(inode->i_rdev) & 0x80) == 0;
- if (STp->device->host->hostt->module)
- __MOD_INC_USE_COUNT(STp->device->host->hostt->module);
- if (osst_template.module)
- __MOD_INC_USE_COUNT(osst_template.module);
- STp->device->access_count++;
- if (mode != STp->current_mode) {
- #if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "osst%d:D: Mode change from %d to %d.n",
- dev, STp->current_mode, mode);
- #endif
- new_session = TRUE;
- STp->current_mode = mode;
- }
- STm = &(STp->modes[STp->current_mode]);
- flags = filp->f_flags;
- STp->write_prot = ((flags & O_ACCMODE) == O_RDONLY);
- STp->raw = (MINOR(inode->i_rdev) & 0x40) != 0;
- if (STp->raw)
- STp->header_ok = 0;
- /* Allocate a buffer for this user */
- need_dma_buffer = STp->restr_dma;
- for (i=0; i < osst_nbr_buffers; i++)
- if (!osst_buffers[i]->in_use &&
- (!need_dma_buffer || osst_buffers[i]->dma))
- break;
- if (i >= osst_nbr_buffers) {
- STp->buffer = new_tape_buffer(FALSE, need_dma_buffer);
- if (STp->buffer == NULL) {
- printk(KERN_WARNING "osst%d:W: Can't allocate tape buffer.n", dev);
- retval = (-EBUSY);
- goto err_out;
- }
- }
- else
- STp->buffer = osst_buffers[i];
- (STp->buffer)->in_use = 1;
- (STp->buffer)->writing = 0;
- (STp->buffer)->syscall_result = 0;
- (STp->buffer)->use_sg = STp->device->host->sg_tablesize;
- /* Compute the usable buffer size for this SCSI adapter */
- if (!(STp->buffer)->use_sg)
- (STp->buffer)->buffer_size = (STp->buffer)->sg[0].length;
- else {
- for (i=0, (STp->buffer)->buffer_size = 0; i < (STp->buffer)->use_sg &&
- i < (STp->buffer)->sg_segs; i++)
- (STp->buffer)->buffer_size += (STp->buffer)->sg[i].length;
- }
- STp->dirty = 0;
- for (i=0; i < ST_NBR_PARTITIONS; i++) {
- STps = &(STp->ps[i]);
- STps->rw = ST_IDLE;
- }
- STp->ready = ST_READY;
- #if DEBUG
- STp->nbr_waits = STp->nbr_finished = 0;
- #endif
- memset (cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = TEST_UNIT_READY;
- SRpnt = osst_do_scsi(NULL, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_READY_RETRIES, TRUE);
- if (!SRpnt) {
- retval = (STp->buffer)->syscall_result;
- goto err_out;
- }
- if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
- (SRpnt->sr_sense_buffer[2] & 0x0f) == NOT_READY &&
- SRpnt->sr_sense_buffer[12] == 4 ) {
- #if DEBUG
- printk(OSST_DEB_MSG "osst%d:D: Unit not ready, cause %xn", dev, SRpnt->sr_sense_buffer[13]);
- #endif
- if (SRpnt->sr_sense_buffer[13] == 2) { /* initialize command required (LOAD) */
- memset (cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = START_STOP;
- cmd[1] = 1;
- cmd[4] = 1;
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE,
- STp->timeout, MAX_READY_RETRIES, TRUE);
- }
- osst_wait_ready(STp, &SRpnt, (SRpnt->sr_sense_buffer[13]==1?15:3) * 60);
- }
- if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
- (SRpnt->sr_sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */
- #if DEBUG
- printk(OSST_DEB_MSG "osst%d:D: Unit wants attentionn", dev);
- #endif
- STp->header_ok = 0;
- for (i=0; i < 10; i++) {
- memset (cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = TEST_UNIT_READY;
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE,
- STp->timeout, MAX_READY_RETRIES, TRUE);
- if ((SRpnt->sr_sense_buffer[0] & 0x70) != 0x70 ||
- (SRpnt->sr_sense_buffer[2] & 0x0f) != UNIT_ATTENTION)
- break;
- }
- STp->device->was_reset = 0;
- STp->partition = STp->new_partition = 0;
- if (STp->can_partitions)
- STp->nbr_partitions = 1; /* This guess will be updated later if necessary */
- for (i=0; i < ST_NBR_PARTITIONS; i++) {
- STps = &(STp->ps[i]);
- STps->rw = ST_IDLE; /* FIXME - seems to be redundant... */
- STps->eof = ST_NOEOF;
- STps->at_sm = 0;
- STps->last_block_valid = FALSE;
- STps->drv_block = 0;
- STps->drv_file = 0 ;
- }
- new_session = TRUE;
- STp->recover_count = 0;
- }
- /*
- * if we have valid headers from before, and the drive/tape seem untouched,
- * open without reconfiguring and re-reading the headers
- */
- if (!STp->buffer->syscall_result && STp->header_ok &&
- !SRpnt->sr_result && SRpnt->sr_sense_buffer[0] == 0) {
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = MODE_SENSE;
- cmd[1] = 8;
- cmd[2] = VENDOR_IDENT_PAGE;
- cmd[4] = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH;
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_READ, STp->timeout, 0, TRUE);
- if (STp->buffer->syscall_result ||
- STp->buffer->b_data[MODE_HEADER_LENGTH + 2] != 'L' ||
- STp->buffer->b_data[MODE_HEADER_LENGTH + 3] != 'I' ||
- STp->buffer->b_data[MODE_HEADER_LENGTH + 4] != 'N' ||
- STp->buffer->b_data[MODE_HEADER_LENGTH + 5] != '4' ) {
- #if DEBUG
- printk(OSST_DEB_MSG "osst%d:D: Signature was changed to %c%c%c%cn", dev,
- STp->buffer->b_data[MODE_HEADER_LENGTH + 2],
- STp->buffer->b_data[MODE_HEADER_LENGTH + 3],
- STp->buffer->b_data[MODE_HEADER_LENGTH + 4],
- STp->buffer->b_data[MODE_HEADER_LENGTH + 5]);
- #endif
- STp->header_ok = 0;
- }
- i = STp->first_frame_position;
- if (STp->header_ok && i == osst_get_frame_position(STp, &SRpnt)) {
- if (STp->door_locked == ST_UNLOCKED) {
- if (osst_int_ioctl(STp, &SRpnt, MTLOCK, 0))
- printk(KERN_INFO "osst%d:I: Can't lock drive doorn", dev);
- else
- STp->door_locked = ST_LOCKED_AUTO;
- }
- if (!STp->frame_in_buffer) {
- STp->block_size = (STm->default_blksize > 0) ?
- STm->default_blksize : OS_DATA_SIZE;
- STp->buffer->buffer_bytes = STp->buffer->read_pointer = 0;
- }
- STp->buffer->buffer_blocks = OS_DATA_SIZE / STp->block_size;
- STp->fast_open = TRUE;
- scsi_release_request(SRpnt);
- return 0;
- }
- #if DEBUG
- if (i != STp->first_frame_position)
- printk(OSST_DEB_MSG "osst%d:D: Tape position changed from %d to %dn",
- dev, i, STp->first_frame_position);
- #endif
- STp->header_ok = 0;
- }
- STp->fast_open = FALSE;
- if ((STp->buffer)->syscall_result != 0 && /* in all error conditions except no medium */
- (SRpnt->sr_sense_buffer[2] != 2 || SRpnt->sr_sense_buffer[12] != 0x3A) ) {
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = MODE_SELECT;
- cmd[1] = 0x10;
- cmd[4] = 4 + MODE_HEADER_LENGTH;
- (STp->buffer)->b_data[0] = cmd[4] - 1;
- (STp->buffer)->b_data[1] = 0; /* Medium Type - ignoring */
- (STp->buffer)->b_data[2] = 0; /* Reserved */
- (STp->buffer)->b_data[3] = 0; /* Block Descriptor Length */
- (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = 0x3f;
- (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 1;
- (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 2;
- (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = 3;
- #if DEBUG
- printk(OSST_DEB_MSG "osst%d:D: Applying soft resetn", dev);
- #endif
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_WRITE, STp->timeout, 0, TRUE);
- STp->header_ok = 0;
- for (i=0; i < 10; i++) {
- memset (cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = TEST_UNIT_READY;
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE,
- STp->timeout, MAX_READY_RETRIES, TRUE);
- if ((SRpnt->sr_sense_buffer[0] & 0x70) != 0x70 ||
- (SRpnt->sr_sense_buffer[2] & 0x0f) == NOT_READY)
- break;
- if ((SRpnt->sr_sense_buffer[2] & 0x0f) == UNIT_ATTENTION) {
- STp->device->was_reset = 0;
- STp->partition = STp->new_partition = 0;
- if (STp->can_partitions)
- STp->nbr_partitions = 1; /* This guess will be updated later if necessary */
- for (i=0; i < ST_NBR_PARTITIONS; i++) {
- STps = &(STp->ps[i]);
- STps->rw = ST_IDLE;
- STps->eof = ST_NOEOF;
- STps->at_sm = 0;
- STps->last_block_valid = FALSE;
- STps->drv_block = 0;
- STps->drv_file = 0 ;
- }
- new_session = TRUE;
- }
- }
- }
- if (osst_wait_ready(STp, &SRpnt, 15 * 60)) /* FIXME - not allowed with NOBLOCK */
- printk(KERN_INFO "osst%i:I: Device did not become Ready in openn",dev);
- if ((STp->buffer)->syscall_result != 0) {
- if ((STp->device)->scsi_level >= SCSI_2 &&
- (SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
- (SRpnt->sr_sense_buffer[2] & 0x0f) == NOT_READY &&
- SRpnt->sr_sense_buffer[12] == 0x3a) { /* Check ASC */
- STp->ready = ST_NO_TAPE;
- } else
- STp->ready = ST_NOT_READY;
- scsi_release_request(SRpnt);
- SRpnt = NULL;
- STp->density = 0; /* Clear the erroneous "residue" */
- STp->write_prot = 0;
- STp->block_size = 0;
- STp->ps[0].drv_file = STp->ps[0].drv_block = (-1);
- STp->partition = STp->new_partition = 0;
- STp->door_locked = ST_UNLOCKED;
- return 0;
- }
- osst_configure_onstream(STp, &SRpnt);
- /* STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0; FIXME */
- if (OS_FRAME_SIZE > (STp->buffer)->buffer_size &&
- !enlarge_buffer(STp->buffer, OS_FRAME_SIZE, STp->restr_dma)) {
- printk(KERN_NOTICE "osst%d:A: Framesize %d too large for buffer.n", dev,
- OS_FRAME_SIZE);
- retval = (-EIO);
- goto err_out;
- }
- if ((STp->buffer)->buffer_size >= OS_FRAME_SIZE) {
- for (i = 0, b_size = 0;
- i < STp->buffer->sg_segs && (b_size + STp->buffer->sg[i].length) <= OS_DATA_SIZE;
- b_size += STp->buffer->sg[i++].length);
- STp->buffer->aux = (os_aux_t *) (STp->buffer->sg[i].address + OS_DATA_SIZE - b_size);
- #if DEBUG
- printk(OSST_DEB_MSG "osst%d:D: b_data points to %p in segment 0 at %pn", dev,
- STp->buffer->b_data, STp->buffer->sg[0].address);
- printk(OSST_DEB_MSG "osst%d:D: AUX points to %p in segment %d at %pn", dev,
- STp->buffer->aux, i, STp->buffer->sg[i].address);
- #endif
- } else
- STp->buffer->aux = NULL; /* this had better never happen! */
- STp->block_size = STp->raw ? OS_FRAME_SIZE : (
- (STm->default_blksize > 0) ? STm->default_blksize : OS_DATA_SIZE);
- STp->buffer->buffer_blocks = STp->raw ? 1 : OS_DATA_SIZE / STp->block_size;
- STp->buffer->buffer_bytes =
- STp->buffer->read_pointer =
- STp->frame_in_buffer = 0;
- #if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "osst%d:D: Block size: %d, frame size: %d, buffer size: %d (%d blocks).n",
- dev, STp->block_size, OS_FRAME_SIZE, (STp->buffer)->buffer_size,
- (STp->buffer)->buffer_blocks);
- #endif
- if (STp->drv_write_prot) {
- STp->write_prot = 1;
- #if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "osst%d:D: Write protectedn", dev);
- #endif
- if ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR) {
- retval = (-EROFS);
- goto err_out;
- }
- }
- if (new_session) { /* Change the drive parameters for the new mode */
- #if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "osst%d:D: New Sessionn", dev);
- #endif
- STp->density_changed = STp->blksize_changed = FALSE;
- STp->compression_changed = FALSE;
- }
- /*
- * properly position the tape and check the ADR headers
- */
- if (STp->door_locked == ST_UNLOCKED) {
- if (osst_int_ioctl(STp, &SRpnt, MTLOCK, 0))
- printk(KERN_INFO "osst%d:I: Can't lock drive doorn", dev);
- else
- STp->door_locked = ST_LOCKED_AUTO;
- }
- osst_analyze_headers(STp, &SRpnt);
- scsi_release_request(SRpnt);
- SRpnt = NULL;
- return 0;
- err_out:
- if (SRpnt != NULL)
- scsi_release_request(SRpnt);
- if (STp->buffer != NULL) {
- STp->buffer->in_use = 0;
- STp->buffer = NULL;
- }
- STp->in_use = 0;
- STp->header_ok = 0;
- STp->device->access_count--;
- if (STp->device->host->hostt->module)
- __MOD_DEC_USE_COUNT(STp->device->host->hostt->module);
- if (osst_template.module)
- __MOD_DEC_USE_COUNT(osst_template.module);
- return retval;
- }
- /* Flush the tape buffer before close */
- static int os_scsi_tape_flush(struct file * filp)
- {
- int result = 0, result2;
- OS_Scsi_Tape * STp;
- ST_mode * STm;
- ST_partstat * STps;
- Scsi_Request *SRpnt = NULL;
- struct inode *inode = filp->f_dentry->d_inode;
- kdev_t devt = inode->i_rdev;
- int dev;
- if (file_count(filp) > 1)
- return 0;
- dev = TAPE_NR(devt);
- STp = os_scsi_tapes[dev];
- STm = &(STp->modes[STp->current_mode]);
- STps = &(STp->ps[STp->partition]);
- if ( STps->rw == ST_WRITING && !(STp->device)->was_reset) {
- result = osst_flush_write_buffer(STp, &SRpnt);
- if (result != 0 && result != (-ENOSPC))
- goto out;
- }
- if ( STps->rw >= ST_WRITING && !(STp->device)->was_reset) {
- #if DEBUG
- if (debugging) {
- printk(OSST_DEB_MSG "osst%d:D: File length %ld bytes.n",
- dev, (long)(filp->f_pos));
- printk(OSST_DEB_MSG "osst%d:D: Async write waits %d, finished %d.n",
- dev, STp->nbr_waits, STp->nbr_finished);
- }
- #endif
- if (STp->write_type != OS_WRITE_NEW_MARK) {
- /* true unless the user wrote the filemark for us */
- result = osst_flush_drive_buffer(STp, &SRpnt);
- if (result < 0) goto out;
- result = osst_write_filemark(STp, &SRpnt);
- if (result < 0) goto out;
- if (STps->drv_file >= 0)
- STps->drv_file++ ;
- STps->drv_block = 0;
- }
- result = osst_write_eod(STp, &SRpnt);
- osst_write_header(STp, &SRpnt, !(STp->rew_at_close));
- STps->eof = ST_FM;
- #if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "osst%d:D: Buffer flushed, %d EOF(s) writtenn",
- dev, 1+STp->two_fm);
- #endif
- }
- else if (!STp->rew_at_close) {
- STps = &(STp->ps[STp->partition]);
- if (!STm->sysv || STps->rw != ST_READING) {
- if (STp->can_bsr)
- result = osst_flush_buffer(STp, &SRpnt, 0); /* this is the default path */
- else if (STps->eof == ST_FM_HIT) {
- result = cross_eof(STp, &SRpnt, FALSE);
- if (result) {
- if (STps->drv_file >= 0)
- STps->drv_file++;
- STps->drv_block = 0;
- STps->eof = ST_FM;
- }
- else
- STps->eof = ST_NOEOF;
- }
- }
- else if ((STps->eof == ST_NOEOF &&
- !(result = cross_eof(STp, &SRpnt, TRUE))) ||
- STps->eof == ST_FM_HIT) {
- if (STps->drv_file >= 0)
- STps->drv_file++;
- STps->drv_block = 0;
- STps->eof = ST_FM;
- }
- }
- out:
- if (STp->rew_at_close) {
- result2 = osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos);
- STps->drv_file = STps->drv_block = STp->frame_seq_number = STp->logical_blk_num = 0;
- if (result == 0 && result2 < 0)
- result = result2;
- }
- if (SRpnt) scsi_release_request(SRpnt);
- if (STp->recover_count) {
- printk(KERN_INFO "osst%d:I: %d recovered errors in", dev, STp->recover_count);
- if (STp->write_count)
- printk(" %d frames written", STp->write_count);
- if (STp->read_count)
- printk(" %d frames read", STp->read_count);
- printk("n");
- STp->recover_count = 0;
- }
- STp->write_count = 0;
- STp->read_count = 0;
- return result;
- }
- /* Close the device and release it */
- static int os_scsi_tape_close(struct inode * inode, struct file * filp)
- {
- int result = 0;
- OS_Scsi_Tape * STp;
- Scsi_Request * SRpnt = NULL;
- kdev_t devt = inode->i_rdev;
- int dev;
- dev = TAPE_NR(devt);
- STp = os_scsi_tapes[dev];
- if (STp->door_locked == ST_LOCKED_AUTO)
- osst_int_ioctl(STp, &SRpnt, MTUNLOCK, 0);
- if (SRpnt) scsi_release_request(SRpnt);
- if (STp->buffer != NULL)
- STp->buffer->in_use = 0;
- if (STp->raw)
- STp->header_ok = 0;
- STp->in_use = 0;
- STp->device->access_count--;
- if (STp->device->host->hostt->module)
- __MOD_DEC_USE_COUNT(STp->device->host->hostt->module);
- if(osst_template.module)
- __MOD_DEC_USE_COUNT(osst_template.module);
- return result;
- }
- /* The ioctl command */
- static int osst_ioctl(struct inode * inode,struct file * file,
- unsigned int cmd_in, unsigned long arg)
- {
- int i, cmd_nr, cmd_type, retval = 0;
- unsigned int blk;
- OS_Scsi_Tape *STp;
- ST_mode *STm;
- ST_partstat *STps;
- Scsi_Request *SRpnt = NULL;
- int dev = TAPE_NR(inode->i_rdev);
- STp = os_scsi_tapes[dev];
- if (down_interruptible(&STp->lock))
- return -ERESTARTSYS;
- #if DEBUG
- if (debugging && !STp->in_use) {
- printk(OSST_DEB_MSG "osst%d:D: Incorrect device.n", dev);
- retval = (-EIO);
- goto out;
- }
- #endif
- STm = &(STp->modes[STp->current_mode]);
- STps = &(STp->ps[STp->partition]);
- /*
- * 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(STp->device) ) {
- retval = (-ENXIO);
- goto out;
- }
- cmd_type = _IOC_TYPE(cmd_in);
- cmd_nr = _IOC_NR(cmd_in);
- #if DEBUG
- printk(OSST_DEB_MSG "osst%d:D: Ioctl %d,%d in %s moden", dev,
- cmd_type, cmd_nr, STp->raw?"raw":"normal");
- #endif
- if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) {
- struct mtop mtc;
- if (_IOC_SIZE(cmd_in) != sizeof(mtc)) {
- retval = (-EINVAL);
- goto out;
- }
- i = copy_from_user((char *) &mtc, (char *)arg, sizeof(struct mtop));
- if (i) {
- retval = (-EFAULT);
- goto out;
- }
- if (mtc.mt_op == MTSETDRVBUFFER && !capable(CAP_SYS_ADMIN)) {
- printk(KERN_WARNING "osst%d:W: MTSETDRVBUFFER only allowed for root.n", dev);
- retval = (-EPERM);
- goto out;
- }
- if (!STm->defined && (mtc.mt_op != MTSETDRVBUFFER && (mtc.mt_count & MT_ST_OPTIONS) == 0)) {
- retval = (-ENXIO);
- goto out;
- }
- if (!(STp->device)->was_reset) {
- if (STps->eof == ST_FM_HIT) {
- if (mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM|| mtc.mt_op == MTEOM) {
- mtc.mt_count -= 1;
- if (STps->drv_file >= 0)
- STps->drv_file += 1;
- }
- else if (mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM) {
- mtc.mt_count += 1;
- if (STps->drv_file >= 0)
- STps->drv_file += 1;
- }
- }
- if (mtc.mt_op == MTSEEK) {
- /* Old position must be restored if partition will be changed */
- i = !STp->can_partitions || (STp->new_partition != STp->partition);
- }
- else {
- i = mtc.mt_op == MTREW || mtc.mt_op == MTOFFL ||
- mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM ||
- mtc.mt_op == MTLOCK || mtc.mt_op == MTLOAD ||
- mtc.mt_op == MTCOMPRESSION;
- }
- i = osst_flush_buffer(STp, &SRpnt, i);
- if (i < 0) {
- retval = i;
- goto out;
- }
- }
- else {
- /*
- * If there was a bus reset, block further access
- * to this device. If the user wants to rewind the tape,
- * then reset the flag and allow access again.
- */
- if(mtc.mt_op != MTREW &&
- mtc.mt_op != MTOFFL &&
- mtc.mt_op != MTRETEN &&
- mtc.mt_op != MTERASE &&
- mtc.mt_op != MTSEEK &&
- mtc.mt_op != MTEOM) {
- retval = (-EIO);
- goto out;
- }
- STp->device->was_reset = 0;
- if (STp->door_locked != ST_UNLOCKED &&
- STp->door_locked != ST_LOCK_FAILS) {
- if (osst_int_ioctl(STp, &SRpnt, MTLOCK, 0)) {
- printk(KERN_NOTICE "osst%d:I: Could not relock door after bus reset.n",
- dev);
- STp->door_locked = ST_UNLOCKED;
- }
- }
- }
- if (mtc.mt_op != MTNOP && mtc.mt_op != MTWEOF && mtc.mt_op != MTWSM &&
- mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTSETBLK &&
- mtc.mt_op != MTSETDRVBUFFER && mtc.mt_op != MTSETPART)
- STps->rw = ST_IDLE; /* Prevent automatic WEOF and fsf */
- if (mtc.mt_op == MTOFFL && STp->door_locked != ST_UNLOCKED)
- osst_int_ioctl(STp, &SRpnt, MTUNLOCK, 0); /* Ignore result! */
- if (mtc.mt_op == MTSETDRVBUFFER &&
- (mtc.mt_count & MT_ST_OPTIONS) != 0) {
- retval = osst_set_options(STp, mtc.mt_count);
- goto out;
- }
- 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)
- return (-EIO);*/
- if (mtc.mt_count >= STp->nbr_partitions)
- retval = -EINVAL;
- else {
- STp->new_partition = mtc.mt_count;
- retval = 0;
- }
- goto out;
- }
- if (mtc.mt_op == MTMKPART) {
- if (!STp->can_partitions) {
- retval = (-EINVAL);
- goto out;
- }
- if ((i = osst_int_ioctl(STp, &SRpnt, MTREW, 0)) < 0 /*||
- (i = partition_tape(inode, mtc.mt_count)) < 0*/) {
- retval = i;
- goto out;
- }
- for (i=0; i < ST_NBR_PARTITIONS; i++) {
- STp->ps[i].rw = ST_IDLE;
- STp->ps[i].at_sm = 0;
- STp->ps[i].last_block_valid = FALSE;
- }
- STp->partition = STp->new_partition = 0;
- STp->nbr_partitions = 1; /* Bad guess ?-) */
- STps->drv_block = STps->drv_file = 0;
- retval = 0;
- goto out;
- }
- if (mtc.mt_op == MTSEEK) {
- if (STp->raw)
- i = osst_set_frame_position(STp, &SRpnt, mtc.mt_count, 0);
- else
- i = osst_seek_sector(STp, &SRpnt, mtc.mt_count);
- if (!STp->can_partitions)
- STp->ps[0].rw = ST_IDLE;
- retval = i;
- goto out;
- }
- /* if (STp->can_partitions && STp->ready == ST_READY &&
- (i = update_partition(inode)) < 0)
- {retval=i;goto out;}*/
- if (mtc.mt_op == MTCOMPRESSION)
- retval = -EINVAL /*osst_compression(STp, (mtc.mt_count & 1))*/;
- else
- retval = osst_int_ioctl(STp, &SRpnt, mtc.mt_op, mtc.mt_count);
- goto out;
- }
- if (!STm->defined) {
- retval = (-ENXIO);
- goto out;
- }
- if ((i = osst_flush_buffer(STp, &SRpnt, FALSE)) < 0) {
- retval = i;
- goto out;
- }
- /* if (STp->can_partitions &&
- (i = update_partition(inode)) < 0)
- {retval=i;goto out;}*/
- if (cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET)) {
- struct mtget mt_status;
- if (_IOC_SIZE(cmd_in) != sizeof(struct mtget)) {
- retval = (-EINVAL);
- goto out;
- }
- mt_status.mt_type = MT_ISONSTREAM_SC;
- mt_status.mt_erreg = STp->recover_erreg << MT_ST_SOFTERR_SHIFT;
- 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);
- mt_status.mt_blkno = STps->drv_block;
- mt_status.mt_fileno = STps->drv_file;
- if (STp->block_size != 0) {
- if (STps->rw == ST_WRITING)
- mt_status.mt_blkno += (STp->buffer)->buffer_bytes / STp->block_size;
- else if (STps->rw == ST_READING)
- mt_status.mt_blkno -= ((STp->buffer)->buffer_bytes +
- STp->block_size - 1) / STp->block_size;
- }
- mt_status.mt_gstat = 0;
- if (STp->drv_write_prot)
- 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
- mt_status.mt_gstat |= GMT_EOF(0xffffffff);
- }
- mt_status.mt_resid = STp->partition;
- if (STps->eof == ST_EOM_OK || STps->eof == ST_EOM_ERROR)
- mt_status.mt_gstat |= GMT_EOT(0xffffffff);
- else if (STps->eof >= ST_EOM_OK)
- mt_status.mt_gstat |= GMT_EOD(0xffffffff);
- if (STp->density == 1)
- mt_status.mt_gstat |= GMT_D_800(0xffffffff);
- else if (STp->density == 2)
- mt_status.mt_gstat |= GMT_D_1600(0xffffffff);
- else if (STp->density == 3)
- mt_status.mt_gstat |= GMT_D_6250(0xffffffff);
- if (STp->ready == ST_READY)
- mt_status.mt_gstat |= GMT_ONLINE(0xffffffff);
- if (STp->ready == ST_NO_TAPE)
- mt_status.mt_gstat |= GMT_DR_OPEN(0xffffffff);
- if (STps->at_sm)
- mt_status.mt_gstat |= GMT_SM(0xffffffff);
- if (STm->do_async_writes || (STm->do_buffer_writes && STp->block_size != 0) ||
- STp->drv_buffer != 0)
- mt_status.mt_gstat |= GMT_IM_REP_EN(0xffffffff);
- i = copy_to_user((char *)arg, (char *)&mt_status,
- sizeof(struct mtget));
- if (i) {
- retval = (-EFAULT);
- goto out;
- }
- STp->recover_erreg = 0; /* Clear after read */
- retval = 0;
- goto out;
- } /* 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)) {
- retval = (-EINVAL);
- goto out;
- }
- if (STp->raw)
- blk = osst_get_frame_position(STp, &SRpnt);
- else
- blk = osst_get_sector(STp, &SRpnt);
- if (blk < 0) {
- retval = blk;
- goto out;
- }
- mt_pos.mt_blkno = blk;
- i = copy_to_user((char *)arg, (char *) (&mt_pos), sizeof(struct mtpos));
- if (i)
- retval = -EFAULT;
- goto out;
- }
- if (SRpnt) scsi_release_request(SRpnt);
- up(&STp->lock);
- return scsi_ioctl(STp->device, cmd_in, (void *) arg);
- out:
- if (SRpnt) scsi_release_request(SRpnt);
- up(&STp->lock);
- return retval;
- }
- /* Memory handling routines */
- /* Try to allocate a new tape buffer */
- static OSST_buffer * new_tape_buffer( int from_initialization, int need_dma )
- {
- int i, priority, b_size, order, got = 0, segs = 0;
- OSST_buffer *tb;
- if (osst_nbr_buffers >= osst_template.dev_max)
- return NULL; /* Should never happen */
- if (from_initialization)
- priority = GFP_ATOMIC;
- else
- priority = GFP_KERNEL;
- i = sizeof(OSST_buffer) + (osst_max_sg_segs - 1) * sizeof(struct scatterlist);
- tb = (OSST_buffer *)kmalloc(i, priority);
- if (tb) {
- // tb->this_size = i;
- if (need_dma)
- priority |= GFP_DMA;
- /* Try to allocate the first segment up to OSST_FIRST_ORDER and the
- others big enough to reach the goal */
- for (b_size = PAGE_SIZE, order = 0;
- b_size < osst_buffer_size && order < OSST_FIRST_ORDER;
- b_size *= 2, order++ );
- for ( ; b_size >= PAGE_SIZE; order--, b_size /= 2) {
- tb->sg[0].address =
- (unsigned char *)__get_free_pages(priority, order);
- if (tb->sg[0].address != NULL) {
- tb->sg[0].page = NULL;
- tb->sg[0].length = b_size;
- break;
- }
- }
- if (tb->sg[segs].address == NULL) {
- kfree(tb);
- tb = NULL;
- }
- else { /* Got something, continue */
- for (b_size = PAGE_SIZE, order = 0;
- osst_buffer_size > tb->sg[0].length + (OSST_FIRST_SG - 1) * b_size;
- b_size *= 2, order++ );
- for (segs=1, got=tb->sg[0].length;
- got < osst_buffer_size && segs < OSST_FIRST_SG; ) {
- tb->sg[segs].address =
- (unsigned char *)__get_free_pages(priority, order);
- if (tb->sg[segs].address == NULL) {
- if (osst_buffer_size - got <=
- (OSST_FIRST_SG - segs) * b_size / 2) {
- b_size /= 2; /* Large enough for the rest of the buffers */
- order--;
- continue;
- }
- tb->sg_segs = segs;
- tb->orig_sg_segs = 0;
- #if DEBUG
- tb->buffer_size = got;
- #endif
- normalize_buffer(tb);
- kfree(tb);
- tb = NULL;
- break;
- }
- tb->sg[segs].page = NULL;
- tb->sg[segs].length = b_size;
- got += b_size;
- segs++;
- }
- }
- }
- if (!tb) {
- printk(KERN_NOTICE "osst :I: Can't allocate new tape buffer (nbr %d).n",
- osst_nbr_buffers);
- return NULL;
- }
- tb->sg_segs = tb->orig_sg_segs = segs;
- tb->b_data = tb->sg[0].address;
- #if DEBUG
- if (debugging) {
- printk(OSST_DEB_MSG
- "osst :D: Allocated tape buffer %d (%d bytes, %d segments, dma: %d, a: %p).n",
- osst_nbr_buffers, got, tb->sg_segs, need_dma, tb->b_data);
- printk(OSST_DEB_MSG
- "osst :D: segment sizes: first %d, last %d bytes.n",
- tb->sg[0].length, tb->sg[segs-1].length);
- }
- #endif
- tb->in_use = 0;
- tb->dma = need_dma;
- tb->buffer_size = got;
- tb->writing = 0;
- osst_buffers[osst_nbr_buffers++] = tb;
- return tb;
- }
- /* Try to allocate a temporary enlarged tape buffer */
- static int enlarge_buffer(OSST_buffer *STbuffer, int new_size, int need_dma)
- {
- int segs, nbr, max_segs, b_size, priority, order, got;
- normalize_buffer(STbuffer);
- max_segs = STbuffer->use_sg;
- if (max_segs > osst_max_sg_segs)
- max_segs = osst_max_sg_segs;
- nbr = max_segs - STbuffer->sg_segs;
- if (nbr <= 0)
- return FALSE;
- priority = GFP_KERNEL;
- if (need_dma)
- priority |= GFP_DMA;
- for (b_size = PAGE_SIZE, order = 0;
- b_size * nbr < new_size - STbuffer->buffer_size;
- b_size *= 2, order++);
- for (segs=STbuffer->sg_segs, got=STbuffer->buffer_size;
- segs < max_segs && got < new_size; ) {
- STbuffer->sg[segs].address =
- (unsigned char *)__get_free_pages(priority, order);
- if (STbuffer->sg[segs].address == NULL) {
- if (new_size - got <= (max_segs - segs) * b_size / 2) {
- b_size /= 2; /* Large enough for the rest of the buffers */
- order--;
- continue;
- }
- printk(KERN_WARNING "osst :W: Failed to enlarge buffer to %d bytes.n",
- new_size);
- #if DEBUG
- STbuffer->buffer_size = got;
- #endif
- normalize_buffer(STbuffer);
- return FALSE;
- }
- STbuffer->sg[segs].page = NULL;
- STbuffer->sg[segs].length = b_size;
- STbuffer->sg_segs += 1;
- got += b_size;
- STbuffer->buffer_size = got;
- segs++;
- }
- #if DEBUG
- if (debugging) {
- for (nbr=0; osst_buffers[nbr] != STbuffer && nbr < osst_nbr_buffers; nbr++);
- printk(OSST_DEB_MSG
- "osst :D: Expanded tape buffer %d (%d bytes, %d->%d segments, dma: %d, a: %p).n",
- nbr, got, STbuffer->orig_sg_segs, STbuffer->sg_segs, need_dma, STbuffer->b_data);
- printk(OSST_DEB_MSG
- "osst :D: segment sizes: first %d, last %d bytes.n",
- STbuffer->sg[0].length, STbuffer->sg[segs-1].length);
- }
- #endif
- return TRUE;
- }
- /* Release the extra buffer */
- static void normalize_buffer(OSST_buffer *STbuffer)
- {
- int i, order, b_size;
- for (i=STbuffer->orig_sg_segs; i < STbuffer->sg_segs; i++) {
- for (b_size = PAGE_SIZE, order = 0;
- b_size < STbuffer->sg[i].length;
- b_size *= 2, order++);
- free_pages((unsigned long)STbuffer->sg[i].address, order);
- STbuffer->buffer_size -= STbuffer->sg[i].length;
- }
- #if DEBUG
- if (debugging && STbuffer->orig_sg_segs < STbuffer->sg_segs)
- printk(OSST_DEB_MSG "osst :D: Buffer at %p normalized to %d bytes (segs %d).n",
- STbuffer->b_data, STbuffer->buffer_size, STbuffer->sg_segs);
- #endif
- STbuffer->sg_segs = STbuffer->orig_sg_segs;
- }
- /* Move data from the user buffer to the tape buffer. Returns zero (success) or
- negative error code. */
- static int append_to_buffer(const char *ubp, OSST_buffer *st_bp, int do_count)
- {
- int i, cnt, res, offset;
- for (i=0, offset=st_bp->buffer_bytes;
- i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
- offset -= st_bp->sg[i].length;
- if (i == st_bp->sg_segs) { /* Should never happen */
- printk(KERN_WARNING "osst :A: Append_to_buffer offset overflow.n");
- return (-EIO);
- }
- for ( ; i < st_bp->sg_segs && do_count > 0; i++) {
- cnt = st_bp->sg[i].length - offset < do_count ?
- st_bp->sg[i].length - offset : do_count;
- res = copy_from_user(st_bp->sg[i].address + offset, ubp, cnt);
- if (res)
- return (-EFAULT);
- do_count -= cnt;
- st_bp->buffer_bytes += cnt;
- ubp += cnt;
- offset = 0;
- }
- if (do_count) { /* Should never happen */
- printk(KERN_WARNING "osst :A: Append_to_buffer overflow (left %d).n",
- do_count);
- return (-EIO);
- }
- return 0;
- }
- /* Move data from the tape buffer to the user buffer. Returns zero (success) or
- negative error code. */
- static int from_buffer(OSST_buffer *st_bp, char *ubp, int do_count)
- {
- int i, cnt, res, offset;
- for (i=0, offset=st_bp->read_pointer;
- i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
- offset -= st_bp->sg[i].length;
- if (i == st_bp->sg_segs) { /* Should never happen */
- printk(KERN_WARNING "osst :A: From_buffer offset overflow.n");
- return (-EIO);
- }
- for ( ; i < st_bp->sg_segs && do_count > 0; i++) {
- cnt = st_bp->sg[i].length - offset < do_count ?
- st_bp->sg[i].length - offset : do_count;
- res = copy_to_user(ubp, st_bp->sg[i].address + offset, cnt);
- if (res)
- return (-EFAULT);
- do_count -= cnt;
- st_bp->buffer_bytes -= cnt;
- st_bp->read_pointer += cnt;
- ubp += cnt;
- offset = 0;
- }
- if (do_count) { /* Should never happen */
- printk(KERN_WARNING "osst :A: From_buffer overflow (left %d).n", do_count);
- return (-EIO);
- }
- return 0;
- }
- /* Sets the tail of the buffer after fill point to zero.
- Returns zero (success) or negative error code. */
- static int osst_zero_buffer_tail(OSST_buffer *st_bp)
- {
- int i, offset, do_count, cnt;
- for (i = 0, offset = st_bp->buffer_bytes;
- i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
- offset -= st_bp->sg[i].length;
- if (i == st_bp->sg_segs) { /* Should never happen */
- printk(KERN_WARNING "osst :A: Zero_buffer offset overflow.n");
- return (-EIO);
- }
- for (do_count = OS_DATA_SIZE - st_bp->buffer_bytes;
- i < st_bp->sg_segs && do_count > 0; i++) {
- cnt = st_bp->sg[i].length - offset < do_count ?
- st_bp->sg[i].length - offset : do_count ;
- memset(st_bp->sg[i].address + offset, 0, cnt);
- do_count -= cnt;
- offset = 0;
- }
- if (do_count) { /* Should never happen */
- printk(KERN_WARNING "osst :A: Zero_buffer overflow (left %d).n", do_count);
- return (-EIO);
- }
- return 0;
- }
- /* Copy a osst 32K chunk of memory into the buffer.
- Returns zero (success) or negative error code. */
- static int osst_copy_to_buffer(OSST_buffer *st_bp, unsigned char *ptr)
- {
- int i, cnt, do_count = OS_DATA_SIZE;
- for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) {
- cnt = st_bp->sg[i].length < do_count ?
- st_bp->sg[i].length : do_count ;
- memcpy(st_bp->sg[i].address, ptr, cnt);
- do_count -= cnt;
- ptr += cnt;
- }
- if (do_count || i != st_bp->sg_segs-1) { /* Should never happen */
- printk(KERN_WARNING "osst :A: Copy_to_buffer overflow (left %d at sg %d).n",
- do_count, i);
- return (-EIO);
- }
- return 0;
- }
- /* Copy a osst 32K chunk of memory from the buffer.
- Returns zero (success) or negative error code. */
- static int osst_copy_from_buffer(OSST_buffer *st_bp, unsigned char *ptr)
- {
- int i, cnt, do_count = OS_DATA_SIZE;
- for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) {
- cnt = st_bp->sg[i].length < do_count ?
- st_bp->sg[i].length : do_count ;
- memcpy(ptr, st_bp->sg[i].address, cnt);
- do_count -= cnt;
- ptr += cnt;
- }
- if (do_count || i != st_bp->sg_segs-1) { /* Should never happen */
- printk(KERN_WARNING "osst :A: Copy_from_buffer overflow (left %d at sg %d).n",
- do_count, i);
- return (-EIO);
- }
- return 0;
- }
- /* Module housekeeping */
- static void validate_options (void)
- {
- if (buffer_kbs > 0)
- osst_buffer_size = buffer_kbs * ST_KILOBYTE;
- if (write_threshold_kbs > 0)
- osst_write_threshold = write_threshold_kbs * ST_KILOBYTE;
- if (osst_write_threshold > osst_buffer_size)
- osst_write_threshold = osst_buffer_size;
- if (max_buffers > 0)
- osst_max_buffers = max_buffers;
- if (max_sg_segs >= OSST_FIRST_SG)
- osst_max_sg_segs = max_sg_segs;
- #if DEBUG
- printk(OSST_DEB_MSG "osst :D: bufsize %d, wrt %d, max buffers %d, s/g segs %d.n",
- osst_buffer_size, osst_write_threshold, osst_max_buffers, osst_max_sg_segs);
- //printk(OSST_DEB_MSG "osst :D: sizeof(header) = %d (%s)n",
- // sizeof(os_header_t),sizeof(os_header_t)==OS_DATA_SIZE?"ok":"error");
- #endif
- }
-
- #ifndef MODULE
- /* Set the boot options. Syntax: osst=xxx,yyy,...
- where xxx is buffer size in 1024 byte blocks and yyy is write threshold
- in 1024 byte blocks. */
- static int __init osst_setup (char *str)
- {
- int i, ints[5];
- char *stp;
- stp = get_options(str, ARRAY_SIZE(ints), ints);
-
- if (ints[0] > 0) {
- for (i = 0; i < ints[0] && i < ARRAY_SIZE(parms); i++)
- *parms[i].val = ints[i + 1];
- } else {
- while (stp != NULL) {
- for (i = 0; i < ARRAY_SIZE(parms); i++) {
- int len = strlen(parms[i].name);
- if (!strncmp(stp, parms[i].name, len) &&
- (*(stp + len) == ':' || *(stp + len) == '=')) {
- *parms[i].val =
- simple_strtoul(stp + len + 1, NULL, 0);
- break;
- }
- }
- if (i >= sizeof(parms) / sizeof(struct osst_dev_parm))
- printk(KERN_INFO "osst :I: Illegal parameter in '%s'n",
- stp);
- stp = strchr(stp, ',');
- if (stp)
- stp++;
- }
- }
- return 1;
- }
- __setup("osst=", osst_setup);
- #endif
- static struct file_operations osst_fops = {
- read: osst_read,
- write: osst_write,
- ioctl: osst_ioctl,
- open: os_scsi_tape_open,
- flush: os_scsi_tape_flush,
- release: os_scsi_tape_close,
- };
- static int osst_supports(Scsi_Device * SDp)
- {
- struct osst_support_data {
- char *vendor;
- char *model;
- char *rev;
- char *driver_hint; /* Name of the correct driver, NULL if unknown */
- };
- static struct osst_support_data support_list[] = {
- /* {"XXX", "Yy-", "", NULL}, example */
- SIGS_FROM_OSST,
- {NULL, }};
- struct osst_support_data *rp;
- /* We are willing to drive OnStream SC-x0 as well as the
- * * IDE, ParPort, FireWire, USB variants, if accessible by
- * * emulation layer (ide-scsi, usb-storage, ...) */
- for (rp=&(support_list[0]); rp->vendor != NULL; rp++)
- if (!strncmp(rp->vendor, SDp->vendor, strlen(rp->vendor)) &&
- !strncmp(rp->model, SDp->model, strlen(rp->model)) &&
- !strncmp(rp->rev, SDp->rev, strlen(rp->rev)))
- return 1;
- return 0;
- }
- static int osst_attach(Scsi_Device * SDp)
- {
- OS_Scsi_Tape * tpnt;
- ST_mode * STm;
- ST_partstat * STps;
- int i, dev;
- #ifdef CONFIG_DEVFS_FS
- int mode;
- #endif
- if (SDp->type != TYPE_TAPE || !osst_supports(SDp))
- return 1;
- if (osst_template.nr_dev >= osst_template.dev_max) {
- SDp->attached--;
- return 1;
- }
-
- /* find a free minor number */
- for (i=0; os_scsi_tapes[i] && i<osst_template.dev_max; i++);
- if(i >= osst_template.dev_max) panic ("Scsi_devices corrupt (osst)");
- /* allocate a OS_Scsi_Tape for this device */
- tpnt = (OS_Scsi_Tape *)kmalloc(sizeof(OS_Scsi_Tape), GFP_ATOMIC);
- if (tpnt == NULL) {
- SDp->attached--;
- printk(KERN_WARNING "osst :W: Can't allocate device descriptor.n");
- return 1;
- }
- memset(tpnt, 0, sizeof(OS_Scsi_Tape));
- os_scsi_tapes[i] = tpnt;
- dev = i;
- tpnt->capacity = 0xfffff;
- /* allocate a buffer for this device */
- if (!new_tape_buffer(TRUE, TRUE))
- printk(KERN_ERR "osst :W: Unable to allocate a tape buffer.n");
- #ifdef CONFIG_DEVFS_FS
- for (mode = 0; mode < ST_NBR_MODES; ++mode) {
- char name[8];
- static char *formats[ST_NBR_MODES] ={"", "l", "m", "a"};
- /* Rewind entry */
- sprintf (name, "mt%s", formats[mode]);
- # if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- tpnt->de_r[mode] =
- devfs_register (SDp->de, name, DEVFS_FL_DEFAULT,
- MAJOR_NR, i + (mode << 5),
- S_IFCHR | S_IRUGO | S_IWUGO,
- &osst_fops, NULL);
- # else
- tpnt->de_r[mode] =
- devfs_register (SDp->de, name, 0, DEVFS_FL_DEFAULT,
- MAJOR_NR, i + (mode << 5),
- S_IFCHR | S_IRUGO | S_IWUGO,
- 0, 0, &osst_fops, NULL);
- # endif
- /* No-rewind entry */
- sprintf (name, "mt%sn", formats[mode]);
- # if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- tpnt->de_n[mode] =
- devfs_register (SDp->de, name, DEVFS_FL_DEFAULT,
- MAJOR_NR, i + (mode << 5) + 128,
- S_IFCHR | S_IRUGO | S_IWUGO,
- &osst_fops, NULL);
- # else
- tpnt->de_n[mode] =
- devfs_register (SDp->de, name, 0, DEVFS_FL_DEFAULT,
- MAJOR_NR, i + (mode << 5) + 128,
- S_IFCHR | S_IRUGO | S_IWUGO,
- 0, 0, &osst_fops, NULL);
- # endif
- }
- devfs_register_tape (tpnt->de_r[0]);
- #endif
- tpnt->device = SDp;
- tpnt->devt = MKDEV(MAJOR_NR, i);
- tpnt->dirty = 0;
- tpnt->in_use = 0;
- tpnt->drv_buffer = 1; /* Try buffering if no mode sense */
- tpnt->restr_dma = (SDp->host)->unchecked_isa_dma;
- tpnt->density = 0;
- tpnt->do_auto_lock = OSST_AUTO_LOCK;
- tpnt->can_bsr = OSST_IN_FILE_POS;
- tpnt->can_partitions = 0;
- tpnt->two_fm = OSST_TWO_FM;
- tpnt->fast_mteom = OSST_FAST_MTEOM;
- tpnt->scsi2_logical = OSST_SCSI2LOGICAL; /* FIXME */
- tpnt->write_threshold = osst_write_threshold;
- tpnt->default_drvbuffer = 0xff; /* No forced buffering */
- tpnt->partition = 0;
- tpnt->new_partition = 0;
- tpnt->nbr_partitions = 0;
- tpnt->min_block = 512;
- tpnt->max_block = OS_DATA_SIZE;
- tpnt->timeout = OSST_TIMEOUT;
- tpnt->long_timeout = OSST_LONG_TIMEOUT;
- /* Recognize OnStream tapes */
- /* We don't need to test for OnStream, as this has been done in detect () */
- tpnt->os_fw_rev = osst_parse_firmware_rev (SDp->rev);
- tpnt->omit_blklims = 1;
- tpnt->poll = (strncmp(SDp->model, "DI-", 3) == 0) || OSST_FW_NEED_POLL(tpnt->os_fw_rev,SDp);
- tpnt->frame_in_buffer = 0;
- tpnt->header_ok = 0;
- tpnt->linux_media = 0;
- tpnt->header_cache = NULL;
- for (i=0; i < ST_NBR_MODES; i++) {
- STm = &(tpnt->modes[i]);
- STm->defined = FALSE;
- STm->sysv = OSST_SYSV;
- STm->defaults_for_writes = 0;
- STm->do_async_writes = OSST_ASYNC_WRITES;
- STm->do_buffer_writes = OSST_BUFFER_WRITES;
- STm->do_read_ahead = OSST_READ_AHEAD;
- STm->default_compression = ST_DONT_TOUCH;
- STm->default_blksize = 512;
- STm->default_density = (-1); /* No forced density */
- }
- for (i=0; i < ST_NBR_PARTITIONS; i++) {
- STps = &(tpnt->ps[i]);
- STps->rw = ST_IDLE;
- STps->eof = ST_NOEOF;
- STps->at_sm = 0;
- STps->last_block_valid = FALSE;
- STps->drv_block = (-1);
- STps->drv_file = (-1);
- }
- tpnt->current_mode = 0;
- tpnt->modes[0].defined = TRUE;
- tpnt->modes[2].defined = TRUE;
- tpnt->density_changed = tpnt->compression_changed = tpnt->blksize_changed = FALSE;
- init_MUTEX(&tpnt->lock);
- osst_template.nr_dev++;
- printk(KERN_INFO
- "osst :I: Attached OnStream %.5s tape at scsi%d, channel %d, id %d, lun %d as osst%dn",
- SDp->model, SDp->host->host_no, SDp->channel, SDp->id, SDp->lun, dev);
- return 0;
- };
- static int osst_detect(Scsi_Device * SDp)
- {
- if (SDp->type != TYPE_TAPE) return 0;
- if ( ! osst_supports(SDp) ) return 0;
-
- osst_template.dev_noticed++;
- return 1;
- }
- static int osst_registered = 0;
- /* Driver initialization (not __initfunc because may be called later) */
- static int osst_init()
- {
- int i;
- if (osst_template.dev_noticed == 0) return 0;
- if(!osst_registered) {
- #ifdef CONFIG_DEVFS_FS
- if (devfs_register_chrdev(MAJOR_NR,"osst",&osst_fops)) {
- #else
- if (register_chrdev(MAJOR_NR,"osst",&osst_fops)) {
- #endif
- printk(KERN_ERR "osst :W: Unable to get major %d for OnStream tapesn",MAJOR_NR);
- return 1;
- }
- osst_registered++;
- }
-
- if (os_scsi_tapes) return 0;
- osst_template.dev_max = OSST_MAX_TAPES;
- if (osst_template.dev_max > 128 / ST_NBR_MODES)
- printk(KERN_INFO "osst :I: Only %d tapes accessible.n", 128 / ST_NBR_MODES);
- os_scsi_tapes =
- (OS_Scsi_Tape **)kmalloc(osst_template.dev_max * sizeof(OS_Scsi_Tape *),
- GFP_ATOMIC);
- if (os_scsi_tapes == NULL) {
- printk(KERN_ERR "osst :W: Unable to allocate array for OnStream SCSI tapes.n");
- #ifdef CONFIG_DEVFS_FS
- devfs_unregister_chrdev(MAJOR_NR, "osst");
- #else
- unregister_chrdev(MAJOR_NR, "osst");
- #endif
- return 1;
- }
- for (i=0; i < osst_template.dev_max; ++i) os_scsi_tapes[i] = NULL;
- /* Allocate the buffer pointers */
- osst_buffers =
- (OSST_buffer **)kmalloc(osst_template.dev_max * sizeof(OSST_buffer *),
- GFP_ATOMIC);
- if (osst_buffers == NULL) {
- printk(KERN_ERR "osst :W: Unable to allocate tape buffer pointers.n");
- #ifdef CONFIG_DEVFS_FS
- devfs_unregister_chrdev(MAJOR_NR, "osst");
- #else
- unregister_chrdev(MAJOR_NR, "osst");
- #endif
- kfree(os_scsi_tapes);
- return 1;
- }
- osst_nbr_buffers = 0;
- printk(KERN_INFO "osst :I: Tape driver with OnStream support version %snosst :I: %sn", osst_version, cvsid);
- #if DEBUG
- printk(OSST_DEB_MSG "osst :D: Buffer size %d bytes, write threshold %d bytes.n",
- osst_buffer_size, osst_write_threshold);
- #endif
- return 0;
- }
- static void osst_detach(Scsi_Device * SDp)
- {
- OS_Scsi_Tape * tpnt;
- int i;
- #ifdef CONFIG_DEVFS_FS
- int mode;
- #endif
- for(i=0; i<osst_template.dev_max; i++) {
- tpnt = os_scsi_tapes[i];
- if(tpnt != NULL && tpnt->device == SDp) {
- tpnt->device = NULL;
- #ifdef CONFIG_DEVFS_FS
- for (mode = 0; mode < ST_NBR_MODES; ++mode) {
- devfs_unregister (tpnt->de_r[mode]);
- tpnt->de_r[mode] = NULL;
- devfs_unregister (tpnt->de_n[mode]);
- tpnt->de_n[mode] = NULL;
- }
- #endif
- kfree(tpnt);
- os_scsi_tapes[i] = NULL;
- SDp->attached--;
- osst_template.nr_dev--;
- osst_template.dev_noticed--;
- return;
- }
- }
- return;
- }
- static int __init init_osst(void)
- {
- validate_options();
- osst_template.module = THIS_MODULE;
- return scsi_register_module(MODULE_SCSI_DEV, &osst_template);
- }
- static void __exit exit_osst (void)
- {
- int i;
- OS_Scsi_Tape * STp;
- scsi_unregister_module(MODULE_SCSI_DEV, &osst_template);
- #ifdef CONFIG_DEVFS_FS
- devfs_unregister_chrdev(MAJOR_NR, "osst");
- #else
- unregister_chrdev(MAJOR_NR, "osst");
- #endif
- osst_registered--;
- if(os_scsi_tapes != NULL) {
- for (i=0; i < osst_template.dev_max; ++i) {
- if ((STp = os_scsi_tapes[i])) {
- if (STp->header_cache != NULL) vfree(STp->header_cache);
- kfree(STp);
- }
- }
- kfree(os_scsi_tapes);
- if (osst_buffers != NULL) {
- for (i=0; i < osst_nbr_buffers; i++)
- if (osst_buffers[i] != NULL) {
- osst_buffers[i]->orig_sg_segs = 0;
- normalize_buffer(osst_buffers[i]);
- kfree(osst_buffers[i]);
- }
- kfree(osst_buffers);
- }
- }
- osst_template.dev_max = 0;
- printk(KERN_INFO "osst :I: Unloaded.n");
- }
- module_init(init_osst);
- module_exit(exit_osst);