📄 st.c
字号:
int dev = inode->i_rdev; int timeout = ST_LONG_TIMEOUT; long ltmp; int ioctl_result; unsigned char cmd[10]; Scsi_Cmnd * SCpnt; dev = dev & 127; SCpnt = allocate_device(NULL, scsi_tapes[dev].device->index, 1); 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 %d files.\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 %d files.\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; SCpnt->result = -1;#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 (scsi_tapes[dev].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 tape media.\n", dev);#endif break; case MTERASE: if (scsi_tapes[dev].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 (scsi_tapes[dev].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 */ if (scsi_tapes[dev].dirty || scsi_tapes[dev].buffer->buffer_bytes != 0) return (-EIO); /* Not allowed if data in buffer */ if (cmd_in == MTSETBLK && (arg < scsi_tapes[dev].min_block || arg > scsi_tapes[dev].max_block || arg > ST_BUFFER_SIZE)) { printk("st%d: Illegal block size.\n", dev); return (-EINVAL); } cmd[0] = MODE_SELECT; cmd[4] = 12; memset(scsi_tapes[dev].buffer->b_data, 0, 12); scsi_tapes[dev].buffer->b_data[2] = 0x10; /* buffered mode */ scsi_tapes[dev].buffer->b_data[3] = 8; /* block descriptor length */ if (cmd_in == MTSETBLK) ltmp = arg; else { scsi_tapes[dev].buffer->b_data[4] = arg; ltmp = scsi_tapes[dev].block_size; } scsi_tapes[dev].buffer->b_data[9] = (ltmp >> 16); scsi_tapes[dev].buffer->b_data[10] = (ltmp >> 8); scsi_tapes[dev].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, scsi_tapes[dev].buffer->b_data[9] * 65536 + scsi_tapes[dev].buffer->b_data[10] * 256 + scsi_tapes[dev].buffer->b_data[11]); else printk("st%d: Setting density code to %x.\n", dev, scsi_tapes[dev].buffer->b_data[4]);#endif break; default: printk("st%d: Unknown st_ioctl command %x.\n", dev, cmd_in); SCpnt->request.dev = -1; /* Mark as not busy */ return (-ENOSYS); } SCpnt->sense_buffer[0] = 0; SCpnt->request.dev = dev; scsi_do_cmd(SCpnt, (void *) cmd, (void *) scsi_tapes[dev].buffer->b_data, ST_BLOCK_SIZE, st_sleep_done, timeout, MAX_RETRIES); if (SCpnt->request.dev == dev) sleep_on( &scsi_tapes[dev].waiting ); SCpnt->request.dev = -1; /* Mark as not busy */ ioctl_result = st_chk_result(dev, SCpnt->result, SCpnt->sense_buffer); if (!ioctl_result) { if (cmd_in == MTBSFM) ioctl_result = st_int_ioctl(inode, file, MTFSF, 1); else if (cmd_in == MTSETBLK) { scsi_tapes[dev].block_size = arg; scsi_tapes[dev].buffer->buffer_blocks = ST_BUFFER_SIZE / scsi_tapes[dev].block_size; scsi_tapes[dev].buffer->buffer_size = scsi_tapes[dev].buffer->buffer_blocks * scsi_tapes[dev].block_size; scsi_tapes[dev].buffer->buffer_bytes = scsi_tapes[dev].buffer->read_pointer = 0; } if (cmd_in == MTEOM || cmd_in == MTWEOF) { scsi_tapes[dev].eof = 2; scsi_tapes[dev].eof_hit = 0; } else if (cmd_in != MTSETBLK && cmd_in != MTNOP) { scsi_tapes[dev].eof = 0; scsi_tapes[dev].eof_hit = 0; } } return ioctl_result ;}/* The ioctl command */static int st_ioctl(struct inode * inode,struct file * file, unsigned int cmd_in, unsigned int arg){ int dev = inode->i_rdev; int i, cmd, result; struct mtop mtc; struct mtpos mt_pos; unsigned char scmd[10]; Scsi_Cmnd *SCpnt; dev = dev & 127;#ifdef DEBUG if (!scsi_tapes[dev].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); verify_area((void *)arg, sizeof(mtc)); 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); verify_area((void *)arg, sizeof(struct mtget)); memcpy_tofs((char *)arg, (char *)scsi_tapes[dev].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; verify_area((void *)arg, sizeof(struct mtpos)); SCpnt = allocate_device(NULL, scsi_tapes[dev].device->index, 1); SCpnt->sense_buffer[0]=0; memset (scmd, 0, 10); if (scsi_tapes[dev].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 *) scsi_tapes[dev].buffer->b_data, ST_BLOCK_SIZE, st_sleep_done, ST_TIMEOUT, MAX_RETRIES); if (SCpnt->request.dev == dev) sleep_on( &scsi_tapes[dev].waiting ); if (SCpnt->result || SCpnt->sense_buffer[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 (scsi_tapes[dev].device->scsi_level < SCSI_2) mt_pos.mt_blkno = (scsi_tapes[dev].buffer->b_data[0] << 16) + (scsi_tapes[dev].buffer->b_data[1] << 8) + scsi_tapes[dev].buffer->b_data[2]; else mt_pos.mt_blkno = (scsi_tapes[dev].buffer->b_data[4] << 24) + (scsi_tapes[dev].buffer->b_data[5] << 16) + (scsi_tapes[dev].buffer->b_data[6] << 8) + scsi_tapes[dev].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 (-EINVAL);}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 */};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 (NR_ST == 0) return mem_start;#ifdef DEBUG printk("st: Init tape.\n");#endif chrdev_fops[MAJOR_NR] = &st_fops; for (i=0; i < NR_ST; ++i) { scsi_tapes[i].capacity = 0xfffff; scsi_tapes[i].dirty = 0; scsi_tapes[i].rw = 0; scsi_tapes[i].eof = 0; scsi_tapes[i].waiting = NULL; scsi_tapes[i].in_use = 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: %x\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 + -