0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #define KMSG_COMPONENT "tape"
0014 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
0015
0016 #include <linux/module.h>
0017 #include <linux/types.h>
0018 #include <linux/proc_fs.h>
0019 #include <linux/mtio.h>
0020 #include <linux/compat.h>
0021
0022 #include <linux/uaccess.h>
0023
0024 #define TAPE_DBF_AREA tape_core_dbf
0025
0026 #include "tape.h"
0027 #include "tape_std.h"
0028 #include "tape_class.h"
0029
0030 #define TAPECHAR_MAJOR 0
0031
0032
0033
0034
0035 static ssize_t tapechar_read(struct file *, char __user *, size_t, loff_t *);
0036 static ssize_t tapechar_write(struct file *, const char __user *, size_t, loff_t *);
0037 static int tapechar_open(struct inode *,struct file *);
0038 static int tapechar_release(struct inode *,struct file *);
0039 static long tapechar_ioctl(struct file *, unsigned int, unsigned long);
0040 #ifdef CONFIG_COMPAT
0041 static long tapechar_compat_ioctl(struct file *, unsigned int, unsigned long);
0042 #endif
0043
0044 static const struct file_operations tape_fops =
0045 {
0046 .owner = THIS_MODULE,
0047 .read = tapechar_read,
0048 .write = tapechar_write,
0049 .unlocked_ioctl = tapechar_ioctl,
0050 #ifdef CONFIG_COMPAT
0051 .compat_ioctl = tapechar_compat_ioctl,
0052 #endif
0053 .open = tapechar_open,
0054 .release = tapechar_release,
0055 .llseek = no_llseek,
0056 };
0057
0058 static int tapechar_major = TAPECHAR_MAJOR;
0059
0060
0061
0062
0063 int
0064 tapechar_setup_device(struct tape_device * device)
0065 {
0066 char device_name[20];
0067
0068 sprintf(device_name, "ntibm%i", device->first_minor / 2);
0069 device->nt = register_tape_dev(
0070 &device->cdev->dev,
0071 MKDEV(tapechar_major, device->first_minor),
0072 &tape_fops,
0073 device_name,
0074 "non-rewinding"
0075 );
0076 device_name[0] = 'r';
0077 device->rt = register_tape_dev(
0078 &device->cdev->dev,
0079 MKDEV(tapechar_major, device->first_minor + 1),
0080 &tape_fops,
0081 device_name,
0082 "rewinding"
0083 );
0084
0085 return 0;
0086 }
0087
0088 void
0089 tapechar_cleanup_device(struct tape_device *device)
0090 {
0091 unregister_tape_dev(&device->cdev->dev, device->rt);
0092 device->rt = NULL;
0093 unregister_tape_dev(&device->cdev->dev, device->nt);
0094 device->nt = NULL;
0095 }
0096
0097 static int
0098 tapechar_check_idalbuffer(struct tape_device *device, size_t block_size)
0099 {
0100 struct idal_buffer *new;
0101
0102 if (device->char_data.idal_buf != NULL &&
0103 device->char_data.idal_buf->size == block_size)
0104 return 0;
0105
0106 if (block_size > MAX_BLOCKSIZE) {
0107 DBF_EVENT(3, "Invalid blocksize (%zd > %d)\n",
0108 block_size, MAX_BLOCKSIZE);
0109 return -EINVAL;
0110 }
0111
0112
0113 new = idal_buffer_alloc(block_size, 0);
0114 if (IS_ERR(new))
0115 return -ENOMEM;
0116
0117 if (device->char_data.idal_buf != NULL)
0118 idal_buffer_free(device->char_data.idal_buf);
0119
0120 device->char_data.idal_buf = new;
0121
0122 return 0;
0123 }
0124
0125
0126
0127
0128 static ssize_t
0129 tapechar_read(struct file *filp, char __user *data, size_t count, loff_t *ppos)
0130 {
0131 struct tape_device *device;
0132 struct tape_request *request;
0133 size_t block_size;
0134 int rc;
0135
0136 DBF_EVENT(6, "TCHAR:read\n");
0137 device = (struct tape_device *) filp->private_data;
0138
0139
0140
0141
0142
0143
0144 if(device->required_tapemarks) {
0145 return tape_std_terminate_write(device);
0146 }
0147
0148
0149 if (device->char_data.block_size != 0) {
0150 if (count < device->char_data.block_size) {
0151 DBF_EVENT(3, "TCHAR:read smaller than block "
0152 "size was requested\n");
0153 return -EINVAL;
0154 }
0155 block_size = device->char_data.block_size;
0156 } else {
0157 block_size = count;
0158 }
0159
0160 rc = tapechar_check_idalbuffer(device, block_size);
0161 if (rc)
0162 return rc;
0163
0164 DBF_EVENT(6, "TCHAR:nbytes: %lx\n", block_size);
0165
0166 request = device->discipline->read_block(device, block_size);
0167 if (IS_ERR(request))
0168 return PTR_ERR(request);
0169
0170 rc = tape_do_io(device, request);
0171 if (rc == 0) {
0172 rc = block_size - request->rescnt;
0173 DBF_EVENT(6, "TCHAR:rbytes: %x\n", rc);
0174
0175 if (idal_buffer_to_user(device->char_data.idal_buf,
0176 data, rc) != 0)
0177 rc = -EFAULT;
0178 }
0179 tape_free_request(request);
0180 return rc;
0181 }
0182
0183
0184
0185
0186 static ssize_t
0187 tapechar_write(struct file *filp, const char __user *data, size_t count, loff_t *ppos)
0188 {
0189 struct tape_device *device;
0190 struct tape_request *request;
0191 size_t block_size;
0192 size_t written;
0193 int nblocks;
0194 int i, rc;
0195
0196 DBF_EVENT(6, "TCHAR:write\n");
0197 device = (struct tape_device *) filp->private_data;
0198
0199 if (device->char_data.block_size != 0) {
0200 if (count < device->char_data.block_size) {
0201 DBF_EVENT(3, "TCHAR:write smaller than block "
0202 "size was requested\n");
0203 return -EINVAL;
0204 }
0205 block_size = device->char_data.block_size;
0206 nblocks = count / block_size;
0207 } else {
0208 block_size = count;
0209 nblocks = 1;
0210 }
0211
0212 rc = tapechar_check_idalbuffer(device, block_size);
0213 if (rc)
0214 return rc;
0215
0216 DBF_EVENT(6,"TCHAR:nbytes: %lx\n", block_size);
0217 DBF_EVENT(6, "TCHAR:nblocks: %x\n", nblocks);
0218
0219 request = device->discipline->write_block(device, block_size);
0220 if (IS_ERR(request))
0221 return PTR_ERR(request);
0222 rc = 0;
0223 written = 0;
0224 for (i = 0; i < nblocks; i++) {
0225
0226 if (idal_buffer_from_user(device->char_data.idal_buf,
0227 data, block_size)) {
0228 rc = -EFAULT;
0229 break;
0230 }
0231 rc = tape_do_io(device, request);
0232 if (rc)
0233 break;
0234 DBF_EVENT(6, "TCHAR:wbytes: %lx\n",
0235 block_size - request->rescnt);
0236 written += block_size - request->rescnt;
0237 if (request->rescnt != 0)
0238 break;
0239 data += block_size;
0240 }
0241 tape_free_request(request);
0242 if (rc == -ENOSPC) {
0243
0244
0245
0246
0247 if (device->discipline->process_eov)
0248 device->discipline->process_eov(device);
0249 if (written > 0)
0250 rc = 0;
0251
0252 }
0253
0254
0255
0256
0257
0258
0259
0260
0261 if (!rc)
0262 device->required_tapemarks = 2;
0263
0264 return rc ? rc : written;
0265 }
0266
0267
0268
0269
0270 static int
0271 tapechar_open (struct inode *inode, struct file *filp)
0272 {
0273 struct tape_device *device;
0274 int minor, rc;
0275
0276 DBF_EVENT(6, "TCHAR:open: %i:%i\n",
0277 imajor(file_inode(filp)),
0278 iminor(file_inode(filp)));
0279
0280 if (imajor(file_inode(filp)) != tapechar_major)
0281 return -ENODEV;
0282
0283 minor = iminor(file_inode(filp));
0284 device = tape_find_device(minor / TAPE_MINORS_PER_DEV);
0285 if (IS_ERR(device)) {
0286 DBF_EVENT(3, "TCHAR:open: tape_find_device() failed\n");
0287 return PTR_ERR(device);
0288 }
0289
0290 rc = tape_open(device);
0291 if (rc == 0) {
0292 filp->private_data = device;
0293 stream_open(inode, filp);
0294 } else
0295 tape_put_device(device);
0296
0297 return rc;
0298 }
0299
0300
0301
0302
0303
0304 static int
0305 tapechar_release(struct inode *inode, struct file *filp)
0306 {
0307 struct tape_device *device;
0308
0309 DBF_EVENT(6, "TCHAR:release: %x\n", iminor(inode));
0310 device = (struct tape_device *) filp->private_data;
0311
0312
0313
0314
0315
0316
0317 if ((iminor(inode) & 1) != 0) {
0318 if (device->required_tapemarks)
0319 tape_std_terminate_write(device);
0320 tape_mtop(device, MTREW, 1);
0321 } else {
0322 if (device->required_tapemarks > 1) {
0323 if (tape_mtop(device, MTWEOF, 1) == 0)
0324 device->required_tapemarks--;
0325 }
0326 }
0327
0328 if (device->char_data.idal_buf != NULL) {
0329 idal_buffer_free(device->char_data.idal_buf);
0330 device->char_data.idal_buf = NULL;
0331 }
0332 tape_release(device);
0333 filp->private_data = NULL;
0334 tape_put_device(device);
0335
0336 return 0;
0337 }
0338
0339
0340
0341
0342 static int
0343 __tapechar_ioctl(struct tape_device *device,
0344 unsigned int no, void __user *data)
0345 {
0346 int rc;
0347
0348 if (no == MTIOCTOP) {
0349 struct mtop op;
0350
0351 if (copy_from_user(&op, data, sizeof(op)) != 0)
0352 return -EFAULT;
0353 if (op.mt_count < 0)
0354 return -EINVAL;
0355
0356
0357
0358
0359
0360 switch (op.mt_op) {
0361 case MTFSF:
0362 case MTBSF:
0363 case MTFSR:
0364 case MTBSR:
0365 case MTREW:
0366 case MTOFFL:
0367 case MTEOM:
0368 case MTRETEN:
0369 case MTBSFM:
0370 case MTFSFM:
0371 case MTSEEK:
0372 if (device->required_tapemarks)
0373 tape_std_terminate_write(device);
0374 }
0375 rc = tape_mtop(device, op.mt_op, op.mt_count);
0376
0377 if (op.mt_op == MTWEOF && rc == 0) {
0378 if (op.mt_count > device->required_tapemarks)
0379 device->required_tapemarks = 0;
0380 else
0381 device->required_tapemarks -= op.mt_count;
0382 }
0383 return rc;
0384 }
0385 if (no == MTIOCPOS) {
0386
0387 struct mtpos pos;
0388
0389 rc = tape_mtop(device, MTTELL, 1);
0390 if (rc < 0)
0391 return rc;
0392 pos.mt_blkno = rc;
0393 return put_user_mtpos(data, &pos);
0394 }
0395 if (no == MTIOCGET) {
0396
0397 struct mtget get;
0398
0399 memset(&get, 0, sizeof(get));
0400 get.mt_type = MT_ISUNKNOWN;
0401 get.mt_resid = 0 ;
0402 get.mt_dsreg =
0403 ((device->char_data.block_size << MT_ST_BLKSIZE_SHIFT)
0404 & MT_ST_BLKSIZE_MASK);
0405
0406 get.mt_gstat = 0;
0407 get.mt_erreg = 0;
0408 get.mt_fileno = 0;
0409 get.mt_gstat = device->tape_generic_status;
0410
0411 if (device->medium_state == MS_LOADED) {
0412 rc = tape_mtop(device, MTTELL, 1);
0413
0414 if (rc < 0)
0415 return rc;
0416
0417 if (rc == 0)
0418 get.mt_gstat |= GMT_BOT(~0);
0419
0420 get.mt_blkno = rc;
0421 }
0422
0423 return put_user_mtget(data, &get);
0424 }
0425
0426 if (device->discipline->ioctl_fn == NULL)
0427 return -EINVAL;
0428 return device->discipline->ioctl_fn(device, no, (unsigned long)data);
0429 }
0430
0431 static long
0432 tapechar_ioctl(struct file *filp, unsigned int no, unsigned long data)
0433 {
0434 struct tape_device *device;
0435 long rc;
0436
0437 DBF_EVENT(6, "TCHAR:ioct\n");
0438
0439 device = (struct tape_device *) filp->private_data;
0440 mutex_lock(&device->mutex);
0441 rc = __tapechar_ioctl(device, no, (void __user *)data);
0442 mutex_unlock(&device->mutex);
0443 return rc;
0444 }
0445
0446 #ifdef CONFIG_COMPAT
0447 static long
0448 tapechar_compat_ioctl(struct file *filp, unsigned int no, unsigned long data)
0449 {
0450 struct tape_device *device = filp->private_data;
0451 long rc;
0452
0453 if (no == MTIOCPOS32)
0454 no = MTIOCPOS;
0455 else if (no == MTIOCGET32)
0456 no = MTIOCGET;
0457
0458 mutex_lock(&device->mutex);
0459 rc = __tapechar_ioctl(device, no, compat_ptr(data));
0460 mutex_unlock(&device->mutex);
0461 return rc;
0462 }
0463 #endif
0464
0465
0466
0467
0468 int
0469 tapechar_init (void)
0470 {
0471 dev_t dev;
0472
0473 if (alloc_chrdev_region(&dev, 0, 256, "tape") != 0)
0474 return -1;
0475
0476 tapechar_major = MAJOR(dev);
0477
0478 return 0;
0479 }
0480
0481
0482
0483
0484 void
0485 tapechar_exit(void)
0486 {
0487 unregister_chrdev_region(MKDEV(tapechar_major, 0), 256);
0488 }