?? 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 intst_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 intst_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 + -