^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * SCSI Media Changer device driver for Linux 2.6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * (c) 1996-2003 Gerd Knorr <kraxel@bytesex.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #define VERSION "0.25"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/fs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/major.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/blkdev.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/completion.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/compat.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/chio.h> /* here are all the ioctls */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/mutex.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/idr.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <scsi/scsi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <scsi/scsi_cmnd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <scsi/scsi_driver.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <scsi/scsi_ioctl.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <scsi/scsi_host.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include <scsi/scsi_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #include <scsi/scsi_eh.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #include <scsi/scsi_dbg.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define CH_DT_MAX 16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define CH_TYPES 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define CH_MAX_DEVS 128
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) MODULE_DESCRIPTION("device driver for scsi media changer devices");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) MODULE_ALIAS_CHARDEV_MAJOR(SCSI_CHANGER_MAJOR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) MODULE_ALIAS_SCSI_DEVICE(TYPE_MEDIUM_CHANGER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) static int init = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) module_param(init, int, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) MODULE_PARM_DESC(init, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) "initialize element status on driver load (default: on)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) static int timeout_move = 300;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) module_param(timeout_move, int, 0644);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) MODULE_PARM_DESC(timeout_move,"timeout for move commands "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) "(default: 300 seconds)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) static int timeout_init = 3600;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) module_param(timeout_init, int, 0644);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) MODULE_PARM_DESC(timeout_init,"timeout for INITIALIZE ELEMENT STATUS "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) "(default: 3600 seconds)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) static int verbose = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) module_param(verbose, int, 0644);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) MODULE_PARM_DESC(verbose,"be verbose (default: on)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) static int debug = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) module_param(debug, int, 0644);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) MODULE_PARM_DESC(debug,"enable/disable debug messages, also prints more "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) "detailed sense codes on scsi errors (default: off)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) static int dt_id[CH_DT_MAX] = { [ 0 ... (CH_DT_MAX-1) ] = -1 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) static int dt_lun[CH_DT_MAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) module_param_array(dt_id, int, NULL, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) module_param_array(dt_lun, int, NULL, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) /* tell the driver about vendor-specific slots */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) static int vendor_firsts[CH_TYPES-4];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) static int vendor_counts[CH_TYPES-4];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) module_param_array(vendor_firsts, int, NULL, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) module_param_array(vendor_counts, int, NULL, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) static const char * vendor_labels[CH_TYPES-4] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) "v0", "v1", "v2", "v3"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) // module_param_string_array(vendor_labels, NULL, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) #define ch_printk(prefix, ch, fmt, a...) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) sdev_prefix_printk(prefix, (ch)->device, (ch)->name, fmt, ##a)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) #define DPRINTK(fmt, arg...) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) do { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) if (debug) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) ch_printk(KERN_DEBUG, ch, fmt, ##arg); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) } while (0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) #define VPRINTK(level, fmt, arg...) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) do { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) if (verbose) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) ch_printk(level, ch, fmt, ##arg); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) } while (0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) /* ------------------------------------------------------------------- */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) #define MAX_RETRIES 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) static struct class * ch_sysfs_class;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) typedef struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) struct kref ref;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) struct list_head list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) int minor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) char name[8];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) struct scsi_device *device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) struct scsi_device **dt; /* ptrs to data transfer elements */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) u_int firsts[CH_TYPES];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) u_int counts[CH_TYPES];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) u_int unit_attention;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) u_int voltags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) struct mutex lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) } scsi_changer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) static DEFINE_IDR(ch_index_idr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) static DEFINE_SPINLOCK(ch_index_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) static const struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) unsigned char sense;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) unsigned char asc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) unsigned char ascq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) int errno;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) } ch_err[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) /* Just filled in what looks right. Hav'nt checked any standard paper for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) these errno assignments, so they may be wrong... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) .sense = ILLEGAL_REQUEST,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) .asc = 0x21,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) .ascq = 0x01,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) .errno = EBADSLT, /* Invalid element address */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) },{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) .sense = ILLEGAL_REQUEST,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) .asc = 0x28,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) .ascq = 0x01,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) .errno = EBADE, /* Import or export element accessed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) },{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) .sense = ILLEGAL_REQUEST,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) .asc = 0x3B,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) .ascq = 0x0D,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) .errno = EXFULL, /* Medium destination element full */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) },{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) .sense = ILLEGAL_REQUEST,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) .asc = 0x3B,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) .ascq = 0x0E,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) .errno = EBADE, /* Medium source element empty */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) },{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) .sense = ILLEGAL_REQUEST,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) .asc = 0x20,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) .ascq = 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) .errno = EBADRQC, /* Invalid command operation code */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) },{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) /* end of list */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) /* ------------------------------------------------------------------- */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) static int ch_find_errno(struct scsi_sense_hdr *sshdr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) int i,errno = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) /* Check to see if additional sense information is available */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) if (scsi_sense_valid(sshdr) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) sshdr->asc != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) for (i = 0; ch_err[i].errno != 0; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) if (ch_err[i].sense == sshdr->sense_key &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) ch_err[i].asc == sshdr->asc &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) ch_err[i].ascq == sshdr->ascq) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) errno = -ch_err[i].errno;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) if (errno == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) errno = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) return errno;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) ch_do_scsi(scsi_changer *ch, unsigned char *cmd, int cmd_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) void *buffer, unsigned buflength,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) enum dma_data_direction direction)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) int errno, retries = 0, timeout, result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) struct scsi_sense_hdr sshdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) timeout = (cmd[0] == INITIALIZE_ELEMENT_STATUS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) ? timeout_init : timeout_move;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) retry:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) errno = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) result = scsi_execute_req(ch->device, cmd, direction, buffer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) buflength, &sshdr, timeout * HZ,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) MAX_RETRIES, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) if (driver_byte(result) == DRIVER_SENSE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) if (debug)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) scsi_print_sense_hdr(ch->device, ch->name, &sshdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) errno = ch_find_errno(&sshdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) switch(sshdr.sense_key) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) case UNIT_ATTENTION:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) ch->unit_attention = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) if (retries++ < 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) goto retry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) return errno;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) /* ------------------------------------------------------------------------ */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) ch_elem_to_typecode(scsi_changer *ch, u_int elem)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) for (i = 0; i < CH_TYPES; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) if (elem >= ch->firsts[i] &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) elem < ch->firsts[i] +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) ch->counts[i])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) return i+1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) ch_read_element_status(scsi_changer *ch, u_int elem, char *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) u_char cmd[12];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) u_char *buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) int result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) buffer = kmalloc(512, GFP_KERNEL | GFP_DMA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) if(!buffer)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) retry:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) memset(cmd,0,sizeof(cmd));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) cmd[0] = READ_ELEMENT_STATUS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) cmd[1] = ((ch->device->lun & 0x7) << 5) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) (ch->voltags ? 0x10 : 0) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) ch_elem_to_typecode(ch,elem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) cmd[2] = (elem >> 8) & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) cmd[3] = elem & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) cmd[5] = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) cmd[9] = 255;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) if (0 == (result = ch_do_scsi(ch, cmd, 12,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) buffer, 256, DMA_FROM_DEVICE))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) if (((buffer[16] << 8) | buffer[17]) != elem) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) DPRINTK("asked for element 0x%02x, got 0x%02x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) elem,(buffer[16] << 8) | buffer[17]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) kfree(buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) memcpy(data,buffer+16,16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) if (ch->voltags) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) ch->voltags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) VPRINTK(KERN_INFO, "device has no volume tag support\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) goto retry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) DPRINTK("READ ELEMENT STATUS for element 0x%x failed\n",elem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) kfree(buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) ch_init_elem(scsi_changer *ch)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) u_char cmd[6];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) VPRINTK(KERN_INFO, "INITIALIZE ELEMENT STATUS, may take some time ...\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) memset(cmd,0,sizeof(cmd));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) cmd[0] = INITIALIZE_ELEMENT_STATUS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) cmd[1] = (ch->device->lun & 0x7) << 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) err = ch_do_scsi(ch, cmd, 6, NULL, 0, DMA_NONE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) VPRINTK(KERN_INFO, "... finished\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) ch_readconfig(scsi_changer *ch)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) u_char cmd[10], data[16];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) u_char *buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) int result,id,lun,i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) u_int elem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) buffer = kzalloc(512, GFP_KERNEL | GFP_DMA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) if (!buffer)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) memset(cmd,0,sizeof(cmd));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) cmd[0] = MODE_SENSE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) cmd[1] = (ch->device->lun & 0x7) << 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) cmd[2] = 0x1d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) cmd[4] = 255;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) result = ch_do_scsi(ch, cmd, 10, buffer, 255, DMA_FROM_DEVICE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) if (0 != result) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) cmd[1] |= (1<<3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) result = ch_do_scsi(ch, cmd, 10, buffer, 255, DMA_FROM_DEVICE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) if (0 == result) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) ch->firsts[CHET_MT] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) (buffer[buffer[3]+ 6] << 8) | buffer[buffer[3]+ 7];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) ch->counts[CHET_MT] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) (buffer[buffer[3]+ 8] << 8) | buffer[buffer[3]+ 9];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) ch->firsts[CHET_ST] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) (buffer[buffer[3]+10] << 8) | buffer[buffer[3]+11];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) ch->counts[CHET_ST] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) (buffer[buffer[3]+12] << 8) | buffer[buffer[3]+13];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) ch->firsts[CHET_IE] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) (buffer[buffer[3]+14] << 8) | buffer[buffer[3]+15];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) ch->counts[CHET_IE] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) (buffer[buffer[3]+16] << 8) | buffer[buffer[3]+17];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) ch->firsts[CHET_DT] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) (buffer[buffer[3]+18] << 8) | buffer[buffer[3]+19];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) ch->counts[CHET_DT] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) (buffer[buffer[3]+20] << 8) | buffer[buffer[3]+21];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) VPRINTK(KERN_INFO, "type #1 (mt): 0x%x+%d [medium transport]\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) ch->firsts[CHET_MT],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) ch->counts[CHET_MT]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) VPRINTK(KERN_INFO, "type #2 (st): 0x%x+%d [storage]\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) ch->firsts[CHET_ST],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) ch->counts[CHET_ST]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) VPRINTK(KERN_INFO, "type #3 (ie): 0x%x+%d [import/export]\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) ch->firsts[CHET_IE],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) ch->counts[CHET_IE]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) VPRINTK(KERN_INFO, "type #4 (dt): 0x%x+%d [data transfer]\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) ch->firsts[CHET_DT],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) ch->counts[CHET_DT]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) VPRINTK(KERN_INFO, "reading element address assignment page failed!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) /* vendor specific element types */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) for (i = 0; i < 4; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) if (0 == vendor_counts[i])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) if (NULL == vendor_labels[i])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) ch->firsts[CHET_V1+i] = vendor_firsts[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) ch->counts[CHET_V1+i] = vendor_counts[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) VPRINTK(KERN_INFO, "type #%d (v%d): 0x%x+%d [%s, vendor specific]\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) i+5,i+1,vendor_firsts[i],vendor_counts[i],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) vendor_labels[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) /* look up the devices of the data transfer elements */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) ch->dt = kcalloc(ch->counts[CHET_DT], sizeof(*ch->dt),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) if (!ch->dt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) kfree(buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) for (elem = 0; elem < ch->counts[CHET_DT]; elem++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) id = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) lun = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) if (elem < CH_DT_MAX && -1 != dt_id[elem]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) id = dt_id[elem];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) lun = dt_lun[elem];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) VPRINTK(KERN_INFO, "dt 0x%x: [insmod option] ",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) elem+ch->firsts[CHET_DT]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) } else if (0 != ch_read_element_status
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) (ch,elem+ch->firsts[CHET_DT],data)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) VPRINTK(KERN_INFO, "dt 0x%x: READ ELEMENT STATUS failed\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) elem+ch->firsts[CHET_DT]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) VPRINTK(KERN_INFO, "dt 0x%x: ",elem+ch->firsts[CHET_DT]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) if (data[6] & 0x80) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) VPRINTK(KERN_CONT, "not this SCSI bus\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) ch->dt[elem] = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) } else if (0 == (data[6] & 0x30)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) VPRINTK(KERN_CONT, "ID/LUN unknown\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) ch->dt[elem] = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) id = ch->device->id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) lun = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) if (data[6] & 0x20) id = data[7];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) if (data[6] & 0x10) lun = data[6] & 7;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) if (-1 != id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) VPRINTK(KERN_CONT, "ID %i, LUN %i, ",id,lun);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) ch->dt[elem] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) scsi_device_lookup(ch->device->host,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) ch->device->channel,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) id,lun);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) if (!ch->dt[elem]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) /* should not happen */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) VPRINTK(KERN_CONT, "Huh? device not found!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) VPRINTK(KERN_CONT, "name: %8.8s %16.16s %4.4s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) ch->dt[elem]->vendor,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) ch->dt[elem]->model,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) ch->dt[elem]->rev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) ch->voltags = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) kfree(buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) /* ------------------------------------------------------------------------ */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) ch_position(scsi_changer *ch, u_int trans, u_int elem, int rotate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) u_char cmd[10];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) DPRINTK("position: 0x%x\n",elem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) if (0 == trans)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) trans = ch->firsts[CHET_MT];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) memset(cmd,0,sizeof(cmd));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) cmd[0] = POSITION_TO_ELEMENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) cmd[1] = (ch->device->lun & 0x7) << 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) cmd[2] = (trans >> 8) & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) cmd[3] = trans & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) cmd[4] = (elem >> 8) & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) cmd[5] = elem & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) cmd[8] = rotate ? 1 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) return ch_do_scsi(ch, cmd, 10, NULL, 0, DMA_NONE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) ch_move(scsi_changer *ch, u_int trans, u_int src, u_int dest, int rotate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) u_char cmd[12];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) DPRINTK("move: 0x%x => 0x%x\n",src,dest);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) if (0 == trans)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) trans = ch->firsts[CHET_MT];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) memset(cmd,0,sizeof(cmd));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) cmd[0] = MOVE_MEDIUM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) cmd[1] = (ch->device->lun & 0x7) << 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) cmd[2] = (trans >> 8) & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) cmd[3] = trans & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) cmd[4] = (src >> 8) & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) cmd[5] = src & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) cmd[6] = (dest >> 8) & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) cmd[7] = dest & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) cmd[10] = rotate ? 1 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) return ch_do_scsi(ch, cmd, 12, NULL,0, DMA_NONE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) ch_exchange(scsi_changer *ch, u_int trans, u_int src,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) u_int dest1, u_int dest2, int rotate1, int rotate2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) u_char cmd[12];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) DPRINTK("exchange: 0x%x => 0x%x => 0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) src,dest1,dest2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) if (0 == trans)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) trans = ch->firsts[CHET_MT];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) memset(cmd,0,sizeof(cmd));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) cmd[0] = EXCHANGE_MEDIUM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) cmd[1] = (ch->device->lun & 0x7) << 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) cmd[2] = (trans >> 8) & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) cmd[3] = trans & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) cmd[4] = (src >> 8) & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) cmd[5] = src & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) cmd[6] = (dest1 >> 8) & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) cmd[7] = dest1 & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) cmd[8] = (dest2 >> 8) & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) cmd[9] = dest2 & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) cmd[10] = (rotate1 ? 1 : 0) | (rotate2 ? 2 : 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) return ch_do_scsi(ch, cmd, 12, NULL, 0, DMA_NONE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) ch_check_voltag(char *tag)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) for (i = 0; i < 32; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) /* restrict to ascii */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) if (tag[i] >= 0x7f || tag[i] < 0x20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) tag[i] = ' ';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) /* don't allow search wildcards */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) if (tag[i] == '?' ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) tag[i] == '*')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) tag[i] = ' ';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) ch_set_voltag(scsi_changer *ch, u_int elem,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) int alternate, int clear, u_char *tag)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) u_char cmd[12];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) u_char *buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) int result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) buffer = kzalloc(512, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) if (!buffer)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) DPRINTK("%s %s voltag: 0x%x => \"%s\"\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) clear ? "clear" : "set",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) alternate ? "alternate" : "primary",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) elem, tag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) memset(cmd,0,sizeof(cmd));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) cmd[0] = SEND_VOLUME_TAG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) cmd[1] = ((ch->device->lun & 0x7) << 5) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) ch_elem_to_typecode(ch,elem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) cmd[2] = (elem >> 8) & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) cmd[3] = elem & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) cmd[5] = clear
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) ? (alternate ? 0x0d : 0x0c)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) : (alternate ? 0x0b : 0x0a);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) cmd[9] = 255;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) memcpy(buffer,tag,32);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) ch_check_voltag(buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) result = ch_do_scsi(ch, cmd, 12, buffer, 256, DMA_TO_DEVICE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) kfree(buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) static int ch_gstatus(scsi_changer *ch, int type, unsigned char __user *dest)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) int retval = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) u_char data[16];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) mutex_lock(&ch->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) for (i = 0; i < ch->counts[type]; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) if (0 != ch_read_element_status
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) (ch, ch->firsts[type]+i,data)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) retval = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) put_user(data[2], dest+i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) if (data[2] & CESTATUS_EXCEPT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) VPRINTK(KERN_INFO, "element 0x%x: asc=0x%x, ascq=0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) ch->firsts[type]+i,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) (int)data[4],(int)data[5]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) retval = ch_read_element_status
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) (ch, ch->firsts[type]+i,data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) if (0 != retval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) mutex_unlock(&ch->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) /* ------------------------------------------------------------------------ */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) static void ch_destroy(struct kref *ref)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) scsi_changer *ch = container_of(ref, scsi_changer, ref);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) ch->device = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) kfree(ch->dt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) kfree(ch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) ch_release(struct inode *inode, struct file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) scsi_changer *ch = file->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) scsi_device_put(ch->device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) file->private_data = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) kref_put(&ch->ref, ch_destroy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) ch_open(struct inode *inode, struct file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) scsi_changer *ch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) int minor = iminor(inode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) spin_lock(&ch_index_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) ch = idr_find(&ch_index_idr, minor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) if (ch == NULL || !kref_get_unless_zero(&ch->ref)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) spin_unlock(&ch_index_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) spin_unlock(&ch_index_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) if (scsi_device_get(ch->device)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) kref_put(&ch->ref, ch_destroy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) /* Synchronize with ch_probe() */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) mutex_lock(&ch->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) file->private_data = ch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) mutex_unlock(&ch->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) ch_checkrange(scsi_changer *ch, unsigned int type, unsigned int unit)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) if (type >= CH_TYPES || unit >= ch->counts[type])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) static long ch_ioctl(struct file *file,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) unsigned int cmd, unsigned long arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) scsi_changer *ch = file->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) int retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) void __user *argp = (void __user *)arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) retval = scsi_ioctl_block_when_processing_errors(ch->device, cmd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) file->f_flags & O_NDELAY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) if (retval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) switch (cmd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) case CHIOGPARAMS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) struct changer_params params;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) params.cp_curpicker = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) params.cp_npickers = ch->counts[CHET_MT];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) params.cp_nslots = ch->counts[CHET_ST];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) params.cp_nportals = ch->counts[CHET_IE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) params.cp_ndrives = ch->counts[CHET_DT];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) if (copy_to_user(argp, ¶ms, sizeof(params)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) case CHIOGVPARAMS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) struct changer_vendor_params vparams;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) memset(&vparams,0,sizeof(vparams));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) if (ch->counts[CHET_V1]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) vparams.cvp_n1 = ch->counts[CHET_V1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) strncpy(vparams.cvp_label1,vendor_labels[0],16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) if (ch->counts[CHET_V2]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) vparams.cvp_n2 = ch->counts[CHET_V2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) strncpy(vparams.cvp_label2,vendor_labels[1],16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) if (ch->counts[CHET_V3]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) vparams.cvp_n3 = ch->counts[CHET_V3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) strncpy(vparams.cvp_label3,vendor_labels[2],16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) if (ch->counts[CHET_V4]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) vparams.cvp_n4 = ch->counts[CHET_V4];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) strncpy(vparams.cvp_label4,vendor_labels[3],16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) if (copy_to_user(argp, &vparams, sizeof(vparams)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) case CHIOPOSITION:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) struct changer_position pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) if (copy_from_user(&pos, argp, sizeof (pos)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) if (0 != ch_checkrange(ch, pos.cp_type, pos.cp_unit)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) DPRINTK("CHIOPOSITION: invalid parameter\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) return -EBADSLT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) mutex_lock(&ch->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) retval = ch_position(ch,0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) ch->firsts[pos.cp_type] + pos.cp_unit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) pos.cp_flags & CP_INVERT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) mutex_unlock(&ch->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) case CHIOMOVE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) struct changer_move mv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) if (copy_from_user(&mv, argp, sizeof (mv)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) if (0 != ch_checkrange(ch, mv.cm_fromtype, mv.cm_fromunit) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) 0 != ch_checkrange(ch, mv.cm_totype, mv.cm_tounit )) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) DPRINTK("CHIOMOVE: invalid parameter\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) return -EBADSLT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) mutex_lock(&ch->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) retval = ch_move(ch,0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) ch->firsts[mv.cm_fromtype] + mv.cm_fromunit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) ch->firsts[mv.cm_totype] + mv.cm_tounit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) mv.cm_flags & CM_INVERT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) mutex_unlock(&ch->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) case CHIOEXCHANGE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) struct changer_exchange mv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) if (copy_from_user(&mv, argp, sizeof (mv)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) if (0 != ch_checkrange(ch, mv.ce_srctype, mv.ce_srcunit ) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) 0 != ch_checkrange(ch, mv.ce_fdsttype, mv.ce_fdstunit) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) 0 != ch_checkrange(ch, mv.ce_sdsttype, mv.ce_sdstunit)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) DPRINTK("CHIOEXCHANGE: invalid parameter\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) return -EBADSLT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) mutex_lock(&ch->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) retval = ch_exchange
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) (ch,0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) ch->firsts[mv.ce_srctype] + mv.ce_srcunit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) ch->firsts[mv.ce_fdsttype] + mv.ce_fdstunit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) ch->firsts[mv.ce_sdsttype] + mv.ce_sdstunit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) mv.ce_flags & CE_INVERT1, mv.ce_flags & CE_INVERT2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) mutex_unlock(&ch->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) case CHIOGSTATUS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) struct changer_element_status ces;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) if (copy_from_user(&ces, argp, sizeof (ces)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) if (ces.ces_type < 0 || ces.ces_type >= CH_TYPES)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) return ch_gstatus(ch, ces.ces_type, ces.ces_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) case CHIOGELEM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) struct changer_get_element cge;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) u_char ch_cmd[12];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) u_char *buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) unsigned int elem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) int result,i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) if (copy_from_user(&cge, argp, sizeof (cge)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) if (0 != ch_checkrange(ch, cge.cge_type, cge.cge_unit))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) elem = ch->firsts[cge.cge_type] + cge.cge_unit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) buffer = kmalloc(512, GFP_KERNEL | GFP_DMA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) if (!buffer)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) mutex_lock(&ch->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) voltag_retry:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) memset(ch_cmd, 0, sizeof(ch_cmd));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) ch_cmd[0] = READ_ELEMENT_STATUS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) ch_cmd[1] = ((ch->device->lun & 0x7) << 5) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) (ch->voltags ? 0x10 : 0) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) ch_elem_to_typecode(ch,elem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) ch_cmd[2] = (elem >> 8) & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) ch_cmd[3] = elem & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) ch_cmd[5] = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) ch_cmd[9] = 255;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) result = ch_do_scsi(ch, ch_cmd, 12,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) buffer, 256, DMA_FROM_DEVICE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) if (!result) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) cge.cge_status = buffer[18];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) cge.cge_flags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) if (buffer[18] & CESTATUS_EXCEPT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) cge.cge_errno = EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) if (buffer[25] & 0x80) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) cge.cge_flags |= CGE_SRC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) if (buffer[25] & 0x40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) cge.cge_flags |= CGE_INVERT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) elem = (buffer[26]<<8) | buffer[27];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) for (i = 0; i < 4; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) if (elem >= ch->firsts[i] &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) elem < ch->firsts[i] + ch->counts[i]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) cge.cge_srctype = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) cge.cge_srcunit = elem-ch->firsts[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) if ((buffer[22] & 0x30) == 0x30) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) cge.cge_flags |= CGE_IDLUN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) cge.cge_id = buffer[23];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) cge.cge_lun = buffer[22] & 7;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) if (buffer[9] & 0x80) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) cge.cge_flags |= CGE_PVOLTAG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) memcpy(cge.cge_pvoltag,buffer+28,36);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) if (buffer[9] & 0x40) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) cge.cge_flags |= CGE_AVOLTAG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) memcpy(cge.cge_avoltag,buffer+64,36);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) } else if (ch->voltags) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) ch->voltags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) VPRINTK(KERN_INFO, "device has no volume tag support\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) goto voltag_retry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) kfree(buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) mutex_unlock(&ch->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) if (copy_to_user(argp, &cge, sizeof (cge)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) case CHIOINITELEM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) mutex_lock(&ch->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) retval = ch_init_elem(ch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) mutex_unlock(&ch->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) case CHIOSVOLTAG:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) struct changer_set_voltag csv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) int elem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) if (copy_from_user(&csv, argp, sizeof(csv)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) if (0 != ch_checkrange(ch, csv.csv_type, csv.csv_unit)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) DPRINTK("CHIOSVOLTAG: invalid parameter\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) return -EBADSLT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) elem = ch->firsts[csv.csv_type] + csv.csv_unit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) mutex_lock(&ch->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) retval = ch_set_voltag(ch, elem,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) csv.csv_flags & CSV_AVOLTAG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) csv.csv_flags & CSV_CLEARTAG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) csv.csv_voltag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) mutex_unlock(&ch->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) return scsi_ioctl(ch->device, cmd, argp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) #ifdef CONFIG_COMPAT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) struct changer_element_status32 {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) int ces_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) compat_uptr_t ces_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) #define CHIOGSTATUS32 _IOW('c', 8,struct changer_element_status32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) static long ch_ioctl_compat(struct file * file,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) unsigned int cmd, unsigned long arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) scsi_changer *ch = file->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) int retval = scsi_ioctl_block_when_processing_errors(ch->device, cmd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) file->f_flags & O_NDELAY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) if (retval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) switch (cmd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) case CHIOGPARAMS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) case CHIOGVPARAMS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) case CHIOPOSITION:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) case CHIOMOVE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) case CHIOEXCHANGE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) case CHIOGELEM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) case CHIOINITELEM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) case CHIOSVOLTAG:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) /* compatible */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) return ch_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) case CHIOGSTATUS32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) struct changer_element_status32 ces32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) unsigned char __user *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) if (copy_from_user(&ces32, (void __user *)arg, sizeof (ces32)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) if (ces32.ces_type < 0 || ces32.ces_type >= CH_TYPES)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) data = compat_ptr(ces32.ces_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) return ch_gstatus(ch, ces32.ces_type, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) return scsi_compat_ioctl(ch->device, cmd, compat_ptr(arg));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) /* ------------------------------------------------------------------------ */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) static int ch_probe(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) struct scsi_device *sd = to_scsi_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) struct device *class_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) scsi_changer *ch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) if (sd->type != TYPE_MEDIUM_CHANGER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) ch = kzalloc(sizeof(*ch), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) if (NULL == ch)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) idr_preload(GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) spin_lock(&ch_index_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) ret = idr_alloc(&ch_index_idr, ch, 0, CH_MAX_DEVS + 1, GFP_NOWAIT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) spin_unlock(&ch_index_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) idr_preload_end();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) if (ret == -ENOSPC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) ret = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) goto free_ch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) ch->minor = ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) sprintf(ch->name,"ch%d",ch->minor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) ret = scsi_device_get(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) sdev_printk(KERN_WARNING, sd, "ch%d: failed to get device\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) ch->minor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) goto remove_idr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) mutex_init(&ch->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) kref_init(&ch->ref);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) ch->device = sd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) class_dev = device_create(ch_sysfs_class, dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) MKDEV(SCSI_CHANGER_MAJOR, ch->minor), ch,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) "s%s", ch->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) if (IS_ERR(class_dev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) sdev_printk(KERN_WARNING, sd, "ch%d: device_create failed\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) ch->minor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) ret = PTR_ERR(class_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) goto put_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) mutex_lock(&ch->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) ret = ch_readconfig(ch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) mutex_unlock(&ch->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) goto destroy_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) if (init)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) ch_init_elem(ch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) mutex_unlock(&ch->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) dev_set_drvdata(dev, ch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) sdev_printk(KERN_INFO, sd, "Attached scsi changer %s\n", ch->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) destroy_dev:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) device_destroy(ch_sysfs_class, MKDEV(SCSI_CHANGER_MAJOR, ch->minor));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) put_device:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) scsi_device_put(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) remove_idr:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) idr_remove(&ch_index_idr, ch->minor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) free_ch:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) kfree(ch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) static int ch_remove(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) scsi_changer *ch = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) spin_lock(&ch_index_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) idr_remove(&ch_index_idr, ch->minor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) dev_set_drvdata(dev, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) spin_unlock(&ch_index_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) device_destroy(ch_sysfs_class, MKDEV(SCSI_CHANGER_MAJOR,ch->minor));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) scsi_device_put(ch->device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) kref_put(&ch->ref, ch_destroy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) static struct scsi_driver ch_template = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) .gendrv = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) .name = "ch",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) .probe = ch_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) .remove = ch_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) static const struct file_operations changer_fops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) .open = ch_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) .release = ch_release,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) .unlocked_ioctl = ch_ioctl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) #ifdef CONFIG_COMPAT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) .compat_ioctl = ch_ioctl_compat,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) .llseek = noop_llseek,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) static int __init init_ch_module(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) printk(KERN_INFO "SCSI Media Changer driver v" VERSION " \n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) ch_sysfs_class = class_create(THIS_MODULE, "scsi_changer");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) if (IS_ERR(ch_sysfs_class)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) rc = PTR_ERR(ch_sysfs_class);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) rc = register_chrdev(SCSI_CHANGER_MAJOR,"ch",&changer_fops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) if (rc < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) printk("Unable to get major %d for SCSI-Changer\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) SCSI_CHANGER_MAJOR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) goto fail1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) rc = scsi_register_driver(&ch_template.gendrv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) if (rc < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) goto fail2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) fail2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) unregister_chrdev(SCSI_CHANGER_MAJOR, "ch");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) fail1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) class_destroy(ch_sysfs_class);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) static void __exit exit_ch_module(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) scsi_unregister_driver(&ch_template.gendrv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) unregister_chrdev(SCSI_CHANGER_MAJOR, "ch");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) class_destroy(ch_sysfs_class);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) idr_destroy(&ch_index_idr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) module_init(init_ch_module);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) module_exit(exit_ch_module);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) * Local variables:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) * c-basic-offset: 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) * End:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) */