Blame view
drivers/scsi/ch.c
24.5 KB
daa6eda65 [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 [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 [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 [SCSI] add scsi c... |
20 21 |
#include <linux/compat.h> #include <linux/chio.h> /* here are all the ioctls */ |
0b9506723 [SCSI] turn most ... |
22 |
#include <linux/mutex.h> |
da707c54c [SCSI] ch: fix de... |
23 |
#include <linux/idr.h> |
5a0e3ad6a include cleanup: ... |
24 |
#include <linux/slab.h> |
daa6eda65 [SCSI] add scsi c... |
25 26 27 28 29 30 31 |
#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 [SCSI] convert ch... |
32 |
#include <scsi/scsi_eh.h> |
daa6eda65 [SCSI] add scsi c... |
33 34 35 36 |
#include <scsi/scsi_dbg.h> #define CH_DT_MAX 16 #define CH_TYPES 8 |
da707c54c [SCSI] ch: fix de... |
37 |
#define CH_MAX_DEVS 128 |
daa6eda65 [SCSI] add scsi c... |
38 39 40 41 |
MODULE_DESCRIPTION("device driver for scsi media changer devices"); MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org>"); MODULE_LICENSE("GPL"); |
f018fa552 [SCSI] MODULE_ALI... |
42 |
MODULE_ALIAS_CHARDEV_MAJOR(SCSI_CHANGER_MAJOR); |
95f6c83f6 [SCSI] ch: Add sc... |
43 |
MODULE_ALIAS_SCSI_DEVICE(TYPE_MEDIUM_CHANGER); |
daa6eda65 [SCSI] add scsi c... |
44 |
|
c45d15d24 scsi: autoconvert... |
45 |
static DEFINE_MUTEX(ch_mutex); |
daa6eda65 [SCSI] add scsi c... |
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 [SCSI] Mark some ... |
80 |
static const char * vendor_labels[CH_TYPES-4] = { |
daa6eda65 [SCSI] add scsi c... |
81 82 83 |
"v0", "v1", "v2", "v3" }; // module_param_string_array(vendor_labels, NULL, 0444); |
28c31729c scsi: Implement c... |
84 |
#define ch_printk(prefix, ch, fmt, a...) \ |
22e0d9941 scsi: introduce s... |
85 |
sdev_prefix_printk(prefix, (ch)->device, (ch)->name, fmt, ##a) |
28c31729c scsi: Implement c... |
86 |
|
87da32356 drivers/scsi/ch.c... |
87 88 89 |
#define DPRINTK(fmt, arg...) \ do { \ if (debug) \ |
28c31729c scsi: Implement c... |
90 |
ch_printk(KERN_DEBUG, ch, fmt, ##arg); \ |
87da32356 drivers/scsi/ch.c... |
91 92 93 94 |
} while (0) #define VPRINTK(level, fmt, arg...) \ do { \ if (verbose) \ |
28c31729c scsi: Implement c... |
95 |
ch_printk(level, ch, fmt, ##arg); \ |
87da32356 drivers/scsi/ch.c... |
96 |
} while (0) |
daa6eda65 [SCSI] add scsi c... |
97 98 99 100 |
/* ------------------------------------------------------------------- */ #define MAX_RETRIES 1 |
21feb5ccd [SCSI] convert sc... |
101 |
static struct class * ch_sysfs_class; |
daa6eda65 [SCSI] add scsi c... |
102 103 104 105 106 107 108 109 110 111 112 |
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 [SCSI] turn most ... |
113 |
struct mutex lock; |
daa6eda65 [SCSI] add scsi c... |
114 |
} scsi_changer; |
da707c54c [SCSI] ch: fix de... |
115 116 |
static DEFINE_IDR(ch_index_idr); static DEFINE_SPINLOCK(ch_index_lock); |
daa6eda65 [SCSI] add scsi c... |
117 |
|
0ad78200b [SCSI] Mark some ... |
118 |
static const struct { |
daa6eda65 [SCSI] add scsi c... |
119 120 121 122 |
unsigned char sense; unsigned char asc; unsigned char ascq; int errno; |
d70d4667e [SCSI] ch: fix sp... |
123 |
} ch_err[] = { |
daa6eda65 [SCSI] add scsi c... |
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 154 155 156 |
/* 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 [SCSI] convert ch... |
157 |
static int ch_find_errno(struct scsi_sense_hdr *sshdr) |
daa6eda65 [SCSI] add scsi c... |
158 159 160 161 |
{ int i,errno = 0; /* Check to see if additional sense information is available */ |
84743bbcf [SCSI] convert ch... |
162 163 |
if (scsi_sense_valid(sshdr) && sshdr->asc != 0) { |
d70d4667e [SCSI] ch: fix sp... |
164 165 166 167 168 |
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 [SCSI] add scsi c... |
169 170 171 172 173 174 175 176 177 178 |
break; } } } if (errno == 0) errno = -EIO; return errno; } static int |
a9a47bf58 scsi: repurpose t... |
179 |
ch_do_scsi(scsi_changer *ch, unsigned char *cmd, int cmd_len, |
daa6eda65 [SCSI] add scsi c... |
180 181 182 |
void *buffer, unsigned buflength, enum dma_data_direction direction) { |
84743bbcf [SCSI] convert ch... |
183 184 |
int errno, retries = 0, timeout, result; struct scsi_sense_hdr sshdr; |
5aa22af3d [SCSI] ch: remove... |
185 |
|
daa6eda65 [SCSI] add scsi c... |
186 187 188 189 190 |
timeout = (cmd[0] == INITIALIZE_ELEMENT_STATUS) ? timeout_init : timeout_move; retry: errno = 0; |
28c31729c scsi: Implement c... |
191 |
result = scsi_execute_req(ch->device, cmd, direction, buffer, |
84743bbcf [SCSI] convert ch... |
192 |
buflength, &sshdr, timeout * HZ, |
f4f4e47e4 [SCSI] add residu... |
193 |
MAX_RETRIES, NULL); |
daa6eda65 [SCSI] add scsi c... |
194 |
|
84743bbcf [SCSI] convert ch... |
195 |
if (driver_byte(result) & DRIVER_SENSE) { |
daa6eda65 [SCSI] add scsi c... |
196 |
if (debug) |
d811b848e scsi: use sdev as... |
197 |
scsi_print_sense_hdr(ch->device, ch->name, &sshdr); |
84743bbcf [SCSI] convert ch... |
198 |
errno = ch_find_errno(&sshdr); |
daa6eda65 [SCSI] add scsi c... |
199 |
|
84743bbcf [SCSI] convert ch... |
200 |
switch(sshdr.sense_key) { |
daa6eda65 [SCSI] add scsi c... |
201 202 203 204 205 206 207 |
case UNIT_ATTENTION: ch->unit_attention = 1; if (retries++ < 3) goto retry; break; } } |
daa6eda65 [SCSI] add scsi c... |
208 209 210 211 212 213 214 215 216 |
return errno; } /* ------------------------------------------------------------------------ */ static int ch_elem_to_typecode(scsi_changer *ch, u_int elem) { int i; |
5aa22af3d [SCSI] ch: remove... |
217 |
|
daa6eda65 [SCSI] add scsi c... |
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 |
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 [SCSI] ch: remove... |
233 |
|
daa6eda65 [SCSI] add scsi c... |
234 235 236 |
buffer = kmalloc(512, GFP_KERNEL | GFP_DMA); if(!buffer) return -ENOMEM; |
5aa22af3d [SCSI] ch: remove... |
237 |
|
daa6eda65 [SCSI] add scsi c... |
238 239 240 |
retry: memset(cmd,0,sizeof(cmd)); cmd[0] = READ_ELEMENT_STATUS; |
9cb78c16f scsi: use 64-bit ... |
241 |
cmd[1] = ((ch->device->lun & 0x7) << 5) | |
daa6eda65 [SCSI] add scsi c... |
242 243 244 245 246 247 |
(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; |
a9a47bf58 scsi: repurpose t... |
248 249 |
if (0 == (result = ch_do_scsi(ch, cmd, 12, buffer, 256, DMA_FROM_DEVICE))) { |
daa6eda65 [SCSI] add scsi c... |
250 |
if (((buffer[16] << 8) | buffer[17]) != elem) { |
87da32356 drivers/scsi/ch.c... |
251 252 |
DPRINTK("asked for element 0x%02x, got 0x%02x ", |
daa6eda65 [SCSI] add scsi c... |
253 254 255 256 257 258 259 260 |
elem,(buffer[16] << 8) | buffer[17]); kfree(buffer); return -EIO; } memcpy(data,buffer+16,16); } else { if (ch->voltags) { ch->voltags = 0; |
87da32356 drivers/scsi/ch.c... |
261 262 |
VPRINTK(KERN_INFO, "device has no volume tag support "); |
daa6eda65 [SCSI] add scsi c... |
263 264 |
goto retry; } |
87da32356 drivers/scsi/ch.c... |
265 266 |
DPRINTK("READ ELEMENT STATUS for element 0x%x failed ",elem); |
daa6eda65 [SCSI] add scsi c... |
267 268 269 270 |
} kfree(buffer); return result; } |
5aa22af3d [SCSI] ch: remove... |
271 |
static int |
daa6eda65 [SCSI] add scsi c... |
272 273 274 275 |
ch_init_elem(scsi_changer *ch) { int err; u_char cmd[6]; |
87da32356 drivers/scsi/ch.c... |
276 277 |
VPRINTK(KERN_INFO, "INITIALIZE ELEMENT STATUS, may take some time ... "); |
daa6eda65 [SCSI] add scsi c... |
278 279 |
memset(cmd,0,sizeof(cmd)); cmd[0] = INITIALIZE_ELEMENT_STATUS; |
9cb78c16f scsi: use 64-bit ... |
280 |
cmd[1] = (ch->device->lun & 0x7) << 5; |
a9a47bf58 scsi: repurpose t... |
281 |
err = ch_do_scsi(ch, cmd, 6, NULL, 0, DMA_NONE); |
87da32356 drivers/scsi/ch.c... |
282 283 |
VPRINTK(KERN_INFO, "... finished "); |
daa6eda65 [SCSI] add scsi c... |
284 285 286 287 288 289 290 291 292 293 |
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 [SCSI] ch: kmallo... |
294 |
buffer = kzalloc(512, GFP_KERNEL | GFP_DMA); |
daa6eda65 [SCSI] add scsi c... |
295 296 |
if (!buffer) return -ENOMEM; |
5aa22af3d [SCSI] ch: remove... |
297 |
|
daa6eda65 [SCSI] add scsi c... |
298 299 |
memset(cmd,0,sizeof(cmd)); cmd[0] = MODE_SENSE; |
9cb78c16f scsi: use 64-bit ... |
300 |
cmd[1] = (ch->device->lun & 0x7) << 5; |
daa6eda65 [SCSI] add scsi c... |
301 302 |
cmd[2] = 0x1d; cmd[4] = 255; |
a9a47bf58 scsi: repurpose t... |
303 |
result = ch_do_scsi(ch, cmd, 10, buffer, 255, DMA_FROM_DEVICE); |
daa6eda65 [SCSI] add scsi c... |
304 305 |
if (0 != result) { cmd[1] |= (1<<3); |
a9a47bf58 scsi: repurpose t... |
306 |
result = ch_do_scsi(ch, cmd, 10, buffer, 255, DMA_FROM_DEVICE); |
daa6eda65 [SCSI] add scsi c... |
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 |
} 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 drivers/scsi/ch.c... |
325 326 |
VPRINTK(KERN_INFO, "type #1 (mt): 0x%x+%d [medium transport] ", |
daa6eda65 [SCSI] add scsi c... |
327 328 |
ch->firsts[CHET_MT], ch->counts[CHET_MT]); |
87da32356 drivers/scsi/ch.c... |
329 330 |
VPRINTK(KERN_INFO, "type #2 (st): 0x%x+%d [storage] ", |
daa6eda65 [SCSI] add scsi c... |
331 332 |
ch->firsts[CHET_ST], ch->counts[CHET_ST]); |
87da32356 drivers/scsi/ch.c... |
333 334 |
VPRINTK(KERN_INFO, "type #3 (ie): 0x%x+%d [import/export] ", |
daa6eda65 [SCSI] add scsi c... |
335 336 |
ch->firsts[CHET_IE], ch->counts[CHET_IE]); |
87da32356 drivers/scsi/ch.c... |
337 338 |
VPRINTK(KERN_INFO, "type #4 (dt): 0x%x+%d [data transfer] ", |
daa6eda65 [SCSI] add scsi c... |
339 340 341 |
ch->firsts[CHET_DT], ch->counts[CHET_DT]); } else { |
f42cf8d6a treewide: Fix typ... |
342 343 |
VPRINTK(KERN_INFO, "reading element address assignment page failed! "); |
daa6eda65 [SCSI] add scsi c... |
344 |
} |
5aa22af3d [SCSI] ch: remove... |
345 |
|
daa6eda65 [SCSI] add scsi c... |
346 347 348 349 350 351 352 353 |
/* 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 drivers/scsi/ch.c... |
354 355 |
VPRINTK(KERN_INFO, "type #%d (v%d): 0x%x+%d [%s, vendor specific] ", |
daa6eda65 [SCSI] add scsi c... |
356 357 358 359 360 |
i+5,i+1,vendor_firsts[i],vendor_counts[i], vendor_labels[i]); } /* look up the devices of the data transfer elements */ |
85bc081f4 drivers/scsi/aic9... |
361 |
ch->dt = kcalloc(ch->counts[CHET_DT], sizeof(*ch->dt), |
daa6eda65 [SCSI] add scsi c... |
362 |
GFP_KERNEL); |
a2cf8a630 [SCSI] ch: Check ... |
363 364 365 366 367 |
if (!ch->dt) { kfree(buffer); return -ENOMEM; } |
daa6eda65 [SCSI] add scsi c... |
368 369 370 371 372 373 |
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 drivers/scsi/ch.c... |
374 |
VPRINTK(KERN_INFO, "dt 0x%x: [insmod option] ", |
daa6eda65 [SCSI] add scsi c... |
375 376 377 |
elem+ch->firsts[CHET_DT]); } else if (0 != ch_read_element_status (ch,elem+ch->firsts[CHET_DT],data)) { |
87da32356 drivers/scsi/ch.c... |
378 379 |
VPRINTK(KERN_INFO, "dt 0x%x: READ ELEMENT STATUS failed ", |
daa6eda65 [SCSI] add scsi c... |
380 381 |
elem+ch->firsts[CHET_DT]); } else { |
87da32356 drivers/scsi/ch.c... |
382 |
VPRINTK(KERN_INFO, "dt 0x%x: ",elem+ch->firsts[CHET_DT]); |
daa6eda65 [SCSI] add scsi c... |
383 |
if (data[6] & 0x80) { |
87da32356 drivers/scsi/ch.c... |
384 385 |
VPRINTK(KERN_CONT, "not this SCSI bus "); |
daa6eda65 [SCSI] add scsi c... |
386 387 |
ch->dt[elem] = NULL; } else if (0 == (data[6] & 0x30)) { |
87da32356 drivers/scsi/ch.c... |
388 389 |
VPRINTK(KERN_CONT, "ID/LUN unknown "); |
daa6eda65 [SCSI] add scsi c... |
390 391 392 393 394 395 396 397 398 |
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 drivers/scsi/ch.c... |
399 |
VPRINTK(KERN_CONT, "ID %i, LUN %i, ",id,lun); |
daa6eda65 [SCSI] add scsi c... |
400 401 402 403 404 405 |
ch->dt[elem] = scsi_device_lookup(ch->device->host, ch->device->channel, id,lun); if (!ch->dt[elem]) { /* should not happen */ |
87da32356 drivers/scsi/ch.c... |
406 407 |
VPRINTK(KERN_CONT, "Huh? device not found! "); |
daa6eda65 [SCSI] add scsi c... |
408 |
} else { |
87da32356 drivers/scsi/ch.c... |
409 410 411 412 413 |
VPRINTK(KERN_CONT, "name: %8.8s %16.16s %4.4s ", ch->dt[elem]->vendor, ch->dt[elem]->model, ch->dt[elem]->rev); |
daa6eda65 [SCSI] add scsi c... |
414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 |
} } } 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 [SCSI] ch: remove... |
429 |
|
87da32356 drivers/scsi/ch.c... |
430 431 |
DPRINTK("position: 0x%x ",elem); |
daa6eda65 [SCSI] add scsi c... |
432 433 434 435 |
if (0 == trans) trans = ch->firsts[CHET_MT]; memset(cmd,0,sizeof(cmd)); cmd[0] = POSITION_TO_ELEMENT; |
9cb78c16f scsi: use 64-bit ... |
436 |
cmd[1] = (ch->device->lun & 0x7) << 5; |
daa6eda65 [SCSI] add scsi c... |
437 438 439 440 441 |
cmd[2] = (trans >> 8) & 0xff; cmd[3] = trans & 0xff; cmd[4] = (elem >> 8) & 0xff; cmd[5] = elem & 0xff; cmd[8] = rotate ? 1 : 0; |
a9a47bf58 scsi: repurpose t... |
442 |
return ch_do_scsi(ch, cmd, 10, NULL, 0, DMA_NONE); |
daa6eda65 [SCSI] add scsi c... |
443 444 445 446 447 448 |
} static int ch_move(scsi_changer *ch, u_int trans, u_int src, u_int dest, int rotate) { u_char cmd[12]; |
5aa22af3d [SCSI] ch: remove... |
449 |
|
87da32356 drivers/scsi/ch.c... |
450 451 |
DPRINTK("move: 0x%x => 0x%x ",src,dest); |
daa6eda65 [SCSI] add scsi c... |
452 453 454 455 |
if (0 == trans) trans = ch->firsts[CHET_MT]; memset(cmd,0,sizeof(cmd)); cmd[0] = MOVE_MEDIUM; |
9cb78c16f scsi: use 64-bit ... |
456 |
cmd[1] = (ch->device->lun & 0x7) << 5; |
daa6eda65 [SCSI] add scsi c... |
457 458 459 460 461 462 463 |
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; |
a9a47bf58 scsi: repurpose t... |
464 |
return ch_do_scsi(ch, cmd, 12, NULL,0, DMA_NONE); |
daa6eda65 [SCSI] add scsi c... |
465 466 467 468 469 470 471 |
} 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 [SCSI] ch: remove... |
472 |
|
87da32356 drivers/scsi/ch.c... |
473 474 |
DPRINTK("exchange: 0x%x => 0x%x => 0x%x ", |
daa6eda65 [SCSI] add scsi c... |
475 476 477 478 479 |
src,dest1,dest2); if (0 == trans) trans = ch->firsts[CHET_MT]; memset(cmd,0,sizeof(cmd)); cmd[0] = EXCHANGE_MEDIUM; |
9cb78c16f scsi: use 64-bit ... |
480 |
cmd[1] = (ch->device->lun & 0x7) << 5; |
daa6eda65 [SCSI] add scsi c... |
481 482 483 484 485 486 487 488 489 |
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 [SCSI] ch: remove... |
490 |
|
a9a47bf58 scsi: repurpose t... |
491 |
return ch_do_scsi(ch, cmd, 12, NULL, 0, DMA_NONE); |
daa6eda65 [SCSI] add scsi c... |
492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 |
} 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 [SCSI] ch: kmallo... |
517 |
buffer = kzalloc(512, GFP_KERNEL); |
daa6eda65 [SCSI] add scsi c... |
518 519 |
if (!buffer) return -ENOMEM; |
daa6eda65 [SCSI] add scsi c... |
520 |
|
87da32356 drivers/scsi/ch.c... |
521 522 |
DPRINTK("%s %s voltag: 0x%x => \"%s\" ", |
daa6eda65 [SCSI] add scsi c... |
523 524 525 526 527 |
clear ? "clear" : "set", alternate ? "alternate" : "primary", elem, tag); memset(cmd,0,sizeof(cmd)); cmd[0] = SEND_VOLUME_TAG; |
9cb78c16f scsi: use 64-bit ... |
528 |
cmd[1] = ((ch->device->lun & 0x7) << 5) | |
daa6eda65 [SCSI] add scsi c... |
529 530 531 532 533 534 |
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 [SCSI] ch: remove... |
535 |
|
daa6eda65 [SCSI] add scsi c... |
536 537 538 539 |
cmd[9] = 255; memcpy(buffer,tag,32); ch_check_voltag(buffer); |
a9a47bf58 scsi: repurpose t... |
540 |
result = ch_do_scsi(ch, cmd, 12, buffer, 256, DMA_TO_DEVICE); |
daa6eda65 [SCSI] add scsi c... |
541 542 543 |
kfree(buffer); return result; } |
fe08ac317 [PATCH] __user an... |
544 |
static int ch_gstatus(scsi_changer *ch, int type, unsigned char __user *dest) |
daa6eda65 [SCSI] add scsi c... |
545 546 547 548 |
{ int retval = 0; u_char data[16]; unsigned int i; |
5aa22af3d [SCSI] ch: remove... |
549 |
|
0b9506723 [SCSI] turn most ... |
550 |
mutex_lock(&ch->lock); |
daa6eda65 [SCSI] add scsi c... |
551 552 553 554 555 556 557 558 |
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 drivers/scsi/ch.c... |
559 560 |
VPRINTK(KERN_INFO, "element 0x%x: asc=0x%x, ascq=0x%x ", |
daa6eda65 [SCSI] add scsi c... |
561 562 563 564 565 566 567 |
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 [SCSI] turn most ... |
568 |
mutex_unlock(&ch->lock); |
daa6eda65 [SCSI] add scsi c... |
569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 |
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 [SCSI] ch: fix de... |
587 |
scsi_changer *ch; |
daa6eda65 [SCSI] add scsi c... |
588 |
int minor = iminor(inode); |
c45d15d24 scsi: autoconvert... |
589 |
mutex_lock(&ch_mutex); |
da707c54c [SCSI] ch: fix de... |
590 591 |
spin_lock(&ch_index_lock); ch = idr_find(&ch_index_idr, minor); |
daa6eda65 [SCSI] add scsi c... |
592 |
if (NULL == ch || scsi_device_get(ch->device)) { |
da707c54c [SCSI] ch: fix de... |
593 |
spin_unlock(&ch_index_lock); |
c45d15d24 scsi: autoconvert... |
594 |
mutex_unlock(&ch_mutex); |
daa6eda65 [SCSI] add scsi c... |
595 596 |
return -ENXIO; } |
da707c54c [SCSI] ch: fix de... |
597 |
spin_unlock(&ch_index_lock); |
daa6eda65 [SCSI] add scsi c... |
598 599 |
file->private_data = ch; |
c45d15d24 scsi: autoconvert... |
600 |
mutex_unlock(&ch_mutex); |
daa6eda65 [SCSI] add scsi c... |
601 602 603 604 605 606 607 608 609 610 |
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 [SCSI] ch: Conver... |
611 |
static long ch_ioctl(struct file *file, |
daa6eda65 [SCSI] add scsi c... |
612 613 614 615 |
unsigned int cmd, unsigned long arg) { scsi_changer *ch = file->private_data; int retval; |
fe08ac317 [PATCH] __user an... |
616 |
void __user *argp = (void __user *)arg; |
5aa22af3d [SCSI] ch: remove... |
617 |
|
906d15fbd scsi: split scsi_... |
618 619 620 621 |
retval = scsi_ioctl_block_when_processing_errors(ch->device, cmd, file->f_flags & O_NDELAY); if (retval) return retval; |
daa6eda65 [SCSI] add scsi c... |
622 623 624 625 |
switch (cmd) { case CHIOGPARAMS: { struct changer_params params; |
5aa22af3d [SCSI] ch: remove... |
626 |
|
daa6eda65 [SCSI] add scsi c... |
627 628 629 630 631 |
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 [SCSI] ch: remove... |
632 |
|
fe08ac317 [PATCH] __user an... |
633 |
if (copy_to_user(argp, ¶ms, sizeof(params))) |
daa6eda65 [SCSI] add scsi c... |
634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 |
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 [PATCH] __user an... |
658 |
if (copy_to_user(argp, &vparams, sizeof(vparams))) |
daa6eda65 [SCSI] add scsi c... |
659 660 661 |
return -EFAULT; return 0; } |
5aa22af3d [SCSI] ch: remove... |
662 |
|
daa6eda65 [SCSI] add scsi c... |
663 664 665 |
case CHIOPOSITION: { struct changer_position pos; |
5aa22af3d [SCSI] ch: remove... |
666 |
|
fe08ac317 [PATCH] __user an... |
667 |
if (copy_from_user(&pos, argp, sizeof (pos))) |
daa6eda65 [SCSI] add scsi c... |
668 669 670 |
return -EFAULT; if (0 != ch_checkrange(ch, pos.cp_type, pos.cp_unit)) { |
87da32356 drivers/scsi/ch.c... |
671 672 |
DPRINTK("CHIOPOSITION: invalid parameter "); |
daa6eda65 [SCSI] add scsi c... |
673 674 |
return -EBADSLT; } |
0b9506723 [SCSI] turn most ... |
675 |
mutex_lock(&ch->lock); |
daa6eda65 [SCSI] add scsi c... |
676 677 678 |
retval = ch_position(ch,0, ch->firsts[pos.cp_type] + pos.cp_unit, pos.cp_flags & CP_INVERT); |
0b9506723 [SCSI] turn most ... |
679 |
mutex_unlock(&ch->lock); |
daa6eda65 [SCSI] add scsi c... |
680 681 |
return retval; } |
5aa22af3d [SCSI] ch: remove... |
682 |
|
daa6eda65 [SCSI] add scsi c... |
683 684 685 |
case CHIOMOVE: { struct changer_move mv; |
fe08ac317 [PATCH] __user an... |
686 |
if (copy_from_user(&mv, argp, sizeof (mv))) |
daa6eda65 [SCSI] add scsi c... |
687 688 689 690 |
return -EFAULT; if (0 != ch_checkrange(ch, mv.cm_fromtype, mv.cm_fromunit) || 0 != ch_checkrange(ch, mv.cm_totype, mv.cm_tounit )) { |
87da32356 drivers/scsi/ch.c... |
691 692 |
DPRINTK("CHIOMOVE: invalid parameter "); |
daa6eda65 [SCSI] add scsi c... |
693 694 |
return -EBADSLT; } |
5aa22af3d [SCSI] ch: remove... |
695 |
|
0b9506723 [SCSI] turn most ... |
696 |
mutex_lock(&ch->lock); |
daa6eda65 [SCSI] add scsi c... |
697 698 699 700 |
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 [SCSI] turn most ... |
701 |
mutex_unlock(&ch->lock); |
daa6eda65 [SCSI] add scsi c... |
702 703 704 705 706 707 |
return retval; } case CHIOEXCHANGE: { struct changer_exchange mv; |
5aa22af3d [SCSI] ch: remove... |
708 |
|
fe08ac317 [PATCH] __user an... |
709 |
if (copy_from_user(&mv, argp, sizeof (mv))) |
daa6eda65 [SCSI] add scsi c... |
710 711 712 713 714 |
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 drivers/scsi/ch.c... |
715 716 |
DPRINTK("CHIOEXCHANGE: invalid parameter "); |
daa6eda65 [SCSI] add scsi c... |
717 718 |
return -EBADSLT; } |
5aa22af3d [SCSI] ch: remove... |
719 |
|
0b9506723 [SCSI] turn most ... |
720 |
mutex_lock(&ch->lock); |
daa6eda65 [SCSI] add scsi c... |
721 722 723 724 725 726 |
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 [SCSI] turn most ... |
727 |
mutex_unlock(&ch->lock); |
daa6eda65 [SCSI] add scsi c... |
728 729 730 731 732 733 |
return retval; } case CHIOGSTATUS: { struct changer_element_status ces; |
5aa22af3d [SCSI] ch: remove... |
734 |
|
fe08ac317 [PATCH] __user an... |
735 |
if (copy_from_user(&ces, argp, sizeof (ces))) |
daa6eda65 [SCSI] add scsi c... |
736 737 738 739 740 741 742 743 744 745 |
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 [SCSI] ch: fix sp... |
746 747 |
u_char ch_cmd[12]; u_char *buffer; |
daa6eda65 [SCSI] add scsi c... |
748 749 |
unsigned int elem; int result,i; |
5aa22af3d [SCSI] ch: remove... |
750 |
|
fe08ac317 [PATCH] __user an... |
751 |
if (copy_from_user(&cge, argp, sizeof (cge))) |
daa6eda65 [SCSI] add scsi c... |
752 753 754 755 756 |
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 [SCSI] ch: remove... |
757 |
|
daa6eda65 [SCSI] add scsi c... |
758 759 760 |
buffer = kmalloc(512, GFP_KERNEL | GFP_DMA); if (!buffer) return -ENOMEM; |
0b9506723 [SCSI] turn most ... |
761 |
mutex_lock(&ch->lock); |
5aa22af3d [SCSI] ch: remove... |
762 |
|
daa6eda65 [SCSI] add scsi c... |
763 |
voltag_retry: |
d70d4667e [SCSI] ch: fix sp... |
764 765 |
memset(ch_cmd, 0, sizeof(ch_cmd)); ch_cmd[0] = READ_ELEMENT_STATUS; |
9cb78c16f scsi: use 64-bit ... |
766 |
ch_cmd[1] = ((ch->device->lun & 0x7) << 5) | |
daa6eda65 [SCSI] add scsi c... |
767 768 |
(ch->voltags ? 0x10 : 0) | ch_elem_to_typecode(ch,elem); |
d70d4667e [SCSI] ch: fix sp... |
769 770 771 772 |
ch_cmd[2] = (elem >> 8) & 0xff; ch_cmd[3] = elem & 0xff; ch_cmd[5] = 1; ch_cmd[9] = 255; |
5aa22af3d [SCSI] ch: remove... |
773 |
|
a9a47bf58 scsi: repurpose t... |
774 775 |
result = ch_do_scsi(ch, ch_cmd, 12, buffer, 256, DMA_FROM_DEVICE); |
d70d4667e [SCSI] ch: fix sp... |
776 |
if (!result) { |
daa6eda65 [SCSI] add scsi c... |
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 808 809 |
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 drivers/scsi/ch.c... |
810 811 |
VPRINTK(KERN_INFO, "device has no volume tag support "); |
daa6eda65 [SCSI] add scsi c... |
812 813 814 |
goto voltag_retry; } kfree(buffer); |
0b9506723 [SCSI] turn most ... |
815 |
mutex_unlock(&ch->lock); |
5aa22af3d [SCSI] ch: remove... |
816 |
|
fe08ac317 [PATCH] __user an... |
817 |
if (copy_to_user(argp, &cge, sizeof (cge))) |
daa6eda65 [SCSI] add scsi c... |
818 819 820 821 822 823 |
return -EFAULT; return result; } case CHIOINITELEM: { |
0b9506723 [SCSI] turn most ... |
824 |
mutex_lock(&ch->lock); |
daa6eda65 [SCSI] add scsi c... |
825 |
retval = ch_init_elem(ch); |
0b9506723 [SCSI] turn most ... |
826 |
mutex_unlock(&ch->lock); |
daa6eda65 [SCSI] add scsi c... |
827 828 |
return retval; } |
5aa22af3d [SCSI] ch: remove... |
829 |
|
daa6eda65 [SCSI] add scsi c... |
830 831 832 833 |
case CHIOSVOLTAG: { struct changer_set_voltag csv; int elem; |
fe08ac317 [PATCH] __user an... |
834 |
if (copy_from_user(&csv, argp, sizeof(csv))) |
daa6eda65 [SCSI] add scsi c... |
835 836 837 |
return -EFAULT; if (0 != ch_checkrange(ch, csv.csv_type, csv.csv_unit)) { |
87da32356 drivers/scsi/ch.c... |
838 839 |
DPRINTK("CHIOSVOLTAG: invalid parameter "); |
daa6eda65 [SCSI] add scsi c... |
840 841 842 |
return -EBADSLT; } elem = ch->firsts[csv.csv_type] + csv.csv_unit; |
0b9506723 [SCSI] turn most ... |
843 |
mutex_lock(&ch->lock); |
daa6eda65 [SCSI] add scsi c... |
844 845 846 847 |
retval = ch_set_voltag(ch, elem, csv.csv_flags & CSV_AVOLTAG, csv.csv_flags & CSV_CLEARTAG, csv.csv_voltag); |
0b9506723 [SCSI] turn most ... |
848 |
mutex_unlock(&ch->lock); |
daa6eda65 [SCSI] add scsi c... |
849 850 851 852 |
return retval; } default: |
fe08ac317 [PATCH] __user an... |
853 |
return scsi_ioctl(ch->device, cmd, argp); |
daa6eda65 [SCSI] add scsi c... |
854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 |
} } #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 [SCSI] ch: remove... |
870 |
|
daa6eda65 [SCSI] add scsi c... |
871 872 873 874 875 876 877 878 879 880 |
switch (cmd) { case CHIOGPARAMS: case CHIOGVPARAMS: case CHIOPOSITION: case CHIOMOVE: case CHIOEXCHANGE: case CHIOGELEM: case CHIOINITELEM: case CHIOSVOLTAG: /* compatible */ |
f7fea185d [SCSI] ch: Conver... |
881 |
return ch_ioctl(file, cmd, arg); |
daa6eda65 [SCSI] add scsi c... |
882 883 884 |
case CHIOGSTATUS32: { struct changer_element_status32 ces32; |
fe08ac317 [PATCH] __user an... |
885 |
unsigned char __user *data; |
5aa22af3d [SCSI] ch: remove... |
886 |
|
fe08ac317 [PATCH] __user an... |
887 |
if (copy_from_user(&ces32, (void __user *)arg, sizeof (ces32))) |
daa6eda65 [SCSI] add scsi c... |
888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 |
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 SCSI: convert str... |
908 |
struct device *class_dev; |
b98c52b57 scsi: convert to ... |
909 |
int ret; |
daa6eda65 [SCSI] add scsi c... |
910 |
scsi_changer *ch; |
a3d2c2e8f [SCSI] ch: handle... |
911 |
|
daa6eda65 [SCSI] add scsi c... |
912 913 |
if (sd->type != TYPE_MEDIUM_CHANGER) return -ENODEV; |
a3d2c2e8f [SCSI] ch: handle... |
914 |
|
4530a1696 [SCSI] ch: kmallo... |
915 |
ch = kzalloc(sizeof(*ch), GFP_KERNEL); |
daa6eda65 [SCSI] add scsi c... |
916 917 |
if (NULL == ch) return -ENOMEM; |
b98c52b57 scsi: convert to ... |
918 |
idr_preload(GFP_KERNEL); |
da707c54c [SCSI] ch: fix de... |
919 |
spin_lock(&ch_index_lock); |
b98c52b57 scsi: convert to ... |
920 |
ret = idr_alloc(&ch_index_idr, ch, 0, CH_MAX_DEVS + 1, GFP_NOWAIT); |
da707c54c [SCSI] ch: fix de... |
921 |
spin_unlock(&ch_index_lock); |
b98c52b57 scsi: convert to ... |
922 |
idr_preload_end(); |
da707c54c [SCSI] ch: fix de... |
923 |
|
b98c52b57 scsi: convert to ... |
924 925 926 |
if (ret < 0) { if (ret == -ENOSPC) ret = -ENODEV; |
da707c54c [SCSI] ch: fix de... |
927 |
goto free_ch; |
da707c54c [SCSI] ch: fix de... |
928 |
} |
b98c52b57 scsi: convert to ... |
929 |
ch->minor = ret; |
daa6eda65 [SCSI] add scsi c... |
930 |
sprintf(ch->name,"ch%d",ch->minor); |
a3d2c2e8f [SCSI] ch: handle... |
931 |
|
d73a1a674 device create: sc... |
932 933 934 |
class_dev = device_create(ch_sysfs_class, dev, MKDEV(SCSI_CHANGER_MAJOR, ch->minor), ch, "s%s", ch->name); |
a3d2c2e8f [SCSI] ch: handle... |
935 |
if (IS_ERR(class_dev)) { |
28c31729c scsi: Implement c... |
936 937 938 |
sdev_printk(KERN_WARNING, sd, "ch%d: device_create failed ", ch->minor); |
da707c54c [SCSI] ch: fix de... |
939 940 |
ret = PTR_ERR(class_dev); goto remove_idr; |
a3d2c2e8f [SCSI] ch: handle... |
941 |
} |
0b9506723 [SCSI] turn most ... |
942 |
mutex_init(&ch->lock); |
daa6eda65 [SCSI] add scsi c... |
943 944 945 946 |
ch->device = sd; ch_readconfig(ch); if (init) ch_init_elem(ch); |
3d164fb09 [SCSI] ch: fix ch... |
947 |
dev_set_drvdata(dev, ch); |
017560fca [SCSI] use sfoo_p... |
948 949 |
sdev_printk(KERN_INFO, sd, "Attached scsi changer %s ", ch->name); |
a3d2c2e8f [SCSI] ch: handle... |
950 |
|
daa6eda65 [SCSI] add scsi c... |
951 |
return 0; |
da707c54c [SCSI] ch: fix de... |
952 |
remove_idr: |
b98c52b57 scsi: convert to ... |
953 |
idr_remove(&ch_index_idr, ch->minor); |
da707c54c [SCSI] ch: fix de... |
954 955 956 |
free_ch: kfree(ch); return ret; |
daa6eda65 [SCSI] add scsi c... |
957 958 959 960 |
} static int ch_remove(struct device *dev) { |
da707c54c [SCSI] ch: fix de... |
961 |
scsi_changer *ch = dev_get_drvdata(dev); |
daa6eda65 [SCSI] add scsi c... |
962 |
|
da707c54c [SCSI] ch: fix de... |
963 964 965 |
spin_lock(&ch_index_lock); idr_remove(&ch_index_idr, ch->minor); spin_unlock(&ch_index_lock); |
daa6eda65 [SCSI] add scsi c... |
966 |
|
ee959b00c SCSI: convert str... |
967 |
device_destroy(ch_sysfs_class, MKDEV(SCSI_CHANGER_MAJOR,ch->minor)); |
daa6eda65 [SCSI] add scsi c... |
968 969 |
kfree(ch->dt); kfree(ch); |
daa6eda65 [SCSI] add scsi c... |
970 971 |
return 0; } |
5aa22af3d [SCSI] ch: remove... |
972 |
static struct scsi_driver ch_template = { |
5aa22af3d [SCSI] ch: remove... |
973 974 |
.gendrv = { .name = "ch", |
3af6b3526 scsi: remove scsi... |
975 |
.owner = THIS_MODULE, |
5aa22af3d [SCSI] ch: remove... |
976 977 978 979 980 981 982 983 984 985 986 987 988 |
.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 |
6038f373a llseek: automatic... |
989 |
.llseek = noop_llseek, |
5aa22af3d [SCSI] ch: remove... |
990 |
}; |
daa6eda65 [SCSI] add scsi c... |
991 992 993 |
static int __init init_ch_module(void) { int rc; |
5aa22af3d [SCSI] ch: remove... |
994 |
|
daa6eda65 [SCSI] add scsi c... |
995 996 |
printk(KERN_INFO "SCSI Media Changer driver v" VERSION " "); |
21feb5ccd [SCSI] convert sc... |
997 |
ch_sysfs_class = class_create(THIS_MODULE, "scsi_changer"); |
daa6eda65 [SCSI] add scsi c... |
998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 |
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 [SCSI] convert sc... |
1017 |
class_destroy(ch_sysfs_class); |
daa6eda65 [SCSI] add scsi c... |
1018 1019 |
return rc; } |
5aa22af3d [SCSI] ch: remove... |
1020 |
static void __exit exit_ch_module(void) |
daa6eda65 [SCSI] add scsi c... |
1021 1022 1023 |
{ scsi_unregister_driver(&ch_template.gendrv); unregister_chrdev(SCSI_CHANGER_MAJOR, "ch"); |
21feb5ccd [SCSI] convert sc... |
1024 |
class_destroy(ch_sysfs_class); |
da707c54c [SCSI] ch: fix de... |
1025 |
idr_destroy(&ch_index_idr); |
daa6eda65 [SCSI] add scsi c... |
1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 |
} module_init(init_ch_module); module_exit(exit_ch_module); /* * Local variables: * c-basic-offset: 8 * End: */ |