Blame view

drivers/scsi/ch.c 24.3 KB
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
1
2
3
4
5
6
7
8
  /*
   * SCSI Media Changer device driver for Linux 2.6
   *
   *     (c) 1996-2003 Gerd Knorr <kraxel@bytesex.org>
   *
   */
  
  #define VERSION "0.25"
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
9
10
11
12
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/fs.h>
  #include <linux/kernel.h>
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
13
14
15
16
17
18
19
  #include <linux/mm.h>
  #include <linux/major.h>
  #include <linux/string.h>
  #include <linux/errno.h>
  #include <linux/interrupt.h>
  #include <linux/blkdev.h>
  #include <linux/completion.h>
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
20
21
  #include <linux/compat.h>
  #include <linux/chio.h>			/* here are all the ioctls */
0b9506723   Arjan van de Ven   [SCSI] turn most ...
22
  #include <linux/mutex.h>
da707c54c   FUJITA Tomonori   [SCSI] ch: fix de...
23
  #include <linux/idr.h>
b0061a0ec   Jonathan Corbet   changer: BKL push...
24
  #include <linux/smp_lock.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
25
  #include <linux/slab.h>
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
26
27
28
29
30
31
32
  
  #include <scsi/scsi.h>
  #include <scsi/scsi_cmnd.h>
  #include <scsi/scsi_driver.h>
  #include <scsi/scsi_ioctl.h>
  #include <scsi/scsi_host.h>
  #include <scsi/scsi_device.h>
84743bbcf   James Bottomley   [SCSI] convert ch...
33
  #include <scsi/scsi_eh.h>
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
34
35
36
37
  #include <scsi/scsi_dbg.h>
  
  #define CH_DT_MAX       16
  #define CH_TYPES        8
da707c54c   FUJITA Tomonori   [SCSI] ch: fix de...
38
  #define CH_MAX_DEVS     128
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
39
40
41
42
  
  MODULE_DESCRIPTION("device driver for scsi media changer devices");
  MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org>");
  MODULE_LICENSE("GPL");
f018fa552   Rene Herman   [SCSI] MODULE_ALI...
43
  MODULE_ALIAS_CHARDEV_MAJOR(SCSI_CHANGER_MAJOR);
95f6c83f6   Scott James Remnant   [SCSI] ch: Add sc...
44
  MODULE_ALIAS_SCSI_DEVICE(TYPE_MEDIUM_CHANGER);
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
  
  static int init = 1;
  module_param(init, int, 0444);
  MODULE_PARM_DESC(init, \
      "initialize element status on driver load (default: on)");
  
  static int timeout_move = 300;
  module_param(timeout_move, int, 0644);
  MODULE_PARM_DESC(timeout_move,"timeout for move commands "
  		 "(default: 300 seconds)");
  
  static int timeout_init = 3600;
  module_param(timeout_init, int, 0644);
  MODULE_PARM_DESC(timeout_init,"timeout for INITIALIZE ELEMENT STATUS "
  		 "(default: 3600 seconds)");
  
  static int verbose = 1;
  module_param(verbose, int, 0644);
  MODULE_PARM_DESC(verbose,"be verbose (default: on)");
  
  static int debug = 0;
  module_param(debug, int, 0644);
  MODULE_PARM_DESC(debug,"enable/disable debug messages, also prints more "
  		 "detailed sense codes on scsi errors (default: off)");
  
  static int dt_id[CH_DT_MAX] = { [ 0 ... (CH_DT_MAX-1) ] = -1 };
  static int dt_lun[CH_DT_MAX];
  module_param_array(dt_id,  int, NULL, 0444);
  module_param_array(dt_lun, int, NULL, 0444);
  
  /* tell the driver about vendor-specific slots */
  static int vendor_firsts[CH_TYPES-4];
  static int vendor_counts[CH_TYPES-4];
  module_param_array(vendor_firsts, int, NULL, 0444);
  module_param_array(vendor_counts, int, NULL, 0444);
0ad78200b   Arjan van de Ven   [SCSI] Mark some ...
80
  static const char * vendor_labels[CH_TYPES-4] = {
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
81
82
83
  	"v0", "v1", "v2", "v3"
  };
  // module_param_string_array(vendor_labels, NULL, 0444);
87da32356   Joe Perches   drivers/scsi/ch.c...
84
85
86
87
88
89
90
91
92
93
  #define DPRINTK(fmt, arg...)						\
  do {									\
  	if (debug)							\
  		printk(KERN_DEBUG "%s: " fmt, ch->name, ##arg);		\
  } while (0)
  #define VPRINTK(level, fmt, arg...)					\
  do {									\
  	if (verbose)							\
  		printk(level "%s: " fmt, ch->name, ##arg);		\
  } while (0)
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
94
95
96
97
  
  /* ------------------------------------------------------------------- */
  
  #define MAX_RETRIES   1
21feb5ccd   Gerd Knorr   [SCSI] convert sc...
98
  static struct class * ch_sysfs_class;
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
99
100
101
102
103
104
105
106
107
108
109
  
  typedef struct {
  	struct list_head    list;
  	int                 minor;
  	char                name[8];
  	struct scsi_device  *device;
  	struct scsi_device  **dt;        /* ptrs to data transfer elements */
  	u_int               firsts[CH_TYPES];
  	u_int               counts[CH_TYPES];
  	u_int               unit_attention;
  	u_int		    voltags;
0b9506723   Arjan van de Ven   [SCSI] turn most ...
110
  	struct mutex	    lock;
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
111
  } scsi_changer;
da707c54c   FUJITA Tomonori   [SCSI] ch: fix de...
112
113
  static DEFINE_IDR(ch_index_idr);
  static DEFINE_SPINLOCK(ch_index_lock);
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
114

0ad78200b   Arjan van de Ven   [SCSI] Mark some ...
115
  static const struct {
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
116
117
118
119
  	unsigned char  sense;
  	unsigned char  asc;
  	unsigned char  ascq;
  	int	       errno;
d70d4667e   Harvey Harrison   [SCSI] ch: fix sp...
120
  } ch_err[] = {
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
  /* Just filled in what looks right. Hav'nt checked any standard paper for
     these errno assignments, so they may be wrong... */
  	{
  		.sense  = ILLEGAL_REQUEST,
  		.asc    = 0x21,
  		.ascq   = 0x01,
  		.errno  = EBADSLT, /* Invalid element address */
  	},{
  		.sense  = ILLEGAL_REQUEST,
  		.asc    = 0x28,
  		.ascq   = 0x01,
  		.errno  = EBADE,   /* Import or export element accessed */
  	},{
  		.sense  = ILLEGAL_REQUEST,
  		.asc    = 0x3B,
  		.ascq   = 0x0D,
  		.errno  = EXFULL,  /* Medium destination element full */
  	},{
  		.sense  = ILLEGAL_REQUEST,
  		.asc    = 0x3B,
  		.ascq   = 0x0E,
  		.errno  = EBADE,   /* Medium source element empty */
  	},{
  		.sense  = ILLEGAL_REQUEST,
  		.asc    = 0x20,
  		.ascq   = 0x00,
  		.errno  = EBADRQC, /* Invalid command operation code */
  	},{
  	        /* end of list */
  	}
  };
  
  /* ------------------------------------------------------------------- */
84743bbcf   James Bottomley   [SCSI] convert ch...
154
  static int ch_find_errno(struct scsi_sense_hdr *sshdr)
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
155
156
157
158
  {
  	int i,errno = 0;
  
  	/* Check to see if additional sense information is available */
84743bbcf   James Bottomley   [SCSI] convert ch...
159
160
  	if (scsi_sense_valid(sshdr) &&
  	    sshdr->asc != 0) {
d70d4667e   Harvey Harrison   [SCSI] ch: fix sp...
161
162
163
164
165
  		for (i = 0; ch_err[i].errno != 0; i++) {
  			if (ch_err[i].sense == sshdr->sense_key &&
  			    ch_err[i].asc   == sshdr->asc &&
  			    ch_err[i].ascq  == sshdr->ascq) {
  				errno = -ch_err[i].errno;
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
166
167
168
169
170
171
172
173
174
175
176
177
178
179
  				break;
  			}
  		}
  	}
  	if (errno == 0)
  		errno = -EIO;
  	return errno;
  }
  
  static int
  ch_do_scsi(scsi_changer *ch, unsigned char *cmd,
  	   void *buffer, unsigned buflength,
  	   enum dma_data_direction direction)
  {
84743bbcf   James Bottomley   [SCSI] convert ch...
180
181
  	int errno, retries = 0, timeout, result;
  	struct scsi_sense_hdr sshdr;
5aa22af3d   FUJITA Tomonori   [SCSI] ch: remove...
182

daa6eda65   Gerd Knorr   [SCSI] add scsi c...
183
184
185
186
187
188
  	timeout = (cmd[0] == INITIALIZE_ELEMENT_STATUS)
  		? timeout_init : timeout_move;
  
   retry:
  	errno = 0;
  	if (debug) {
87da32356   Joe Perches   drivers/scsi/ch.c...
189
  		DPRINTK("command: ");
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
190
191
  		__scsi_print_command(cmd);
  	}
84743bbcf   James Bottomley   [SCSI] convert ch...
192
193
          result = scsi_execute_req(ch->device, cmd, direction, buffer,
  				  buflength, &sshdr, timeout * HZ,
f4f4e47e4   FUJITA Tomonori   [SCSI] add residu...
194
  				  MAX_RETRIES, NULL);
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
195

87da32356   Joe Perches   drivers/scsi/ch.c...
196
197
  	DPRINTK("result: 0x%x
  ",result);
84743bbcf   James Bottomley   [SCSI] convert ch...
198
  	if (driver_byte(result) & DRIVER_SENSE) {
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
199
  		if (debug)
84743bbcf   James Bottomley   [SCSI] convert ch...
200
201
  			scsi_print_sense_hdr(ch->name, &sshdr);
  		errno = ch_find_errno(&sshdr);
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
202

84743bbcf   James Bottomley   [SCSI] convert ch...
203
  		switch(sshdr.sense_key) {
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
204
205
206
207
208
209
210
  		case UNIT_ATTENTION:
  			ch->unit_attention = 1;
  			if (retries++ < 3)
  				goto retry;
  			break;
  		}
  	}
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
211
212
213
214
215
216
217
218
219
  	return errno;
  }
  
  /* ------------------------------------------------------------------------ */
  
  static int
  ch_elem_to_typecode(scsi_changer *ch, u_int elem)
  {
  	int i;
5aa22af3d   FUJITA Tomonori   [SCSI] ch: remove...
220

daa6eda65   Gerd Knorr   [SCSI] add scsi c...
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
  	for (i = 0; i < CH_TYPES; i++) {
  		if (elem >= ch->firsts[i]  &&
  		    elem <  ch->firsts[i] +
  	            ch->counts[i])
  			return i+1;
  	}
  	return 0;
  }
  
  static int
  ch_read_element_status(scsi_changer *ch, u_int elem, char *data)
  {
  	u_char  cmd[12];
  	u_char  *buffer;
  	int     result;
5aa22af3d   FUJITA Tomonori   [SCSI] ch: remove...
236

daa6eda65   Gerd Knorr   [SCSI] add scsi c...
237
238
239
  	buffer = kmalloc(512, GFP_KERNEL | GFP_DMA);
  	if(!buffer)
  		return -ENOMEM;
5aa22af3d   FUJITA Tomonori   [SCSI] ch: remove...
240

daa6eda65   Gerd Knorr   [SCSI] add scsi c...
241
242
243
   retry:
  	memset(cmd,0,sizeof(cmd));
  	cmd[0] = READ_ELEMENT_STATUS;
5aa22af3d   FUJITA Tomonori   [SCSI] ch: remove...
244
  	cmd[1] = (ch->device->lun << 5) |
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
245
246
247
248
249
250
251
252
  		(ch->voltags ? 0x10 : 0) |
  		ch_elem_to_typecode(ch,elem);
  	cmd[2] = (elem >> 8) & 0xff;
  	cmd[3] = elem        & 0xff;
  	cmd[5] = 1;
  	cmd[9] = 255;
  	if (0 == (result = ch_do_scsi(ch, cmd, buffer, 256, DMA_FROM_DEVICE))) {
  		if (((buffer[16] << 8) | buffer[17]) != elem) {
87da32356   Joe Perches   drivers/scsi/ch.c...
253
254
  			DPRINTK("asked for element 0x%02x, got 0x%02x
  ",
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
255
256
257
258
259
260
261
262
  				elem,(buffer[16] << 8) | buffer[17]);
  			kfree(buffer);
  			return -EIO;
  		}
  		memcpy(data,buffer+16,16);
  	} else {
  		if (ch->voltags) {
  			ch->voltags = 0;
87da32356   Joe Perches   drivers/scsi/ch.c...
263
264
  			VPRINTK(KERN_INFO, "device has no volume tag support
  ");
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
265
266
  			goto retry;
  		}
87da32356   Joe Perches   drivers/scsi/ch.c...
267
268
  		DPRINTK("READ ELEMENT STATUS for element 0x%x failed
  ",elem);
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
269
270
271
272
  	}
  	kfree(buffer);
  	return result;
  }
5aa22af3d   FUJITA Tomonori   [SCSI] ch: remove...
273
  static int
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
274
275
276
277
  ch_init_elem(scsi_changer *ch)
  {
  	int err;
  	u_char cmd[6];
87da32356   Joe Perches   drivers/scsi/ch.c...
278
279
  	VPRINTK(KERN_INFO, "INITIALIZE ELEMENT STATUS, may take some time ...
  ");
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
280
281
282
283
  	memset(cmd,0,sizeof(cmd));
  	cmd[0] = INITIALIZE_ELEMENT_STATUS;
  	cmd[1] = ch->device->lun << 5;
  	err = ch_do_scsi(ch, cmd, NULL, 0, DMA_NONE);
87da32356   Joe Perches   drivers/scsi/ch.c...
284
285
  	VPRINTK(KERN_INFO, "... finished
  ");
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
286
287
288
289
290
291
292
293
294
295
  	return err;
  }
  
  static int
  ch_readconfig(scsi_changer *ch)
  {
  	u_char  cmd[10], data[16];
  	u_char  *buffer;
  	int     result,id,lun,i;
  	u_int   elem;
4530a1696   vignesh.babu@wipro.com   [SCSI] ch: kmallo...
296
  	buffer = kzalloc(512, GFP_KERNEL | GFP_DMA);
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
297
298
  	if (!buffer)
  		return -ENOMEM;
5aa22af3d   FUJITA Tomonori   [SCSI] ch: remove...
299

daa6eda65   Gerd Knorr   [SCSI] add scsi c...
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
  	memset(cmd,0,sizeof(cmd));
  	cmd[0] = MODE_SENSE;
  	cmd[1] = ch->device->lun << 5;
  	cmd[2] = 0x1d;
  	cmd[4] = 255;
  	result = ch_do_scsi(ch, cmd, buffer, 255, DMA_FROM_DEVICE);
  	if (0 != result) {
  		cmd[1] |= (1<<3);
  		result  = ch_do_scsi(ch, cmd, buffer, 255, DMA_FROM_DEVICE);
  	}
  	if (0 == result) {
  		ch->firsts[CHET_MT] =
  			(buffer[buffer[3]+ 6] << 8) | buffer[buffer[3]+ 7];
  		ch->counts[CHET_MT] =
  			(buffer[buffer[3]+ 8] << 8) | buffer[buffer[3]+ 9];
  		ch->firsts[CHET_ST] =
  			(buffer[buffer[3]+10] << 8) | buffer[buffer[3]+11];
  		ch->counts[CHET_ST] =
  			(buffer[buffer[3]+12] << 8) | buffer[buffer[3]+13];
  		ch->firsts[CHET_IE] =
  			(buffer[buffer[3]+14] << 8) | buffer[buffer[3]+15];
  		ch->counts[CHET_IE] =
  			(buffer[buffer[3]+16] << 8) | buffer[buffer[3]+17];
  		ch->firsts[CHET_DT] =
  			(buffer[buffer[3]+18] << 8) | buffer[buffer[3]+19];
  		ch->counts[CHET_DT] =
  			(buffer[buffer[3]+20] << 8) | buffer[buffer[3]+21];
87da32356   Joe Perches   drivers/scsi/ch.c...
327
328
  		VPRINTK(KERN_INFO, "type #1 (mt): 0x%x+%d [medium transport]
  ",
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
329
330
  			ch->firsts[CHET_MT],
  			ch->counts[CHET_MT]);
87da32356   Joe Perches   drivers/scsi/ch.c...
331
332
  		VPRINTK(KERN_INFO, "type #2 (st): 0x%x+%d [storage]
  ",
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
333
334
  			ch->firsts[CHET_ST],
  			ch->counts[CHET_ST]);
87da32356   Joe Perches   drivers/scsi/ch.c...
335
336
  		VPRINTK(KERN_INFO, "type #3 (ie): 0x%x+%d [import/export]
  ",
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
337
338
  			ch->firsts[CHET_IE],
  			ch->counts[CHET_IE]);
87da32356   Joe Perches   drivers/scsi/ch.c...
339
340
  		VPRINTK(KERN_INFO, "type #4 (dt): 0x%x+%d [data transfer]
  ",
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
341
342
343
  			ch->firsts[CHET_DT],
  			ch->counts[CHET_DT]);
  	} else {
87da32356   Joe Perches   drivers/scsi/ch.c...
344
345
  		VPRINTK(KERN_INFO, "reading element address assigment page failed!
  ");
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
346
  	}
5aa22af3d   FUJITA Tomonori   [SCSI] ch: remove...
347

daa6eda65   Gerd Knorr   [SCSI] add scsi c...
348
349
350
351
352
353
354
355
  	/* vendor specific element types */
  	for (i = 0; i < 4; i++) {
  		if (0 == vendor_counts[i])
  			continue;
  		if (NULL == vendor_labels[i])
  			continue;
  		ch->firsts[CHET_V1+i] = vendor_firsts[i];
  		ch->counts[CHET_V1+i] = vendor_counts[i];
87da32356   Joe Perches   drivers/scsi/ch.c...
356
357
  		VPRINTK(KERN_INFO, "type #%d (v%d): 0x%x+%d [%s, vendor specific]
  ",
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
358
359
360
361
362
  			i+5,i+1,vendor_firsts[i],vendor_counts[i],
  			vendor_labels[i]);
  	}
  
  	/* look up the devices of the data transfer elements */
85bc081f4   Julia Lawall   drivers/scsi/aic9...
363
  	ch->dt = kcalloc(ch->counts[CHET_DT], sizeof(*ch->dt),
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
364
  			 GFP_KERNEL);
a2cf8a630   Davidlohr Bueso A   [SCSI] ch: Check ...
365
366
367
368
369
  
  	if (!ch->dt) {
  		kfree(buffer);
  		return -ENOMEM;
  	}
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
370
371
372
373
374
375
  	for (elem = 0; elem < ch->counts[CHET_DT]; elem++) {
  		id  = -1;
  		lun = 0;
  		if (elem < CH_DT_MAX  &&  -1 != dt_id[elem]) {
  			id  = dt_id[elem];
  			lun = dt_lun[elem];
87da32356   Joe Perches   drivers/scsi/ch.c...
376
  			VPRINTK(KERN_INFO, "dt 0x%x: [insmod option] ",
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
377
378
379
  				elem+ch->firsts[CHET_DT]);
  		} else if (0 != ch_read_element_status
  			   (ch,elem+ch->firsts[CHET_DT],data)) {
87da32356   Joe Perches   drivers/scsi/ch.c...
380
381
  			VPRINTK(KERN_INFO, "dt 0x%x: READ ELEMENT STATUS failed
  ",
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
382
383
  				elem+ch->firsts[CHET_DT]);
  		} else {
87da32356   Joe Perches   drivers/scsi/ch.c...
384
  			VPRINTK(KERN_INFO, "dt 0x%x: ",elem+ch->firsts[CHET_DT]);
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
385
  			if (data[6] & 0x80) {
87da32356   Joe Perches   drivers/scsi/ch.c...
386
387
  				VPRINTK(KERN_CONT, "not this SCSI bus
  ");
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
388
389
  				ch->dt[elem] = NULL;
  			} else if (0 == (data[6] & 0x30)) {
87da32356   Joe Perches   drivers/scsi/ch.c...
390
391
  				VPRINTK(KERN_CONT, "ID/LUN unknown
  ");
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
392
393
394
395
396
397
398
399
400
  				ch->dt[elem] = NULL;
  			} else {
  				id  = ch->device->id;
  				lun = 0;
  				if (data[6] & 0x20) id  = data[7];
  				if (data[6] & 0x10) lun = data[6] & 7;
  			}
  		}
  		if (-1 != id) {
87da32356   Joe Perches   drivers/scsi/ch.c...
401
  			VPRINTK(KERN_CONT, "ID %i, LUN %i, ",id,lun);
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
402
403
404
405
406
407
  			ch->dt[elem] =
  				scsi_device_lookup(ch->device->host,
  						   ch->device->channel,
  						   id,lun);
  			if (!ch->dt[elem]) {
  				/* should not happen */
87da32356   Joe Perches   drivers/scsi/ch.c...
408
409
  				VPRINTK(KERN_CONT, "Huh? device not found!
  ");
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
410
  			} else {
87da32356   Joe Perches   drivers/scsi/ch.c...
411
412
413
414
415
  				VPRINTK(KERN_CONT, "name: %8.8s %16.16s %4.4s
  ",
  					ch->dt[elem]->vendor,
  					ch->dt[elem]->model,
  					ch->dt[elem]->rev);
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
  			}
  		}
  	}
  	ch->voltags = 1;
  	kfree(buffer);
  
  	return 0;
  }
  
  /* ------------------------------------------------------------------------ */
  
  static int
  ch_position(scsi_changer *ch, u_int trans, u_int elem, int rotate)
  {
  	u_char  cmd[10];
5aa22af3d   FUJITA Tomonori   [SCSI] ch: remove...
431

87da32356   Joe Perches   drivers/scsi/ch.c...
432
433
  	DPRINTK("position: 0x%x
  ",elem);
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
  	if (0 == trans)
  		trans = ch->firsts[CHET_MT];
  	memset(cmd,0,sizeof(cmd));
  	cmd[0]  = POSITION_TO_ELEMENT;
  	cmd[1]  = ch->device->lun << 5;
  	cmd[2]  = (trans >> 8) & 0xff;
  	cmd[3]  =  trans       & 0xff;
  	cmd[4]  = (elem  >> 8) & 0xff;
  	cmd[5]  =  elem        & 0xff;
  	cmd[8]  = rotate ? 1 : 0;
  	return ch_do_scsi(ch, cmd, NULL, 0, DMA_NONE);
  }
  
  static int
  ch_move(scsi_changer *ch, u_int trans, u_int src, u_int dest, int rotate)
  {
  	u_char  cmd[12];
5aa22af3d   FUJITA Tomonori   [SCSI] ch: remove...
451

87da32356   Joe Perches   drivers/scsi/ch.c...
452
453
  	DPRINTK("move: 0x%x => 0x%x
  ",src,dest);
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
  	if (0 == trans)
  		trans = ch->firsts[CHET_MT];
  	memset(cmd,0,sizeof(cmd));
  	cmd[0]  = MOVE_MEDIUM;
  	cmd[1]  = ch->device->lun << 5;
  	cmd[2]  = (trans >> 8) & 0xff;
  	cmd[3]  =  trans       & 0xff;
  	cmd[4]  = (src   >> 8) & 0xff;
  	cmd[5]  =  src         & 0xff;
  	cmd[6]  = (dest  >> 8) & 0xff;
  	cmd[7]  =  dest        & 0xff;
  	cmd[10] = rotate ? 1 : 0;
  	return ch_do_scsi(ch, cmd, NULL,0, DMA_NONE);
  }
  
  static int
  ch_exchange(scsi_changer *ch, u_int trans, u_int src,
  	    u_int dest1, u_int dest2, int rotate1, int rotate2)
  {
  	u_char  cmd[12];
5aa22af3d   FUJITA Tomonori   [SCSI] ch: remove...
474

87da32356   Joe Perches   drivers/scsi/ch.c...
475
476
  	DPRINTK("exchange: 0x%x => 0x%x => 0x%x
  ",
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
  		src,dest1,dest2);
  	if (0 == trans)
  		trans = ch->firsts[CHET_MT];
  	memset(cmd,0,sizeof(cmd));
  	cmd[0]  = EXCHANGE_MEDIUM;
  	cmd[1]  = ch->device->lun << 5;
  	cmd[2]  = (trans >> 8) & 0xff;
  	cmd[3]  =  trans       & 0xff;
  	cmd[4]  = (src   >> 8) & 0xff;
  	cmd[5]  =  src         & 0xff;
  	cmd[6]  = (dest1 >> 8) & 0xff;
  	cmd[7]  =  dest1       & 0xff;
  	cmd[8]  = (dest2 >> 8) & 0xff;
  	cmd[9]  =  dest2       & 0xff;
  	cmd[10] = (rotate1 ? 1 : 0) | (rotate2 ? 2 : 0);
5aa22af3d   FUJITA Tomonori   [SCSI] ch: remove...
492

daa6eda65   Gerd Knorr   [SCSI] add scsi c...
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
  	return ch_do_scsi(ch, cmd, NULL,0, DMA_NONE);
  }
  
  static void
  ch_check_voltag(char *tag)
  {
  	int i;
  
  	for (i = 0; i < 32; i++) {
  		/* restrict to ascii */
  		if (tag[i] >= 0x7f || tag[i] < 0x20)
  			tag[i] = ' ';
  		/* don't allow search wildcards */
  		if (tag[i] == '?' ||
  		    tag[i] == '*')
  			tag[i] = ' ';
  	}
  }
  
  static int
  ch_set_voltag(scsi_changer *ch, u_int elem,
  	      int alternate, int clear, u_char *tag)
  {
  	u_char  cmd[12];
  	u_char  *buffer;
  	int result;
4530a1696   vignesh.babu@wipro.com   [SCSI] ch: kmallo...
519
  	buffer = kzalloc(512, GFP_KERNEL);
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
520
521
  	if (!buffer)
  		return -ENOMEM;
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
522

87da32356   Joe Perches   drivers/scsi/ch.c...
523
524
  	DPRINTK("%s %s voltag: 0x%x => \"%s\"
  ",
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
525
526
527
528
529
  		clear     ? "clear"     : "set",
  		alternate ? "alternate" : "primary",
  		elem, tag);
  	memset(cmd,0,sizeof(cmd));
  	cmd[0]  = SEND_VOLUME_TAG;
5aa22af3d   FUJITA Tomonori   [SCSI] ch: remove...
530
  	cmd[1] = (ch->device->lun << 5) |
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
531
532
533
534
535
536
  		ch_elem_to_typecode(ch,elem);
  	cmd[2] = (elem >> 8) & 0xff;
  	cmd[3] = elem        & 0xff;
  	cmd[5] = clear
  		? (alternate ? 0x0d : 0x0c)
  		: (alternate ? 0x0b : 0x0a);
5aa22af3d   FUJITA Tomonori   [SCSI] ch: remove...
537

daa6eda65   Gerd Knorr   [SCSI] add scsi c...
538
539
540
541
542
543
544
545
546
  	cmd[9] = 255;
  
  	memcpy(buffer,tag,32);
  	ch_check_voltag(buffer);
  
  	result = ch_do_scsi(ch, cmd, buffer, 256, DMA_TO_DEVICE);
  	kfree(buffer);
  	return result;
  }
fe08ac317   Al Viro   [PATCH] __user an...
547
  static int ch_gstatus(scsi_changer *ch, int type, unsigned char __user *dest)
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
548
549
550
551
  {
  	int retval = 0;
  	u_char data[16];
  	unsigned int i;
5aa22af3d   FUJITA Tomonori   [SCSI] ch: remove...
552

0b9506723   Arjan van de Ven   [SCSI] turn most ...
553
  	mutex_lock(&ch->lock);
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
554
555
556
557
558
559
560
561
  	for (i = 0; i < ch->counts[type]; i++) {
  		if (0 != ch_read_element_status
  		    (ch, ch->firsts[type]+i,data)) {
  			retval = -EIO;
  			break;
  		}
  		put_user(data[2], dest+i);
  		if (data[2] & CESTATUS_EXCEPT)
87da32356   Joe Perches   drivers/scsi/ch.c...
562
563
  			VPRINTK(KERN_INFO, "element 0x%x: asc=0x%x, ascq=0x%x
  ",
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
564
565
566
567
568
569
570
  				ch->firsts[type]+i,
  				(int)data[4],(int)data[5]);
  		retval = ch_read_element_status
  			(ch, ch->firsts[type]+i,data);
  		if (0 != retval)
  			break;
  	}
0b9506723   Arjan van de Ven   [SCSI] turn most ...
571
  	mutex_unlock(&ch->lock);
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
  	return retval;
  }
  
  /* ------------------------------------------------------------------------ */
  
  static int
  ch_release(struct inode *inode, struct file *file)
  {
  	scsi_changer *ch = file->private_data;
  
  	scsi_device_put(ch->device);
  	file->private_data = NULL;
  	return 0;
  }
  
  static int
  ch_open(struct inode *inode, struct file *file)
  {
da707c54c   FUJITA Tomonori   [SCSI] ch: fix de...
590
  	scsi_changer *ch;
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
591
  	int minor = iminor(inode);
b0061a0ec   Jonathan Corbet   changer: BKL push...
592
  	lock_kernel();
da707c54c   FUJITA Tomonori   [SCSI] ch: fix de...
593
594
  	spin_lock(&ch_index_lock);
  	ch = idr_find(&ch_index_idr, minor);
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
595
  	if (NULL == ch || scsi_device_get(ch->device)) {
da707c54c   FUJITA Tomonori   [SCSI] ch: fix de...
596
  		spin_unlock(&ch_index_lock);
b0061a0ec   Jonathan Corbet   changer: BKL push...
597
  		unlock_kernel();
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
598
599
  		return -ENXIO;
  	}
da707c54c   FUJITA Tomonori   [SCSI] ch: fix de...
600
  	spin_unlock(&ch_index_lock);
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
601
602
  
  	file->private_data = ch;
b0061a0ec   Jonathan Corbet   changer: BKL push...
603
  	unlock_kernel();
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
604
605
606
607
608
609
610
611
612
613
  	return 0;
  }
  
  static int
  ch_checkrange(scsi_changer *ch, unsigned int type, unsigned int unit)
  {
  	if (type >= CH_TYPES  ||  unit >= ch->counts[type])
  		return -1;
  	return 0;
  }
f7fea185d   Mathieu Segaud   [SCSI] ch: Conver...
614
  static long ch_ioctl(struct file *file,
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
615
616
617
618
  		    unsigned int cmd, unsigned long arg)
  {
  	scsi_changer *ch = file->private_data;
  	int retval;
fe08ac317   Al Viro   [PATCH] __user an...
619
  	void __user *argp = (void __user *)arg;
5aa22af3d   FUJITA Tomonori   [SCSI] ch: remove...
620

daa6eda65   Gerd Knorr   [SCSI] add scsi c...
621
622
623
624
  	switch (cmd) {
  	case CHIOGPARAMS:
  	{
  		struct changer_params params;
5aa22af3d   FUJITA Tomonori   [SCSI] ch: remove...
625

daa6eda65   Gerd Knorr   [SCSI] add scsi c...
626
627
628
629
630
  		params.cp_curpicker = 0;
  		params.cp_npickers  = ch->counts[CHET_MT];
  		params.cp_nslots    = ch->counts[CHET_ST];
  		params.cp_nportals  = ch->counts[CHET_IE];
  		params.cp_ndrives   = ch->counts[CHET_DT];
5aa22af3d   FUJITA Tomonori   [SCSI] ch: remove...
631

fe08ac317   Al Viro   [PATCH] __user an...
632
  		if (copy_to_user(argp, &params, sizeof(params)))
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
  			return -EFAULT;
  		return 0;
  	}
  	case CHIOGVPARAMS:
  	{
  		struct changer_vendor_params vparams;
  
  		memset(&vparams,0,sizeof(vparams));
  		if (ch->counts[CHET_V1]) {
  			vparams.cvp_n1  = ch->counts[CHET_V1];
  			strncpy(vparams.cvp_label1,vendor_labels[0],16);
  		}
  		if (ch->counts[CHET_V2]) {
  			vparams.cvp_n2  = ch->counts[CHET_V2];
  			strncpy(vparams.cvp_label2,vendor_labels[1],16);
  		}
  		if (ch->counts[CHET_V3]) {
  			vparams.cvp_n3  = ch->counts[CHET_V3];
  			strncpy(vparams.cvp_label3,vendor_labels[2],16);
  		}
  		if (ch->counts[CHET_V4]) {
  			vparams.cvp_n4  = ch->counts[CHET_V4];
  			strncpy(vparams.cvp_label4,vendor_labels[3],16);
  		}
fe08ac317   Al Viro   [PATCH] __user an...
657
  		if (copy_to_user(argp, &vparams, sizeof(vparams)))
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
658
659
660
  			return -EFAULT;
  		return 0;
  	}
5aa22af3d   FUJITA Tomonori   [SCSI] ch: remove...
661

daa6eda65   Gerd Knorr   [SCSI] add scsi c...
662
663
664
  	case CHIOPOSITION:
  	{
  		struct changer_position pos;
5aa22af3d   FUJITA Tomonori   [SCSI] ch: remove...
665

fe08ac317   Al Viro   [PATCH] __user an...
666
  		if (copy_from_user(&pos, argp, sizeof (pos)))
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
667
668
669
  			return -EFAULT;
  
  		if (0 != ch_checkrange(ch, pos.cp_type, pos.cp_unit)) {
87da32356   Joe Perches   drivers/scsi/ch.c...
670
671
  			DPRINTK("CHIOPOSITION: invalid parameter
  ");
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
672
673
  			return -EBADSLT;
  		}
0b9506723   Arjan van de Ven   [SCSI] turn most ...
674
  		mutex_lock(&ch->lock);
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
675
676
677
  		retval = ch_position(ch,0,
  				     ch->firsts[pos.cp_type] + pos.cp_unit,
  				     pos.cp_flags & CP_INVERT);
0b9506723   Arjan van de Ven   [SCSI] turn most ...
678
  		mutex_unlock(&ch->lock);
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
679
680
  		return retval;
  	}
5aa22af3d   FUJITA Tomonori   [SCSI] ch: remove...
681

daa6eda65   Gerd Knorr   [SCSI] add scsi c...
682
683
684
  	case CHIOMOVE:
  	{
  		struct changer_move mv;
fe08ac317   Al Viro   [PATCH] __user an...
685
  		if (copy_from_user(&mv, argp, sizeof (mv)))
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
686
687
688
689
  			return -EFAULT;
  
  		if (0 != ch_checkrange(ch, mv.cm_fromtype, mv.cm_fromunit) ||
  		    0 != ch_checkrange(ch, mv.cm_totype,   mv.cm_tounit  )) {
87da32356   Joe Perches   drivers/scsi/ch.c...
690
691
  			DPRINTK("CHIOMOVE: invalid parameter
  ");
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
692
693
  			return -EBADSLT;
  		}
5aa22af3d   FUJITA Tomonori   [SCSI] ch: remove...
694

0b9506723   Arjan van de Ven   [SCSI] turn most ...
695
  		mutex_lock(&ch->lock);
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
696
697
698
699
  		retval = ch_move(ch,0,
  				 ch->firsts[mv.cm_fromtype] + mv.cm_fromunit,
  				 ch->firsts[mv.cm_totype]   + mv.cm_tounit,
  				 mv.cm_flags & CM_INVERT);
0b9506723   Arjan van de Ven   [SCSI] turn most ...
700
  		mutex_unlock(&ch->lock);
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
701
702
703
704
705
706
  		return retval;
  	}
  
  	case CHIOEXCHANGE:
  	{
  		struct changer_exchange mv;
5aa22af3d   FUJITA Tomonori   [SCSI] ch: remove...
707

fe08ac317   Al Viro   [PATCH] __user an...
708
  		if (copy_from_user(&mv, argp, sizeof (mv)))
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
709
710
711
712
713
  			return -EFAULT;
  
  		if (0 != ch_checkrange(ch, mv.ce_srctype,  mv.ce_srcunit ) ||
  		    0 != ch_checkrange(ch, mv.ce_fdsttype, mv.ce_fdstunit) ||
  		    0 != ch_checkrange(ch, mv.ce_sdsttype, mv.ce_sdstunit)) {
87da32356   Joe Perches   drivers/scsi/ch.c...
714
715
  			DPRINTK("CHIOEXCHANGE: invalid parameter
  ");
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
716
717
  			return -EBADSLT;
  		}
5aa22af3d   FUJITA Tomonori   [SCSI] ch: remove...
718

0b9506723   Arjan van de Ven   [SCSI] turn most ...
719
  		mutex_lock(&ch->lock);
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
720
721
722
723
724
725
  		retval = ch_exchange
  			(ch,0,
  			 ch->firsts[mv.ce_srctype]  + mv.ce_srcunit,
  			 ch->firsts[mv.ce_fdsttype] + mv.ce_fdstunit,
  			 ch->firsts[mv.ce_sdsttype] + mv.ce_sdstunit,
  			 mv.ce_flags & CE_INVERT1, mv.ce_flags & CE_INVERT2);
0b9506723   Arjan van de Ven   [SCSI] turn most ...
726
  		mutex_unlock(&ch->lock);
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
727
728
729
730
731
732
  		return retval;
  	}
  
  	case CHIOGSTATUS:
  	{
  		struct changer_element_status ces;
5aa22af3d   FUJITA Tomonori   [SCSI] ch: remove...
733

fe08ac317   Al Viro   [PATCH] __user an...
734
  		if (copy_from_user(&ces, argp, sizeof (ces)))
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
735
736
737
738
739
740
741
742
743
744
  			return -EFAULT;
  		if (ces.ces_type < 0 || ces.ces_type >= CH_TYPES)
  			return -EINVAL;
  
  		return ch_gstatus(ch, ces.ces_type, ces.ces_data);
  	}
  
  	case CHIOGELEM:
  	{
  		struct changer_get_element cge;
d70d4667e   Harvey Harrison   [SCSI] ch: fix sp...
745
746
  		u_char ch_cmd[12];
  		u_char *buffer;
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
747
748
  		unsigned int elem;
  		int     result,i;
5aa22af3d   FUJITA Tomonori   [SCSI] ch: remove...
749

fe08ac317   Al Viro   [PATCH] __user an...
750
  		if (copy_from_user(&cge, argp, sizeof (cge)))
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
751
752
753
754
755
  			return -EFAULT;
  
  		if (0 != ch_checkrange(ch, cge.cge_type, cge.cge_unit))
  			return -EINVAL;
  		elem = ch->firsts[cge.cge_type] + cge.cge_unit;
5aa22af3d   FUJITA Tomonori   [SCSI] ch: remove...
756

daa6eda65   Gerd Knorr   [SCSI] add scsi c...
757
758
759
  		buffer = kmalloc(512, GFP_KERNEL | GFP_DMA);
  		if (!buffer)
  			return -ENOMEM;
0b9506723   Arjan van de Ven   [SCSI] turn most ...
760
  		mutex_lock(&ch->lock);
5aa22af3d   FUJITA Tomonori   [SCSI] ch: remove...
761

daa6eda65   Gerd Knorr   [SCSI] add scsi c...
762
  	voltag_retry:
d70d4667e   Harvey Harrison   [SCSI] ch: fix sp...
763
764
765
  		memset(ch_cmd, 0, sizeof(ch_cmd));
  		ch_cmd[0] = READ_ELEMENT_STATUS;
  		ch_cmd[1] = (ch->device->lun << 5) |
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
766
767
  			(ch->voltags ? 0x10 : 0) |
  			ch_elem_to_typecode(ch,elem);
d70d4667e   Harvey Harrison   [SCSI] ch: fix sp...
768
769
770
771
  		ch_cmd[2] = (elem >> 8) & 0xff;
  		ch_cmd[3] = elem        & 0xff;
  		ch_cmd[5] = 1;
  		ch_cmd[9] = 255;
5aa22af3d   FUJITA Tomonori   [SCSI] ch: remove...
772

d70d4667e   Harvey Harrison   [SCSI] ch: fix sp...
773
774
  		result = ch_do_scsi(ch, ch_cmd, buffer, 256, DMA_FROM_DEVICE);
  		if (!result) {
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
  			cge.cge_status = buffer[18];
  			cge.cge_flags = 0;
  			if (buffer[18] & CESTATUS_EXCEPT) {
  				cge.cge_errno = EIO;
  			}
  			if (buffer[25] & 0x80) {
  				cge.cge_flags |= CGE_SRC;
  				if (buffer[25] & 0x40)
  					cge.cge_flags |= CGE_INVERT;
  				elem = (buffer[26]<<8) | buffer[27];
  				for (i = 0; i < 4; i++) {
  					if (elem >= ch->firsts[i] &&
  					    elem <  ch->firsts[i] + ch->counts[i]) {
  						cge.cge_srctype = i;
  						cge.cge_srcunit = elem-ch->firsts[i];
  					}
  				}
  			}
  			if ((buffer[22] & 0x30) == 0x30) {
  				cge.cge_flags |= CGE_IDLUN;
  				cge.cge_id  = buffer[23];
  				cge.cge_lun = buffer[22] & 7;
  			}
  			if (buffer[9] & 0x80) {
  				cge.cge_flags |= CGE_PVOLTAG;
  				memcpy(cge.cge_pvoltag,buffer+28,36);
  			}
  			if (buffer[9] & 0x40) {
  				cge.cge_flags |= CGE_AVOLTAG;
  				memcpy(cge.cge_avoltag,buffer+64,36);
  			}
  		} else if (ch->voltags) {
  			ch->voltags = 0;
87da32356   Joe Perches   drivers/scsi/ch.c...
808
809
  			VPRINTK(KERN_INFO, "device has no volume tag support
  ");
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
810
811
812
  			goto voltag_retry;
  		}
  		kfree(buffer);
0b9506723   Arjan van de Ven   [SCSI] turn most ...
813
  		mutex_unlock(&ch->lock);
5aa22af3d   FUJITA Tomonori   [SCSI] ch: remove...
814

fe08ac317   Al Viro   [PATCH] __user an...
815
  		if (copy_to_user(argp, &cge, sizeof (cge)))
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
816
817
818
819
820
821
  			return -EFAULT;
  		return result;
  	}
  
  	case CHIOINITELEM:
  	{
0b9506723   Arjan van de Ven   [SCSI] turn most ...
822
  		mutex_lock(&ch->lock);
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
823
  		retval = ch_init_elem(ch);
0b9506723   Arjan van de Ven   [SCSI] turn most ...
824
  		mutex_unlock(&ch->lock);
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
825
826
  		return retval;
  	}
5aa22af3d   FUJITA Tomonori   [SCSI] ch: remove...
827

daa6eda65   Gerd Knorr   [SCSI] add scsi c...
828
829
830
831
  	case CHIOSVOLTAG:
  	{
  		struct changer_set_voltag csv;
  		int elem;
fe08ac317   Al Viro   [PATCH] __user an...
832
  		if (copy_from_user(&csv, argp, sizeof(csv)))
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
833
834
835
  			return -EFAULT;
  
  		if (0 != ch_checkrange(ch, csv.csv_type, csv.csv_unit)) {
87da32356   Joe Perches   drivers/scsi/ch.c...
836
837
  			DPRINTK("CHIOSVOLTAG: invalid parameter
  ");
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
838
839
840
  			return -EBADSLT;
  		}
  		elem = ch->firsts[csv.csv_type] + csv.csv_unit;
0b9506723   Arjan van de Ven   [SCSI] turn most ...
841
  		mutex_lock(&ch->lock);
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
842
843
844
845
  		retval = ch_set_voltag(ch, elem,
  				       csv.csv_flags & CSV_AVOLTAG,
  				       csv.csv_flags & CSV_CLEARTAG,
  				       csv.csv_voltag);
0b9506723   Arjan van de Ven   [SCSI] turn most ...
846
  		mutex_unlock(&ch->lock);
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
847
848
849
850
  		return retval;
  	}
  
  	default:
fe08ac317   Al Viro   [PATCH] __user an...
851
  		return scsi_ioctl(ch->device, cmd, argp);
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
  
  	}
  }
  
  #ifdef CONFIG_COMPAT
  
  struct changer_element_status32 {
  	int		ces_type;
  	compat_uptr_t	ces_data;
  };
  #define CHIOGSTATUS32  _IOW('c', 8,struct changer_element_status32)
  
  static long ch_ioctl_compat(struct file * file,
  			    unsigned int cmd, unsigned long arg)
  {
  	scsi_changer *ch = file->private_data;
5aa22af3d   FUJITA Tomonori   [SCSI] ch: remove...
868

daa6eda65   Gerd Knorr   [SCSI] add scsi c...
869
870
871
872
873
874
875
876
877
878
  	switch (cmd) {
  	case CHIOGPARAMS:
  	case CHIOGVPARAMS:
  	case CHIOPOSITION:
  	case CHIOMOVE:
  	case CHIOEXCHANGE:
  	case CHIOGELEM:
  	case CHIOINITELEM:
  	case CHIOSVOLTAG:
  		/* compatible */
f7fea185d   Mathieu Segaud   [SCSI] ch: Conver...
879
  		return ch_ioctl(file, cmd, arg);
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
880
881
882
  	case CHIOGSTATUS32:
  	{
  		struct changer_element_status32 ces32;
fe08ac317   Al Viro   [PATCH] __user an...
883
  		unsigned char __user *data;
5aa22af3d   FUJITA Tomonori   [SCSI] ch: remove...
884

fe08ac317   Al Viro   [PATCH] __user an...
885
  		if (copy_from_user(&ces32, (void __user *)arg, sizeof (ces32)))
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
  			return -EFAULT;
  		if (ces32.ces_type < 0 || ces32.ces_type >= CH_TYPES)
  			return -EINVAL;
  
  		data = compat_ptr(ces32.ces_data);
  		return ch_gstatus(ch, ces32.ces_type, data);
  	}
  	default:
  		// return scsi_ioctl_compat(ch->device, cmd, (void*)arg);
  		return -ENOIOCTLCMD;
  
  	}
  }
  #endif
  
  /* ------------------------------------------------------------------------ */
  
  static int ch_probe(struct device *dev)
  {
  	struct scsi_device *sd = to_scsi_device(dev);
ee959b00c   Tony Jones   SCSI: convert str...
906
  	struct device *class_dev;
da707c54c   FUJITA Tomonori   [SCSI] ch: fix de...
907
  	int minor, ret = -ENOMEM;
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
908
  	scsi_changer *ch;
a3d2c2e8f   FUJITA Tomonori   [SCSI] ch: handle...
909

daa6eda65   Gerd Knorr   [SCSI] add scsi c...
910
911
  	if (sd->type != TYPE_MEDIUM_CHANGER)
  		return -ENODEV;
a3d2c2e8f   FUJITA Tomonori   [SCSI] ch: handle...
912

4530a1696   vignesh.babu@wipro.com   [SCSI] ch: kmallo...
913
  	ch = kzalloc(sizeof(*ch), GFP_KERNEL);
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
914
915
  	if (NULL == ch)
  		return -ENOMEM;
da707c54c   FUJITA Tomonori   [SCSI] ch: fix de...
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
  	if (!idr_pre_get(&ch_index_idr, GFP_KERNEL))
  		goto free_ch;
  
  	spin_lock(&ch_index_lock);
  	ret = idr_get_new(&ch_index_idr, ch, &minor);
  	spin_unlock(&ch_index_lock);
  
  	if (ret)
  		goto free_ch;
  
  	if (minor > CH_MAX_DEVS) {
  		ret = -ENODEV;
  		goto remove_idr;
  	}
  
  	ch->minor = minor;
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
932
  	sprintf(ch->name,"ch%d",ch->minor);
a3d2c2e8f   FUJITA Tomonori   [SCSI] ch: handle...
933

d73a1a674   Greg Kroah-Hartman   device create: sc...
934
935
936
  	class_dev = device_create(ch_sysfs_class, dev,
  				  MKDEV(SCSI_CHANGER_MAJOR, ch->minor), ch,
  				  "s%s", ch->name);
a3d2c2e8f   FUJITA Tomonori   [SCSI] ch: handle...
937
  	if (IS_ERR(class_dev)) {
ee959b00c   Tony Jones   SCSI: convert str...
938
939
  		printk(KERN_WARNING "ch%d: device_create failed
  ",
a3d2c2e8f   FUJITA Tomonori   [SCSI] ch: handle...
940
  		       ch->minor);
da707c54c   FUJITA Tomonori   [SCSI] ch: fix de...
941
942
  		ret = PTR_ERR(class_dev);
  		goto remove_idr;
a3d2c2e8f   FUJITA Tomonori   [SCSI] ch: handle...
943
  	}
0b9506723   Arjan van de Ven   [SCSI] turn most ...
944
  	mutex_init(&ch->lock);
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
945
946
947
948
  	ch->device = sd;
  	ch_readconfig(ch);
  	if (init)
  		ch_init_elem(ch);
3d164fb09   FUJITA Tomonori   [SCSI] ch: fix ch...
949
  	dev_set_drvdata(dev, ch);
017560fca   Jeff Garzik   [SCSI] use sfoo_p...
950
951
  	sdev_printk(KERN_INFO, sd, "Attached scsi changer %s
  ", ch->name);
a3d2c2e8f   FUJITA Tomonori   [SCSI] ch: handle...
952

daa6eda65   Gerd Knorr   [SCSI] add scsi c...
953
  	return 0;
da707c54c   FUJITA Tomonori   [SCSI] ch: fix de...
954
955
956
957
958
  remove_idr:
  	idr_remove(&ch_index_idr, minor);
  free_ch:
  	kfree(ch);
  	return ret;
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
959
960
961
962
  }
  
  static int ch_remove(struct device *dev)
  {
da707c54c   FUJITA Tomonori   [SCSI] ch: fix de...
963
  	scsi_changer *ch = dev_get_drvdata(dev);
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
964

da707c54c   FUJITA Tomonori   [SCSI] ch: fix de...
965
966
967
  	spin_lock(&ch_index_lock);
  	idr_remove(&ch_index_idr, ch->minor);
  	spin_unlock(&ch_index_lock);
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
968

ee959b00c   Tony Jones   SCSI: convert str...
969
  	device_destroy(ch_sysfs_class, MKDEV(SCSI_CHANGER_MAJOR,ch->minor));
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
970
971
  	kfree(ch->dt);
  	kfree(ch);
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
972
973
  	return 0;
  }
5aa22af3d   FUJITA Tomonori   [SCSI] ch: remove...
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
  static struct scsi_driver ch_template = {
  	.owner     	= THIS_MODULE,
  	.gendrv     	= {
  		.name	= "ch",
  		.probe  = ch_probe,
  		.remove = ch_remove,
  	},
  };
  
  static const struct file_operations changer_fops = {
  	.owner		= THIS_MODULE,
  	.open		= ch_open,
  	.release	= ch_release,
  	.unlocked_ioctl	= ch_ioctl,
  #ifdef CONFIG_COMPAT
  	.compat_ioctl	= ch_ioctl_compat,
  #endif
  };
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
992
993
994
  static int __init init_ch_module(void)
  {
  	int rc;
5aa22af3d   FUJITA Tomonori   [SCSI] ch: remove...
995

daa6eda65   Gerd Knorr   [SCSI] add scsi c...
996
997
  	printk(KERN_INFO "SCSI Media Changer driver v" VERSION " 
  ");
21feb5ccd   Gerd Knorr   [SCSI] convert sc...
998
          ch_sysfs_class = class_create(THIS_MODULE, "scsi_changer");
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
          if (IS_ERR(ch_sysfs_class)) {
  		rc = PTR_ERR(ch_sysfs_class);
  		return rc;
          }
  	rc = register_chrdev(SCSI_CHANGER_MAJOR,"ch",&changer_fops);
  	if (rc < 0) {
  		printk("Unable to get major %d for SCSI-Changer
  ",
  		       SCSI_CHANGER_MAJOR);
  		goto fail1;
  	}
  	rc = scsi_register_driver(&ch_template.gendrv);
  	if (rc < 0)
  		goto fail2;
  	return 0;
  
   fail2:
  	unregister_chrdev(SCSI_CHANGER_MAJOR, "ch");
   fail1:
21feb5ccd   Gerd Knorr   [SCSI] convert sc...
1018
  	class_destroy(ch_sysfs_class);
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
1019
1020
  	return rc;
  }
5aa22af3d   FUJITA Tomonori   [SCSI] ch: remove...
1021
  static void __exit exit_ch_module(void)
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
1022
1023
1024
  {
  	scsi_unregister_driver(&ch_template.gendrv);
  	unregister_chrdev(SCSI_CHANGER_MAJOR, "ch");
21feb5ccd   Gerd Knorr   [SCSI] convert sc...
1025
  	class_destroy(ch_sysfs_class);
da707c54c   FUJITA Tomonori   [SCSI] ch: fix de...
1026
  	idr_destroy(&ch_index_idr);
daa6eda65   Gerd Knorr   [SCSI] add scsi c...
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
  }
  
  module_init(init_ch_module);
  module_exit(exit_ch_module);
  
  /*
   * Local variables:
   * c-basic-offset: 8
   * End:
   */