Lines Matching +full:4 +full:- +full:ch

1 // SPDX-License-Identifier: GPL-2.0-only
5 * (c) 1996-2003 Gerd Knorr <kraxel@bytesex.org>
71 static int dt_id[CH_DT_MAX] = { [ 0 ... (CH_DT_MAX-1) ] = -1 };
76 /* tell the driver about vendor-specific slots */
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] = {
87 #define ch_printk(prefix, ch, fmt, a...) \ argument
88 sdev_prefix_printk(prefix, (ch)->device, (ch)->name, fmt, ##a)
93 ch_printk(KERN_DEBUG, ch, fmt, ##arg); \
98 ch_printk(level, ch, fmt, ##arg); \
101 /* ------------------------------------------------------------------- */
163 /* ------------------------------------------------------------------- */
171 sshdr->asc != 0) { in ch_find_errno()
173 if (ch_err[i].sense == sshdr->sense_key && in ch_find_errno()
174 ch_err[i].asc == sshdr->asc && in ch_find_errno()
175 ch_err[i].ascq == sshdr->ascq) { in ch_find_errno()
176 errno = -ch_err[i].errno; in ch_find_errno()
182 errno = -EIO; in ch_find_errno()
187 ch_do_scsi(scsi_changer *ch, unsigned char *cmd, int cmd_len, in ch_do_scsi() argument
213 result = scsi_execute_cmd(ch->device, cmd, op, buffer, buflength, in ch_do_scsi()
219 scsi_print_sense_hdr(ch->device, ch->name, &sshdr); in ch_do_scsi()
225 /* ------------------------------------------------------------------------ */
228 ch_elem_to_typecode(scsi_changer *ch, u_int elem) in ch_elem_to_typecode() argument
233 if (elem >= ch->firsts[i] && in ch_elem_to_typecode()
234 elem < ch->firsts[i] + in ch_elem_to_typecode()
235 ch->counts[i]) in ch_elem_to_typecode()
242 ch_read_element_status(scsi_changer *ch, u_int elem, char *data) in ch_read_element_status() argument
250 return -ENOMEM; in ch_read_element_status()
255 cmd[1] = ((ch->device->lun & 0x7) << 5) | in ch_read_element_status()
256 (ch->voltags ? 0x10 : 0) | in ch_read_element_status()
257 ch_elem_to_typecode(ch,elem); in ch_read_element_status()
262 if (0 == (result = ch_do_scsi(ch, cmd, 12, in ch_read_element_status()
268 return -EIO; in ch_read_element_status()
272 if (ch->voltags) { in ch_read_element_status()
273 ch->voltags = 0; in ch_read_element_status()
284 ch_init_elem(scsi_changer *ch) in ch_init_elem() argument
292 cmd[1] = (ch->device->lun & 0x7) << 5; in ch_init_elem()
293 err = ch_do_scsi(ch, cmd, 6, NULL, 0, REQ_OP_DRV_IN); in ch_init_elem()
299 ch_readconfig(scsi_changer *ch) in ch_readconfig() argument
308 return -ENOMEM; in ch_readconfig()
312 cmd[1] = (ch->device->lun & 0x7) << 5; in ch_readconfig()
314 cmd[4] = 255; in ch_readconfig()
315 result = ch_do_scsi(ch, cmd, 10, buffer, 255, REQ_OP_DRV_IN); in ch_readconfig()
318 result = ch_do_scsi(ch, cmd, 10, buffer, 255, REQ_OP_DRV_IN); in ch_readconfig()
321 ch->firsts[CHET_MT] = in ch_readconfig()
323 ch->counts[CHET_MT] = in ch_readconfig()
325 ch->firsts[CHET_ST] = in ch_readconfig()
327 ch->counts[CHET_ST] = in ch_readconfig()
329 ch->firsts[CHET_IE] = in ch_readconfig()
331 ch->counts[CHET_IE] = in ch_readconfig()
333 ch->firsts[CHET_DT] = in ch_readconfig()
335 ch->counts[CHET_DT] = in ch_readconfig()
338 ch->firsts[CHET_MT], in ch_readconfig()
339 ch->counts[CHET_MT]); in ch_readconfig()
341 ch->firsts[CHET_ST], in ch_readconfig()
342 ch->counts[CHET_ST]); in ch_readconfig()
344 ch->firsts[CHET_IE], in ch_readconfig()
345 ch->counts[CHET_IE]); in ch_readconfig()
346 VPRINTK(KERN_INFO, "type #4 (dt): 0x%x+%d [data transfer]\n", in ch_readconfig()
347 ch->firsts[CHET_DT], in ch_readconfig()
348 ch->counts[CHET_DT]); in ch_readconfig()
354 for (i = 0; i < 4; i++) { in ch_readconfig()
359 ch->firsts[CHET_V1+i] = vendor_firsts[i]; in ch_readconfig()
360 ch->counts[CHET_V1+i] = vendor_counts[i]; in ch_readconfig()
367 ch->dt = kcalloc(ch->counts[CHET_DT], sizeof(*ch->dt), in ch_readconfig()
370 if (!ch->dt) { in ch_readconfig()
372 return -ENOMEM; in ch_readconfig()
375 for (elem = 0; elem < ch->counts[CHET_DT]; elem++) { in ch_readconfig()
376 id = -1; in ch_readconfig()
378 if (elem < CH_DT_MAX && -1 != dt_id[elem]) { in ch_readconfig()
382 elem+ch->firsts[CHET_DT]); in ch_readconfig()
384 (ch,elem+ch->firsts[CHET_DT],data)) { in ch_readconfig()
386 elem+ch->firsts[CHET_DT]); in ch_readconfig()
388 VPRINTK(KERN_INFO, "dt 0x%x: ",elem+ch->firsts[CHET_DT]); in ch_readconfig()
391 ch->dt[elem] = NULL; in ch_readconfig()
394 ch->dt[elem] = NULL; in ch_readconfig()
396 id = ch->device->id; in ch_readconfig()
402 if (-1 != id) { in ch_readconfig()
404 ch->dt[elem] = in ch_readconfig()
405 scsi_device_lookup(ch->device->host, in ch_readconfig()
406 ch->device->channel, in ch_readconfig()
408 if (!ch->dt[elem]) { in ch_readconfig()
413 ch->dt[elem]->vendor, in ch_readconfig()
414 ch->dt[elem]->model, in ch_readconfig()
415 ch->dt[elem]->rev); in ch_readconfig()
419 ch->voltags = 1; in ch_readconfig()
425 /* ------------------------------------------------------------------------ */
428 ch_position(scsi_changer *ch, u_int trans, u_int elem, int rotate) in ch_position() argument
434 trans = ch->firsts[CHET_MT]; in ch_position()
437 cmd[1] = (ch->device->lun & 0x7) << 5; in ch_position()
440 cmd[4] = (elem >> 8) & 0xff; in ch_position()
443 return ch_do_scsi(ch, cmd, 10, NULL, 0, REQ_OP_DRV_IN); in ch_position()
447 ch_move(scsi_changer *ch, u_int trans, u_int src, u_int dest, int rotate) in ch_move() argument
453 trans = ch->firsts[CHET_MT]; in ch_move()
456 cmd[1] = (ch->device->lun & 0x7) << 5; in ch_move()
459 cmd[4] = (src >> 8) & 0xff; in ch_move()
464 return ch_do_scsi(ch, cmd, 12, NULL, 0, REQ_OP_DRV_IN); in ch_move()
468 ch_exchange(scsi_changer *ch, u_int trans, u_int src, in ch_exchange() argument
476 trans = ch->firsts[CHET_MT]; in ch_exchange()
479 cmd[1] = (ch->device->lun & 0x7) << 5; in ch_exchange()
482 cmd[4] = (src >> 8) & 0xff; in ch_exchange()
490 return ch_do_scsi(ch, cmd, 12, NULL, 0, REQ_OP_DRV_IN); in ch_exchange()
510 ch_set_voltag(scsi_changer *ch, u_int elem, in ch_set_voltag() argument
519 return -ENOMEM; in ch_set_voltag()
527 cmd[1] = ((ch->device->lun & 0x7) << 5) | in ch_set_voltag()
528 ch_elem_to_typecode(ch,elem); in ch_set_voltag()
540 result = ch_do_scsi(ch, cmd, 12, buffer, 256, REQ_OP_DRV_OUT); in ch_set_voltag()
545 static int ch_gstatus(scsi_changer *ch, int type, unsigned char __user *dest) in ch_gstatus() argument
551 mutex_lock(&ch->lock); in ch_gstatus()
552 for (i = 0; i < ch->counts[type]; i++) { in ch_gstatus()
554 (ch, ch->firsts[type]+i,data)) { in ch_gstatus()
555 retval = -EIO; in ch_gstatus()
561 ch->firsts[type]+i, in ch_gstatus()
562 (int)data[4],(int)data[5]); in ch_gstatus()
564 (ch, ch->firsts[type]+i,data); in ch_gstatus()
568 mutex_unlock(&ch->lock); in ch_gstatus()
572 /* ------------------------------------------------------------------------ */
576 scsi_changer *ch = container_of(ref, scsi_changer, ref); in ch_destroy() local
578 ch->device = NULL; in ch_destroy()
579 kfree(ch->dt); in ch_destroy()
580 kfree(ch); in ch_destroy()
586 scsi_changer *ch = file->private_data; in ch_release() local
588 scsi_device_put(ch->device); in ch_release()
589 file->private_data = NULL; in ch_release()
590 kref_put(&ch->ref, ch_destroy); in ch_release()
597 scsi_changer *ch; in ch_open() local
601 ch = idr_find(&ch_index_idr, minor); in ch_open()
603 if (ch == NULL || !kref_get_unless_zero(&ch->ref)) { in ch_open()
605 return -ENXIO; in ch_open()
608 if (scsi_device_get(ch->device)) { in ch_open()
609 kref_put(&ch->ref, ch_destroy); in ch_open()
610 return -ENXIO; in ch_open()
613 mutex_lock(&ch->lock); in ch_open()
614 file->private_data = ch; in ch_open()
615 mutex_unlock(&ch->lock); in ch_open()
620 ch_checkrange(scsi_changer *ch, unsigned int type, unsigned int unit) in ch_checkrange() argument
622 if (type >= CH_TYPES || unit >= ch->counts[type]) in ch_checkrange()
623 return -1; in ch_checkrange()
636 scsi_changer *ch = file->private_data; in ch_ioctl() local
640 retval = scsi_ioctl_block_when_processing_errors(ch->device, cmd, in ch_ioctl()
641 file->f_flags & O_NDELAY); in ch_ioctl()
651 params.cp_npickers = ch->counts[CHET_MT]; in ch_ioctl()
652 params.cp_nslots = ch->counts[CHET_ST]; in ch_ioctl()
653 params.cp_nportals = ch->counts[CHET_IE]; in ch_ioctl()
654 params.cp_ndrives = ch->counts[CHET_DT]; in ch_ioctl()
657 return -EFAULT; in ch_ioctl()
665 if (ch->counts[CHET_V1]) { in ch_ioctl()
666 vparams.cvp_n1 = ch->counts[CHET_V1]; in ch_ioctl()
670 if (ch->counts[CHET_V2]) { in ch_ioctl()
671 vparams.cvp_n2 = ch->counts[CHET_V2]; in ch_ioctl()
675 if (ch->counts[CHET_V3]) { in ch_ioctl()
676 vparams.cvp_n3 = ch->counts[CHET_V3]; in ch_ioctl()
680 if (ch->counts[CHET_V4]) { in ch_ioctl()
681 vparams.cvp_n4 = ch->counts[CHET_V4]; in ch_ioctl()
686 return -EFAULT; in ch_ioctl()
695 return -EFAULT; in ch_ioctl()
697 if (0 != ch_checkrange(ch, pos.cp_type, pos.cp_unit)) { in ch_ioctl()
699 return -EBADSLT; in ch_ioctl()
701 mutex_lock(&ch->lock); in ch_ioctl()
702 retval = ch_position(ch,0, in ch_ioctl()
703 ch->firsts[pos.cp_type] + pos.cp_unit, in ch_ioctl()
705 mutex_unlock(&ch->lock); in ch_ioctl()
714 return -EFAULT; in ch_ioctl()
716 if (0 != ch_checkrange(ch, mv.cm_fromtype, mv.cm_fromunit) || in ch_ioctl()
717 0 != ch_checkrange(ch, mv.cm_totype, mv.cm_tounit )) { in ch_ioctl()
719 return -EBADSLT; in ch_ioctl()
722 mutex_lock(&ch->lock); in ch_ioctl()
723 retval = ch_move(ch,0, in ch_ioctl()
724 ch->firsts[mv.cm_fromtype] + mv.cm_fromunit, in ch_ioctl()
725 ch->firsts[mv.cm_totype] + mv.cm_tounit, in ch_ioctl()
727 mutex_unlock(&ch->lock); in ch_ioctl()
736 return -EFAULT; in ch_ioctl()
738 if (0 != ch_checkrange(ch, mv.ce_srctype, mv.ce_srcunit ) || in ch_ioctl()
739 0 != ch_checkrange(ch, mv.ce_fdsttype, mv.ce_fdstunit) || in ch_ioctl()
740 0 != ch_checkrange(ch, mv.ce_sdsttype, mv.ce_sdstunit)) { in ch_ioctl()
742 return -EBADSLT; in ch_ioctl()
745 mutex_lock(&ch->lock); in ch_ioctl()
747 (ch,0, in ch_ioctl()
748 ch->firsts[mv.ce_srctype] + mv.ce_srcunit, in ch_ioctl()
749 ch->firsts[mv.ce_fdsttype] + mv.ce_fdstunit, in ch_ioctl()
750 ch->firsts[mv.ce_sdsttype] + mv.ce_sdstunit, in ch_ioctl()
752 mutex_unlock(&ch->lock); in ch_ioctl()
761 return -EFAULT; in ch_ioctl()
763 return -EINVAL; in ch_ioctl()
765 return ch_gstatus(ch, ces.ces_type, ces.ces_data); in ch_ioctl()
773 return -EFAULT; in ch_ioctl()
775 return -EINVAL; in ch_ioctl()
777 return ch_gstatus(ch, ces32.ces_type, in ch_ioctl()
790 return -EFAULT; in ch_ioctl()
792 if (0 != ch_checkrange(ch, cge.cge_type, cge.cge_unit)) in ch_ioctl()
793 return -EINVAL; in ch_ioctl()
794 elem = ch->firsts[cge.cge_type] + cge.cge_unit; in ch_ioctl()
798 return -ENOMEM; in ch_ioctl()
799 mutex_lock(&ch->lock); in ch_ioctl()
804 ch_cmd[1] = ((ch->device->lun & 0x7) << 5) | in ch_ioctl()
805 (ch->voltags ? 0x10 : 0) | in ch_ioctl()
806 ch_elem_to_typecode(ch,elem); in ch_ioctl()
812 result = ch_do_scsi(ch, ch_cmd, 12, buffer, 256, REQ_OP_DRV_IN); in ch_ioctl()
824 for (i = 0; i < 4; i++) { in ch_ioctl()
825 if (elem >= ch->firsts[i] && in ch_ioctl()
826 elem < ch->firsts[i] + ch->counts[i]) { in ch_ioctl()
828 cge.cge_srcunit = elem-ch->firsts[i]; in ch_ioctl()
845 } else if (ch->voltags) { in ch_ioctl()
846 ch->voltags = 0; in ch_ioctl()
851 mutex_unlock(&ch->lock); in ch_ioctl()
854 return -EFAULT; in ch_ioctl()
860 mutex_lock(&ch->lock); in ch_ioctl()
861 retval = ch_init_elem(ch); in ch_ioctl()
862 mutex_unlock(&ch->lock); in ch_ioctl()
872 return -EFAULT; in ch_ioctl()
874 if (0 != ch_checkrange(ch, csv.csv_type, csv.csv_unit)) { in ch_ioctl()
876 return -EBADSLT; in ch_ioctl()
878 elem = ch->firsts[csv.csv_type] + csv.csv_unit; in ch_ioctl()
879 mutex_lock(&ch->lock); in ch_ioctl()
880 retval = ch_set_voltag(ch, elem, in ch_ioctl()
884 mutex_unlock(&ch->lock); in ch_ioctl()
889 return scsi_ioctl(ch->device, file->f_mode & FMODE_WRITE, cmd, in ch_ioctl()
895 /* ------------------------------------------------------------------------ */
902 scsi_changer *ch; in ch_probe() local
904 if (sd->type != TYPE_MEDIUM_CHANGER) in ch_probe()
905 return -ENODEV; in ch_probe()
907 ch = kzalloc(sizeof(*ch), GFP_KERNEL); in ch_probe()
908 if (NULL == ch) in ch_probe()
909 return -ENOMEM; in ch_probe()
913 ret = idr_alloc(&ch_index_idr, ch, 0, CH_MAX_DEVS + 1, GFP_NOWAIT); in ch_probe()
918 if (ret == -ENOSPC) in ch_probe()
919 ret = -ENODEV; in ch_probe()
923 ch->minor = ret; in ch_probe()
924 sprintf(ch->name,"ch%d",ch->minor); in ch_probe()
927 sdev_printk(KERN_WARNING, sd, "ch%d: failed to get device\n", in ch_probe()
928 ch->minor); in ch_probe()
932 mutex_init(&ch->lock); in ch_probe()
933 kref_init(&ch->ref); in ch_probe()
934 ch->device = sd; in ch_probe()
936 MKDEV(SCSI_CHANGER_MAJOR, ch->minor), ch, in ch_probe()
937 "s%s", ch->name); in ch_probe()
939 sdev_printk(KERN_WARNING, sd, "ch%d: device_create failed\n", in ch_probe()
940 ch->minor); in ch_probe()
945 mutex_lock(&ch->lock); in ch_probe()
946 ret = ch_readconfig(ch); in ch_probe()
948 mutex_unlock(&ch->lock); in ch_probe()
952 ch_init_elem(ch); in ch_probe()
954 mutex_unlock(&ch->lock); in ch_probe()
955 dev_set_drvdata(dev, ch); in ch_probe()
956 sdev_printk(KERN_INFO, sd, "Attached scsi changer %s\n", ch->name); in ch_probe()
960 device_destroy(&ch_sysfs_class, MKDEV(SCSI_CHANGER_MAJOR, ch->minor)); in ch_probe()
964 idr_remove(&ch_index_idr, ch->minor); in ch_probe()
966 kfree(ch); in ch_probe()
972 scsi_changer *ch = dev_get_drvdata(dev); in ch_remove() local
975 idr_remove(&ch_index_idr, ch->minor); in ch_remove()
979 device_destroy(&ch_sysfs_class, MKDEV(SCSI_CHANGER_MAJOR, ch->minor)); in ch_remove()
980 scsi_device_put(ch->device); in ch_remove()
981 kref_put(&ch->ref, ch_destroy); in ch_remove()
987 .name = "ch",
1011 rc = register_chrdev(SCSI_CHANGER_MAJOR,"ch",&changer_fops); in init_ch_module()
1013 printk("Unable to get major %d for SCSI-Changer\n", in init_ch_module()
1023 unregister_chrdev(SCSI_CHANGER_MAJOR, "ch"); in init_ch_module()
1032 unregister_chrdev(SCSI_CHANGER_MAJOR, "ch"); in exit_ch_module()