?? st.c
字號:
transfer = (STp->buffer)->buffer_bytes < count - total ?
(STp->buffer)->buffer_bytes : count - total;
memcpy_tofs(buf, (STp->buffer)->b_data +
(STp->buffer)->read_pointer,transfer);
filp->f_pos += transfer;
buf += transfer;
total += transfer;
(STp->buffer)->buffer_bytes -= transfer;
(STp->buffer)->read_pointer += transfer;
}
else if (STp->eof != ST_NOEOF) {
STp->eof_hit = 1;
SCpnt->request.dev = -1; /* Mark as not busy */
if (total == 0 && STp->eof == ST_FM)
STp->eof = 0;
if (total == 0 && STp->eof == ST_EOM_OK)
return (-EIO); /* ST_EOM_ERROR not used in read */
return total;
}
if (STp->block_size == 0)
count = total; /* Read only one variable length block */
} /* for (total = 0; total < count; ) */
SCpnt->request.dev = -1; /* Mark as not busy */
return total;
}
/* Internal ioctl function */
static int
st_int_ioctl(struct inode * inode,struct file * file,
unsigned int cmd_in, unsigned long arg)
{
int dev = MINOR(inode->i_rdev);
int timeout = ST_LONG_TIMEOUT;
long ltmp;
int ioctl_result;
unsigned char cmd[10];
Scsi_Cmnd * SCpnt;
Scsi_Tape * STp;
dev = dev & 127;
STp = &(scsi_tapes[dev]);
memset(cmd, 0, 10);
switch (cmd_in) {
case MTFSF:
case MTFSFM:
cmd[0] = SPACE;
cmd[1] = 0x01; /* Space FileMarks */
cmd[2] = (arg >> 16);
cmd[3] = (arg >> 8);
cmd[4] = arg;
#ifdef DEBUG
printk("st%d: Spacing tape forward over %d filemarks.\n", dev,
cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
#endif
break;
case MTBSF:
case MTBSFM:
cmd[0] = SPACE;
cmd[1] = 0x01; /* Space FileMarks */
ltmp = (-arg);
cmd[2] = (ltmp >> 16);
cmd[3] = (ltmp >> 8);
cmd[4] = ltmp;
#ifdef DEBUG
if (cmd[2] & 0x80)
ltmp = 0xff000000;
ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
printk("st%d: Spacing tape backward over %d filemarks.\n", dev, (-ltmp));
#endif
break;
case MTFSR:
cmd[0] = SPACE;
cmd[1] = 0x00; /* Space Blocks */
cmd[2] = (arg >> 16);
cmd[3] = (arg >> 8);
cmd[4] = arg;
#ifdef DEBUG
printk("st%d: Spacing tape forward %d blocks.\n", dev,
cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
#endif
break;
case MTBSR:
cmd[0] = SPACE;
cmd[1] = 0x00; /* Space Blocks */
ltmp = (-arg);
cmd[2] = (ltmp >> 16);
cmd[3] = (ltmp >> 8);
cmd[4] = ltmp;
#ifdef DEBUG
if (cmd[2] & 0x80)
ltmp = 0xff000000;
ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
printk("st%d: Spacing tape backward %d blocks.\n", dev, (-ltmp));
#endif
break;
case MTWEOF:
if (STp->write_prot)
return (-EACCES);
cmd[0] = WRITE_FILEMARKS;
cmd[2] = (arg >> 16);
cmd[3] = (arg >> 8);
cmd[4] = arg;
timeout = ST_TIMEOUT;
#ifdef DEBUG
printk("st%d: Writing %d filemarks.\n", dev,
cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
#endif
break;
case MTREW:
cmd[0] = REZERO_UNIT;
#ifdef ST_NOWAIT
cmd[1] = 1; /* Don't wait for completion */
timeout = ST_TIMEOUT;
#endif
#ifdef DEBUG
printk("st%d: Rewinding tape.\n", dev);
#endif
break;
case MTOFFL:
cmd[0] = START_STOP;
#ifdef ST_NOWAIT
cmd[1] = 1; /* Don't wait for completion */
timeout = ST_TIMEOUT;
#endif
#ifdef DEBUG
printk("st%d: Unloading tape.\n", dev);
#endif
break;
case MTNOP:
#ifdef DEBUG
printk("st%d: No op on tape.\n", dev);
#endif
return 0; /* Should do something ? */
break;
case MTRETEN:
cmd[0] = START_STOP;
#ifdef ST_NOWAIT
cmd[1] = 1; /* Don't wait for completion */
timeout = ST_TIMEOUT;
#endif
cmd[4] = 3;
#ifdef DEBUG
printk("st%d: Retensioning tape.\n", dev);
#endif
break;
case MTEOM:
cmd[0] = SPACE;
cmd[1] = 3;
#ifdef DEBUG
printk("st%d: Spacing to end of recorded medium.\n", dev);
#endif
break;
case MTERASE:
if (STp->write_prot)
return (-EACCES);
cmd[0] = ERASE;
cmd[1] = 1; /* To the end of tape */
#ifdef DEBUG
printk("st%d: Erasing tape.\n", dev);
#endif
break;
case MTSEEK:
if ((STp->device)->scsi_level < SCSI_2) {
cmd[0] = QFA_SEEK_BLOCK;
cmd[2] = (arg >> 16);
cmd[3] = (arg >> 8);
cmd[4] = arg;
cmd[5] = 0;
}
else {
cmd[0] = SEEK_10;
cmd[1] = 4;
cmd[3] = (arg >> 24);
cmd[4] = (arg >> 16);
cmd[5] = (arg >> 8);
cmd[6] = arg;
}
#ifdef ST_NOWAIT
cmd[1] |= 1; /* Don't wait for completion */
timeout = ST_TIMEOUT;
#endif
#ifdef DEBUG
printk("st%d: Seeking tape to block %d.\n", dev, arg);
#endif
break;
case MTSETBLK: /* Set block length */
case MTSETDENSITY: /* Set tape density */
case MTSETDRVBUFFER: /* Set drive buffering */
if (STp->dirty || (STp->buffer)->buffer_bytes != 0)
return (-EIO); /* Not allowed if data in buffer */
if (cmd_in == MTSETBLK &&
arg != 0 &&
(arg < STp->min_block || arg > STp->max_block ||
arg > ST_BUFFER_SIZE)) {
printk("st%d: Illegal block size.\n", dev);
return (-EINVAL);
}
cmd[0] = MODE_SELECT;
cmd[4] = 12;
memset((STp->buffer)->b_data, 0, 12);
if (cmd_in == MTSETDRVBUFFER)
(STp->buffer)->b_data[2] = (arg & 7) << 4;
else
(STp->buffer)->b_data[2] =
STp->drv_buffer << 4;
(STp->buffer)->b_data[3] = 8; /* block descriptor length */
if (cmd_in == MTSETDENSITY)
(STp->buffer)->b_data[4] = arg;
else
(STp->buffer)->b_data[4] = STp->density;
if (cmd_in == MTSETBLK)
ltmp = arg;
else
ltmp = STp->block_size;
(STp->buffer)->b_data[9] = (ltmp >> 16);
(STp->buffer)->b_data[10] = (ltmp >> 8);
(STp->buffer)->b_data[11] = ltmp;
timeout = ST_TIMEOUT;
#ifdef DEBUG
if (cmd_in == MTSETBLK)
printk("st%d: Setting block size to %d bytes.\n", dev,
(STp->buffer)->b_data[9] * 65536 +
(STp->buffer)->b_data[10] * 256 +
(STp->buffer)->b_data[11]);
else if (cmd_in == MTSETDENSITY)
printk("st%d: Setting density code to %x.\n", dev,
(STp->buffer)->b_data[4]);
else
printk("st%d: Setting drive buffer code to %d.\n", dev,
((STp->buffer)->b_data[2] >> 4) & 7);
#endif
break;
default:
printk("st%d: Unknown st_ioctl command %x.\n", dev, cmd_in);
return (-ENOSYS);
}
SCpnt = allocate_device(NULL, (STp->device)->index, 1);
SCpnt->sense_buffer[0] = 0;
SCpnt->request.dev = dev;
scsi_do_cmd(SCpnt,
(void *) cmd, (void *) (STp->buffer)->b_data, ST_BLOCK_SIZE,
st_sleep_done, timeout, MAX_RETRIES);
if (SCpnt->request.dev == dev) sleep_on( &(STp->waiting) );
ioctl_result = (STp->buffer)->last_result_fatal;
SCpnt->request.dev = -1; /* Mark as not busy */
if (!ioctl_result) {
if (cmd_in == MTBSFM)
ioctl_result = st_int_ioctl(inode, file, MTFSF, 1);
else if (cmd_in == MTFSFM)
ioctl_result = st_int_ioctl(inode, file, MTBSF, 1);
else if (cmd_in == MTSETBLK) {
STp->block_size = arg;
if (arg != 0) {
(STp->buffer)->buffer_blocks =
ST_BUFFER_SIZE / STp->block_size;
(STp->buffer)->buffer_size =
(STp->buffer)->buffer_blocks * STp->block_size;
}
else {
(STp->buffer)->buffer_blocks = 1;
(STp->buffer)->buffer_size = ST_BUFFER_SIZE;
}
(STp->buffer)->buffer_bytes =
(STp->buffer)->read_pointer = 0;
}
else if (cmd_in == MTSETDRVBUFFER)
STp->drv_buffer = arg;
else if (cmd_in == MTSETDENSITY)
STp->density = arg;
if (cmd_in == MTEOM || cmd_in == MTWEOF) {
STp->eof = ST_EOM_OK;
STp->eof_hit = 0;
}
else if (cmd_in != MTSETBLK && cmd_in != MTNOP) {
STp->eof = ST_NOEOF;
STp->eof_hit = 0;
}
}
return ioctl_result ;
}
/* The ioctl command */
static int
st_ioctl(struct inode * inode,struct file * file,
unsigned int cmd_in, unsigned long arg)
{
int dev = MINOR(inode->i_rdev);
int i, cmd, result;
struct mtop mtc;
struct mtpos mt_pos;
unsigned char scmd[10];
Scsi_Cmnd *SCpnt;
Scsi_Tape *STp;
dev = dev & 127;
STp = &(scsi_tapes[dev]);
#ifdef DEBUG
if (!STp->in_use) {
printk("st%d: Incorrect device.\n", dev);
return (-EIO);
}
#endif
cmd = cmd_in & IOCCMD_MASK;
if (cmd == (MTIOCTOP & IOCCMD_MASK)) {
if (((cmd_in & IOCSIZE_MASK) >> IOCSIZE_SHIFT) != sizeof(mtc))
return (-EINVAL);
i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(mtc));
if (i)
return i;
memcpy_fromfs((char *) &mtc, (char *)arg, sizeof(struct mtop));
i = flush_buffer(inode, file, mtc.mt_op == MTSEEK ||
mtc.mt_op == MTREW || mtc.mt_op == MTOFFL ||
mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM);
if (i < 0)
return i;
return st_int_ioctl(inode, file, mtc.mt_op, mtc.mt_count);
}
else if (cmd == (MTIOCGET & IOCCMD_MASK)) {
if (((cmd_in & IOCSIZE_MASK) >> IOCSIZE_SHIFT) != sizeof(struct mtget))
return (-EINVAL);
i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct mtget));
if (i)
return i;
memcpy_tofs((char *)arg, (char *)(STp->buffer)->mt_status,
sizeof(struct mtget));
return 0;
}
else if (cmd == (MTIOCPOS & IOCCMD_MASK)) {
#ifdef DEBUG
printk("st%d: get tape position.\n", dev);
#endif
if (((cmd_in & IOCSIZE_MASK) >> IOCSIZE_SHIFT) != sizeof(struct mtpos))
return (-EINVAL);
i = flush_buffer(inode, file, 0);
if (i < 0)
return i;
i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct mtpos));
if (i)
return i;
SCpnt = allocate_device(NULL, (STp->device)->index, 1);
SCpnt->sense_buffer[0]=0;
memset (scmd, 0, 10);
if ((STp->device)->scsi_level < SCSI_2) {
scmd[0] = QFA_REQUEST_BLOCK;
scmd[4] = 3;
}
else {
scmd[0] = READ_POSITION;
scmd[1] = 1;
}
SCpnt->request.dev = dev;
SCpnt->sense_buffer[0] = 0;
scsi_do_cmd(SCpnt,
(void *) scmd, (void *) (STp->buffer)->b_data,
ST_BLOCK_SIZE, st_sleep_done, ST_TIMEOUT, MAX_READY_RETRIES);
if (SCpnt->request.dev == dev) sleep_on( &(STp->waiting) );
if ((STp->buffer)->last_result_fatal != 0) {
mt_pos.mt_blkno = (-1);
#ifdef DEBUG
printk("st%d: Can't read tape position.\n", dev);
#endif
result = (-EIO);
}
else {
result = 0;
if ((STp->device)->scsi_level < SCSI_2)
mt_pos.mt_blkno = ((STp->buffer)->b_data[0] << 16)
+ ((STp->buffer)->b_data[1] << 8)
+ (STp->buffer)->b_data[2];
else
mt_pos.mt_blkno = ((STp->buffer)->b_data[4] << 24)
+ ((STp->buffer)->b_data[5] << 16)
+ ((STp->buffer)->b_data[6] << 8)
+ (STp->buffer)->b_data[7];
}
SCpnt->request.dev = -1; /* Mark as not busy */
memcpy_tofs((char *)arg, (char *) (&mt_pos), sizeof(struct mtpos));
return result;
}
else
return scsi_ioctl(STp->device, cmd_in, (void *) arg);
}
static struct file_operations st_fops = {
NULL, /* lseek - default */
st_read, /* read - general block-dev read */
st_write, /* write - general block-dev write */
NULL, /* readdir - bad */
NULL, /* select */
st_ioctl, /* ioctl */
NULL, /* mmap */
scsi_tape_open, /* open */
scsi_tape_close, /* release */
NULL /* fsync */
};
void st_attach(Scsi_Device * SDp){
scsi_tapes[NR_ST++].device = SDp;
if(NR_ST > MAX_ST) panic ("scsi_devices corrupt (st)");
};
unsigned long st_init1(unsigned long mem_start, unsigned long mem_end){
scsi_tapes = (Scsi_Tape *) mem_start;
mem_start += MAX_ST * sizeof(Scsi_Tape);
return mem_start;
};
/* Driver initialization */
unsigned long st_init(unsigned long mem_start, unsigned long mem_end)
{
int i;
if (register_chrdev(MAJOR_NR,"st",&st_fops)) {
printk("Unable to get major %d for SCSI tapes\n",MAJOR_NR);
return mem_start;
}
if (NR_ST == 0) return mem_start;
#ifdef DEBUG
printk("st: Init tape.\n");
#endif
for (i=0; i < NR_ST; ++i) {
scsi_tapes[i].capacity = 0xfffff;
scsi_tapes[i].dirty = 0;
scsi_tapes[i].rw = ST_IDLE;
scsi_tapes[i].eof = ST_NOEOF;
scsi_tapes[i].waiting = NULL;
scsi_tapes[i].in_use = 0;
scsi_tapes[i].drv_buffer = 1; /* Try buffering if no mode sense */
scsi_tapes[i].density = 0;
}
/* Allocate the buffers */
if (NR_ST == 1)
st_nbr_buffers = 1;
else
st_nbr_buffers = 2;
for (i=0; i < st_nbr_buffers; i++) {
st_buffers[i] = (ST_buffer *) mem_start;
#ifdef DEBUG
printk("st: Buffer address: %p\n", st_buffers[i]);
#endif
mem_start += sizeof(ST_buffer) - 1 + ST_BUFFER_BLOCKS * ST_BLOCK_SIZE;
st_buffers[i]->mt_status = (struct mtget *) mem_start;
mem_start += sizeof(struct mtget);
st_buffers[i]->in_use = 0;
st_buffers[i]->writing = 0;
/* "generic" status */
memset((void *) st_buffers[i]->mt_status, 0, sizeof(struct mtget));
st_buffers[i]->mt_status->mt_type = MT_ISSCSI1;
}
return mem_start;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -