10 #include <linux/module.h>
13 #include <linux/kernel.h>
16 #include <linux/string.h>
17 #include <linux/errno.h>
25 #include <linux/slab.h>
27 #include <scsi/scsi.h>
38 #define CH_MAX_DEVS 128
50 "initialize element status on driver load (default: on)");
52 static int timeout_move = 300;
55 "(default: 300 seconds)");
57 static int timeout_init = 3600;
60 "(default: 3600 seconds)");
69 "detailed sense codes on scsi errors (default: off)");
77 static int vendor_firsts[
CH_TYPES-4];
78 static int vendor_counts[
CH_TYPES-4];
82 static const char * vendor_labels[
CH_TYPES-4] = {
83 "v0",
"v1",
"v2",
"v3"
87 #define DPRINTK(fmt, arg...) \
90 printk(KERN_DEBUG "%s: " fmt, ch->name, ##arg); \
92 #define VPRINTK(level, fmt, arg...) \
95 printk(level "%s: " fmt, ch->name, ##arg); \
100 #define MAX_RETRIES 1
102 static struct class * ch_sysfs_class;
120 static const struct {
165 if (scsi_sense_valid(sshdr) &&
167 for (i = 0; ch_err[
i].errno != 0; i++) {
169 ch_err[i].asc == sshdr->
asc &&
170 ch_err[i].ascq == sshdr->
ascq) {
171 errno = -ch_err[
i].errno;
183 void *
buffer,
unsigned buflength,
190 ? timeout_init : timeout_move;
200 buflength, &sshdr, timeout *
HZ,
203 DPRINTK(
"result: 0x%x\n",result);
207 errno = ch_find_errno(&sshdr);
228 if (elem >= ch->
firsts[i] &&
229 elem < ch->firsts[i] +
248 memset(cmd,0,
sizeof(cmd));
250 cmd[1] = (ch->
device->lun << 5) |
252 ch_elem_to_typecode(ch,elem);
253 cmd[2] = (elem >> 8) & 0xff;
254 cmd[3] = elem & 0xff;
257 if (0 == (result = ch_do_scsi(ch, cmd, buffer, 256,
DMA_FROM_DEVICE))) {
258 if (((buffer[16] << 8) | buffer[17]) !=
elem) {
259 DPRINTK(
"asked for element 0x%02x, got 0x%02x\n",
260 elem,(buffer[16] << 8) | buffer[17]);
264 memcpy(data,buffer+16,16);
271 DPRINTK(
"READ ELEMENT STATUS for element 0x%x failed\n",elem);
284 memset(cmd,0,
sizeof(cmd));
286 cmd[1] = ch->
device->lun << 5;
304 memset(cmd,0,
sizeof(cmd));
306 cmd[1] = ch->
device->lun << 5;
316 (buffer[buffer[3]+ 6] << 8) | buffer[buffer[3]+ 7];
318 (buffer[buffer[3]+ 8] << 8) | buffer[buffer[3]+ 9];
320 (buffer[buffer[3]+10] << 8) | buffer[buffer[3]+11];
322 (buffer[buffer[3]+12] << 8) | buffer[buffer[3]+13];
324 (buffer[buffer[3]+14] << 8) | buffer[buffer[3]+15];
326 (buffer[buffer[3]+16] << 8) | buffer[buffer[3]+17];
328 (buffer[buffer[3]+18] << 8) | buffer[buffer[3]+19];
330 (buffer[buffer[3]+20] << 8) | buffer[buffer[3]+21];
348 for (i = 0; i < 4; i++) {
349 if (0 == vendor_counts[i])
351 if (
NULL == vendor_labels[i])
356 i+5,i+1,vendor_firsts[i],vendor_counts[i],
372 if (elem <
CH_DT_MAX && -1 != dt_id[elem]) {
377 }
else if (0 != ch_read_element_status
383 if (data[6] & 0x80) {
386 }
else if (0 == (data[6] & 0x30)) {
392 if (data[6] & 0x20)
id = data[7];
393 if (data[6] & 0x10) lun = data[6] & 7;
407 ch->
dt[elem]->vendor,
426 DPRINTK(
"position: 0x%x\n",elem);
429 memset(cmd,0,
sizeof(cmd));
431 cmd[1] = ch->
device->lun << 5;
432 cmd[2] = (trans >> 8) & 0xff;
433 cmd[3] = trans & 0xff;
434 cmd[4] = (elem >> 8) & 0xff;
435 cmd[5] = elem & 0xff;
436 cmd[8] = rotate ? 1 : 0;
445 DPRINTK(
"move: 0x%x => 0x%x\n",src,dest);
448 memset(cmd,0,
sizeof(cmd));
450 cmd[1] = ch->
device->lun << 5;
451 cmd[2] = (trans >> 8) & 0xff;
452 cmd[3] = trans & 0xff;
453 cmd[4] = (src >> 8) & 0xff;
455 cmd[6] = (dest >> 8) & 0xff;
456 cmd[7] = dest & 0xff;
457 cmd[10] = rotate ? 1 : 0;
463 u_int dest1,
u_int dest2,
int rotate1,
int rotate2)
467 DPRINTK(
"exchange: 0x%x => 0x%x => 0x%x\n",
471 memset(cmd,0,
sizeof(cmd));
473 cmd[1] = ch->
device->lun << 5;
474 cmd[2] = (trans >> 8) & 0xff;
475 cmd[3] = trans & 0xff;
476 cmd[4] = (src >> 8) & 0xff;
478 cmd[6] = (dest1 >> 8) & 0xff;
479 cmd[7] = dest1 & 0xff;
480 cmd[8] = (dest2 >> 8) & 0xff;
481 cmd[9] = dest2 & 0xff;
482 cmd[10] = (rotate1 ? 1 : 0) | (rotate2 ? 2 : 0);
488 ch_check_voltag(
char *
tag)
492 for (i = 0; i < 32; i++) {
494 if (tag[i] >= 0x7f || tag[i] < 0x20)
515 DPRINTK(
"%s %s voltag: 0x%x => \"%s\"\n",
516 clear ?
"clear" :
"set",
517 alternate ?
"alternate" :
"primary",
519 memset(cmd,0,
sizeof(cmd));
521 cmd[1] = (ch->
device->lun << 5) |
522 ch_elem_to_typecode(ch,elem);
523 cmd[2] = (elem >> 8) & 0xff;
524 cmd[3] = elem & 0xff;
526 ? (alternate ? 0x0d : 0x0c)
527 : (alternate ? 0x0b : 0x0a);
532 ch_check_voltag(buffer);
539 static int ch_gstatus(
scsi_changer *ch,
int type,
unsigned char __user *dest)
547 if (0 != ch_read_element_status
548 (ch, ch->
firsts[type]+i,data)) {
556 (
int)data[4],(
int)data[5]);
557 retval = ch_read_element_status
558 (ch, ch->
firsts[type]+i,data);
582 int minor = iminor(inode);
585 spin_lock(&ch_index_lock);
586 ch =
idr_find(&ch_index_idr, minor);
589 spin_unlock(&ch_index_lock);
593 spin_unlock(&ch_index_lock);
603 if (type >= CH_TYPES || unit >= ch->
counts[type])
608 static long ch_ioctl(
struct file *file,
609 unsigned int cmd,
unsigned long arg)
634 memset(&vparams,0,
sizeof(vparams));
637 strncpy(vparams.cvp_label1,vendor_labels[0],16);
641 strncpy(vparams.cvp_label2,vendor_labels[1],16);
645 strncpy(vparams.cvp_label3,vendor_labels[2],16);
649 strncpy(vparams.cvp_label4,vendor_labels[3],16);
663 if (0 != ch_checkrange(ch,
pos.cp_type,
pos.cp_unit)) {
664 DPRINTK(
"CHIOPOSITION: invalid parameter\n");
668 retval = ch_position(ch,0,
682 if (0 != ch_checkrange(ch, mv.cm_fromtype, mv.cm_fromunit) ||
683 0 != ch_checkrange(ch, mv.cm_totype, mv.cm_tounit )) {
684 DPRINTK(
"CHIOMOVE: invalid parameter\n");
689 retval = ch_move(ch,0,
690 ch->
firsts[mv.cm_fromtype] + mv.cm_fromunit,
691 ch->
firsts[mv.cm_totype] + mv.cm_tounit,
704 if (0 != ch_checkrange(ch, mv.ce_srctype, mv.ce_srcunit ) ||
705 0 != ch_checkrange(ch, mv.ce_fdsttype, mv.ce_fdstunit) ||
706 0 != ch_checkrange(ch, mv.ce_sdsttype, mv.ce_sdstunit)) {
707 DPRINTK(
"CHIOEXCHANGE: invalid parameter\n");
714 ch->
firsts[mv.ce_srctype] + mv.ce_srcunit,
715 ch->
firsts[mv.ce_fdsttype] + mv.ce_fdstunit,
716 ch->
firsts[mv.ce_sdsttype] + mv.ce_sdstunit,
728 if (ces.ces_type < 0 || ces.ces_type >= CH_TYPES)
731 return ch_gstatus(ch, ces.ces_type, ces.ces_data);
745 if (0 != ch_checkrange(ch, cge.cge_type, cge.cge_unit))
747 elem = ch->
firsts[cge.cge_type] + cge.cge_unit;
755 memset(ch_cmd, 0,
sizeof(ch_cmd));
757 ch_cmd[1] = (ch->
device->lun << 5) |
759 ch_elem_to_typecode(ch,elem);
760 ch_cmd[2] = (elem >> 8) & 0xff;
761 ch_cmd[3] = elem & 0xff;
767 cge.cge_status = buffer[18];
772 if (buffer[25] & 0x80) {
774 if (buffer[25] & 0x40)
776 elem = (buffer[26]<<8) | buffer[27];
777 for (i = 0; i < 4; i++) {
778 if (elem >= ch->
firsts[i] &&
779 elem < ch->firsts[i] + ch->
counts[i]) {
781 cge.cge_srcunit = elem-ch->
firsts[
i];
785 if ((buffer[22] & 0x30) == 0x30) {
787 cge.cge_id = buffer[23];
788 cge.cge_lun = buffer[22] & 7;
790 if (buffer[9] & 0x80) {
792 memcpy(cge.cge_pvoltag,buffer+28,36);
794 if (buffer[9] & 0x40) {
796 memcpy(cge.cge_avoltag,buffer+64,36);
814 retval = ch_init_elem(ch);
827 if (0 != ch_checkrange(ch, csv.csv_type, csv.csv_unit)) {
828 DPRINTK(
"CHIOSVOLTAG: invalid parameter\n");
831 elem = ch->
firsts[csv.csv_type] + csv.csv_unit;
833 retval = ch_set_voltag(ch, elem,
849 struct changer_element_status32 {
853 #define CHIOGSTATUS32 _IOW('c', 8,struct changer_element_status32)
855 static long ch_ioctl_compat(
struct file * file,
856 unsigned int cmd,
unsigned long arg)
870 return ch_ioctl(file, cmd, arg);
873 struct changer_element_status32 ces32;
878 if (ces32.ces_type < 0 || ces32.ces_type >= CH_TYPES)
881 data = compat_ptr(ces32.ces_data);
882 return ch_gstatus(ch, ces32.ces_type, data);
911 spin_lock(&ch_index_lock);
913 spin_unlock(&ch_index_lock);
929 if (IS_ERR(class_dev)) {
932 ret = PTR_ERR(class_dev);
953 static int ch_remove(
struct device *dev)
957 spin_lock(&ch_index_lock);
959 spin_unlock(&ch_index_lock);
979 .release = ch_release,
980 .unlocked_ioctl = ch_ioctl,
982 .compat_ioctl = ch_ioctl_compat,
987 static int __init init_ch_module(
void)
993 if (IS_ERR(ch_sysfs_class)) {
994 rc = PTR_ERR(ch_sysfs_class);
999 printk(
"Unable to get major %d for SCSI-Changer\n",
1015 static void __exit exit_ch_module(
void)