Blame view

drivers/block/pktcdvd.c 76.4 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
  /*
   * Copyright (C) 2000 Jens Axboe <axboe@suse.de>
   * Copyright (C) 2001-2004 Peter Osterlund <petero2@telia.com>
adb9250a0   Thomas Maier   [PATCH] pktcdvd: ...
4
   * Copyright (C) 2006 Thomas Maier <balagi@justmail.de>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5
6
7
8
   *
   * May be copied or modified under the terms of the GNU General Public
   * License.  See linux/COPYING for more information.
   *
a676f8d09   Peter Osterlund   [PATCH] pktcdvd: ...
9
10
   * Packet writing layer for ATAPI and SCSI CD-RW, DVD+RW, DVD-RW and
   * DVD-RAM devices.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
12
13
   *
   * Theory of operation:
   *
a676f8d09   Peter Osterlund   [PATCH] pktcdvd: ...
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
   * At the lowest level, there is the standard driver for the CD/DVD device,
   * typically ide-cd.c or sr.c. This driver can handle read and write requests,
   * but it doesn't know anything about the special restrictions that apply to
   * packet writing. One restriction is that write requests must be aligned to
   * packet boundaries on the physical media, and the size of a write request
   * must be equal to the packet size. Another restriction is that a
   * GPCMD_FLUSH_CACHE command has to be issued to the drive before a read
   * command, if the previous command was a write.
   *
   * The purpose of the packet writing driver is to hide these restrictions from
   * higher layers, such as file systems, and present a block device that can be
   * randomly read and written using 2kB-sized blocks.
   *
   * The lowest layer in the packet writing driver is the packet I/O scheduler.
   * Its data is defined by the struct packet_iosched and includes two bio
   * queues with pending read and write requests. These queues are processed
   * by the pkt_iosched_process_queue() function. The write requests in this
   * queue are already properly aligned and sized. This layer is responsible for
   * issuing the flush cache commands and scheduling the I/O in a good order.
   *
   * The next layer transforms unaligned write requests to aligned writes. This
   * transformation requires reading missing pieces of data from the underlying
   * block device, assembling the pieces to full packets and queuing them to the
   * packet I/O scheduler.
   *
   * At the top layer there is a custom make_request_fn function that forwards
   * read requests directly to the iosched queue and puts write requests in the
   * unaligned write queue. A kernel thread performs the necessary read
   * gathering to convert the unaligned writes to aligned writes and then feeds
   * them to the packet I/O scheduler.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
45
   *
   *************************************************************************/
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
  #include <linux/pktcdvd.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
48
49
  #include <linux/module.h>
  #include <linux/types.h>
  #include <linux/kernel.h>
f80a0ca6a   Arnd Bergmann   pktcdvd: improve ...
50
  #include <linux/compat.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51
52
53
54
55
56
57
  #include <linux/kthread.h>
  #include <linux/errno.h>
  #include <linux/spinlock.h>
  #include <linux/file.h>
  #include <linux/proc_fs.h>
  #include <linux/seq_file.h>
  #include <linux/miscdevice.h>
7dfb71030   Nigel Cunningham   [PATCH] Add inclu...
58
  #include <linux/freezer.h>
1657f824e   Jes Sorensen   [PATCH] sem2mutex...
59
  #include <linux/mutex.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
60
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
62
  #include <scsi/scsi_cmnd.h>
  #include <scsi/scsi_ioctl.h>
cef289633   Peter Osterlund   [PATCH] pktcdvd: ...
63
  #include <scsi/scsi.h>
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
64
65
  #include <linux/debugfs.h>
  #include <linux/device.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66
67
  
  #include <asm/uaccess.h>
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
68
  #define DRIVER_NAME	"pktcdvd"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
  #if PACKET_DEBUG
  #define DPRINTK(fmt, args...) printk(KERN_NOTICE fmt, ##args)
  #else
  #define DPRINTK(fmt, args...)
  #endif
  
  #if PACKET_DEBUG > 1
  #define VPRINTK(fmt, args...) printk(KERN_NOTICE fmt, ##args)
  #else
  #define VPRINTK(fmt, args...)
  #endif
  
  #define MAX_SPEED 0xffff
  
  #define ZONE(sector, pd) (((sector) + (pd)->offset) & ~((pd)->settings.size - 1))
2a48fc0ab   Arnd Bergmann   block: autoconver...
84
  static DEFINE_MUTEX(pktcdvd_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
86
  static struct pktcdvd_device *pkt_devs[MAX_WRITERS];
  static struct proc_dir_entry *pkt_proc;
add216608   Thomas Maier   [PATCH] pktcdvd: ...
87
  static int pktdev_major;
0a0fc9601   Thomas Maier   [PATCH] pktcdvd: ...
88
89
  static int write_congestion_on  = PKT_WRITE_CONGESTION_ON;
  static int write_congestion_off = PKT_WRITE_CONGESTION_OFF;
1657f824e   Jes Sorensen   [PATCH] sem2mutex...
90
  static struct mutex ctl_mutex;	/* Serialize open/close/setup/teardown */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
  static mempool_t *psd_pool;
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
92
  static struct class	*class_pktcdvd = NULL;    /* /sys/class/pktcdvd */
ea5ffff57   GeunSik Lim   debugfs: Modify d...
93
  static struct dentry	*pkt_debugfs_root = NULL; /* /sys/kernel/debug/pktcdvd */
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
  
  /* forward declaration */
  static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev);
  static int pkt_remove_dev(dev_t pkt_dev);
  static int pkt_seq_show(struct seq_file *m, void *p);
  
  
  
  /*
   * create and register a pktcdvd kernel object.
   */
  static struct pktcdvd_kobj* pkt_kobj_create(struct pktcdvd_device *pd,
  					const char* name,
  					struct kobject* parent,
  					struct kobj_type* ktype)
  {
  	struct pktcdvd_kobj *p;
89c426066   Greg Kroah-Hartman   Kobject: change d...
111
  	int error;
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
112
113
114
  	p = kzalloc(sizeof(*p), GFP_KERNEL);
  	if (!p)
  		return NULL;
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
115
  	p->pd = pd;
89c426066   Greg Kroah-Hartman   Kobject: change d...
116
117
  	error = kobject_init_and_add(&p->kobj, ktype, parent, "%s", name);
  	if (error) {
d17a18dd9   Dave Young   pktcdvd: add kobj...
118
  		kobject_put(&p->kobj);
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
119
  		return NULL;
d17a18dd9   Dave Young   pktcdvd: add kobj...
120
  	}
89c426066   Greg Kroah-Hartman   Kobject: change d...
121
  	kobject_uevent(&p->kobj, KOBJ_ADD);
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
122
123
124
125
126
127
128
129
  	return p;
  }
  /*
   * remove a pktcdvd kernel object.
   */
  static void pkt_kobj_remove(struct pktcdvd_kobj *p)
  {
  	if (p)
c10997f65   Greg Kroah-Hartman   Kobject: convert ...
130
  		kobject_put(&p->kobj);
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
  }
  /*
   * default release function for pktcdvd kernel objects.
   */
  static void pkt_kobj_release(struct kobject *kobj)
  {
  	kfree(to_pktcdvdkobj(kobj));
  }
  
  
  /**********************************************************
   *
   * sysfs interface for pktcdvd
   * by (C) 2006  Thomas Maier <balagi@justmail.de>
   *
   **********************************************************/
  
  #define DEF_ATTR(_obj,_name,_mode) \
7b595756e   Tejun Heo   sysfs: kill unnec...
149
  	static struct attribute _obj = { .name = _name, .mode = _mode }
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
  
  /**********************************************************
    /sys/class/pktcdvd/pktcdvd[0-7]/
                       stat/reset
                       stat/packets_started
                       stat/packets_finished
                       stat/kb_written
                       stat/kb_read
                       stat/kb_read_gather
                       write_queue/size
                       write_queue/congestion_off
                       write_queue/congestion_on
   **********************************************************/
  
  DEF_ATTR(kobj_pkt_attr_st1, "reset", 0200);
  DEF_ATTR(kobj_pkt_attr_st2, "packets_started", 0444);
  DEF_ATTR(kobj_pkt_attr_st3, "packets_finished", 0444);
  DEF_ATTR(kobj_pkt_attr_st4, "kb_written", 0444);
  DEF_ATTR(kobj_pkt_attr_st5, "kb_read", 0444);
  DEF_ATTR(kobj_pkt_attr_st6, "kb_read_gather", 0444);
  
  static struct attribute *kobj_pkt_attrs_stat[] = {
  	&kobj_pkt_attr_st1,
  	&kobj_pkt_attr_st2,
  	&kobj_pkt_attr_st3,
  	&kobj_pkt_attr_st4,
  	&kobj_pkt_attr_st5,
  	&kobj_pkt_attr_st6,
  	NULL
  };
  
  DEF_ATTR(kobj_pkt_attr_wq1, "size", 0444);
  DEF_ATTR(kobj_pkt_attr_wq2, "congestion_off", 0644);
  DEF_ATTR(kobj_pkt_attr_wq3, "congestion_on",  0644);
  
  static struct attribute *kobj_pkt_attrs_wqueue[] = {
  	&kobj_pkt_attr_wq1,
  	&kobj_pkt_attr_wq2,
  	&kobj_pkt_attr_wq3,
  	NULL
  };
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
  static ssize_t kobj_pkt_show(struct kobject *kobj,
  			struct attribute *attr, char *data)
  {
  	struct pktcdvd_device *pd = to_pktcdvdkobj(kobj)->pd;
  	int n = 0;
  	int v;
  	if (strcmp(attr->name, "packets_started") == 0) {
  		n = sprintf(data, "%lu
  ", pd->stats.pkt_started);
  
  	} else if (strcmp(attr->name, "packets_finished") == 0) {
  		n = sprintf(data, "%lu
  ", pd->stats.pkt_ended);
  
  	} else if (strcmp(attr->name, "kb_written") == 0) {
  		n = sprintf(data, "%lu
  ", pd->stats.secs_w >> 1);
  
  	} else if (strcmp(attr->name, "kb_read") == 0) {
  		n = sprintf(data, "%lu
  ", pd->stats.secs_r >> 1);
  
  	} else if (strcmp(attr->name, "kb_read_gather") == 0) {
  		n = sprintf(data, "%lu
  ", pd->stats.secs_rg >> 1);
  
  	} else if (strcmp(attr->name, "size") == 0) {
  		spin_lock(&pd->lock);
  		v = pd->bio_queue_size;
  		spin_unlock(&pd->lock);
  		n = sprintf(data, "%d
  ", v);
  
  	} else if (strcmp(attr->name, "congestion_off") == 0) {
  		spin_lock(&pd->lock);
  		v = pd->write_congestion_off;
  		spin_unlock(&pd->lock);
  		n = sprintf(data, "%d
  ", v);
  
  	} else if (strcmp(attr->name, "congestion_on") == 0) {
  		spin_lock(&pd->lock);
  		v = pd->write_congestion_on;
  		spin_unlock(&pd->lock);
  		n = sprintf(data, "%d
  ", v);
  	}
  	return n;
  }
  
  static void init_write_congestion_marks(int* lo, int* hi)
  {
  	if (*hi > 0) {
  		*hi = max(*hi, 500);
  		*hi = min(*hi, 1000000);
  		if (*lo <= 0)
  			*lo = *hi - 100;
  		else {
  			*lo = min(*lo, *hi - 100);
  			*lo = max(*lo, 100);
  		}
  	} else {
  		*hi = -1;
  		*lo = -1;
  	}
  }
  
  static ssize_t kobj_pkt_store(struct kobject *kobj,
  			struct attribute *attr,
  			const char *data, size_t len)
  {
  	struct pktcdvd_device *pd = to_pktcdvdkobj(kobj)->pd;
  	int val;
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
264

83f3aa3dc   Thomas Maier   [PATCH] pktcdvd: ...
265
  	if (strcmp(attr->name, "reset") == 0 && len > 0) {
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
266
267
268
269
270
271
272
  		pd->stats.pkt_started = 0;
  		pd->stats.pkt_ended = 0;
  		pd->stats.secs_w = 0;
  		pd->stats.secs_rg = 0;
  		pd->stats.secs_r = 0;
  
  	} else if (strcmp(attr->name, "congestion_off") == 0
83f3aa3dc   Thomas Maier   [PATCH] pktcdvd: ...
273
  		   && sscanf(data, "%d", &val) == 1) {
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
274
275
276
277
278
279
280
  		spin_lock(&pd->lock);
  		pd->write_congestion_off = val;
  		init_write_congestion_marks(&pd->write_congestion_off,
  					&pd->write_congestion_on);
  		spin_unlock(&pd->lock);
  
  	} else if (strcmp(attr->name, "congestion_on") == 0
83f3aa3dc   Thomas Maier   [PATCH] pktcdvd: ...
281
  		   && sscanf(data, "%d", &val) == 1) {
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
282
283
284
285
286
287
288
289
  		spin_lock(&pd->lock);
  		pd->write_congestion_on = val;
  		init_write_congestion_marks(&pd->write_congestion_off,
  					&pd->write_congestion_on);
  		spin_unlock(&pd->lock);
  	}
  	return len;
  }
52cf25d0a   Emese Revfy   Driver core: Cons...
290
  static const struct sysfs_ops kobj_pkt_ops = {
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
  	.show = kobj_pkt_show,
  	.store = kobj_pkt_store
  };
  static struct kobj_type kobj_pkt_type_stat = {
  	.release = pkt_kobj_release,
  	.sysfs_ops = &kobj_pkt_ops,
  	.default_attrs = kobj_pkt_attrs_stat
  };
  static struct kobj_type kobj_pkt_type_wqueue = {
  	.release = pkt_kobj_release,
  	.sysfs_ops = &kobj_pkt_ops,
  	.default_attrs = kobj_pkt_attrs_wqueue
  };
  
  static void pkt_sysfs_dev_new(struct pktcdvd_device *pd)
  {
  	if (class_pktcdvd) {
cba767175   Kay Sievers   pktcdvd: remove b...
308
  		pd->dev = device_create(class_pktcdvd, NULL, MKDEV(0, 0), NULL,
1ff9f542e   Greg Kroah-Hartman   device create: bl...
309
  					"%s", pd->name);
6013c12be   Tony Jones   pktcdvd: Convert ...
310
311
  		if (IS_ERR(pd->dev))
  			pd->dev = NULL;
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
312
  	}
6013c12be   Tony Jones   pktcdvd: Convert ...
313
  	if (pd->dev) {
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
314
  		pd->kobj_stat = pkt_kobj_create(pd, "stat",
6013c12be   Tony Jones   pktcdvd: Convert ...
315
  					&pd->dev->kobj,
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
316
317
  					&kobj_pkt_type_stat);
  		pd->kobj_wqueue = pkt_kobj_create(pd, "write_queue",
6013c12be   Tony Jones   pktcdvd: Convert ...
318
  					&pd->dev->kobj,
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
319
320
321
322
323
324
325
326
327
  					&kobj_pkt_type_wqueue);
  	}
  }
  
  static void pkt_sysfs_dev_remove(struct pktcdvd_device *pd)
  {
  	pkt_kobj_remove(pd->kobj_stat);
  	pkt_kobj_remove(pd->kobj_wqueue);
  	if (class_pktcdvd)
ca0bf64d9   Thadeu Lima de Souza Cascardo   pktcdvd: removing...
328
  		device_unregister(pd->dev);
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
329
330
331
332
333
334
335
336
337
338
339
340
341
342
  }
  
  
  /********************************************************************
    /sys/class/pktcdvd/
                       add            map block device
                       remove         unmap packet dev
                       device_map     show mappings
   *******************************************************************/
  
  static void class_pktcdvd_release(struct class *cls)
  {
  	kfree(cls);
  }
28812fe11   Andi Kleen   driver-core: Add ...
343
344
345
  static ssize_t class_pktcdvd_show_map(struct class *c,
  					struct class_attribute *attr,
  					char *data)
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
  {
  	int n = 0;
  	int idx;
  	mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
  	for (idx = 0; idx < MAX_WRITERS; idx++) {
  		struct pktcdvd_device *pd = pkt_devs[idx];
  		if (!pd)
  			continue;
  		n += sprintf(data+n, "%s %u:%u %u:%u
  ",
  			pd->name,
  			MAJOR(pd->pkt_dev), MINOR(pd->pkt_dev),
  			MAJOR(pd->bdev->bd_dev),
  			MINOR(pd->bdev->bd_dev));
  	}
  	mutex_unlock(&ctl_mutex);
  	return n;
  }
28812fe11   Andi Kleen   driver-core: Add ...
364
365
366
  static ssize_t class_pktcdvd_store_add(struct class *c,
  					struct class_attribute *attr,
  					const char *buf,
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
367
368
369
  					size_t count)
  {
  	unsigned int major, minor;
fffe487d5   Tejun Heo   pktcdvd: fix BUG ...
370

83f3aa3dc   Thomas Maier   [PATCH] pktcdvd: ...
371
  	if (sscanf(buf, "%u:%u", &major, &minor) == 2) {
fffe487d5   Tejun Heo   pktcdvd: fix BUG ...
372
373
374
  		/* pkt_setup_dev() expects caller to hold reference to self */
  		if (!try_module_get(THIS_MODULE))
  			return -ENODEV;
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
375
  		pkt_setup_dev(MKDEV(major, minor), NULL);
fffe487d5   Tejun Heo   pktcdvd: fix BUG ...
376
377
  
  		module_put(THIS_MODULE);
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
378
379
  		return count;
  	}
fffe487d5   Tejun Heo   pktcdvd: fix BUG ...
380

32694850a   Thomas Maier   [PATCH] pktcdvd: ...
381
382
  	return -EINVAL;
  }
28812fe11   Andi Kleen   driver-core: Add ...
383
384
385
  static ssize_t class_pktcdvd_store_remove(struct class *c,
  					  struct class_attribute *attr,
  					  const char *buf,
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
386
387
388
  					size_t count)
  {
  	unsigned int major, minor;
83f3aa3dc   Thomas Maier   [PATCH] pktcdvd: ...
389
  	if (sscanf(buf, "%u:%u", &major, &minor) == 2) {
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
  		pkt_remove_dev(MKDEV(major, minor));
  		return count;
  	}
  	return -EINVAL;
  }
  
  static struct class_attribute class_pktcdvd_attrs[] = {
   __ATTR(add,            0200, NULL, class_pktcdvd_store_add),
   __ATTR(remove,         0200, NULL, class_pktcdvd_store_remove),
   __ATTR(device_map,     0444, class_pktcdvd_show_map, NULL),
   __ATTR_NULL
  };
  
  
  static int pkt_sysfs_init(void)
  {
  	int ret = 0;
  
  	/*
  	 * create control files in sysfs
  	 * /sys/class/pktcdvd/...
  	 */
  	class_pktcdvd = kzalloc(sizeof(*class_pktcdvd), GFP_KERNEL);
  	if (!class_pktcdvd)
  		return -ENOMEM;
  	class_pktcdvd->name = DRIVER_NAME;
  	class_pktcdvd->owner = THIS_MODULE;
  	class_pktcdvd->class_release = class_pktcdvd_release;
  	class_pktcdvd->class_attrs = class_pktcdvd_attrs;
  	ret = class_register(class_pktcdvd);
  	if (ret) {
  		kfree(class_pktcdvd);
  		class_pktcdvd = NULL;
  		printk(DRIVER_NAME": failed to create class pktcdvd
  ");
  		return ret;
  	}
  	return 0;
  }
  
  static void pkt_sysfs_cleanup(void)
  {
  	if (class_pktcdvd)
  		class_destroy(class_pktcdvd);
  	class_pktcdvd = NULL;
  }
  
  /********************************************************************
    entries in debugfs
156f5a780   GeunSik Lim   debugfs: Fix term...
439
    /sys/kernel/debug/pktcdvd[0-7]/
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
440
441
442
443
444
445
446
447
448
449
450
451
452
  			info
  
   *******************************************************************/
  
  static int pkt_debugfs_seq_show(struct seq_file *m, void *p)
  {
  	return pkt_seq_show(m, p);
  }
  
  static int pkt_debugfs_fops_open(struct inode *inode, struct file *file)
  {
  	return single_open(file, pkt_debugfs_seq_show, inode->i_private);
  }
2b8693c06   Arjan van de Ven   [PATCH] mark stru...
453
  static const struct file_operations debug_fops = {
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
  	.open		= pkt_debugfs_fops_open,
  	.read		= seq_read,
  	.llseek		= seq_lseek,
  	.release	= single_release,
  	.owner		= THIS_MODULE,
  };
  
  static void pkt_debugfs_dev_new(struct pktcdvd_device *pd)
  {
  	if (!pkt_debugfs_root)
  		return;
  	pd->dfs_f_info = NULL;
  	pd->dfs_d_root = debugfs_create_dir(pd->name, pkt_debugfs_root);
  	if (IS_ERR(pd->dfs_d_root)) {
  		pd->dfs_d_root = NULL;
  		return;
  	}
  	pd->dfs_f_info = debugfs_create_file("info", S_IRUGO,
  				pd->dfs_d_root, pd, &debug_fops);
  	if (IS_ERR(pd->dfs_f_info)) {
  		pd->dfs_f_info = NULL;
  		return;
  	}
  }
  
  static void pkt_debugfs_dev_remove(struct pktcdvd_device *pd)
  {
  	if (!pkt_debugfs_root)
  		return;
  	if (pd->dfs_f_info)
  		debugfs_remove(pd->dfs_f_info);
  	pd->dfs_f_info = NULL;
  	if (pd->dfs_d_root)
  		debugfs_remove(pd->dfs_d_root);
  	pd->dfs_d_root = NULL;
  }
  
  static void pkt_debugfs_init(void)
  {
  	pkt_debugfs_root = debugfs_create_dir(DRIVER_NAME, NULL);
  	if (IS_ERR(pkt_debugfs_root)) {
  		pkt_debugfs_root = NULL;
  		return;
  	}
  }
  
  static void pkt_debugfs_cleanup(void)
  {
  	if (!pkt_debugfs_root)
  		return;
  	debugfs_remove(pkt_debugfs_root);
  	pkt_debugfs_root = NULL;
  }
  
  /* ----------------------------------------------------------*/
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
509
510
511
512
513
  
  static void pkt_bio_finished(struct pktcdvd_device *pd)
  {
  	BUG_ON(atomic_read(&pd->cdrw.pending_bios) <= 0);
  	if (atomic_dec_and_test(&pd->cdrw.pending_bios)) {
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
514
515
  		VPRINTK(DRIVER_NAME": queue empty
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
  		atomic_set(&pd->iosched.attention, 1);
  		wake_up(&pd->wqueue);
  	}
  }
  
  static void pkt_bio_destructor(struct bio *bio)
  {
  	kfree(bio->bi_io_vec);
  	kfree(bio);
  }
  
  static struct bio *pkt_bio_alloc(int nr_iovecs)
  {
  	struct bio_vec *bvl = NULL;
  	struct bio *bio;
  
  	bio = kmalloc(sizeof(struct bio), GFP_KERNEL);
  	if (!bio)
  		goto no_bio;
  	bio_init(bio);
1107d2e03   Peter Osterlund   [PATCH] pktcdvd: ...
536
  	bvl = kcalloc(nr_iovecs, sizeof(struct bio_vec), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
537
538
  	if (!bvl)
  		goto no_bvl;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
  
  	bio->bi_max_vecs = nr_iovecs;
  	bio->bi_io_vec = bvl;
  	bio->bi_destructor = pkt_bio_destructor;
  
  	return bio;
  
   no_bvl:
  	kfree(bio);
   no_bio:
  	return NULL;
  }
  
  /*
   * Allocate a packet_data struct
   */
e1bc89bc9   Peter Osterlund   [PATCH] pktcdvd: ...
555
  static struct packet_data *pkt_alloc_packet_data(int frames)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
556
557
558
  {
  	int i;
  	struct packet_data *pkt;
1107d2e03   Peter Osterlund   [PATCH] pktcdvd: ...
559
  	pkt = kzalloc(sizeof(struct packet_data), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
560
561
  	if (!pkt)
  		goto no_pkt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
562

e1bc89bc9   Peter Osterlund   [PATCH] pktcdvd: ...
563
564
  	pkt->frames = frames;
  	pkt->w_bio = pkt_bio_alloc(frames);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
565
566
  	if (!pkt->w_bio)
  		goto no_bio;
e1bc89bc9   Peter Osterlund   [PATCH] pktcdvd: ...
567
  	for (i = 0; i < frames / FRAMES_PER_PAGE; i++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
568
569
570
571
572
573
  		pkt->pages[i] = alloc_page(GFP_KERNEL|__GFP_ZERO);
  		if (!pkt->pages[i])
  			goto no_page;
  	}
  
  	spin_lock_init(&pkt->lock);
c5ecc484c   Akinobu Mita   pktcdvd: use BIO ...
574
  	bio_list_init(&pkt->orig_bios);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
575

e1bc89bc9   Peter Osterlund   [PATCH] pktcdvd: ...
576
  	for (i = 0; i < frames; i++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
577
578
579
580
581
582
583
584
585
  		struct bio *bio = pkt_bio_alloc(1);
  		if (!bio)
  			goto no_rd_bio;
  		pkt->r_bios[i] = bio;
  	}
  
  	return pkt;
  
  no_rd_bio:
e1bc89bc9   Peter Osterlund   [PATCH] pktcdvd: ...
586
  	for (i = 0; i < frames; i++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
587
588
589
590
591
592
  		struct bio *bio = pkt->r_bios[i];
  		if (bio)
  			bio_put(bio);
  	}
  
  no_page:
e1bc89bc9   Peter Osterlund   [PATCH] pktcdvd: ...
593
  	for (i = 0; i < frames / FRAMES_PER_PAGE; i++)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
  		if (pkt->pages[i])
  			__free_page(pkt->pages[i]);
  	bio_put(pkt->w_bio);
  no_bio:
  	kfree(pkt);
  no_pkt:
  	return NULL;
  }
  
  /*
   * Free a packet_data struct
   */
  static void pkt_free_packet_data(struct packet_data *pkt)
  {
  	int i;
e1bc89bc9   Peter Osterlund   [PATCH] pktcdvd: ...
609
  	for (i = 0; i < pkt->frames; i++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
610
611
612
613
  		struct bio *bio = pkt->r_bios[i];
  		if (bio)
  			bio_put(bio);
  	}
e1bc89bc9   Peter Osterlund   [PATCH] pktcdvd: ...
614
  	for (i = 0; i < pkt->frames / FRAMES_PER_PAGE; i++)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
615
616
617
618
619
620
621
622
623
624
625
626
627
628
  		__free_page(pkt->pages[i]);
  	bio_put(pkt->w_bio);
  	kfree(pkt);
  }
  
  static void pkt_shrink_pktlist(struct pktcdvd_device *pd)
  {
  	struct packet_data *pkt, *next;
  
  	BUG_ON(!list_empty(&pd->cdrw.pkt_active_list));
  
  	list_for_each_entry_safe(pkt, next, &pd->cdrw.pkt_free_list, list) {
  		pkt_free_packet_data(pkt);
  	}
e1bc89bc9   Peter Osterlund   [PATCH] pktcdvd: ...
629
  	INIT_LIST_HEAD(&pd->cdrw.pkt_free_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
630
631
632
633
634
  }
  
  static int pkt_grow_pktlist(struct pktcdvd_device *pd, int nr_packets)
  {
  	struct packet_data *pkt;
e1bc89bc9   Peter Osterlund   [PATCH] pktcdvd: ...
635
  	BUG_ON(!list_empty(&pd->cdrw.pkt_free_list));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
636
  	while (nr_packets > 0) {
e1bc89bc9   Peter Osterlund   [PATCH] pktcdvd: ...
637
  		pkt = pkt_alloc_packet_data(pd->settings.size >> 2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
638
639
640
641
642
643
644
645
646
647
648
  		if (!pkt) {
  			pkt_shrink_pktlist(pd);
  			return 0;
  		}
  		pkt->id = nr_packets;
  		pkt->pd = pd;
  		list_add(&pkt->list, &pd->cdrw.pkt_free_list);
  		nr_packets--;
  	}
  	return 1;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
649
650
651
652
653
654
655
  static inline struct pkt_rb_node *pkt_rbtree_next(struct pkt_rb_node *node)
  {
  	struct rb_node *n = rb_next(&node->rb_node);
  	if (!n)
  		return NULL;
  	return rb_entry(n, struct pkt_rb_node, rb_node);
  }
ac8939630   Peter Osterlund   [PATCH] pktcdvd: ...
656
  static void pkt_rbtree_erase(struct pktcdvd_device *pd, struct pkt_rb_node *node)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
  {
  	rb_erase(&node->rb_node, &pd->bio_queue);
  	mempool_free(node, pd->rb_pool);
  	pd->bio_queue_size--;
  	BUG_ON(pd->bio_queue_size < 0);
  }
  
  /*
   * Find the first node in the pd->bio_queue rb tree with a starting sector >= s.
   */
  static struct pkt_rb_node *pkt_rbtree_find(struct pktcdvd_device *pd, sector_t s)
  {
  	struct rb_node *n = pd->bio_queue.rb_node;
  	struct rb_node *next;
  	struct pkt_rb_node *tmp;
  
  	if (!n) {
  		BUG_ON(pd->bio_queue_size > 0);
  		return NULL;
  	}
  
  	for (;;) {
  		tmp = rb_entry(n, struct pkt_rb_node, rb_node);
  		if (s <= tmp->bio->bi_sector)
  			next = n->rb_left;
  		else
  			next = n->rb_right;
  		if (!next)
  			break;
  		n = next;
  	}
  
  	if (s > tmp->bio->bi_sector) {
  		tmp = pkt_rbtree_next(tmp);
  		if (!tmp)
  			return NULL;
  	}
  	BUG_ON(s > tmp->bio->bi_sector);
  	return tmp;
  }
  
  /*
   * Insert a node into the pd->bio_queue rb tree.
   */
  static void pkt_rbtree_insert(struct pktcdvd_device *pd, struct pkt_rb_node *node)
  {
  	struct rb_node **p = &pd->bio_queue.rb_node;
  	struct rb_node *parent = NULL;
  	sector_t s = node->bio->bi_sector;
  	struct pkt_rb_node *tmp;
  
  	while (*p) {
  		parent = *p;
  		tmp = rb_entry(parent, struct pkt_rb_node, rb_node);
  		if (s < tmp->bio->bi_sector)
  			p = &(*p)->rb_left;
  		else
  			p = &(*p)->rb_right;
  	}
  	rb_link_node(&node->rb_node, parent, p);
  	rb_insert_color(&node->rb_node, &pd->bio_queue);
  	pd->bio_queue_size++;
  }
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
722
723
724
725
726
   * Send a packet_command to the underlying block device and
   * wait for completion.
   */
  static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command *cgc)
  {
165125e1e   Jens Axboe   [BLOCK] Get rid o...
727
  	struct request_queue *q = bdev_get_queue(pd->bdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
728
  	struct request *rq;
406c9b605   Christoph Hellwig   [PATCH] Fix BUG a...
729
730
731
732
733
734
735
736
737
  	int ret = 0;
  
  	rq = blk_get_request(q, (cgc->data_direction == CGC_DATA_WRITE) ?
  			     WRITE : READ, __GFP_WAIT);
  
  	if (cgc->buflen) {
  		if (blk_rq_map_kern(q, rq, cgc->buffer, cgc->buflen, __GFP_WAIT))
  			goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
738

91e4ee381   Gerhard Dirschl   [PATCH] pktcdvd: ...
739
  	rq->cmd_len = COMMAND_SIZE(cgc->cmd[0]);
406c9b605   Christoph Hellwig   [PATCH] Fix BUG a...
740
  	memcpy(rq->cmd, cgc->cmd, CDROM_PACKET_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
741

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
742
  	rq->timeout = 60*HZ;
4aff5e233   Jens Axboe   [PATCH] Split str...
743
  	rq->cmd_type = REQ_TYPE_BLOCK_PC;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
744
  	if (cgc->quiet)
4aff5e233   Jens Axboe   [PATCH] Split str...
745
  		rq->cmd_flags |= REQ_QUIET;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
746

406c9b605   Christoph Hellwig   [PATCH] Fix BUG a...
747
  	blk_execute_rq(rq->q, pd->bdev->bd_disk, rq, 0);
cbc31a475   Andrew Morton   packet: fix error...
748
749
  	if (rq->errors)
  		ret = -EIO;
406c9b605   Christoph Hellwig   [PATCH] Fix BUG a...
750
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
751
  	blk_put_request(rq);
406c9b605   Christoph Hellwig   [PATCH] Fix BUG a...
752
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753
754
755
756
757
758
759
760
761
762
763
764
765
  }
  
  /*
   * A generic sense dump / resolve mechanism should be implemented across
   * all ATAPI + SCSI devices.
   */
  static void pkt_dump_sense(struct packet_command *cgc)
  {
  	static char *info[9] = { "No sense", "Recovered error", "Not ready",
  				 "Medium error", "Hardware error", "Illegal request",
  				 "Unit attention", "Data protect", "Blank check" };
  	int i;
  	struct request_sense *sense = cgc->sense;
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
766
  	printk(DRIVER_NAME":");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
767
768
769
770
771
772
773
774
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
808
809
810
811
812
  	for (i = 0; i < CDROM_PACKET_SIZE; i++)
  		printk(" %02x", cgc->cmd[i]);
  	printk(" - ");
  
  	if (sense == NULL) {
  		printk("no sense
  ");
  		return;
  	}
  
  	printk("sense %02x.%02x.%02x", sense->sense_key, sense->asc, sense->ascq);
  
  	if (sense->sense_key > 8) {
  		printk(" (INVALID)
  ");
  		return;
  	}
  
  	printk(" (%s)
  ", info[sense->sense_key]);
  }
  
  /*
   * flush the drive cache to media
   */
  static int pkt_flush_cache(struct pktcdvd_device *pd)
  {
  	struct packet_command cgc;
  
  	init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
  	cgc.cmd[0] = GPCMD_FLUSH_CACHE;
  	cgc.quiet = 1;
  
  	/*
  	 * the IMMED bit -- we default to not setting it, although that
  	 * would allow a much faster close, this is safer
  	 */
  #if 0
  	cgc.cmd[1] = 1 << 1;
  #endif
  	return pkt_generic_packet(pd, &cgc);
  }
  
  /*
   * speed is given as the normal factor, e.g. 4 for 4x
   */
05680d86d   Peter Osterlund   pktcdvd: reduce s...
813
814
  static noinline_for_stack int pkt_set_speed(struct pktcdvd_device *pd,
  				unsigned write_speed, unsigned read_speed)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
  {
  	struct packet_command cgc;
  	struct request_sense sense;
  	int ret;
  
  	init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
  	cgc.sense = &sense;
  	cgc.cmd[0] = GPCMD_SET_SPEED;
  	cgc.cmd[2] = (read_speed >> 8) & 0xff;
  	cgc.cmd[3] = read_speed & 0xff;
  	cgc.cmd[4] = (write_speed >> 8) & 0xff;
  	cgc.cmd[5] = write_speed & 0xff;
  
  	if ((ret = pkt_generic_packet(pd, &cgc)))
  		pkt_dump_sense(&cgc);
  
  	return ret;
  }
  
  /*
   * Queue a bio for processing by the low-level CD device. Must be called
   * from process context.
   */
46c271bed   Peter Osterlund   [PATCH] Improve C...
838
  static void pkt_queue_bio(struct pktcdvd_device *pd, struct bio *bio)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
839
840
  {
  	spin_lock(&pd->iosched.lock);
c5ecc484c   Akinobu Mita   pktcdvd: use BIO ...
841
842
843
844
  	if (bio_data_dir(bio) == READ)
  		bio_list_add(&pd->iosched.read_queue, bio);
  	else
  		bio_list_add(&pd->iosched.write_queue, bio);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
845
846
847
848
849
850
851
852
853
854
855
  	spin_unlock(&pd->iosched.lock);
  
  	atomic_set(&pd->iosched.attention, 1);
  	wake_up(&pd->wqueue);
  }
  
  /*
   * Process the queued read/write requests. This function handles special
   * requirements for CDRW drives:
   * - A cache flush command must be inserted before a read request if the
   *   previous request was a write.
46c271bed   Peter Osterlund   [PATCH] Improve C...
856
   * - Switching between reading and writing is slow, so don't do it more often
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
857
   *   than necessary.
46c271bed   Peter Osterlund   [PATCH] Improve C...
858
859
860
861
   * - Optimize for throughput at the expense of latency. This means that streaming
   *   writes will never be interrupted by a read, but if the drive has to seek
   *   before the next write, switch to reading instead if there are any pending
   *   read requests.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
862
863
864
865
   * - Set the read speed according to current usage pattern. When only reading
   *   from the device, it's best to use the highest possible read speed, but
   *   when switching often between reading and writing, it's better to have the
   *   same read and write speeds.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
866
867
868
   */
  static void pkt_iosched_process_queue(struct pktcdvd_device *pd)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
869
870
871
872
  
  	if (atomic_read(&pd->iosched.attention) == 0)
  		return;
  	atomic_set(&pd->iosched.attention, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
873
874
  	for (;;) {
  		struct bio *bio;
46c271bed   Peter Osterlund   [PATCH] Improve C...
875
  		int reads_queued, writes_queued;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
876
877
  
  		spin_lock(&pd->iosched.lock);
c5ecc484c   Akinobu Mita   pktcdvd: use BIO ...
878
879
  		reads_queued = !bio_list_empty(&pd->iosched.read_queue);
  		writes_queued = !bio_list_empty(&pd->iosched.write_queue);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
880
881
882
883
884
885
  		spin_unlock(&pd->iosched.lock);
  
  		if (!reads_queued && !writes_queued)
  			break;
  
  		if (pd->iosched.writing) {
46c271bed   Peter Osterlund   [PATCH] Improve C...
886
887
  			int need_write_seek = 1;
  			spin_lock(&pd->iosched.lock);
c5ecc484c   Akinobu Mita   pktcdvd: use BIO ...
888
  			bio = bio_list_peek(&pd->iosched.write_queue);
46c271bed   Peter Osterlund   [PATCH] Improve C...
889
890
891
892
  			spin_unlock(&pd->iosched.lock);
  			if (bio && (bio->bi_sector == pd->iosched.last_write))
  				need_write_seek = 0;
  			if (need_write_seek && reads_queued) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
893
  				if (atomic_read(&pd->cdrw.pending_bios) > 0) {
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
894
895
  					VPRINTK(DRIVER_NAME": write, waiting
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
896
897
898
899
900
901
902
903
  					break;
  				}
  				pkt_flush_cache(pd);
  				pd->iosched.writing = 0;
  			}
  		} else {
  			if (!reads_queued && writes_queued) {
  				if (atomic_read(&pd->cdrw.pending_bios) > 0) {
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
904
905
  					VPRINTK(DRIVER_NAME": read, waiting
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
906
907
908
909
910
911
912
  					break;
  				}
  				pd->iosched.writing = 1;
  			}
  		}
  
  		spin_lock(&pd->iosched.lock);
c5ecc484c   Akinobu Mita   pktcdvd: use BIO ...
913
914
915
916
  		if (pd->iosched.writing)
  			bio = bio_list_pop(&pd->iosched.write_queue);
  		else
  			bio = bio_list_pop(&pd->iosched.read_queue);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
917
918
919
920
921
922
923
  		spin_unlock(&pd->iosched.lock);
  
  		if (!bio)
  			continue;
  
  		if (bio_data_dir(bio) == READ)
  			pd->iosched.successive_reads += bio->bi_size >> 10;
46c271bed   Peter Osterlund   [PATCH] Improve C...
924
  		else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
925
  			pd->iosched.successive_reads = 0;
46c271bed   Peter Osterlund   [PATCH] Improve C...
926
927
  			pd->iosched.last_write = bio->bi_sector + bio_sectors(bio);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
  		if (pd->iosched.successive_reads >= HI_SPEED_SWITCH) {
  			if (pd->read_speed == pd->write_speed) {
  				pd->read_speed = MAX_SPEED;
  				pkt_set_speed(pd, pd->write_speed, pd->read_speed);
  			}
  		} else {
  			if (pd->read_speed != pd->write_speed) {
  				pd->read_speed = pd->write_speed;
  				pkt_set_speed(pd, pd->write_speed, pd->read_speed);
  			}
  		}
  
  		atomic_inc(&pd->cdrw.pending_bios);
  		generic_make_request(bio);
  	}
  }
  
  /*
   * Special care is needed if the underlying block device has a small
   * max_phys_segments value.
   */
165125e1e   Jens Axboe   [BLOCK] Get rid o...
949
  static int pkt_set_segment_merging(struct pktcdvd_device *pd, struct request_queue *q)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
950
  {
ae03bf639   Martin K. Petersen   block: Use access...
951
  	if ((pd->settings.size << 9) / CD_FRAMESIZE
8a78362c4   Martin K. Petersen   block: Consolidat...
952
  	    <= queue_max_segments(q)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
953
954
955
956
957
  		/*
  		 * The cdrom device can handle one segment/frame
  		 */
  		clear_bit(PACKET_MERGE_SEGS, &pd->flags);
  		return 0;
ae03bf639   Martin K. Petersen   block: Use access...
958
  	} else if ((pd->settings.size << 9) / PAGE_SIZE
8a78362c4   Martin K. Petersen   block: Consolidat...
959
  		   <= queue_max_segments(q)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
960
961
962
963
964
965
966
  		/*
  		 * We can handle this case at the expense of some extra memory
  		 * copies during write operations
  		 */
  		set_bit(PACKET_MERGE_SEGS, &pd->flags);
  		return 0;
  	} else {
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
967
968
  		printk(DRIVER_NAME": cdrom max_phys_segments too small
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
  		return -EIO;
  	}
  }
  
  /*
   * Copy CD_FRAMESIZE bytes from src_bio into a destination page
   */
  static void pkt_copy_bio_data(struct bio *src_bio, int seg, int offs, struct page *dst_page, int dst_offs)
  {
  	unsigned int copy_size = CD_FRAMESIZE;
  
  	while (copy_size > 0) {
  		struct bio_vec *src_bvl = bio_iovec_idx(src_bio, seg);
  		void *vfrom = kmap_atomic(src_bvl->bv_page, KM_USER0) +
  			src_bvl->bv_offset + offs;
  		void *vto = page_address(dst_page) + dst_offs;
  		int len = min_t(int, copy_size, src_bvl->bv_len - offs);
  
  		BUG_ON(len < 0);
  		memcpy(vto, vfrom, len);
  		kunmap_atomic(vfrom, KM_USER0);
  
  		seg++;
  		offs = 0;
  		dst_offs += len;
  		copy_size -= len;
  	}
  }
  
  /*
   * Copy all data for this packet to pkt->pages[], so that
   * a) The number of required segments for the write bio is minimized, which
   *    is necessary for some scsi controllers.
   * b) The data can be used as cache to avoid read requests if we receive a
   *    new write request for the same zone.
   */
727723237   Peter Osterlund   [PATCH] pktcdvd: ...
1005
  static void pkt_make_local_copy(struct packet_data *pkt, struct bio_vec *bvec)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1006
1007
1008
1009
1010
1011
1012
  {
  	int f, p, offs;
  
  	/* Copy all data to pkt->pages[] */
  	p = 0;
  	offs = 0;
  	for (f = 0; f < pkt->frames; f++) {
727723237   Peter Osterlund   [PATCH] pktcdvd: ...
1013
1014
  		if (bvec[f].bv_page != pkt->pages[p]) {
  			void *vfrom = kmap_atomic(bvec[f].bv_page, KM_USER0) + bvec[f].bv_offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1015
1016
1017
  			void *vto = page_address(pkt->pages[p]) + offs;
  			memcpy(vto, vfrom, CD_FRAMESIZE);
  			kunmap_atomic(vfrom, KM_USER0);
727723237   Peter Osterlund   [PATCH] pktcdvd: ...
1018
1019
  			bvec[f].bv_page = pkt->pages[p];
  			bvec[f].bv_offset = offs;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1020
  		} else {
727723237   Peter Osterlund   [PATCH] pktcdvd: ...
1021
  			BUG_ON(bvec[f].bv_offset != offs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1022
1023
1024
  		}
  		offs += CD_FRAMESIZE;
  		if (offs >= PAGE_SIZE) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1025
1026
1027
1028
1029
  			offs = 0;
  			p++;
  		}
  	}
  }
6712ecf8f   NeilBrown   Drop 'size' argum...
1030
  static void pkt_end_io_read(struct bio *bio, int err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1031
1032
1033
1034
  {
  	struct packet_data *pkt = bio->bi_private;
  	struct pktcdvd_device *pd = pkt->pd;
  	BUG_ON(!pd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
  	VPRINTK("pkt_end_io_read: bio=%p sec0=%llx sec=%llx err=%d
  ", bio,
  		(unsigned long long)pkt->sector, (unsigned long long)bio->bi_sector, err);
  
  	if (err)
  		atomic_inc(&pkt->io_errors);
  	if (atomic_dec_and_test(&pkt->io_wait)) {
  		atomic_inc(&pkt->run_sm);
  		wake_up(&pd->wqueue);
  	}
  	pkt_bio_finished(pd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1046
  }
6712ecf8f   NeilBrown   Drop 'size' argum...
1047
  static void pkt_end_io_packet_write(struct bio *bio, int err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1048
1049
1050
1051
  {
  	struct packet_data *pkt = bio->bi_private;
  	struct pktcdvd_device *pd = pkt->pd;
  	BUG_ON(!pd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1052
1053
1054
1055
1056
1057
1058
1059
1060
  	VPRINTK("pkt_end_io_packet_write: id=%d, err=%d
  ", pkt->id, err);
  
  	pd->stats.pkt_ended++;
  
  	pkt_bio_finished(pd);
  	atomic_dec(&pkt->io_wait);
  	atomic_inc(&pkt->run_sm);
  	wake_up(&pd->wqueue);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
  }
  
  /*
   * Schedule reads for the holes in a packet
   */
  static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt)
  {
  	int frames_read = 0;
  	struct bio *bio;
  	int f;
  	char written[PACKET_MAX_SIZE];
c5ecc484c   Akinobu Mita   pktcdvd: use BIO ...
1072
  	BUG_ON(bio_list_empty(&pkt->orig_bios));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1073
1074
1075
  
  	atomic_set(&pkt->io_wait, 0);
  	atomic_set(&pkt->io_errors, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1076
1077
1078
1079
1080
  	/*
  	 * Figure out which frames we need to read before we can write.
  	 */
  	memset(written, 0, sizeof(written));
  	spin_lock(&pkt->lock);
c5ecc484c   Akinobu Mita   pktcdvd: use BIO ...
1081
  	bio_list_for_each(bio, &pkt->orig_bios) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1082
1083
  		int first_frame = (bio->bi_sector - pkt->sector) / (CD_FRAMESIZE >> 9);
  		int num_frames = bio->bi_size / CD_FRAMESIZE;
06e7ab53f   Peter Osterlund   [PATCH] pktcdvd: ...
1084
  		pd->stats.secs_w += num_frames * (CD_FRAMESIZE >> 9);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1085
1086
1087
1088
1089
1090
  		BUG_ON(first_frame < 0);
  		BUG_ON(first_frame + num_frames > pkt->frames);
  		for (f = first_frame; f < first_frame + num_frames; f++)
  			written[f] = 1;
  	}
  	spin_unlock(&pkt->lock);
06e7ab53f   Peter Osterlund   [PATCH] pktcdvd: ...
1091
1092
1093
1094
1095
1096
  	if (pkt->cache_valid) {
  		VPRINTK("pkt_gather_data: zone %llx cached
  ",
  			(unsigned long long)pkt->sector);
  		goto out_account;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1097
1098
1099
1100
  	/*
  	 * Schedule reads for missing parts of the packet.
  	 */
  	for (f = 0; f < pkt->frames; f++) {
761a15e7a   Jens Axboe   pktcdvd: don't re...
1101
  		struct bio_vec *vec;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1102
1103
1104
1105
  		int p, offset;
  		if (written[f])
  			continue;
  		bio = pkt->r_bios[f];
761a15e7a   Jens Axboe   pktcdvd: don't re...
1106
  		vec = bio->bi_io_vec;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1107
1108
1109
1110
1111
1112
  		bio_init(bio);
  		bio->bi_max_vecs = 1;
  		bio->bi_sector = pkt->sector + f * (CD_FRAMESIZE >> 9);
  		bio->bi_bdev = pd->bdev;
  		bio->bi_end_io = pkt_end_io_read;
  		bio->bi_private = pkt;
761a15e7a   Jens Axboe   pktcdvd: don't re...
1113
  		bio->bi_io_vec = vec;
7e3da6c4b   Laurent Riffard   pktcdvd: don't re...
1114
  		bio->bi_destructor = pkt_bio_destructor;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
  
  		p = (f * CD_FRAMESIZE) / PAGE_SIZE;
  		offset = (f * CD_FRAMESIZE) % PAGE_SIZE;
  		VPRINTK("pkt_gather_data: Adding frame %d, page:%p offs:%d
  ",
  			f, pkt->pages[p], offset);
  		if (!bio_add_page(bio, pkt->pages[p], CD_FRAMESIZE, offset))
  			BUG();
  
  		atomic_inc(&pkt->io_wait);
  		bio->bi_rw = READ;
46c271bed   Peter Osterlund   [PATCH] Improve C...
1126
  		pkt_queue_bio(pd, bio);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1127
1128
1129
1130
1131
1132
1133
1134
1135
  		frames_read++;
  	}
  
  out_account:
  	VPRINTK("pkt_gather_data: need %d frames for zone %llx
  ",
  		frames_read, (unsigned long long)pkt->sector);
  	pd->stats.pkt_started++;
  	pd->stats.secs_rg += frames_read * (CD_FRAMESIZE >> 9);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
  }
  
  /*
   * Find a packet matching zone, or the least recently used packet if
   * there is no match.
   */
  static struct packet_data *pkt_get_packet_data(struct pktcdvd_device *pd, int zone)
  {
  	struct packet_data *pkt;
  
  	list_for_each_entry(pkt, &pd->cdrw.pkt_free_list, list) {
  		if (pkt->sector == zone || pkt->list.next == &pd->cdrw.pkt_free_list) {
  			list_del_init(&pkt->list);
  			if (pkt->sector != zone)
  				pkt->cache_valid = 0;
610827dee   Peter Osterlund   [PATCH] pktcdvd: ...
1151
  			return pkt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1152
1153
  		}
  	}
610827dee   Peter Osterlund   [PATCH] pktcdvd: ...
1154
1155
  	BUG();
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
  }
  
  static void pkt_put_packet_data(struct pktcdvd_device *pd, struct packet_data *pkt)
  {
  	if (pkt->cache_valid) {
  		list_add(&pkt->list, &pd->cdrw.pkt_free_list);
  	} else {
  		list_add_tail(&pkt->list, &pd->cdrw.pkt_free_list);
  	}
  }
  
  /*
   * recover a failed write, query for relocation if possible
   *
   * returns 1 if recovery is possible, or 0 if not
   *
   */
  static int pkt_start_recovery(struct packet_data *pkt)
  {
  	/*
  	 * FIXME. We need help from the file system to implement
  	 * recovery handling.
  	 */
  	return 0;
  #if 0
  	struct request *rq = pkt->rq;
  	struct pktcdvd_device *pd = rq->rq_disk->private_data;
  	struct block_device *pkt_bdev;
  	struct super_block *sb = NULL;
  	unsigned long old_block, new_block;
  	sector_t new_sector;
  
  	pkt_bdev = bdget(kdev_t_to_nr(pd->pkt_dev));
  	if (pkt_bdev) {
  		sb = get_super(pkt_bdev);
  		bdput(pkt_bdev);
  	}
  
  	if (!sb)
  		return 0;
e7f590970   Al Viro   kill useless chec...
1196
  	if (!sb->s_op->relocate_blocks)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
  		goto out;
  
  	old_block = pkt->sector / (CD_FRAMESIZE >> 9);
  	if (sb->s_op->relocate_blocks(sb, old_block, &new_block))
  		goto out;
  
  	new_sector = new_block * (CD_FRAMESIZE >> 9);
  	pkt->sector = new_sector;
  
  	pkt->bio->bi_sector = new_sector;
  	pkt->bio->bi_next = NULL;
  	pkt->bio->bi_flags = 1 << BIO_UPTODATE;
  	pkt->bio->bi_idx = 0;
7b6d91dae   Christoph Hellwig   block: unify flag...
1210
  	BUG_ON(pkt->bio->bi_rw != REQ_WRITE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
  	BUG_ON(pkt->bio->bi_vcnt != pkt->frames);
  	BUG_ON(pkt->bio->bi_size != pkt->frames * CD_FRAMESIZE);
  	BUG_ON(pkt->bio->bi_end_io != pkt_end_io_packet_write);
  	BUG_ON(pkt->bio->bi_private != pkt);
  
  	drop_super(sb);
  	return 1;
  
  out:
  	drop_super(sb);
  	return 0;
  #endif
  }
  
  static inline void pkt_set_state(struct packet_data *pkt, enum packet_data_state state)
  {
  #if PACKET_DEBUG > 1
  	static const char *state_name[] = {
  		"IDLE", "WAITING", "READ_WAIT", "WRITE_WAIT", "RECOVERY", "FINISHED"
  	};
  	enum packet_data_state old_state = pkt->state;
  	VPRINTK("pkt %2d : s=%6llx %s -> %s
  ", pkt->id, (unsigned long long)pkt->sector,
  		state_name[old_state], state_name[state]);
  #endif
  	pkt->state = state;
  }
  
  /*
   * Scan the work queue to see if we can start a new packet.
   * returns non-zero if any work was done.
   */
  static int pkt_handle_queue(struct pktcdvd_device *pd)
  {
  	struct packet_data *pkt, *p;
  	struct bio *bio = NULL;
  	sector_t zone = 0; /* Suppress gcc warning */
  	struct pkt_rb_node *node, *first_node;
  	struct rb_node *n;
0a0fc9601   Thomas Maier   [PATCH] pktcdvd: ...
1250
  	int wakeup;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
  
  	VPRINTK("handle_queue
  ");
  
  	atomic_set(&pd->scan_queue, 0);
  
  	if (list_empty(&pd->cdrw.pkt_free_list)) {
  		VPRINTK("handle_queue: no pkt
  ");
  		return 0;
  	}
  
  	/*
  	 * Try to find a zone we are not already working on.
  	 */
  	spin_lock(&pd->lock);
  	first_node = pkt_rbtree_find(pd, pd->current_sector);
  	if (!first_node) {
  		n = rb_first(&pd->bio_queue);
  		if (n)
  			first_node = rb_entry(n, struct pkt_rb_node, rb_node);
  	}
  	node = first_node;
  	while (node) {
  		bio = node->bio;
  		zone = ZONE(bio->bi_sector, pd);
  		list_for_each_entry(p, &pd->cdrw.pkt_active_list, list) {
7baeb6a5c   Peter Osterlund   [PATCH] CDRW/DVD ...
1278
1279
  			if (p->sector == zone) {
  				bio = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1280
  				goto try_next_bio;
7baeb6a5c   Peter Osterlund   [PATCH] CDRW/DVD ...
1281
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
  		}
  		break;
  try_next_bio:
  		node = pkt_rbtree_next(node);
  		if (!node) {
  			n = rb_first(&pd->bio_queue);
  			if (n)
  				node = rb_entry(n, struct pkt_rb_node, rb_node);
  		}
  		if (node == first_node)
  			node = NULL;
  	}
  	spin_unlock(&pd->lock);
  	if (!bio) {
  		VPRINTK("handle_queue: no bio
  ");
  		return 0;
  	}
  
  	pkt = pkt_get_packet_data(pd, zone);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1302
1303
1304
  
  	pd->current_sector = zone + pd->settings.size;
  	pkt->sector = zone;
e1bc89bc9   Peter Osterlund   [PATCH] pktcdvd: ...
1305
  	BUG_ON(pkt->frames != pd->settings.size >> 2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
  	pkt->write_size = 0;
  
  	/*
  	 * Scan work queue for bios in the same zone and link them
  	 * to this packet.
  	 */
  	spin_lock(&pd->lock);
  	VPRINTK("pkt_handle_queue: looking for zone %llx
  ", (unsigned long long)zone);
  	while ((node = pkt_rbtree_find(pd, zone)) != NULL) {
  		bio = node->bio;
  		VPRINTK("pkt_handle_queue: found zone=%llx
  ",
  			(unsigned long long)ZONE(bio->bi_sector, pd));
  		if (ZONE(bio->bi_sector, pd) != zone)
  			break;
  		pkt_rbtree_erase(pd, node);
  		spin_lock(&pkt->lock);
c5ecc484c   Akinobu Mita   pktcdvd: use BIO ...
1324
  		bio_list_add(&pkt->orig_bios, bio);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1325
1326
1327
  		pkt->write_size += bio->bi_size / CD_FRAMESIZE;
  		spin_unlock(&pkt->lock);
  	}
0a0fc9601   Thomas Maier   [PATCH] pktcdvd: ...
1328
1329
1330
1331
  	/* check write congestion marks, and if bio_queue_size is
  	   below, wake up any waiters */
  	wakeup = (pd->write_congestion_on > 0
  	 		&& pd->bio_queue_size <= pd->write_congestion_off);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1332
  	spin_unlock(&pd->lock);
8aa7e847d   Jens Axboe   Fix congestion_wa...
1333
1334
1335
1336
  	if (wakeup) {
  		clear_bdi_congested(&pd->disk->queue->backing_dev_info,
  					BLK_RW_ASYNC);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
  
  	pkt->sleep_time = max(PACKET_WAIT_TIME, 1);
  	pkt_set_state(pkt, PACKET_WAITING_STATE);
  	atomic_set(&pkt->run_sm, 1);
  
  	spin_lock(&pd->cdrw.active_list_lock);
  	list_add(&pkt->list, &pd->cdrw.pkt_active_list);
  	spin_unlock(&pd->cdrw.active_list_lock);
  
  	return 1;
  }
  
  /*
   * Assemble a bio to write one packet and queue the bio for processing
   * by the underlying block device.
   */
  static void pkt_start_write(struct pktcdvd_device *pd, struct packet_data *pkt)
  {
  	struct bio *bio;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1356
1357
  	int f;
  	int frames_write;
727723237   Peter Osterlund   [PATCH] pktcdvd: ...
1358
  	struct bio_vec *bvec = pkt->w_bio->bi_io_vec;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1359
1360
  
  	for (f = 0; f < pkt->frames; f++) {
727723237   Peter Osterlund   [PATCH] pktcdvd: ...
1361
1362
  		bvec[f].bv_page = pkt->pages[(f * CD_FRAMESIZE) / PAGE_SIZE];
  		bvec[f].bv_offset = (f * CD_FRAMESIZE) % PAGE_SIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1363
1364
1365
  	}
  
  	/*
727723237   Peter Osterlund   [PATCH] pktcdvd: ...
1366
  	 * Fill-in bvec with data from orig_bios.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1367
1368
1369
  	 */
  	frames_write = 0;
  	spin_lock(&pkt->lock);
c5ecc484c   Akinobu Mita   pktcdvd: use BIO ...
1370
  	bio_list_for_each(bio, &pkt->orig_bios) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
  		int segment = bio->bi_idx;
  		int src_offs = 0;
  		int first_frame = (bio->bi_sector - pkt->sector) / (CD_FRAMESIZE >> 9);
  		int num_frames = bio->bi_size / CD_FRAMESIZE;
  		BUG_ON(first_frame < 0);
  		BUG_ON(first_frame + num_frames > pkt->frames);
  		for (f = first_frame; f < first_frame + num_frames; f++) {
  			struct bio_vec *src_bvl = bio_iovec_idx(bio, segment);
  
  			while (src_offs >= src_bvl->bv_len) {
  				src_offs -= src_bvl->bv_len;
  				segment++;
  				BUG_ON(segment >= bio->bi_vcnt);
  				src_bvl = bio_iovec_idx(bio, segment);
  			}
  
  			if (src_bvl->bv_len - src_offs >= CD_FRAMESIZE) {
727723237   Peter Osterlund   [PATCH] pktcdvd: ...
1388
1389
  				bvec[f].bv_page = src_bvl->bv_page;
  				bvec[f].bv_offset = src_bvl->bv_offset + src_offs;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1390
1391
  			} else {
  				pkt_copy_bio_data(bio, segment, src_offs,
727723237   Peter Osterlund   [PATCH] pktcdvd: ...
1392
  						  bvec[f].bv_page, bvec[f].bv_offset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
  			}
  			src_offs += CD_FRAMESIZE;
  			frames_write++;
  		}
  	}
  	pkt_set_state(pkt, PACKET_WRITE_WAIT_STATE);
  	spin_unlock(&pkt->lock);
  
  	VPRINTK("pkt_start_write: Writing %d frames for zone %llx
  ",
  		frames_write, (unsigned long long)pkt->sector);
  	BUG_ON(frames_write != pkt->write_size);
  
  	if (test_bit(PACKET_MERGE_SEGS, &pd->flags) || (pkt->write_size < pkt->frames)) {
727723237   Peter Osterlund   [PATCH] pktcdvd: ...
1407
  		pkt_make_local_copy(pkt, bvec);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
  		pkt->cache_valid = 1;
  	} else {
  		pkt->cache_valid = 0;
  	}
  
  	/* Start the write request */
  	bio_init(pkt->w_bio);
  	pkt->w_bio->bi_max_vecs = PACKET_MAX_SIZE;
  	pkt->w_bio->bi_sector = pkt->sector;
  	pkt->w_bio->bi_bdev = pd->bdev;
  	pkt->w_bio->bi_end_io = pkt_end_io_packet_write;
  	pkt->w_bio->bi_private = pkt;
761a15e7a   Jens Axboe   pktcdvd: don't re...
1420
  	pkt->w_bio->bi_io_vec = bvec;
7e3da6c4b   Laurent Riffard   pktcdvd: don't re...
1421
  	pkt->w_bio->bi_destructor = pkt_bio_destructor;
727723237   Peter Osterlund   [PATCH] pktcdvd: ...
1422
1423
1424
  	for (f = 0; f < pkt->frames; f++)
  		if (!bio_add_page(pkt->w_bio, bvec[f].bv_page, CD_FRAMESIZE, bvec[f].bv_offset))
  			BUG();
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
1425
1426
  	VPRINTK(DRIVER_NAME": vcnt=%d
  ", pkt->w_bio->bi_vcnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1427
1428
1429
  
  	atomic_set(&pkt->io_wait, 1);
  	pkt->w_bio->bi_rw = WRITE;
46c271bed   Peter Osterlund   [PATCH] Improve C...
1430
  	pkt_queue_bio(pd, pkt->w_bio);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1431
1432
1433
1434
  }
  
  static void pkt_finish_packet(struct packet_data *pkt, int uptodate)
  {
c5ecc484c   Akinobu Mita   pktcdvd: use BIO ...
1435
  	struct bio *bio;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1436
1437
1438
1439
1440
  
  	if (!uptodate)
  		pkt->cache_valid = 0;
  
  	/* Finish all bios corresponding to this packet */
c5ecc484c   Akinobu Mita   pktcdvd: use BIO ...
1441
  	while ((bio = bio_list_pop(&pkt->orig_bios)))
6712ecf8f   NeilBrown   Drop 'size' argum...
1442
  		bio_endio(bio, uptodate ? 0 : -EIO);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
  }
  
  static void pkt_run_state_machine(struct pktcdvd_device *pd, struct packet_data *pkt)
  {
  	int uptodate;
  
  	VPRINTK("run_state_machine: pkt %d
  ", pkt->id);
  
  	for (;;) {
  		switch (pkt->state) {
  		case PACKET_WAITING_STATE:
  			if ((pkt->write_size < pkt->frames) && (pkt->sleep_time > 0))
  				return;
  
  			pkt->sleep_time = 0;
  			pkt_gather_data(pd, pkt);
  			pkt_set_state(pkt, PACKET_READ_WAIT_STATE);
  			break;
  
  		case PACKET_READ_WAIT_STATE:
  			if (atomic_read(&pkt->io_wait) > 0)
  				return;
  
  			if (atomic_read(&pkt->io_errors) > 0) {
  				pkt_set_state(pkt, PACKET_RECOVERY_STATE);
  			} else {
  				pkt_start_write(pd, pkt);
  			}
  			break;
  
  		case PACKET_WRITE_WAIT_STATE:
  			if (atomic_read(&pkt->io_wait) > 0)
  				return;
  
  			if (test_bit(BIO_UPTODATE, &pkt->w_bio->bi_flags)) {
  				pkt_set_state(pkt, PACKET_FINISHED_STATE);
  			} else {
  				pkt_set_state(pkt, PACKET_RECOVERY_STATE);
  			}
  			break;
  
  		case PACKET_RECOVERY_STATE:
  			if (pkt_start_recovery(pkt)) {
  				pkt_start_write(pd, pkt);
  			} else {
  				VPRINTK("No recovery possible
  ");
  				pkt_set_state(pkt, PACKET_FINISHED_STATE);
  			}
  			break;
  
  		case PACKET_FINISHED_STATE:
  			uptodate = test_bit(BIO_UPTODATE, &pkt->w_bio->bi_flags);
  			pkt_finish_packet(pkt, uptodate);
  			return;
  
  		default:
  			BUG();
  			break;
  		}
  	}
  }
  
  static void pkt_handle_packets(struct pktcdvd_device *pd)
  {
  	struct packet_data *pkt, *next;
  
  	VPRINTK("pkt_handle_packets
  ");
  
  	/*
  	 * Run state machine for active packets
  	 */
  	list_for_each_entry(pkt, &pd->cdrw.pkt_active_list, list) {
  		if (atomic_read(&pkt->run_sm) > 0) {
  			atomic_set(&pkt->run_sm, 0);
  			pkt_run_state_machine(pd, pkt);
  		}
  	}
  
  	/*
  	 * Move no longer active packets to the free list
  	 */
  	spin_lock(&pd->cdrw.active_list_lock);
  	list_for_each_entry_safe(pkt, next, &pd->cdrw.pkt_active_list, list) {
  		if (pkt->state == PACKET_FINISHED_STATE) {
  			list_del(&pkt->list);
  			pkt_put_packet_data(pd, pkt);
  			pkt_set_state(pkt, PACKET_IDLE_STATE);
  			atomic_set(&pd->scan_queue, 1);
  		}
  	}
  	spin_unlock(&pd->cdrw.active_list_lock);
  }
  
  static void pkt_count_states(struct pktcdvd_device *pd, int *states)
  {
  	struct packet_data *pkt;
  	int i;
ae7642bb0   Peter Osterlund   [PATCH] packet wr...
1543
  	for (i = 0; i < PACKET_NUM_STATES; i++)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
  		states[i] = 0;
  
  	spin_lock(&pd->cdrw.active_list_lock);
  	list_for_each_entry(pkt, &pd->cdrw.pkt_active_list, list) {
  		states[pkt->state]++;
  	}
  	spin_unlock(&pd->cdrw.active_list_lock);
  }
  
  /*
   * kcdrwd is woken up when writes have been queued for one of our
   * registered devices
   */
  static int kcdrwd(void *foobar)
  {
  	struct pktcdvd_device *pd = foobar;
  	struct packet_data *pkt;
  	long min_sleep_time, residue;
  
  	set_user_nice(current, -20);
831441862   Rafael J. Wysocki   Freezer: make ker...
1564
  	set_freezable();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
  
  	for (;;) {
  		DECLARE_WAITQUEUE(wait, current);
  
  		/*
  		 * Wait until there is something to do
  		 */
  		add_wait_queue(&pd->wqueue, &wait);
  		for (;;) {
  			set_current_state(TASK_INTERRUPTIBLE);
  
  			/* Check if we need to run pkt_handle_queue */
  			if (atomic_read(&pd->scan_queue) > 0)
  				goto work_to_do;
  
  			/* Check if we need to run the state machine for some packet */
  			list_for_each_entry(pkt, &pd->cdrw.pkt_active_list, list) {
  				if (atomic_read(&pkt->run_sm) > 0)
  					goto work_to_do;
  			}
  
  			/* Check if we need to process the iosched queues */
  			if (atomic_read(&pd->iosched.attention) != 0)
  				goto work_to_do;
  
  			/* Otherwise, go to sleep */
  			if (PACKET_DEBUG > 1) {
  				int states[PACKET_NUM_STATES];
  				pkt_count_states(pd, states);
  				VPRINTK("kcdrwd: i:%d ow:%d rw:%d ww:%d rec:%d fin:%d
  ",
  					states[0], states[1], states[2], states[3],
  					states[4], states[5]);
  			}
  
  			min_sleep_time = MAX_SCHEDULE_TIMEOUT;
  			list_for_each_entry(pkt, &pd->cdrw.pkt_active_list, list) {
  				if (pkt->sleep_time && pkt->sleep_time < min_sleep_time)
  					min_sleep_time = pkt->sleep_time;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1605
1606
1607
1608
1609
1610
1611
  			VPRINTK("kcdrwd: sleeping
  ");
  			residue = schedule_timeout(min_sleep_time);
  			VPRINTK("kcdrwd: wake up
  ");
  
  			/* make swsusp happy with our thread */
3e1d1d28d   Christoph Lameter   [PATCH] Cleanup p...
1612
  			try_to_freeze();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
  
  			list_for_each_entry(pkt, &pd->cdrw.pkt_active_list, list) {
  				if (!pkt->sleep_time)
  					continue;
  				pkt->sleep_time -= min_sleep_time - residue;
  				if (pkt->sleep_time <= 0) {
  					pkt->sleep_time = 0;
  					atomic_inc(&pkt->run_sm);
  				}
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
  			if (kthread_should_stop())
  				break;
  		}
  work_to_do:
  		set_current_state(TASK_RUNNING);
  		remove_wait_queue(&pd->wqueue, &wait);
  
  		if (kthread_should_stop())
  			break;
  
  		/*
  		 * if pkt_handle_queue returns true, we can queue
  		 * another request.
  		 */
  		while (pkt_handle_queue(pd))
  			;
  
  		/*
  		 * Handle packet state machine
  		 */
  		pkt_handle_packets(pd);
  
  		/*
  		 * Handle iosched queues
  		 */
  		pkt_iosched_process_queue(pd);
  	}
  
  	return 0;
  }
  
  static void pkt_print_settings(struct pktcdvd_device *pd)
  {
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
1656
  	printk(DRIVER_NAME": %s packets, ", pd->settings.fp ? "Fixed" : "Variable");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
  	printk("%u blocks, ", pd->settings.size >> 2);
  	printk("Mode-%c disc
  ", pd->settings.block_mode == 8 ? '1' : '2');
  }
  
  static int pkt_mode_sense(struct pktcdvd_device *pd, struct packet_command *cgc, int page_code, int page_control)
  {
  	memset(cgc->cmd, 0, sizeof(cgc->cmd));
  
  	cgc->cmd[0] = GPCMD_MODE_SENSE_10;
  	cgc->cmd[2] = page_code | (page_control << 6);
  	cgc->cmd[7] = cgc->buflen >> 8;
  	cgc->cmd[8] = cgc->buflen & 0xff;
  	cgc->data_direction = CGC_DATA_READ;
  	return pkt_generic_packet(pd, cgc);
  }
  
  static int pkt_mode_select(struct pktcdvd_device *pd, struct packet_command *cgc)
  {
  	memset(cgc->cmd, 0, sizeof(cgc->cmd));
  	memset(cgc->buffer, 0, 2);
  	cgc->cmd[0] = GPCMD_MODE_SELECT_10;
  	cgc->cmd[1] = 0x10;		/* PF */
  	cgc->cmd[7] = cgc->buflen >> 8;
  	cgc->cmd[8] = cgc->buflen & 0xff;
  	cgc->data_direction = CGC_DATA_WRITE;
  	return pkt_generic_packet(pd, cgc);
  }
  
  static int pkt_get_disc_info(struct pktcdvd_device *pd, disc_information *di)
  {
  	struct packet_command cgc;
  	int ret;
  
  	/* set up command and get the disc info */
  	init_cdrom_command(&cgc, di, sizeof(*di), CGC_DATA_READ);
  	cgc.cmd[0] = GPCMD_READ_DISC_INFO;
  	cgc.cmd[8] = cgc.buflen = 2;
  	cgc.quiet = 1;
  
  	if ((ret = pkt_generic_packet(pd, &cgc)))
  		return ret;
  
  	/* not all drives have the same disc_info length, so requeue
  	 * packet with the length the drive tells us it can supply
  	 */
  	cgc.buflen = be16_to_cpu(di->disc_information_length) +
  		     sizeof(di->disc_information_length);
  
  	if (cgc.buflen > sizeof(disc_information))
  		cgc.buflen = sizeof(disc_information);
  
  	cgc.cmd[8] = cgc.buflen;
  	return pkt_generic_packet(pd, &cgc);
  }
  
  static int pkt_get_track_info(struct pktcdvd_device *pd, __u16 track, __u8 type, track_information *ti)
  {
  	struct packet_command cgc;
  	int ret;
  
  	init_cdrom_command(&cgc, ti, 8, CGC_DATA_READ);
  	cgc.cmd[0] = GPCMD_READ_TRACK_RZONE_INFO;
  	cgc.cmd[1] = type & 3;
  	cgc.cmd[4] = (track & 0xff00) >> 8;
  	cgc.cmd[5] = track & 0xff;
  	cgc.cmd[8] = 8;
  	cgc.quiet = 1;
  
  	if ((ret = pkt_generic_packet(pd, &cgc)))
  		return ret;
  
  	cgc.buflen = be16_to_cpu(ti->track_information_length) +
  		     sizeof(ti->track_information_length);
  
  	if (cgc.buflen > sizeof(track_information))
  		cgc.buflen = sizeof(track_information);
  
  	cgc.cmd[8] = cgc.buflen;
  	return pkt_generic_packet(pd, &cgc);
  }
05680d86d   Peter Osterlund   pktcdvd: reduce s...
1738
1739
  static noinline_for_stack int pkt_get_last_written(struct pktcdvd_device *pd,
  						long *last_written)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
  {
  	disc_information di;
  	track_information ti;
  	__u32 last_track;
  	int ret = -1;
  
  	if ((ret = pkt_get_disc_info(pd, &di)))
  		return ret;
  
  	last_track = (di.last_track_msb << 8) | di.last_track_lsb;
  	if ((ret = pkt_get_track_info(pd, last_track, 1, &ti)))
  		return ret;
  
  	/* if this track is blank, try the previous. */
  	if (ti.blank) {
  		last_track--;
  		if ((ret = pkt_get_track_info(pd, last_track, 1, &ti)))
  			return ret;
  	}
  
  	/* if last recorded field is valid, return it. */
  	if (ti.lra_v) {
  		*last_written = be32_to_cpu(ti.last_rec_address);
  	} else {
  		/* make it up instead */
  		*last_written = be32_to_cpu(ti.track_start) +
  				be32_to_cpu(ti.track_size);
  		if (ti.free_blocks)
  			*last_written -= (be32_to_cpu(ti.free_blocks) + 7);
  	}
  	return 0;
  }
  
  /*
   * write mode select package based on pd->settings
   */
05680d86d   Peter Osterlund   pktcdvd: reduce s...
1776
  static noinline_for_stack int pkt_set_write_settings(struct pktcdvd_device *pd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
  {
  	struct packet_command cgc;
  	struct request_sense sense;
  	write_param_page *wp;
  	char buffer[128];
  	int ret, size;
  
  	/* doesn't apply to DVD+RW or DVD-RAM */
  	if ((pd->mmc3_profile == 0x1a) || (pd->mmc3_profile == 0x12))
  		return 0;
  
  	memset(buffer, 0, sizeof(buffer));
  	init_cdrom_command(&cgc, buffer, sizeof(*wp), CGC_DATA_READ);
  	cgc.sense = &sense;
  	if ((ret = pkt_mode_sense(pd, &cgc, GPMODE_WRITE_PARMS_PAGE, 0))) {
  		pkt_dump_sense(&cgc);
  		return ret;
  	}
  
  	size = 2 + ((buffer[0] << 8) | (buffer[1] & 0xff));
  	pd->mode_offset = (buffer[6] << 8) | (buffer[7] & 0xff);
  	if (size > sizeof(buffer))
  		size = sizeof(buffer);
  
  	/*
  	 * now get it all
  	 */
  	init_cdrom_command(&cgc, buffer, size, CGC_DATA_READ);
  	cgc.sense = &sense;
  	if ((ret = pkt_mode_sense(pd, &cgc, GPMODE_WRITE_PARMS_PAGE, 0))) {
  		pkt_dump_sense(&cgc);
  		return ret;
  	}
  
  	/*
  	 * write page is offset header + block descriptor length
  	 */
  	wp = (write_param_page *) &buffer[sizeof(struct mode_page_header) + pd->mode_offset];
  
  	wp->fp = pd->settings.fp;
  	wp->track_mode = pd->settings.track_mode;
  	wp->write_type = pd->settings.write_type;
  	wp->data_block_type = pd->settings.block_mode;
  
  	wp->multi_session = 0;
  
  #ifdef PACKET_USE_LS
  	wp->link_size = 7;
  	wp->ls_v = 1;
  #endif
  
  	if (wp->data_block_type == PACKET_BLOCK_MODE1) {
  		wp->session_format = 0;
  		wp->subhdr2 = 0x20;
  	} else if (wp->data_block_type == PACKET_BLOCK_MODE2) {
  		wp->session_format = 0x20;
  		wp->subhdr2 = 8;
  #if 0
  		wp->mcn[0] = 0x80;
  		memcpy(&wp->mcn[1], PACKET_MCN, sizeof(wp->mcn) - 1);
  #endif
  	} else {
  		/*
  		 * paranoia
  		 */
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
1842
1843
  		printk(DRIVER_NAME": write mode wrong %d
  ", wp->data_block_type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
  		return 1;
  	}
  	wp->packet_size = cpu_to_be32(pd->settings.size >> 2);
  
  	cgc.buflen = cgc.cmd[8] = size;
  	if ((ret = pkt_mode_select(pd, &cgc))) {
  		pkt_dump_sense(&cgc);
  		return ret;
  	}
  
  	pkt_print_settings(pd);
  	return 0;
  }
  
  /*
7c613d593   Peter Osterlund   [PATCH] pktcdvd: ...
1859
   * 1 -- we can write to this track, 0 -- we can't
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1860
   */
ab863ec34   Peter Osterlund   [PATCH] pktcdvd: ...
1861
  static int pkt_writable_track(struct pktcdvd_device *pd, track_information *ti)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1862
  {
ab863ec34   Peter Osterlund   [PATCH] pktcdvd: ...
1863
1864
1865
1866
1867
1868
1869
1870
  	switch (pd->mmc3_profile) {
  		case 0x1a: /* DVD+RW */
  		case 0x12: /* DVD-RAM */
  			/* The track is always writable on DVD+RW/DVD-RAM */
  			return 1;
  		default:
  			break;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1871

ab863ec34   Peter Osterlund   [PATCH] pktcdvd: ...
1872
1873
  	if (!ti->packet || !ti->fp)
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1874
1875
1876
1877
  
  	/*
  	 * "good" settings as per Mt Fuji.
  	 */
ab863ec34   Peter Osterlund   [PATCH] pktcdvd: ...
1878
  	if (ti->rt == 0 && ti->blank == 0)
7c613d593   Peter Osterlund   [PATCH] pktcdvd: ...
1879
  		return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1880

ab863ec34   Peter Osterlund   [PATCH] pktcdvd: ...
1881
  	if (ti->rt == 0 && ti->blank == 1)
7c613d593   Peter Osterlund   [PATCH] pktcdvd: ...
1882
  		return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1883

ab863ec34   Peter Osterlund   [PATCH] pktcdvd: ...
1884
  	if (ti->rt == 1 && ti->blank == 0)
7c613d593   Peter Osterlund   [PATCH] pktcdvd: ...
1885
  		return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1886

7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
1887
1888
  	printk(DRIVER_NAME": bad state %d-%d-%d
  ", ti->rt, ti->blank, ti->packet);
7c613d593   Peter Osterlund   [PATCH] pktcdvd: ...
1889
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1890
1891
1892
  }
  
  /*
7c613d593   Peter Osterlund   [PATCH] pktcdvd: ...
1893
   * 1 -- we can write to this disc, 0 -- we can't
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1894
   */
7c613d593   Peter Osterlund   [PATCH] pktcdvd: ...
1895
  static int pkt_writable_disc(struct pktcdvd_device *pd, disc_information *di)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1896
1897
1898
1899
1900
1901
1902
1903
  {
  	switch (pd->mmc3_profile) {
  		case 0x0a: /* CD-RW */
  		case 0xffff: /* MMC3 not supported */
  			break;
  		case 0x1a: /* DVD+RW */
  		case 0x13: /* DVD-RW */
  		case 0x12: /* DVD-RAM */
7c613d593   Peter Osterlund   [PATCH] pktcdvd: ...
1904
  			return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1905
  		default:
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
1906
1907
  			VPRINTK(DRIVER_NAME": Wrong disc profile (%x)
  ", pd->mmc3_profile);
7c613d593   Peter Osterlund   [PATCH] pktcdvd: ...
1908
  			return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1909
1910
1911
1912
1913
1914
1915
  	}
  
  	/*
  	 * for disc type 0xff we should probably reserve a new track.
  	 * but i'm not sure, should we leave this to user apps? probably.
  	 */
  	if (di->disc_type == 0xff) {
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
1916
1917
  		printk(DRIVER_NAME": Unknown disc. No track?
  ");
7c613d593   Peter Osterlund   [PATCH] pktcdvd: ...
1918
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1919
1920
1921
  	}
  
  	if (di->disc_type != 0x20 && di->disc_type != 0) {
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
1922
1923
  		printk(DRIVER_NAME": Wrong disc type (%x)
  ", di->disc_type);
7c613d593   Peter Osterlund   [PATCH] pktcdvd: ...
1924
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1925
1926
1927
  	}
  
  	if (di->erasable == 0) {
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
1928
1929
  		printk(DRIVER_NAME": Disc not erasable
  ");
7c613d593   Peter Osterlund   [PATCH] pktcdvd: ...
1930
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1931
1932
1933
  	}
  
  	if (di->border_status == PACKET_SESSION_RESERVED) {
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
1934
1935
  		printk(DRIVER_NAME": Can't write to last track (reserved)
  ");
7c613d593   Peter Osterlund   [PATCH] pktcdvd: ...
1936
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1937
  	}
7c613d593   Peter Osterlund   [PATCH] pktcdvd: ...
1938
  	return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1939
  }
05680d86d   Peter Osterlund   pktcdvd: reduce s...
1940
  static noinline_for_stack int pkt_probe_settings(struct pktcdvd_device *pd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
  {
  	struct packet_command cgc;
  	unsigned char buf[12];
  	disc_information di;
  	track_information ti;
  	int ret, track;
  
  	init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ);
  	cgc.cmd[0] = GPCMD_GET_CONFIGURATION;
  	cgc.cmd[8] = 8;
  	ret = pkt_generic_packet(pd, &cgc);
  	pd->mmc3_profile = ret ? 0xffff : buf[6] << 8 | buf[7];
  
  	memset(&di, 0, sizeof(disc_information));
  	memset(&ti, 0, sizeof(track_information));
  
  	if ((ret = pkt_get_disc_info(pd, &di))) {
  		printk("failed get_disc
  ");
  		return ret;
  	}
7c613d593   Peter Osterlund   [PATCH] pktcdvd: ...
1962
  	if (!pkt_writable_disc(pd, &di))
9db915465   Peter Osterlund   [PATCH] pktcdvd: ...
1963
  		return -EROFS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1964

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1965
1966
1967
1968
  	pd->type = di.erasable ? PACKET_CDRW : PACKET_CDR;
  
  	track = 1; /* (di.last_track_msb << 8) | di.last_track_lsb; */
  	if ((ret = pkt_get_track_info(pd, track, 1, &ti))) {
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
1969
1970
  		printk(DRIVER_NAME": failed get_track
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1971
1972
  		return ret;
  	}
ab863ec34   Peter Osterlund   [PATCH] pktcdvd: ...
1973
  	if (!pkt_writable_track(pd, &ti)) {
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
1974
1975
  		printk(DRIVER_NAME": can't write to this track
  ");
9db915465   Peter Osterlund   [PATCH] pktcdvd: ...
1976
  		return -EROFS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1977
1978
1979
1980
1981
1982
1983
1984
  	}
  
  	/*
  	 * we keep packet size in 512 byte units, makes it easier to
  	 * deal with request calculations.
  	 */
  	pd->settings.size = be32_to_cpu(ti.fixed_packet_size) << 2;
  	if (pd->settings.size == 0) {
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
1985
1986
  		printk(DRIVER_NAME": detected zero packet size!
  ");
a460ad622   Phillip Susi   [PATCH] pktcdvd: ...
1987
  		return -ENXIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1988
  	}
d0272e78e   Peter Osterlund   [PATCH] pktcdvd: ...
1989
  	if (pd->settings.size > PACKET_MAX_SECTORS) {
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
1990
1991
  		printk(DRIVER_NAME": packet size is too big
  ");
9db915465   Peter Osterlund   [PATCH] pktcdvd: ...
1992
  		return -EROFS;
d0272e78e   Peter Osterlund   [PATCH] pktcdvd: ...
1993
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
  	pd->settings.fp = ti.fp;
  	pd->offset = (be32_to_cpu(ti.track_start) << 2) & (pd->settings.size - 1);
  
  	if (ti.nwa_v) {
  		pd->nwa = be32_to_cpu(ti.next_writable);
  		set_bit(PACKET_NWA_VALID, &pd->flags);
  	}
  
  	/*
  	 * in theory we could use lra on -RW media as well and just zero
  	 * blocks that haven't been written yet, but in practice that
  	 * is just a no-go. we'll use that for -R, naturally.
  	 */
  	if (ti.lra_v) {
  		pd->lra = be32_to_cpu(ti.last_rec_address);
  		set_bit(PACKET_LRA_VALID, &pd->flags);
  	} else {
  		pd->lra = 0xffffffff;
  		set_bit(PACKET_LRA_VALID, &pd->flags);
  	}
  
  	/*
  	 * fine for now
  	 */
  	pd->settings.link_loss = 7;
  	pd->settings.write_type = 0;	/* packet */
  	pd->settings.track_mode = ti.track_mode;
  
  	/*
  	 * mode1 or mode2 disc
  	 */
  	switch (ti.data_mode) {
  		case PACKET_MODE1:
  			pd->settings.block_mode = PACKET_BLOCK_MODE1;
  			break;
  		case PACKET_MODE2:
  			pd->settings.block_mode = PACKET_BLOCK_MODE2;
  			break;
  		default:
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
2033
2034
  			printk(DRIVER_NAME": unknown data mode
  ");
9db915465   Peter Osterlund   [PATCH] pktcdvd: ...
2035
  			return -EROFS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2036
2037
2038
2039
2040
2041
2042
  	}
  	return 0;
  }
  
  /*
   * enable/disable write caching on drive
   */
05680d86d   Peter Osterlund   pktcdvd: reduce s...
2043
2044
  static noinline_for_stack int pkt_write_caching(struct pktcdvd_device *pd,
  						int set)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2045
2046
2047
2048
2049
  {
  	struct packet_command cgc;
  	struct request_sense sense;
  	unsigned char buf[64];
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
  	init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ);
  	cgc.sense = &sense;
  	cgc.buflen = pd->mode_offset + 12;
  
  	/*
  	 * caching mode page might not be there, so quiet this command
  	 */
  	cgc.quiet = 1;
  
  	if ((ret = pkt_mode_sense(pd, &cgc, GPMODE_WCACHING_PAGE, 0)))
  		return ret;
  
  	buf[pd->mode_offset + 10] |= (!!set << 2);
  
  	cgc.buflen = cgc.cmd[8] = 2 + ((buf[0] << 8) | (buf[1] & 0xff));
  	ret = pkt_mode_select(pd, &cgc);
  	if (ret) {
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
2067
2068
  		printk(DRIVER_NAME": write caching control failed
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2069
2070
  		pkt_dump_sense(&cgc);
  	} else if (!ret && set)
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
2071
2072
  		printk(DRIVER_NAME": enabled write caching on %s
  ", pd->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
  	return ret;
  }
  
  static int pkt_lock_door(struct pktcdvd_device *pd, int lockflag)
  {
  	struct packet_command cgc;
  
  	init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
  	cgc.cmd[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL;
  	cgc.cmd[4] = lockflag ? 1 : 0;
  	return pkt_generic_packet(pd, &cgc);
  }
  
  /*
   * Returns drive maximum write speed
   */
05680d86d   Peter Osterlund   pktcdvd: reduce s...
2089
2090
  static noinline_for_stack int pkt_get_max_speed(struct pktcdvd_device *pd,
  						unsigned *write_speed)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2091
2092
2093
2094
2095
2096
  {
  	struct packet_command cgc;
  	struct request_sense sense;
  	unsigned char buf[256+18];
  	unsigned char *cap_buf;
  	int ret, offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
  	cap_buf = &buf[sizeof(struct mode_page_header) + pd->mode_offset];
  	init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_UNKNOWN);
  	cgc.sense = &sense;
  
  	ret = pkt_mode_sense(pd, &cgc, GPMODE_CAPABILITIES_PAGE, 0);
  	if (ret) {
  		cgc.buflen = pd->mode_offset + cap_buf[1] + 2 +
  			     sizeof(struct mode_page_header);
  		ret = pkt_mode_sense(pd, &cgc, GPMODE_CAPABILITIES_PAGE, 0);
  		if (ret) {
  			pkt_dump_sense(&cgc);
  			return ret;
  		}
  	}
  
  	offset = 20;			    /* Obsoleted field, used by older drives */
  	if (cap_buf[1] >= 28)
  		offset = 28;		    /* Current write speed selected */
  	if (cap_buf[1] >= 30) {
  		/* If the drive reports at least one "Logical Unit Write
  		 * Speed Performance Descriptor Block", use the information
  		 * in the first block. (contains the highest speed)
  		 */
  		int num_spdb = (cap_buf[30] << 8) + cap_buf[31];
  		if (num_spdb > 0)
  			offset = 34;
  	}
  
  	*write_speed = (cap_buf[offset] << 8) | cap_buf[offset + 1];
  	return 0;
  }
  
  /* These tables from cdrecord - I don't have orange book */
  /* standard speed CD-RW (1-4x) */
  static char clv_to_speed[16] = {
  	/* 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 */
  	   0, 2, 4, 6, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
  };
  /* high speed CD-RW (-10x) */
  static char hs_clv_to_speed[16] = {
  	/* 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 */
  	   0, 2, 4, 6, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
  };
  /* ultra high speed CD-RW */
  static char us_clv_to_speed[16] = {
  	/* 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 */
  	   0, 2, 4, 8, 0, 0,16, 0,24,32,40,48, 0, 0, 0, 0
  };
  
  /*
   * reads the maximum media speed from ATIP
   */
05680d86d   Peter Osterlund   pktcdvd: reduce s...
2149
2150
  static noinline_for_stack int pkt_media_speed(struct pktcdvd_device *pd,
  						unsigned *speed)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
  {
  	struct packet_command cgc;
  	struct request_sense sense;
  	unsigned char buf[64];
  	unsigned int size, st, sp;
  	int ret;
  
  	init_cdrom_command(&cgc, buf, 2, CGC_DATA_READ);
  	cgc.sense = &sense;
  	cgc.cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
  	cgc.cmd[1] = 2;
  	cgc.cmd[2] = 4; /* READ ATIP */
  	cgc.cmd[8] = 2;
  	ret = pkt_generic_packet(pd, &cgc);
  	if (ret) {
  		pkt_dump_sense(&cgc);
  		return ret;
  	}
  	size = ((unsigned int) buf[0]<<8) + buf[1] + 2;
  	if (size > sizeof(buf))
  		size = sizeof(buf);
  
  	init_cdrom_command(&cgc, buf, size, CGC_DATA_READ);
  	cgc.sense = &sense;
  	cgc.cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
  	cgc.cmd[1] = 2;
  	cgc.cmd[2] = 4;
  	cgc.cmd[8] = size;
  	ret = pkt_generic_packet(pd, &cgc);
  	if (ret) {
  		pkt_dump_sense(&cgc);
  		return ret;
  	}
eaa0ff15c   Alexey Dobriyan   fix ! versus & pr...
2184
  	if (!(buf[6] & 0x40)) {
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
2185
2186
  		printk(DRIVER_NAME": Disc type is not CD-RW
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2187
2188
  		return 1;
  	}
eaa0ff15c   Alexey Dobriyan   fix ! versus & pr...
2189
  	if (!(buf[6] & 0x4)) {
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
2190
2191
  		printk(DRIVER_NAME": A1 values on media are not valid, maybe not CDRW?
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
  		return 1;
  	}
  
  	st = (buf[6] >> 3) & 0x7; /* disc sub-type */
  
  	sp = buf[16] & 0xf; /* max speed from ATIP A1 field */
  
  	/* Info from cdrecord */
  	switch (st) {
  		case 0: /* standard speed */
  			*speed = clv_to_speed[sp];
  			break;
  		case 1: /* high speed */
  			*speed = hs_clv_to_speed[sp];
  			break;
  		case 2: /* ultra high speed */
  			*speed = us_clv_to_speed[sp];
  			break;
  		default:
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
2211
2212
  			printk(DRIVER_NAME": Unknown disc sub-type %d
  ",st);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2213
2214
2215
  			return 1;
  	}
  	if (*speed) {
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
2216
2217
  		printk(DRIVER_NAME": Max. media speed: %d
  ",*speed);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2218
2219
  		return 0;
  	} else {
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
2220
2221
  		printk(DRIVER_NAME": Unknown speed %d for sub-type %d
  ",sp,st);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2222
2223
2224
  		return 1;
  	}
  }
05680d86d   Peter Osterlund   pktcdvd: reduce s...
2225
  static noinline_for_stack int pkt_perform_opc(struct pktcdvd_device *pd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2226
2227
2228
2229
  {
  	struct packet_command cgc;
  	struct request_sense sense;
  	int ret;
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
2230
2231
  	VPRINTK(DRIVER_NAME": Performing OPC
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
  
  	init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
  	cgc.sense = &sense;
  	cgc.timeout = 60*HZ;
  	cgc.cmd[0] = GPCMD_SEND_OPC;
  	cgc.cmd[1] = 1;
  	if ((ret = pkt_generic_packet(pd, &cgc)))
  		pkt_dump_sense(&cgc);
  	return ret;
  }
  
  static int pkt_open_write(struct pktcdvd_device *pd)
  {
  	int ret;
  	unsigned int write_speed, media_write_speed, read_speed;
  
  	if ((ret = pkt_probe_settings(pd))) {
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
2249
2250
  		VPRINTK(DRIVER_NAME": %s failed probe
  ", pd->name);
9db915465   Peter Osterlund   [PATCH] pktcdvd: ...
2251
  		return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2252
2253
2254
  	}
  
  	if ((ret = pkt_set_write_settings(pd))) {
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
2255
2256
  		DPRINTK(DRIVER_NAME": %s failed saving write settings
  ", pd->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
  		return -EIO;
  	}
  
  	pkt_write_caching(pd, USE_WCACHING);
  
  	if ((ret = pkt_get_max_speed(pd, &write_speed)))
  		write_speed = 16 * 177;
  	switch (pd->mmc3_profile) {
  		case 0x13: /* DVD-RW */
  		case 0x1a: /* DVD+RW */
  		case 0x12: /* DVD-RAM */
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
2268
2269
  			DPRINTK(DRIVER_NAME": write speed %ukB/s
  ", write_speed);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2270
2271
2272
2273
2274
  			break;
  		default:
  			if ((ret = pkt_media_speed(pd, &media_write_speed)))
  				media_write_speed = 16;
  			write_speed = min(write_speed, media_write_speed * 177);
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
2275
2276
  			DPRINTK(DRIVER_NAME": write speed %ux
  ", write_speed / 176);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2277
2278
2279
2280
2281
  			break;
  	}
  	read_speed = write_speed;
  
  	if ((ret = pkt_set_speed(pd, write_speed, read_speed))) {
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
2282
2283
  		DPRINTK(DRIVER_NAME": %s couldn't set write speed
  ", pd->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2284
2285
2286
2287
2288
2289
  		return -EIO;
  	}
  	pd->write_speed = write_speed;
  	pd->read_speed = read_speed;
  
  	if ((ret = pkt_perform_opc(pd))) {
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
2290
2291
  		DPRINTK(DRIVER_NAME": %s Optimum Power Calibration failed
  ", pd->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2292
2293
2294
2295
2296
2297
2298
2299
  	}
  
  	return 0;
  }
  
  /*
   * called at open time.
   */
aeb5d7270   Al Viro   [PATCH] introduce...
2300
  static int pkt_open_dev(struct pktcdvd_device *pd, fmode_t write)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2301
2302
2303
  {
  	int ret;
  	long lba;
165125e1e   Jens Axboe   [BLOCK] Get rid o...
2304
  	struct request_queue *q;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2305
2306
2307
2308
2309
2310
2311
  
  	/*
  	 * We need to re-open the cdrom device without O_NONBLOCK to be able
  	 * to read/write from/to it. It is already opened in O_NONBLOCK mode
  	 * so bdget() can't fail.
  	 */
  	bdget(pd->bdev->bd_dev);
e525fd89d   Tejun Heo   block: make blkde...
2312
  	if ((ret = blkdev_get(pd->bdev, FMODE_READ | FMODE_EXCL, pd)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2313
2314
2315
  		goto out;
  
  	if ((ret = pkt_get_last_written(pd, &lba))) {
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
2316
2317
  		printk(DRIVER_NAME": pkt_get_last_written failed
  ");
e525fd89d   Tejun Heo   block: make blkde...
2318
  		goto out_putdev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2319
2320
2321
2322
2323
2324
2325
2326
2327
  	}
  
  	set_capacity(pd->disk, lba << 2);
  	set_capacity(pd->bdev->bd_disk, lba << 2);
  	bd_set_size(pd->bdev, (loff_t)lba << 11);
  
  	q = bdev_get_queue(pd->bdev);
  	if (write) {
  		if ((ret = pkt_open_write(pd)))
e525fd89d   Tejun Heo   block: make blkde...
2328
  			goto out_putdev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2329
2330
2331
2332
2333
  		/*
  		 * Some CDRW drives can not handle writes larger than one packet,
  		 * even if the size is a multiple of the packet size.
  		 */
  		spin_lock_irq(q->queue_lock);
086fa5ff0   Martin K. Petersen   block: Rename blk...
2334
  		blk_queue_max_hw_sectors(q, pd->settings.size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2335
2336
2337
2338
2339
2340
2341
2342
  		spin_unlock_irq(q->queue_lock);
  		set_bit(PACKET_WRITABLE, &pd->flags);
  	} else {
  		pkt_set_speed(pd, MAX_SPEED, MAX_SPEED);
  		clear_bit(PACKET_WRITABLE, &pd->flags);
  	}
  
  	if ((ret = pkt_set_segment_merging(pd, q)))
e525fd89d   Tejun Heo   block: make blkde...
2343
  		goto out_putdev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2344

e1bc89bc9   Peter Osterlund   [PATCH] pktcdvd: ...
2345
2346
  	if (write) {
  		if (!pkt_grow_pktlist(pd, CONFIG_CDROM_PKTCDVD_BUFFERS)) {
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
2347
2348
  			printk(DRIVER_NAME": not enough memory for buffers
  ");
e1bc89bc9   Peter Osterlund   [PATCH] pktcdvd: ...
2349
  			ret = -ENOMEM;
e525fd89d   Tejun Heo   block: make blkde...
2350
  			goto out_putdev;
e1bc89bc9   Peter Osterlund   [PATCH] pktcdvd: ...
2351
  		}
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
2352
2353
  		printk(DRIVER_NAME": %lukB available on disc
  ", lba << 1);
e1bc89bc9   Peter Osterlund   [PATCH] pktcdvd: ...
2354
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2355
2356
2357
2358
  
  	return 0;
  
  out_putdev:
e525fd89d   Tejun Heo   block: make blkde...
2359
  	blkdev_put(pd->bdev, FMODE_READ | FMODE_EXCL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
  out:
  	return ret;
  }
  
  /*
   * called when the device is closed. makes sure that the device flushes
   * the internal cache before we close.
   */
  static void pkt_release_dev(struct pktcdvd_device *pd, int flush)
  {
  	if (flush && pkt_flush_cache(pd))
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
2371
2372
  		DPRINTK(DRIVER_NAME": %s not flushing cache
  ", pd->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2373
2374
2375
2376
  
  	pkt_lock_door(pd, 0);
  
  	pkt_set_speed(pd, MAX_SPEED, MAX_SPEED);
e525fd89d   Tejun Heo   block: make blkde...
2377
  	blkdev_put(pd->bdev, FMODE_READ | FMODE_EXCL);
e1bc89bc9   Peter Osterlund   [PATCH] pktcdvd: ...
2378
2379
  
  	pkt_shrink_pktlist(pd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2380
  }
252a52aa4   Dan Rosenberg   Fix pktcdvd ioctl...
2381
  static struct pktcdvd_device *pkt_find_dev_from_minor(unsigned int dev_minor)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2382
2383
2384
2385
2386
  {
  	if (dev_minor >= MAX_WRITERS)
  		return NULL;
  	return pkt_devs[dev_minor];
  }
5e5e007c2   Al Viro   [PATCH] switch pk...
2387
  static int pkt_open(struct block_device *bdev, fmode_t mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2388
2389
2390
  {
  	struct pktcdvd_device *pd = NULL;
  	int ret;
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
2391
2392
  	VPRINTK(DRIVER_NAME": entering open
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2393

2a48fc0ab   Arnd Bergmann   block: autoconver...
2394
  	mutex_lock(&pktcdvd_mutex);
1657f824e   Jes Sorensen   [PATCH] sem2mutex...
2395
  	mutex_lock(&ctl_mutex);
5e5e007c2   Al Viro   [PATCH] switch pk...
2396
  	pd = pkt_find_dev_from_minor(MINOR(bdev->bd_dev));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2397
2398
2399
2400
2401
2402
2403
  	if (!pd) {
  		ret = -ENODEV;
  		goto out;
  	}
  	BUG_ON(pd->refcnt < 0);
  
  	pd->refcnt++;
46f4e1b7d   Peter Osterlund   [PATCH] packet dr...
2404
  	if (pd->refcnt > 1) {
5e5e007c2   Al Viro   [PATCH] switch pk...
2405
  		if ((mode & FMODE_WRITE) &&
46f4e1b7d   Peter Osterlund   [PATCH] packet dr...
2406
2407
2408
2409
2410
  		    !test_bit(PACKET_WRITABLE, &pd->flags)) {
  			ret = -EBUSY;
  			goto out_dec;
  		}
  	} else {
5e5e007c2   Al Viro   [PATCH] switch pk...
2411
  		ret = pkt_open_dev(pd, mode & FMODE_WRITE);
01fd9fda2   Peter Osterlund   [PATCH] pktcdvd: ...
2412
  		if (ret)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2413
  			goto out_dec;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2414
2415
2416
2417
  		/*
  		 * needed here as well, since ext2 (among others) may change
  		 * the blocksize at mount time
  		 */
5e5e007c2   Al Viro   [PATCH] switch pk...
2418
  		set_blocksize(bdev, CD_FRAMESIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2419
  	}
1657f824e   Jes Sorensen   [PATCH] sem2mutex...
2420
  	mutex_unlock(&ctl_mutex);
2a48fc0ab   Arnd Bergmann   block: autoconver...
2421
  	mutex_unlock(&pktcdvd_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2422
2423
2424
2425
2426
  	return 0;
  
  out_dec:
  	pd->refcnt--;
  out:
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
2427
2428
  	VPRINTK(DRIVER_NAME": failed open (%d)
  ", ret);
1657f824e   Jes Sorensen   [PATCH] sem2mutex...
2429
  	mutex_unlock(&ctl_mutex);
2a48fc0ab   Arnd Bergmann   block: autoconver...
2430
  	mutex_unlock(&pktcdvd_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2431
2432
  	return ret;
  }
5e5e007c2   Al Viro   [PATCH] switch pk...
2433
  static int pkt_close(struct gendisk *disk, fmode_t mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2434
  {
5e5e007c2   Al Viro   [PATCH] switch pk...
2435
  	struct pktcdvd_device *pd = disk->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2436
  	int ret = 0;
2a48fc0ab   Arnd Bergmann   block: autoconver...
2437
  	mutex_lock(&pktcdvd_mutex);
1657f824e   Jes Sorensen   [PATCH] sem2mutex...
2438
  	mutex_lock(&ctl_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2439
2440
2441
2442
2443
2444
  	pd->refcnt--;
  	BUG_ON(pd->refcnt < 0);
  	if (pd->refcnt == 0) {
  		int flush = test_bit(PACKET_WRITABLE, &pd->flags);
  		pkt_release_dev(pd, flush);
  	}
1657f824e   Jes Sorensen   [PATCH] sem2mutex...
2445
  	mutex_unlock(&ctl_mutex);
2a48fc0ab   Arnd Bergmann   block: autoconver...
2446
  	mutex_unlock(&pktcdvd_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2447
2448
  	return ret;
  }
6712ecf8f   NeilBrown   Drop 'size' argum...
2449
  static void pkt_end_io_read_cloned(struct bio *bio, int err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2450
2451
2452
  {
  	struct packet_stacked_data *psd = bio->bi_private;
  	struct pktcdvd_device *pd = psd->pd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2453
  	bio_put(bio);
6712ecf8f   NeilBrown   Drop 'size' argum...
2454
  	bio_endio(psd->bio, err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2455
2456
  	mempool_free(psd, psd_pool);
  	pkt_bio_finished(pd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2457
  }
5a7bbad27   Christoph Hellwig   block: remove sup...
2458
  static void pkt_make_request(struct request_queue *q, struct bio *bio)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
  {
  	struct pktcdvd_device *pd;
  	char b[BDEVNAME_SIZE];
  	sector_t zone;
  	struct packet_data *pkt;
  	int was_empty, blocked_bio;
  	struct pkt_rb_node *node;
  
  	pd = q->queuedata;
  	if (!pd) {
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
2469
2470
  		printk(DRIVER_NAME": %s incorrect request queue
  ", bdevname(bio->bi_bdev, b));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
  		goto end_io;
  	}
  
  	/*
  	 * Clone READ bios so we can have our own bi_end_io callback.
  	 */
  	if (bio_data_dir(bio) == READ) {
  		struct bio *cloned_bio = bio_clone(bio, GFP_NOIO);
  		struct packet_stacked_data *psd = mempool_alloc(psd_pool, GFP_NOIO);
  
  		psd->pd = pd;
  		psd->bio = bio;
  		cloned_bio->bi_bdev = pd->bdev;
  		cloned_bio->bi_private = psd;
  		cloned_bio->bi_end_io = pkt_end_io_read_cloned;
  		pd->stats.secs_r += bio->bi_size >> 9;
46c271bed   Peter Osterlund   [PATCH] Improve C...
2487
  		pkt_queue_bio(pd, cloned_bio);
5a7bbad27   Christoph Hellwig   block: remove sup...
2488
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2489
2490
2491
  	}
  
  	if (!test_bit(PACKET_WRITABLE, &pd->flags)) {
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
2492
2493
  		printk(DRIVER_NAME": WRITE for ro device %s (%llu)
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2494
2495
2496
2497
2498
  			pd->name, (unsigned long long)bio->bi_sector);
  		goto end_io;
  	}
  
  	if (!bio->bi_size || (bio->bi_size % CD_FRAMESIZE)) {
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
2499
2500
  		printk(DRIVER_NAME": wrong bio size
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
  		goto end_io;
  	}
  
  	blk_queue_bounce(q, &bio);
  
  	zone = ZONE(bio->bi_sector, pd);
  	VPRINTK("pkt_make_request: start = %6llx stop = %6llx
  ",
  		(unsigned long long)bio->bi_sector,
  		(unsigned long long)(bio->bi_sector + bio_sectors(bio)));
  
  	/* Check if we have to split the bio */
  	{
  		struct bio_pair *bp;
  		sector_t last_zone;
  		int first_sectors;
  
  		last_zone = ZONE(bio->bi_sector + bio_sectors(bio) - 1, pd);
  		if (last_zone != zone) {
  			BUG_ON(last_zone != zone + pd->settings.size);
  			first_sectors = last_zone - bio->bi_sector;
6feef531f   Denis ChengRq   block: mark bio_s...
2522
  			bp = bio_split(bio, first_sectors);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2523
2524
2525
2526
  			BUG_ON(!bp);
  			pkt_make_request(q, &bp->bio1);
  			pkt_make_request(q, &bp->bio2);
  			bio_pair_release(bp);
5a7bbad27   Christoph Hellwig   block: remove sup...
2527
  			return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
  		}
  	}
  
  	/*
  	 * If we find a matching packet in state WAITING or READ_WAIT, we can
  	 * just append this bio to that packet.
  	 */
  	spin_lock(&pd->cdrw.active_list_lock);
  	blocked_bio = 0;
  	list_for_each_entry(pkt, &pd->cdrw.pkt_active_list, list) {
  		if (pkt->sector == zone) {
  			spin_lock(&pkt->lock);
  			if ((pkt->state == PACKET_WAITING_STATE) ||
  			    (pkt->state == PACKET_READ_WAIT_STATE)) {
c5ecc484c   Akinobu Mita   pktcdvd: use BIO ...
2542
  				bio_list_add(&pkt->orig_bios, bio);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2543
2544
2545
2546
2547
2548
2549
2550
  				pkt->write_size += bio->bi_size / CD_FRAMESIZE;
  				if ((pkt->write_size >= pkt->frames) &&
  				    (pkt->state == PACKET_WAITING_STATE)) {
  					atomic_inc(&pkt->run_sm);
  					wake_up(&pd->wqueue);
  				}
  				spin_unlock(&pkt->lock);
  				spin_unlock(&pd->cdrw.active_list_lock);
5a7bbad27   Christoph Hellwig   block: remove sup...
2551
  				return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2552
2553
2554
2555
2556
2557
2558
  			} else {
  				blocked_bio = 1;
  			}
  			spin_unlock(&pkt->lock);
  		}
  	}
  	spin_unlock(&pd->cdrw.active_list_lock);
0a0fc9601   Thomas Maier   [PATCH] pktcdvd: ...
2559
2560
2561
2562
2563
2564
2565
2566
   	/*
  	 * Test if there is enough room left in the bio work queue
  	 * (queue size >= congestion on mark).
  	 * If not, wait till the work queue size is below the congestion off mark.
  	 */
  	spin_lock(&pd->lock);
  	if (pd->write_congestion_on > 0
  	    && pd->bio_queue_size >= pd->write_congestion_on) {
8aa7e847d   Jens Axboe   Fix congestion_wa...
2567
  		set_bdi_congested(&q->backing_dev_info, BLK_RW_ASYNC);
0a0fc9601   Thomas Maier   [PATCH] pktcdvd: ...
2568
2569
  		do {
  			spin_unlock(&pd->lock);
8aa7e847d   Jens Axboe   Fix congestion_wa...
2570
  			congestion_wait(BLK_RW_ASYNC, HZ);
0a0fc9601   Thomas Maier   [PATCH] pktcdvd: ...
2571
2572
2573
2574
  			spin_lock(&pd->lock);
  		} while(pd->bio_queue_size > pd->write_congestion_off);
  	}
  	spin_unlock(&pd->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2575
2576
2577
2578
  	/*
  	 * No matching packet found. Store the bio in the work queue.
  	 */
  	node = mempool_alloc(pd->rb_pool, GFP_NOIO);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
  	node->bio = bio;
  	spin_lock(&pd->lock);
  	BUG_ON(pd->bio_queue_size < 0);
  	was_empty = (pd->bio_queue_size == 0);
  	pkt_rbtree_insert(pd, node);
  	spin_unlock(&pd->lock);
  
  	/*
  	 * Wake up the worker thread.
  	 */
  	atomic_set(&pd->scan_queue, 1);
  	if (was_empty) {
  		/* This wake_up is required for correct operation */
  		wake_up(&pd->wqueue);
  	} else if (!list_empty(&pd->cdrw.pkt_free_list) && !blocked_bio) {
  		/*
  		 * This wake up is not required for correct operation,
  		 * but improves performance in some cases.
  		 */
  		wake_up(&pd->wqueue);
  	}
5a7bbad27   Christoph Hellwig   block: remove sup...
2600
  	return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2601
  end_io:
6712ecf8f   NeilBrown   Drop 'size' argum...
2602
  	bio_io_error(bio);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2603
  }
cc371e66e   Alasdair G Kergon   Add bvec_merge_da...
2604
2605
  static int pkt_merge_bvec(struct request_queue *q, struct bvec_merge_data *bmd,
  			  struct bio_vec *bvec)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2606
2607
  {
  	struct pktcdvd_device *pd = q->queuedata;
cc371e66e   Alasdair G Kergon   Add bvec_merge_da...
2608
2609
  	sector_t zone = ZONE(bmd->bi_sector, pd);
  	int used = ((bmd->bi_sector - zone) << 9) + bmd->bi_size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2610
2611
2612
2613
2614
2615
2616
  	int remaining = (pd->settings.size << 9) - used;
  	int remaining2;
  
  	/*
  	 * A bio <= PAGE_SIZE must be allowed. If it crosses a packet
  	 * boundary, pkt_make_request() will split the bio.
  	 */
cc371e66e   Alasdair G Kergon   Add bvec_merge_da...
2617
  	remaining2 = PAGE_SIZE - bmd->bi_size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2618
2619
2620
2621
2622
2623
2624
2625
  	remaining = max(remaining, remaining2);
  
  	BUG_ON(remaining < 0);
  	return remaining;
  }
  
  static void pkt_init_queue(struct pktcdvd_device *pd)
  {
165125e1e   Jens Axboe   [BLOCK] Get rid o...
2626
  	struct request_queue *q = pd->disk->queue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2627
2628
  
  	blk_queue_make_request(q, pkt_make_request);
e1defc4ff   Martin K. Petersen   block: Do away wi...
2629
  	blk_queue_logical_block_size(q, CD_FRAMESIZE);
086fa5ff0   Martin K. Petersen   block: Rename blk...
2630
  	blk_queue_max_hw_sectors(q, PACKET_MAX_SECTORS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
  	blk_queue_merge_bvec(q, pkt_merge_bvec);
  	q->queuedata = pd;
  }
  
  static int pkt_seq_show(struct seq_file *m, void *p)
  {
  	struct pktcdvd_device *pd = m->private;
  	char *msg;
  	char bdev_buf[BDEVNAME_SIZE];
  	int states[PACKET_NUM_STATES];
  
  	seq_printf(m, "Writer %s mapped to %s:
  ", pd->name,
  		   bdevname(pd->bdev, bdev_buf));
  
  	seq_printf(m, "
  Settings:
  ");
  	seq_printf(m, "\tpacket size:\t\t%dkB
  ", pd->settings.size / 2);
  
  	if (pd->settings.write_type == 0)
  		msg = "Packet";
  	else
  		msg = "Unknown";
  	seq_printf(m, "\twrite type:\t\t%s
  ", msg);
  
  	seq_printf(m, "\tpacket type:\t\t%s
  ", pd->settings.fp ? "Fixed" : "Variable");
  	seq_printf(m, "\tlink loss:\t\t%d
  ", pd->settings.link_loss);
  
  	seq_printf(m, "\ttrack mode:\t\t%d
  ", pd->settings.track_mode);
  
  	if (pd->settings.block_mode == PACKET_BLOCK_MODE1)
  		msg = "Mode 1";
  	else if (pd->settings.block_mode == PACKET_BLOCK_MODE2)
  		msg = "Mode 2";
  	else
  		msg = "Unknown";
  	seq_printf(m, "\tblock mode:\t\t%s
  ", msg);
  
  	seq_printf(m, "
  Statistics:
  ");
  	seq_printf(m, "\tpackets started:\t%lu
  ", pd->stats.pkt_started);
  	seq_printf(m, "\tpackets ended:\t\t%lu
  ", pd->stats.pkt_ended);
  	seq_printf(m, "\twritten:\t\t%lukB
  ", pd->stats.secs_w >> 1);
  	seq_printf(m, "\tread gather:\t\t%lukB
  ", pd->stats.secs_rg >> 1);
  	seq_printf(m, "\tread:\t\t\t%lukB
  ", pd->stats.secs_r >> 1);
  
  	seq_printf(m, "
  Misc:
  ");
  	seq_printf(m, "\treference count:\t%d
  ", pd->refcnt);
  	seq_printf(m, "\tflags:\t\t\t0x%lx
  ", pd->flags);
  	seq_printf(m, "\tread speed:\t\t%ukB/s
  ", pd->read_speed);
  	seq_printf(m, "\twrite speed:\t\t%ukB/s
  ", pd->write_speed);
  	seq_printf(m, "\tstart offset:\t\t%lu
  ", pd->offset);
  	seq_printf(m, "\tmode page offset:\t%u
  ", pd->mode_offset);
  
  	seq_printf(m, "
  Queue state:
  ");
  	seq_printf(m, "\tbios queued:\t\t%d
  ", pd->bio_queue_size);
  	seq_printf(m, "\tbios pending:\t\t%d
  ", atomic_read(&pd->cdrw.pending_bios));
  	seq_printf(m, "\tcurrent sector:\t\t0x%llx
  ", (unsigned long long)pd->current_sector);
  
  	pkt_count_states(pd, states);
  	seq_printf(m, "\tstate:\t\t\ti:%d ow:%d rw:%d ww:%d rec:%d fin:%d
  ",
  		   states[0], states[1], states[2], states[3], states[4], states[5]);
0a0fc9601   Thomas Maier   [PATCH] pktcdvd: ...
2720
2721
2722
2723
  	seq_printf(m, "\twrite congestion marks:\toff=%d on=%d
  ",
  			pd->write_congestion_off,
  			pd->write_congestion_on);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2724
2725
2726
2727
2728
2729
2730
  	return 0;
  }
  
  static int pkt_seq_open(struct inode *inode, struct file *file)
  {
  	return single_open(file, pkt_seq_show, PDE(inode)->data);
  }
2b8693c06   Arjan van de Ven   [PATCH] mark stru...
2731
  static const struct file_operations pkt_proc_fops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
  	.open	= pkt_seq_open,
  	.read	= seq_read,
  	.llseek	= seq_lseek,
  	.release = single_release
  };
  
  static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev)
  {
  	int i;
  	int ret = 0;
  	char b[BDEVNAME_SIZE];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2743
2744
2745
  	struct block_device *bdev;
  
  	if (pd->pkt_dev == dev) {
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
2746
2747
  		printk(DRIVER_NAME": Recursive setup not allowed
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2748
2749
2750
2751
2752
2753
2754
  		return -EBUSY;
  	}
  	for (i = 0; i < MAX_WRITERS; i++) {
  		struct pktcdvd_device *pd2 = pkt_devs[i];
  		if (!pd2)
  			continue;
  		if (pd2->bdev->bd_dev == dev) {
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
2755
2756
  			printk(DRIVER_NAME": %s already setup
  ", bdevname(pd2->bdev, b));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2757
2758
2759
  			return -EBUSY;
  		}
  		if (pd2->pkt_dev == dev) {
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
2760
2761
  			printk(DRIVER_NAME": Can't chain pktcdvd devices
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2762
2763
2764
2765
2766
2767
2768
  			return -EBUSY;
  		}
  	}
  
  	bdev = bdget(dev);
  	if (!bdev)
  		return -ENOMEM;
e525fd89d   Tejun Heo   block: make blkde...
2769
  	ret = blkdev_get(bdev, FMODE_READ | FMODE_NDELAY, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2770
2771
2772
2773
2774
  	if (ret)
  		return ret;
  
  	/* This is safe, since we have a reference from open(). */
  	__module_get(THIS_MODULE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2775
2776
2777
2778
2779
2780
2781
2782
  	pd->bdev = bdev;
  	set_blocksize(bdev, CD_FRAMESIZE);
  
  	pkt_init_queue(pd);
  
  	atomic_set(&pd->cdrw.pending_bios, 0);
  	pd->cdrw.thread = kthread_run(kcdrwd, pd, "%s", pd->name);
  	if (IS_ERR(pd->cdrw.thread)) {
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
2783
2784
  		printk(DRIVER_NAME": can't start kernel thread
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2785
  		ret = -ENOMEM;
e1bc89bc9   Peter Osterlund   [PATCH] pktcdvd: ...
2786
  		goto out_mem;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2787
  	}
c7705f344   Denis V. Lunev   drivers: use non-...
2788
  	proc_create_data(pd->name, 0, pkt_proc, &pkt_proc_fops, pd);
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
2789
2790
  	DPRINTK(DRIVER_NAME": writer %s mapped to %s
  ", pd->name, bdevname(bdev, b));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2791
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2792
  out_mem:
2cbed8906   Al Viro   [PATCH] fix bogus...
2793
  	blkdev_put(bdev, FMODE_READ | FMODE_NDELAY);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2794
2795
2796
2797
  	/* This is safe: open() is still holding a reference. */
  	module_put(THIS_MODULE);
  	return ret;
  }
5e5e007c2   Al Viro   [PATCH] switch pk...
2798
  static int pkt_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2799
  {
5e5e007c2   Al Viro   [PATCH] switch pk...
2800
  	struct pktcdvd_device *pd = bdev->bd_disk->private_data;
8a6cfeb6d   Arnd Bergmann   block: push down ...
2801
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2802

5e5e007c2   Al Viro   [PATCH] switch pk...
2803
2804
2805
  	VPRINTK("pkt_ioctl: cmd %x, dev %d:%d
  ", cmd,
  		MAJOR(bdev->bd_dev), MINOR(bdev->bd_dev));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2806

2a48fc0ab   Arnd Bergmann   block: autoconver...
2807
  	mutex_lock(&pktcdvd_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2808
  	switch (cmd) {
a0eb62a0a   Al Viro   [PATCH] switch pk...
2809
2810
2811
2812
2813
2814
2815
2816
  	case CDROMEJECT:
  		/*
  		 * The door gets locked when the device is opened, so we
  		 * have to unlock it or else the eject command fails.
  		 */
  		if (pd->refcnt == 1)
  			pkt_lock_door(pd, 0);
  		/* fallthru */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2817
2818
2819
2820
2821
2822
2823
2824
  	/*
  	 * forward selected CDROM ioctls to CD-ROM, for UDF
  	 */
  	case CDROMMULTISESSION:
  	case CDROMREADTOCENTRY:
  	case CDROM_LAST_WRITTEN:
  	case CDROM_SEND_PACKET:
  	case SCSI_IOCTL_SEND_COMMAND:
8a6cfeb6d   Arnd Bergmann   block: push down ...
2825
2826
  		ret = __blkdev_driver_ioctl(pd->bdev, mode, cmd, arg);
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2827
2828
  
  	default:
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
2829
2830
  		VPRINTK(DRIVER_NAME": Unknown ioctl for %s (%x)
  ", pd->name, cmd);
8a6cfeb6d   Arnd Bergmann   block: push down ...
2831
  		ret = -ENOTTY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2832
  	}
2a48fc0ab   Arnd Bergmann   block: autoconver...
2833
  	mutex_unlock(&pktcdvd_mutex);
8560c650f   Linus Torvalds   Revert "pktcdvd: ...
2834

8a6cfeb6d   Arnd Bergmann   block: push down ...
2835
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2836
  }
3c0d20609   Tejun Heo   pktcdvd: Convert ...
2837
2838
  static unsigned int pkt_check_events(struct gendisk *disk,
  				     unsigned int clearing)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2839
2840
2841
2842
2843
2844
2845
2846
2847
  {
  	struct pktcdvd_device *pd = disk->private_data;
  	struct gendisk *attached_disk;
  
  	if (!pd)
  		return 0;
  	if (!pd->bdev)
  		return 0;
  	attached_disk = pd->bdev->bd_disk;
3c0d20609   Tejun Heo   pktcdvd: Convert ...
2848
  	if (!attached_disk || !attached_disk->fops->check_events)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2849
  		return 0;
3c0d20609   Tejun Heo   pktcdvd: Convert ...
2850
  	return attached_disk->fops->check_events(attached_disk, clearing);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2851
  }
83d5cde47   Alexey Dobriyan   const: make block...
2852
  static const struct block_device_operations pktcdvd_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2853
  	.owner =		THIS_MODULE,
5e5e007c2   Al Viro   [PATCH] switch pk...
2854
2855
  	.open =			pkt_open,
  	.release =		pkt_close,
8a6cfeb6d   Arnd Bergmann   block: push down ...
2856
  	.ioctl =		pkt_ioctl,
3c0d20609   Tejun Heo   pktcdvd: Convert ...
2857
  	.check_events =		pkt_check_events,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2858
  };
2c9ede55e   Al Viro   switch device_get...
2859
  static char *pktcdvd_devnode(struct gendisk *gd, umode_t *mode)
b03f38b68   Kay Sievers   Driver Core: bloc...
2860
2861
2862
  {
  	return kasprintf(GFP_KERNEL, "pktcdvd/%s", gd->disk_name);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2863
2864
2865
  /*
   * Set up mapping from pktcdvd device to CD-ROM device.
   */
adb9250a0   Thomas Maier   [PATCH] pktcdvd: ...
2866
  static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2867
2868
2869
2870
2871
  {
  	int idx;
  	int ret = -ENOMEM;
  	struct pktcdvd_device *pd;
  	struct gendisk *disk;
adb9250a0   Thomas Maier   [PATCH] pktcdvd: ...
2872
2873
  
  	mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2874
2875
2876
2877
2878
  
  	for (idx = 0; idx < MAX_WRITERS; idx++)
  		if (!pkt_devs[idx])
  			break;
  	if (idx == MAX_WRITERS) {
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
2879
2880
  		printk(DRIVER_NAME": max %d writers supported
  ", MAX_WRITERS);
adb9250a0   Thomas Maier   [PATCH] pktcdvd: ...
2881
2882
  		ret = -EBUSY;
  		goto out_mutex;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2883
  	}
1107d2e03   Peter Osterlund   [PATCH] pktcdvd: ...
2884
  	pd = kzalloc(sizeof(struct pktcdvd_device), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2885
  	if (!pd)
adb9250a0   Thomas Maier   [PATCH] pktcdvd: ...
2886
  		goto out_mutex;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2887

0eaae62ab   Matthew Dobson   [PATCH] mempool: ...
2888
2889
  	pd->rb_pool = mempool_create_kmalloc_pool(PKT_RB_POOL_SIZE,
  						  sizeof(struct pkt_rb_node));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2890
2891
  	if (!pd->rb_pool)
  		goto out_mem;
e1bc89bc9   Peter Osterlund   [PATCH] pktcdvd: ...
2892
2893
2894
  	INIT_LIST_HEAD(&pd->cdrw.pkt_free_list);
  	INIT_LIST_HEAD(&pd->cdrw.pkt_active_list);
  	spin_lock_init(&pd->cdrw.active_list_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2895
2896
  	spin_lock_init(&pd->lock);
  	spin_lock_init(&pd->iosched.lock);
c5ecc484c   Akinobu Mita   pktcdvd: use BIO ...
2897
2898
  	bio_list_init(&pd->iosched.read_queue);
  	bio_list_init(&pd->iosched.write_queue);
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
2899
  	sprintf(pd->name, DRIVER_NAME"%d", idx);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2900
2901
  	init_waitqueue_head(&pd->wqueue);
  	pd->bio_queue = RB_ROOT;
0a0fc9601   Thomas Maier   [PATCH] pktcdvd: ...
2902
2903
  	pd->write_congestion_on  = write_congestion_on;
  	pd->write_congestion_off = write_congestion_off;
adb9250a0   Thomas Maier   [PATCH] pktcdvd: ...
2904
2905
2906
2907
  	disk = alloc_disk(1);
  	if (!disk)
  		goto out_mem;
  	pd->disk = disk;
add216608   Thomas Maier   [PATCH] pktcdvd: ...
2908
  	disk->major = pktdev_major;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2909
2910
2911
  	disk->first_minor = idx;
  	disk->fops = &pktcdvd_ops;
  	disk->flags = GENHD_FL_REMOVABLE;
adb9250a0   Thomas Maier   [PATCH] pktcdvd: ...
2912
  	strcpy(disk->disk_name, pd->name);
e454cea20   Kay Sievers   Driver-Core: exte...
2913
  	disk->devnode = pktcdvd_devnode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2914
2915
2916
2917
  	disk->private_data = pd;
  	disk->queue = blk_alloc_queue(GFP_KERNEL);
  	if (!disk->queue)
  		goto out_mem2;
f331c0296   Tejun Heo   block: don't depe...
2918
  	pd->pkt_dev = MKDEV(pktdev_major, idx);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2919
2920
2921
  	ret = pkt_new_dev(pd, dev);
  	if (ret)
  		goto out_new_dev;
3c0d20609   Tejun Heo   pktcdvd: Convert ...
2922
2923
2924
  	/* inherit events of the host device */
  	disk->events = pd->bdev->bd_disk->events;
  	disk->async_events = pd->bdev->bd_disk->async_events;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2925
  	add_disk(disk);
adb9250a0   Thomas Maier   [PATCH] pktcdvd: ...
2926

32694850a   Thomas Maier   [PATCH] pktcdvd: ...
2927
2928
  	pkt_sysfs_dev_new(pd);
  	pkt_debugfs_dev_new(pd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2929
  	pkt_devs[idx] = pd;
adb9250a0   Thomas Maier   [PATCH] pktcdvd: ...
2930
2931
2932
2933
  	if (pkt_dev)
  		*pkt_dev = pd->pkt_dev;
  
  	mutex_unlock(&ctl_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2934
2935
2936
  	return 0;
  
  out_new_dev:
1312f40e1   Al Viro   [PATCH] regulariz...
2937
  	blk_cleanup_queue(disk->queue);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2938
2939
2940
2941
2942
2943
  out_mem2:
  	put_disk(disk);
  out_mem:
  	if (pd->rb_pool)
  		mempool_destroy(pd->rb_pool);
  	kfree(pd);
adb9250a0   Thomas Maier   [PATCH] pktcdvd: ...
2944
2945
2946
2947
  out_mutex:
  	mutex_unlock(&ctl_mutex);
  	printk(DRIVER_NAME": setup of pktcdvd device failed
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2948
2949
2950
2951
2952
2953
  	return ret;
  }
  
  /*
   * Tear down mapping from pktcdvd device to CD-ROM device.
   */
adb9250a0   Thomas Maier   [PATCH] pktcdvd: ...
2954
  static int pkt_remove_dev(dev_t pkt_dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2955
2956
2957
  {
  	struct pktcdvd_device *pd;
  	int idx;
adb9250a0   Thomas Maier   [PATCH] pktcdvd: ...
2958
2959
2960
  	int ret = 0;
  
  	mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2961
2962
2963
2964
2965
2966
2967
  
  	for (idx = 0; idx < MAX_WRITERS; idx++) {
  		pd = pkt_devs[idx];
  		if (pd && (pd->pkt_dev == pkt_dev))
  			break;
  	}
  	if (idx == MAX_WRITERS) {
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
2968
2969
  		DPRINTK(DRIVER_NAME": dev not setup
  ");
adb9250a0   Thomas Maier   [PATCH] pktcdvd: ...
2970
2971
  		ret = -ENXIO;
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2972
  	}
adb9250a0   Thomas Maier   [PATCH] pktcdvd: ...
2973
2974
2975
2976
  	if (pd->refcnt > 0) {
  		ret = -EBUSY;
  		goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2977
2978
  	if (!IS_ERR(pd->cdrw.thread))
  		kthread_stop(pd->cdrw.thread);
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
2979
2980
2981
2982
  	pkt_devs[idx] = NULL;
  
  	pkt_debugfs_dev_remove(pd);
  	pkt_sysfs_dev_remove(pd);
2cbed8906   Al Viro   [PATCH] fix bogus...
2983
  	blkdev_put(pd->bdev, FMODE_READ | FMODE_NDELAY);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2984

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2985
  	remove_proc_entry(pd->name, pkt_proc);
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
2986
2987
  	DPRINTK(DRIVER_NAME": writer %s unmapped
  ", pd->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2988
2989
  
  	del_gendisk(pd->disk);
1312f40e1   Al Viro   [PATCH] regulariz...
2990
  	blk_cleanup_queue(pd->disk->queue);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2991
  	put_disk(pd->disk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2992
2993
2994
2995
2996
  	mempool_destroy(pd->rb_pool);
  	kfree(pd);
  
  	/* This is safe: open() is still holding a reference. */
  	module_put(THIS_MODULE);
adb9250a0   Thomas Maier   [PATCH] pktcdvd: ...
2997
2998
2999
3000
  
  out:
  	mutex_unlock(&ctl_mutex);
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3001
3002
3003
3004
  }
  
  static void pkt_get_status(struct pkt_ctrl_command *ctrl_cmd)
  {
adb9250a0   Thomas Maier   [PATCH] pktcdvd: ...
3005
3006
3007
3008
3009
  	struct pktcdvd_device *pd;
  
  	mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
  
  	pd = pkt_find_dev_from_minor(ctrl_cmd->dev_index);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3010
3011
3012
3013
3014
3015
3016
3017
  	if (pd) {
  		ctrl_cmd->dev = new_encode_dev(pd->bdev->bd_dev);
  		ctrl_cmd->pkt_dev = new_encode_dev(pd->pkt_dev);
  	} else {
  		ctrl_cmd->dev = 0;
  		ctrl_cmd->pkt_dev = 0;
  	}
  	ctrl_cmd->num_devices = MAX_WRITERS;
adb9250a0   Thomas Maier   [PATCH] pktcdvd: ...
3018
3019
  
  	mutex_unlock(&ctl_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3020
  }
f80a0ca6a   Arnd Bergmann   pktcdvd: improve ...
3021
  static long pkt_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3022
3023
3024
3025
  {
  	void __user *argp = (void __user *)arg;
  	struct pkt_ctrl_command ctrl_cmd;
  	int ret = 0;
adb9250a0   Thomas Maier   [PATCH] pktcdvd: ...
3026
  	dev_t pkt_dev = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
  
  	if (cmd != PACKET_CTRL_CMD)
  		return -ENOTTY;
  
  	if (copy_from_user(&ctrl_cmd, argp, sizeof(struct pkt_ctrl_command)))
  		return -EFAULT;
  
  	switch (ctrl_cmd.command) {
  	case PKT_CTRL_CMD_SETUP:
  		if (!capable(CAP_SYS_ADMIN))
  			return -EPERM;
adb9250a0   Thomas Maier   [PATCH] pktcdvd: ...
3038
3039
  		ret = pkt_setup_dev(new_decode_dev(ctrl_cmd.dev), &pkt_dev);
  		ctrl_cmd.pkt_dev = new_encode_dev(pkt_dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3040
3041
3042
3043
  		break;
  	case PKT_CTRL_CMD_TEARDOWN:
  		if (!capable(CAP_SYS_ADMIN))
  			return -EPERM;
adb9250a0   Thomas Maier   [PATCH] pktcdvd: ...
3044
  		ret = pkt_remove_dev(new_decode_dev(ctrl_cmd.pkt_dev));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3045
3046
  		break;
  	case PKT_CTRL_CMD_STATUS:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3047
  		pkt_get_status(&ctrl_cmd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3048
3049
3050
3051
3052
3053
3054
3055
3056
  		break;
  	default:
  		return -ENOTTY;
  	}
  
  	if (copy_to_user(argp, &ctrl_cmd, sizeof(struct pkt_ctrl_command)))
  		return -EFAULT;
  	return ret;
  }
f80a0ca6a   Arnd Bergmann   pktcdvd: improve ...
3057
3058
3059
3060
3061
3062
  #ifdef CONFIG_COMPAT
  static long pkt_ctl_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
  {
  	return pkt_ctl_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
  }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3063

2b8693c06   Arjan van de Ven   [PATCH] mark stru...
3064
  static const struct file_operations pkt_ctl_fops = {
f80a0ca6a   Arnd Bergmann   pktcdvd: improve ...
3065
3066
3067
3068
3069
3070
  	.open		= nonseekable_open,
  	.unlocked_ioctl	= pkt_ctl_ioctl,
  #ifdef CONFIG_COMPAT
  	.compat_ioctl	= pkt_ctl_compat_ioctl,
  #endif
  	.owner		= THIS_MODULE,
6038f373a   Arnd Bergmann   llseek: automatic...
3071
  	.llseek		= no_llseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3072
3073
3074
3075
  };
  
  static struct miscdevice pkt_misc = {
  	.minor 		= MISC_DYNAMIC_MINOR,
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
3076
  	.name  		= DRIVER_NAME,
e454cea20   Kay Sievers   Driver-Core: exte...
3077
  	.nodename	= "pktcdvd/control",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3078
3079
3080
3081
3082
3083
  	.fops  		= &pkt_ctl_fops
  };
  
  static int __init pkt_init(void)
  {
  	int ret;
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
3084
  	mutex_init(&ctl_mutex);
0eaae62ab   Matthew Dobson   [PATCH] mempool: ...
3085
3086
  	psd_pool = mempool_create_kmalloc_pool(PSD_POOL_SIZE,
  					sizeof(struct packet_stacked_data));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3087
3088
  	if (!psd_pool)
  		return -ENOMEM;
add216608   Thomas Maier   [PATCH] pktcdvd: ...
3089
  	ret = register_blkdev(pktdev_major, DRIVER_NAME);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3090
  	if (ret < 0) {
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
3091
3092
  		printk(DRIVER_NAME": Unable to register block device
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3093
3094
  		goto out2;
  	}
add216608   Thomas Maier   [PATCH] pktcdvd: ...
3095
3096
  	if (!pktdev_major)
  		pktdev_major = ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3097

32694850a   Thomas Maier   [PATCH] pktcdvd: ...
3098
3099
3100
3101
3102
  	ret = pkt_sysfs_init();
  	if (ret)
  		goto out;
  
  	pkt_debugfs_init();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3103
3104
  	ret = misc_register(&pkt_misc);
  	if (ret) {
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
3105
3106
  		printk(DRIVER_NAME": Unable to register misc device
  ");
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
3107
  		goto out_misc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3108
  	}
928b4d8c8   Alexey Dobriyan   proc: remove proc...
3109
  	pkt_proc = proc_mkdir("driver/"DRIVER_NAME, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3110

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3111
  	return 0;
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
3112
3113
3114
  out_misc:
  	pkt_debugfs_cleanup();
  	pkt_sysfs_cleanup();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3115
  out:
add216608   Thomas Maier   [PATCH] pktcdvd: ...
3116
  	unregister_blkdev(pktdev_major, DRIVER_NAME);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3117
3118
3119
3120
3121
3122
3123
  out2:
  	mempool_destroy(psd_pool);
  	return ret;
  }
  
  static void __exit pkt_exit(void)
  {
928b4d8c8   Alexey Dobriyan   proc: remove proc...
3124
  	remove_proc_entry("driver/"DRIVER_NAME, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3125
  	misc_deregister(&pkt_misc);
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
3126
3127
3128
  
  	pkt_debugfs_cleanup();
  	pkt_sysfs_cleanup();
add216608   Thomas Maier   [PATCH] pktcdvd: ...
3129
  	unregister_blkdev(pktdev_major, DRIVER_NAME);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3130
3131
3132
3133
3134
3135
3136
3137
3138
  	mempool_destroy(psd_pool);
  }
  
  MODULE_DESCRIPTION("Packet writing layer for CD/DVD drives");
  MODULE_AUTHOR("Jens Axboe <axboe@suse.de>");
  MODULE_LICENSE("GPL");
  
  module_init(pkt_init);
  module_exit(pkt_exit);