Blame view

drivers/block/pktcdvd.c 71.1 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
   * 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.
   *
c62b37d96   Christoph Hellwig   block: move ->mak...
39
   * At the top layer there is a custom ->submit_bio function that forwards
a676f8d09   Peter Osterlund   [PATCH] pktcdvd: ...
40
41
42
43
   * 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
   *
   *************************************************************************/
99481334b   Joe Perches   pktcdvd: convert ...
46
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
  #include <linux/pktcdvd.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
49
50
  #include <linux/module.h>
  #include <linux/types.h>
  #include <linux/kernel.h>
f80a0ca6a   Arnd Bergmann   pktcdvd: improve ...
51
  #include <linux/compat.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
53
54
55
56
57
58
  #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...
59
  #include <linux/freezer.h>
1657f824e   Jes Sorensen   [PATCH] sem2mutex...
60
  #include <linux/mutex.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
61
  #include <linux/slab.h>
66114cad6   Tejun Heo   writeback: separa...
62
  #include <linux/backing-dev.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
64
  #include <scsi/scsi_cmnd.h>
  #include <scsi/scsi_ioctl.h>
cef289633   Peter Osterlund   [PATCH] pktcdvd: ...
65
  #include <scsi/scsi.h>
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
66
67
  #include <linux/debugfs.h>
  #include <linux/device.h>
55690c07b   Jinbum Park   pktcdvd: Fix poss...
68
  #include <linux/nospec.h>
7c0f6ba68   Linus Torvalds   Replace <asm/uacc...
69
  #include <linux/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70

7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
71
  #define DRIVER_NAME	"pktcdvd"
fa63c0ab8   Joe Perches   pktcdvd: add stru...
72
73
  #define pkt_err(pd, fmt, ...)						\
  	pr_err("%s: " fmt, pd->name, ##__VA_ARGS__)
ca73dabc3   Joe Perches   pktcdvd: convert ...
74
75
  #define pkt_notice(pd, fmt, ...)					\
  	pr_notice("%s: " fmt, pd->name, ##__VA_ARGS__)
0c075d64d   Joe Perches   pktcdvd: convert ...
76
77
  #define pkt_info(pd, fmt, ...)						\
  	pr_info("%s: " fmt, pd->name, ##__VA_ARGS__)
fa63c0ab8   Joe Perches   pktcdvd: add stru...
78

844aa7974   Joe Perches   pktcdvd: add stru...
79
80
81
82
83
84
85
  #define pkt_dbg(level, pd, fmt, ...)					\
  do {									\
  	if (level == 2 && PACKET_DEBUG >= 2)				\
  		pr_notice("%s: %s():" fmt,				\
  			  pd->name, __func__, ##__VA_ARGS__);		\
  	else if (level == 1 && PACKET_DEBUG >= 1)			\
  		pr_notice("%s: " fmt, pd->name, ##__VA_ARGS__);		\
cd3f2cd05   Joe Perches   pktcdvd: consolid...
86
  } while (0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
87
88
  
  #define MAX_SPEED 0xffff
2a48fc0ab   Arnd Bergmann   block: autoconver...
89
  static DEFINE_MUTEX(pktcdvd_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90
91
  static struct pktcdvd_device *pkt_devs[MAX_WRITERS];
  static struct proc_dir_entry *pkt_proc;
add216608   Thomas Maier   [PATCH] pktcdvd: ...
92
  static int pktdev_major;
0a0fc9601   Thomas Maier   [PATCH] pktcdvd: ...
93
94
  static int write_congestion_on  = PKT_WRITE_CONGESTION_ON;
  static int write_congestion_off = PKT_WRITE_CONGESTION_OFF;
1657f824e   Jes Sorensen   [PATCH] sem2mutex...
95
  static struct mutex ctl_mutex;	/* Serialize open/close/setup/teardown */
64c4bc4de   Kent Overstreet   pktcdvd: convert ...
96
97
  static mempool_t psd_pool;
  static struct bio_set pkt_bio_set;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98

32694850a   Thomas Maier   [PATCH] pktcdvd: ...
99
  static struct class	*class_pktcdvd = NULL;    /* /sys/class/pktcdvd */
ea5ffff57   GeunSik Lim   debugfs: Modify d...
100
  static struct dentry	*pkt_debugfs_root = NULL; /* /sys/kernel/debug/pktcdvd */
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
101
102
103
104
105
  
  /* 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);
5323fb770   Joe Perches   pktcdvd: convert ...
106
107
108
109
  static sector_t get_zone(sector_t sector, struct pktcdvd_device *pd)
  {
  	return (sector + pd->offset) & ~(sector_t)(pd->settings.size - 1);
  }
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
110
111
112
113
114
115
116
117
118
119
  
  /*
   * 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...
120
  	int error;
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
121
122
123
  	p = kzalloc(sizeof(*p), GFP_KERNEL);
  	if (!p)
  		return NULL;
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
124
  	p->pd = pd;
89c426066   Greg Kroah-Hartman   Kobject: change d...
125
126
  	error = kobject_init_and_add(&p->kobj, ktype, parent, "%s", name);
  	if (error) {
d17a18dd9   Dave Young   pktcdvd: add kobj...
127
  		kobject_put(&p->kobj);
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
128
  		return NULL;
d17a18dd9   Dave Young   pktcdvd: add kobj...
129
  	}
89c426066   Greg Kroah-Hartman   Kobject: change d...
130
  	kobject_uevent(&p->kobj, KOBJ_ADD);
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
131
132
133
134
135
136
137
138
  	return p;
  }
  /*
   * remove a pktcdvd kernel object.
   */
  static void pkt_kobj_remove(struct pktcdvd_kobj *p)
  {
  	if (p)
c10997f65   Greg Kroah-Hartman   Kobject: convert ...
139
  		kobject_put(&p->kobj);
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
  }
  /*
   * 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...
158
  	static struct attribute _obj = { .name = _name, .mode = _mode }
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
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
191
192
193
194
195
196
197
198
199
  
  /**********************************************************
    /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: ...
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
264
265
266
267
268
269
270
271
272
  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: ...
273

83f3aa3dc   Thomas Maier   [PATCH] pktcdvd: ...
274
  	if (strcmp(attr->name, "reset") == 0 && len > 0) {
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
275
276
277
278
279
280
281
  		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: ...
282
  		   && sscanf(data, "%d", &val) == 1) {
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
283
284
285
286
287
288
289
  		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: ...
290
  		   && sscanf(data, "%d", &val) == 1) {
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
291
292
293
294
295
296
297
298
  		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...
299
  static const struct sysfs_ops kobj_pkt_ops = {
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
  	.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...
317
  		pd->dev = device_create(class_pktcdvd, NULL, MKDEV(0, 0), NULL,
1ff9f542e   Greg Kroah-Hartman   device create: bl...
318
  					"%s", pd->name);
6013c12be   Tony Jones   pktcdvd: Convert ...
319
320
  		if (IS_ERR(pd->dev))
  			pd->dev = NULL;
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
321
  	}
6013c12be   Tony Jones   pktcdvd: Convert ...
322
  	if (pd->dev) {
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
323
  		pd->kobj_stat = pkt_kobj_create(pd, "stat",
6013c12be   Tony Jones   pktcdvd: Convert ...
324
  					&pd->dev->kobj,
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
325
326
  					&kobj_pkt_type_stat);
  		pd->kobj_wqueue = pkt_kobj_create(pd, "write_queue",
6013c12be   Tony Jones   pktcdvd: Convert ...
327
  					&pd->dev->kobj,
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
328
329
330
331
332
333
334
335
336
  					&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...
337
  		device_unregister(pd->dev);
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
338
339
340
341
342
343
344
345
346
347
348
349
350
351
  }
  
  
  /********************************************************************
    /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);
  }
dc307f921   Greg Kroah-Hartman   pktcdvd: use clas...
352
353
354
  
  static ssize_t device_map_show(struct class *c, struct class_attribute *attr,
  			       char *data)
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
  {
  	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;
  }
dc307f921   Greg Kroah-Hartman   pktcdvd: use clas...
373
  static CLASS_ATTR_RO(device_map);
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
374

dc307f921   Greg Kroah-Hartman   pktcdvd: use clas...
375
376
  static ssize_t add_store(struct class *c, struct class_attribute *attr,
  			 const char *buf, size_t count)
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
377
378
  {
  	unsigned int major, minor;
fffe487d5   Tejun Heo   pktcdvd: fix BUG ...
379

83f3aa3dc   Thomas Maier   [PATCH] pktcdvd: ...
380
  	if (sscanf(buf, "%u:%u", &major, &minor) == 2) {
fffe487d5   Tejun Heo   pktcdvd: fix BUG ...
381
382
383
  		/* pkt_setup_dev() expects caller to hold reference to self */
  		if (!try_module_get(THIS_MODULE))
  			return -ENODEV;
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
384
  		pkt_setup_dev(MKDEV(major, minor), NULL);
fffe487d5   Tejun Heo   pktcdvd: fix BUG ...
385
386
  
  		module_put(THIS_MODULE);
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
387
388
  		return count;
  	}
fffe487d5   Tejun Heo   pktcdvd: fix BUG ...
389

32694850a   Thomas Maier   [PATCH] pktcdvd: ...
390
391
  	return -EINVAL;
  }
dc307f921   Greg Kroah-Hartman   pktcdvd: use clas...
392
  static CLASS_ATTR_WO(add);
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
393

dc307f921   Greg Kroah-Hartman   pktcdvd: use clas...
394
395
  static ssize_t remove_store(struct class *c, struct class_attribute *attr,
  			    const char *buf, size_t count)
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
396
397
  {
  	unsigned int major, minor;
83f3aa3dc   Thomas Maier   [PATCH] pktcdvd: ...
398
  	if (sscanf(buf, "%u:%u", &major, &minor) == 2) {
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
399
400
401
402
403
  		pkt_remove_dev(MKDEV(major, minor));
  		return count;
  	}
  	return -EINVAL;
  }
dc307f921   Greg Kroah-Hartman   pktcdvd: use clas...
404
  static CLASS_ATTR_WO(remove);
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
405

dc307f921   Greg Kroah-Hartman   pktcdvd: use clas...
406
407
408
409
410
  static struct attribute *class_pktcdvd_attrs[] = {
  	&class_attr_add.attr,
  	&class_attr_remove.attr,
  	&class_attr_device_map.attr,
  	NULL,
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
411
  };
dc307f921   Greg Kroah-Hartman   pktcdvd: use clas...
412
  ATTRIBUTE_GROUPS(class_pktcdvd);
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
  
  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;
dc307f921   Greg Kroah-Hartman   pktcdvd: use clas...
428
  	class_pktcdvd->class_groups = class_pktcdvd_groups;
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
429
430
431
432
  	ret = class_register(class_pktcdvd);
  	if (ret) {
  		kfree(class_pktcdvd);
  		class_pktcdvd = NULL;
99481334b   Joe Perches   pktcdvd: convert ...
433
434
  		pr_err("failed to create class pktcdvd
  ");
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
435
436
437
438
439
440
441
442
443
444
445
446
447
448
  		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...
449
    /sys/kernel/debug/pktcdvd[0-7]/
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
450
451
452
453
454
455
456
457
458
459
460
461
462
  			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...
463
  static const struct file_operations debug_fops = {
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
464
465
466
467
468
469
470
471
472
473
474
  	.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;
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
475
  	pd->dfs_d_root = debugfs_create_dir(pd->name, pkt_debugfs_root);
49c2856af   Dan Carpenter   pktcdvd: debugfs ...
476
  	if (!pd->dfs_d_root)
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
477
  		return;
49c2856af   Dan Carpenter   pktcdvd: debugfs ...
478

5657a819a   Joe Perches   block drivers/blo...
479
480
  	pd->dfs_f_info = debugfs_create_file("info", 0444,
  					     pd->dfs_d_root, pd, &debug_fops);
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
481
482
483
484
485
486
  }
  
  static void pkt_debugfs_dev_remove(struct pktcdvd_device *pd)
  {
  	if (!pkt_debugfs_root)
  		return;
49c2856af   Dan Carpenter   pktcdvd: debugfs ...
487
488
  	debugfs_remove(pd->dfs_f_info);
  	debugfs_remove(pd->dfs_d_root);
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
489
  	pd->dfs_f_info = NULL;
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
490
491
492
493
494
495
  	pd->dfs_d_root = NULL;
  }
  
  static void pkt_debugfs_init(void)
  {
  	pkt_debugfs_root = debugfs_create_dir(DRIVER_NAME, NULL);
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
496
497
498
499
  }
  
  static void pkt_debugfs_cleanup(void)
  {
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
500
501
502
503
504
  	debugfs_remove(pkt_debugfs_root);
  	pkt_debugfs_root = NULL;
  }
  
  /* ----------------------------------------------------------*/
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
505
506
507
508
509
  
  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)) {
844aa7974   Joe Perches   pktcdvd: add stru...
510
511
  		pkt_dbg(2, pd, "queue empty
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
512
513
514
515
  		atomic_set(&pd->iosched.attention, 1);
  		wake_up(&pd->wqueue);
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
516
517
518
  /*
   * Allocate a packet_data struct
   */
e1bc89bc9   Peter Osterlund   [PATCH] pktcdvd: ...
519
  static struct packet_data *pkt_alloc_packet_data(int frames)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
520
521
522
  {
  	int i;
  	struct packet_data *pkt;
1107d2e03   Peter Osterlund   [PATCH] pktcdvd: ...
523
  	pkt = kzalloc(sizeof(struct packet_data), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
524
525
  	if (!pkt)
  		goto no_pkt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
526

e1bc89bc9   Peter Osterlund   [PATCH] pktcdvd: ...
527
  	pkt->frames = frames;
ccc5c9ca6   Kent Overstreet   pktcdvd: Switch t...
528
  	pkt->w_bio = bio_kmalloc(GFP_KERNEL, frames);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
529
530
  	if (!pkt->w_bio)
  		goto no_bio;
e1bc89bc9   Peter Osterlund   [PATCH] pktcdvd: ...
531
  	for (i = 0; i < frames / FRAMES_PER_PAGE; i++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
532
533
534
535
536
537
  		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 ...
538
  	bio_list_init(&pkt->orig_bios);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539

e1bc89bc9   Peter Osterlund   [PATCH] pktcdvd: ...
540
  	for (i = 0; i < frames; i++) {
ccc5c9ca6   Kent Overstreet   pktcdvd: Switch t...
541
  		struct bio *bio = bio_kmalloc(GFP_KERNEL, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542
543
  		if (!bio)
  			goto no_rd_bio;
ccc5c9ca6   Kent Overstreet   pktcdvd: Switch t...
544

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
545
546
547
548
549
550
  		pkt->r_bios[i] = bio;
  	}
  
  	return pkt;
  
  no_rd_bio:
e1bc89bc9   Peter Osterlund   [PATCH] pktcdvd: ...
551
  	for (i = 0; i < frames; i++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
552
553
554
555
556
557
  		struct bio *bio = pkt->r_bios[i];
  		if (bio)
  			bio_put(bio);
  	}
  
  no_page:
e1bc89bc9   Peter Osterlund   [PATCH] pktcdvd: ...
558
  	for (i = 0; i < frames / FRAMES_PER_PAGE; i++)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
  		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: ...
574
  	for (i = 0; i < pkt->frames; i++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
575
576
577
578
  		struct bio *bio = pkt->r_bios[i];
  		if (bio)
  			bio_put(bio);
  	}
e1bc89bc9   Peter Osterlund   [PATCH] pktcdvd: ...
579
  	for (i = 0; i < pkt->frames / FRAMES_PER_PAGE; i++)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
580
581
582
583
584
585
586
587
588
589
590
591
592
593
  		__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: ...
594
  	INIT_LIST_HEAD(&pd->cdrw.pkt_free_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
595
596
597
598
599
  }
  
  static int pkt_grow_pktlist(struct pktcdvd_device *pd, int nr_packets)
  {
  	struct packet_data *pkt;
e1bc89bc9   Peter Osterlund   [PATCH] pktcdvd: ...
600
  	BUG_ON(!list_empty(&pd->cdrw.pkt_free_list));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
601
  	while (nr_packets > 0) {
e1bc89bc9   Peter Osterlund   [PATCH] pktcdvd: ...
602
  		pkt = pkt_alloc_packet_data(pd->settings.size >> 2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
603
604
605
606
607
608
609
610
611
612
613
  		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
614
615
616
617
618
619
620
  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: ...
621
  static void pkt_rbtree_erase(struct pktcdvd_device *pd, struct pkt_rb_node *node)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
622
623
  {
  	rb_erase(&node->rb_node, &pd->bio_queue);
64c4bc4de   Kent Overstreet   pktcdvd: convert ...
624
  	mempool_free(node, &pd->rb_pool);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
  	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);
4f024f379   Kent Overstreet   block: Abstract o...
645
  		if (s <= tmp->bio->bi_iter.bi_sector)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
646
647
648
649
650
651
652
  			next = n->rb_left;
  		else
  			next = n->rb_right;
  		if (!next)
  			break;
  		n = next;
  	}
4f024f379   Kent Overstreet   block: Abstract o...
653
  	if (s > tmp->bio->bi_iter.bi_sector) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
654
655
656
657
  		tmp = pkt_rbtree_next(tmp);
  		if (!tmp)
  			return NULL;
  	}
4f024f379   Kent Overstreet   block: Abstract o...
658
  	BUG_ON(s > tmp->bio->bi_iter.bi_sector);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
659
660
661
662
663
664
665
666
667
668
  	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;
4f024f379   Kent Overstreet   block: Abstract o...
669
  	sector_t s = node->bio->bi_iter.bi_sector;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
670
671
672
673
674
  	struct pkt_rb_node *tmp;
  
  	while (*p) {
  		parent = *p;
  		tmp = rb_entry(parent, struct pkt_rb_node, rb_node);
4f024f379   Kent Overstreet   block: Abstract o...
675
  		if (s < tmp->bio->bi_iter.bi_sector)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
676
677
678
679
680
681
682
683
684
685
  			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
686
687
688
689
690
   * 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...
691
  	struct request_queue *q = bdev_get_queue(pd->bdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
692
  	struct request *rq;
406c9b605   Christoph Hellwig   [PATCH] Fix BUG a...
693
694
695
  	int ret = 0;
  
  	rq = blk_get_request(q, (cgc->data_direction == CGC_DATA_WRITE) ?
ff005a066   Christoph Hellwig   block: sanitize b...
696
  			     REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, 0);
a492f0754   Joe Lawrence   block,scsi: fixup...
697
698
  	if (IS_ERR(rq))
  		return PTR_ERR(rq);
406c9b605   Christoph Hellwig   [PATCH] Fix BUG a...
699
700
  
  	if (cgc->buflen) {
8586ea96b   Julia Lawall   pktcdvd: fix erro...
701
  		ret = blk_rq_map_kern(q, rq, cgc->buffer, cgc->buflen,
0eb0b63c1   Christoph Hellwig   block: consistent...
702
  				      GFP_NOIO);
8586ea96b   Julia Lawall   pktcdvd: fix erro...
703
  		if (ret)
406c9b605   Christoph Hellwig   [PATCH] Fix BUG a...
704
705
  			goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
706

82ed4db49   Christoph Hellwig   block: split scsi...
707
708
  	scsi_req(rq)->cmd_len = COMMAND_SIZE(cgc->cmd[0]);
  	memcpy(scsi_req(rq)->cmd, cgc->cmd, CDROM_PACKET_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
709

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
710
  	rq->timeout = 60*HZ;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
711
  	if (cgc->quiet)
e80640213   Christoph Hellwig   block: split out ...
712
  		rq->rq_flags |= RQF_QUIET;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
713

406c9b605   Christoph Hellwig   [PATCH] Fix BUG a...
714
  	blk_execute_rq(rq->q, pd->bdev->bd_disk, rq, 0);
17d5363b8   Christoph Hellwig   scsi: introduce a...
715
  	if (scsi_req(rq)->result)
cbc31a475   Andrew Morton   packet: fix error...
716
  		ret = -EIO;
406c9b605   Christoph Hellwig   [PATCH] Fix BUG a...
717
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
718
  	blk_put_request(rq);
406c9b605   Christoph Hellwig   [PATCH] Fix BUG a...
719
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
720
  }
99481334b   Joe Perches   pktcdvd: convert ...
721
722
723
724
725
726
727
728
729
730
  static const char *sense_key_string(__u8 index)
  {
  	static const char * const info[] = {
  		"No sense", "Recovered error", "Not ready",
  		"Medium error", "Hardware error", "Illegal request",
  		"Unit attention", "Data protect", "Blank check",
  	};
  
  	return index < ARRAY_SIZE(info) ? info[index] : "INVALID";
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
731
732
733
734
  /*
   * A generic sense dump / resolve mechanism should be implemented across
   * all ATAPI + SCSI devices.
   */
f3ded788b   Joe Perches   pktcdvd: add stru...
735
736
  static void pkt_dump_sense(struct pktcdvd_device *pd,
  			   struct packet_command *cgc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
737
  {
e7d0748dd   Kees Cook   block: Switch str...
738
  	struct scsi_sense_hdr *sshdr = cgc->sshdr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
739

e7d0748dd   Kees Cook   block: Switch str...
740
  	if (sshdr)
f3ded788b   Joe Perches   pktcdvd: add stru...
741
742
743
  		pkt_err(pd, "%*ph - sense %02x.%02x.%02x (%s)
  ",
  			CDROM_PACKET_SIZE, cgc->cmd,
e7d0748dd   Kees Cook   block: Switch str...
744
745
  			sshdr->sense_key, sshdr->asc, sshdr->ascq,
  			sense_key_string(sshdr->sense_key));
99481334b   Joe Perches   pktcdvd: convert ...
746
  	else
f3ded788b   Joe Perches   pktcdvd: add stru...
747
748
  		pkt_err(pd, "%*ph - no sense
  ", CDROM_PACKET_SIZE, cgc->cmd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
  }
  
  /*
   * 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...
775
776
  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
777
778
  {
  	struct packet_command cgc;
e7d0748dd   Kees Cook   block: Switch str...
779
  	struct scsi_sense_hdr sshdr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
780
781
782
  	int ret;
  
  	init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
e7d0748dd   Kees Cook   block: Switch str...
783
  	cgc.sshdr = &sshdr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
784
785
786
787
788
  	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;
ada94973f   RAGHU Halharvi   pktcdvd: remove a...
789
790
  	ret = pkt_generic_packet(pd, &cgc);
  	if (ret)
f3ded788b   Joe Perches   pktcdvd: add stru...
791
  		pkt_dump_sense(pd, &cgc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
792
793
794
795
796
797
798
799
  
  	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...
800
  static void pkt_queue_bio(struct pktcdvd_device *pd, struct bio *bio)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
801
802
  {
  	spin_lock(&pd->iosched.lock);
c5ecc484c   Akinobu Mita   pktcdvd: use BIO ...
803
804
805
806
  	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
807
808
809
810
811
812
813
814
815
816
817
  	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...
818
   * - Switching between reading and writing is slow, so don't do it more often
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
819
   *   than necessary.
46c271bed   Peter Osterlund   [PATCH] Improve C...
820
821
822
823
   * - 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
824
825
826
827
   * - 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
828
829
830
   */
  static void pkt_iosched_process_queue(struct pktcdvd_device *pd)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
831
832
833
834
  
  	if (atomic_read(&pd->iosched.attention) == 0)
  		return;
  	atomic_set(&pd->iosched.attention, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
835
836
  	for (;;) {
  		struct bio *bio;
46c271bed   Peter Osterlund   [PATCH] Improve C...
837
  		int reads_queued, writes_queued;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
838
839
  
  		spin_lock(&pd->iosched.lock);
c5ecc484c   Akinobu Mita   pktcdvd: use BIO ...
840
841
  		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
842
843
844
845
846
847
  		spin_unlock(&pd->iosched.lock);
  
  		if (!reads_queued && !writes_queued)
  			break;
  
  		if (pd->iosched.writing) {
46c271bed   Peter Osterlund   [PATCH] Improve C...
848
849
  			int need_write_seek = 1;
  			spin_lock(&pd->iosched.lock);
c5ecc484c   Akinobu Mita   pktcdvd: use BIO ...
850
  			bio = bio_list_peek(&pd->iosched.write_queue);
46c271bed   Peter Osterlund   [PATCH] Improve C...
851
  			spin_unlock(&pd->iosched.lock);
4f024f379   Kent Overstreet   block: Abstract o...
852
853
  			if (bio && (bio->bi_iter.bi_sector ==
  				    pd->iosched.last_write))
46c271bed   Peter Osterlund   [PATCH] Improve C...
854
855
  				need_write_seek = 0;
  			if (need_write_seek && reads_queued) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
856
  				if (atomic_read(&pd->cdrw.pending_bios) > 0) {
844aa7974   Joe Perches   pktcdvd: add stru...
857
858
  					pkt_dbg(2, pd, "write, waiting
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
859
860
861
862
863
864
865
866
  					break;
  				}
  				pkt_flush_cache(pd);
  				pd->iosched.writing = 0;
  			}
  		} else {
  			if (!reads_queued && writes_queued) {
  				if (atomic_read(&pd->cdrw.pending_bios) > 0) {
844aa7974   Joe Perches   pktcdvd: add stru...
867
868
  					pkt_dbg(2, pd, "read, waiting
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
869
870
871
872
873
874
875
  					break;
  				}
  				pd->iosched.writing = 1;
  			}
  		}
  
  		spin_lock(&pd->iosched.lock);
c5ecc484c   Akinobu Mita   pktcdvd: use BIO ...
876
877
878
879
  		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
880
881
882
883
884
885
  		spin_unlock(&pd->iosched.lock);
  
  		if (!bio)
  			continue;
  
  		if (bio_data_dir(bio) == READ)
4f024f379   Kent Overstreet   block: Abstract o...
886
887
  			pd->iosched.successive_reads +=
  				bio->bi_iter.bi_size >> 10;
46c271bed   Peter Osterlund   [PATCH] Improve C...
888
  		else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
889
  			pd->iosched.successive_reads = 0;
f73a1c7d1   Kent Overstreet   block: Add bio_en...
890
  			pd->iosched.last_write = bio_end_sector(bio);
46c271bed   Peter Osterlund   [PATCH] Improve C...
891
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
892
893
894
895
896
897
898
899
900
901
902
903
904
  		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);
ed00aabd5   Christoph Hellwig   block: rename gen...
905
  		submit_bio_noacct(bio);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
906
907
908
909
910
911
912
  	}
  }
  
  /*
   * Special care is needed if the underlying block device has a small
   * max_phys_segments value.
   */
165125e1e   Jens Axboe   [BLOCK] Get rid o...
913
  static int pkt_set_segment_merging(struct pktcdvd_device *pd, struct request_queue *q)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
914
  {
ae03bf639   Martin K. Petersen   block: Use access...
915
  	if ((pd->settings.size << 9) / CD_FRAMESIZE
8a78362c4   Martin K. Petersen   block: Consolidat...
916
  	    <= queue_max_segments(q)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
917
918
919
920
921
  		/*
  		 * The cdrom device can handle one segment/frame
  		 */
  		clear_bit(PACKET_MERGE_SEGS, &pd->flags);
  		return 0;
ae03bf639   Martin K. Petersen   block: Use access...
922
  	} else if ((pd->settings.size << 9) / PAGE_SIZE
8a78362c4   Martin K. Petersen   block: Consolidat...
923
  		   <= queue_max_segments(q)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
924
925
926
927
928
929
930
  		/*
  		 * 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 {
fa63c0ab8   Joe Perches   pktcdvd: add stru...
931
932
  		pkt_err(pd, "cdrom max_phys_segments too small
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
933
934
935
  		return -EIO;
  	}
  }
4246a0b63   Christoph Hellwig   block: add a bi_e...
936
  static void pkt_end_io_read(struct bio *bio)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
937
938
939
940
  {
  	struct packet_data *pkt = bio->bi_private;
  	struct pktcdvd_device *pd = pkt->pd;
  	BUG_ON(!pd);
844aa7974   Joe Perches   pktcdvd: add stru...
941
942
  	pkt_dbg(2, pd, "bio=%p sec0=%llx sec=%llx err=%d
  ",
cd3f2cd05   Joe Perches   pktcdvd: consolid...
943
  		bio, (unsigned long long)pkt->sector,
4e4cbee93   Christoph Hellwig   block: switch bio...
944
  		(unsigned long long)bio->bi_iter.bi_sector, bio->bi_status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
945

4e4cbee93   Christoph Hellwig   block: switch bio...
946
  	if (bio->bi_status)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
947
948
949
950
951
952
  		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
953
  }
4246a0b63   Christoph Hellwig   block: add a bi_e...
954
  static void pkt_end_io_packet_write(struct bio *bio)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
955
956
957
958
  {
  	struct packet_data *pkt = bio->bi_private;
  	struct pktcdvd_device *pd = pkt->pd;
  	BUG_ON(!pd);
4e4cbee93   Christoph Hellwig   block: switch bio...
959
960
  	pkt_dbg(2, pd, "id=%d, err=%d
  ", pkt->id, bio->bi_status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
961
962
963
964
965
966
967
  
  	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
968
969
970
971
972
973
974
975
976
977
978
  }
  
  /*
   * 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 ...
979
  	BUG_ON(bio_list_empty(&pkt->orig_bios));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
980
981
982
  
  	atomic_set(&pkt->io_wait, 0);
  	atomic_set(&pkt->io_errors, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
983
984
985
986
987
  	/*
  	 * 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 ...
988
  	bio_list_for_each(bio, &pkt->orig_bios) {
4f024f379   Kent Overstreet   block: Abstract o...
989
990
991
  		int first_frame = (bio->bi_iter.bi_sector - pkt->sector) /
  			(CD_FRAMESIZE >> 9);
  		int num_frames = bio->bi_iter.bi_size / CD_FRAMESIZE;
06e7ab53f   Peter Osterlund   [PATCH] pktcdvd: ...
992
  		pd->stats.secs_w += num_frames * (CD_FRAMESIZE >> 9);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
993
994
995
996
997
998
  		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: ...
999
  	if (pkt->cache_valid) {
844aa7974   Joe Perches   pktcdvd: add stru...
1000
1001
  		pkt_dbg(2, pd, "zone %llx cached
  ",
06e7ab53f   Peter Osterlund   [PATCH] pktcdvd: ...
1002
1003
1004
  			(unsigned long long)pkt->sector);
  		goto out_account;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1005
1006
1007
1008
1009
  	/*
  	 * Schedule reads for missing parts of the packet.
  	 */
  	for (f = 0; f < pkt->frames; f++) {
  		int p, offset;
ccc5c9ca6   Kent Overstreet   pktcdvd: Switch t...
1010

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1011
1012
  		if (written[f])
  			continue;
ccc5c9ca6   Kent Overstreet   pktcdvd: Switch t...
1013

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1014
  		bio = pkt->r_bios[f];
ccc5c9ca6   Kent Overstreet   pktcdvd: Switch t...
1015
  		bio_reset(bio);
4f024f379   Kent Overstreet   block: Abstract o...
1016
  		bio->bi_iter.bi_sector = pkt->sector + f * (CD_FRAMESIZE >> 9);
74d46992e   Christoph Hellwig   block: replace bi...
1017
  		bio_set_dev(bio, pd->bdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1018
1019
1020
1021
1022
  		bio->bi_end_io = pkt_end_io_read;
  		bio->bi_private = pkt;
  
  		p = (f * CD_FRAMESIZE) / PAGE_SIZE;
  		offset = (f * CD_FRAMESIZE) % PAGE_SIZE;
844aa7974   Joe Perches   pktcdvd: add stru...
1023
1024
  		pkt_dbg(2, pd, "Adding frame %d, page:%p offs:%d
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1025
1026
1027
1028
1029
  			f, pkt->pages[p], offset);
  		if (!bio_add_page(bio, pkt->pages[p], CD_FRAMESIZE, offset))
  			BUG();
  
  		atomic_inc(&pkt->io_wait);
95fe6c1a2   Mike Christie   block, fs, mm, dr...
1030
  		bio_set_op_attrs(bio, REQ_OP_READ, 0);
46c271bed   Peter Osterlund   [PATCH] Improve C...
1031
  		pkt_queue_bio(pd, bio);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1032
1033
1034
1035
  		frames_read++;
  	}
  
  out_account:
844aa7974   Joe Perches   pktcdvd: add stru...
1036
1037
  	pkt_dbg(2, pd, "need %d frames for zone %llx
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1038
1039
1040
  		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
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
  }
  
  /*
   * 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: ...
1056
  			return pkt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1057
1058
  		}
  	}
610827dee   Peter Osterlund   [PATCH] pktcdvd: ...
1059
1060
  	BUG();
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
  }
  
  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);
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1071
1072
1073
1074
1075
1076
1077
  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;
844aa7974   Joe Perches   pktcdvd: add stru...
1078
1079
  	pkt_dbg(2, pd, "pkt %2d : s=%6llx %s -> %s
  ",
cd3f2cd05   Joe Perches   pktcdvd: consolid...
1080
  		pkt->id, (unsigned long long)pkt->sector,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
  		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: ...
1097
  	int wakeup;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1098

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1099
1100
1101
  	atomic_set(&pd->scan_queue, 0);
  
  	if (list_empty(&pd->cdrw.pkt_free_list)) {
844aa7974   Joe Perches   pktcdvd: add stru...
1102
1103
  		pkt_dbg(2, pd, "no pkt
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
  		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;
4f024f379   Kent Overstreet   block: Abstract o...
1120
  		zone = get_zone(bio->bi_iter.bi_sector, pd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1121
  		list_for_each_entry(p, &pd->cdrw.pkt_active_list, list) {
7baeb6a5c   Peter Osterlund   [PATCH] CDRW/DVD ...
1122
1123
  			if (p->sector == zone) {
  				bio = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1124
  				goto try_next_bio;
7baeb6a5c   Peter Osterlund   [PATCH] CDRW/DVD ...
1125
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
  		}
  		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) {
844aa7974   Joe Perches   pktcdvd: add stru...
1140
1141
  		pkt_dbg(2, pd, "no bio
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1142
1143
1144
1145
  		return 0;
  	}
  
  	pkt = pkt_get_packet_data(pd, zone);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1146
1147
1148
  
  	pd->current_sector = zone + pd->settings.size;
  	pkt->sector = zone;
e1bc89bc9   Peter Osterlund   [PATCH] pktcdvd: ...
1149
  	BUG_ON(pkt->frames != pd->settings.size >> 2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1150
1151
1152
1153
1154
1155
1156
  	pkt->write_size = 0;
  
  	/*
  	 * Scan work queue for bios in the same zone and link them
  	 * to this packet.
  	 */
  	spin_lock(&pd->lock);
844aa7974   Joe Perches   pktcdvd: add stru...
1157
1158
  	pkt_dbg(2, pd, "looking for zone %llx
  ", (unsigned long long)zone);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1159
1160
  	while ((node = pkt_rbtree_find(pd, zone)) != NULL) {
  		bio = node->bio;
4f024f379   Kent Overstreet   block: Abstract o...
1161
1162
1163
1164
  		pkt_dbg(2, pd, "found zone=%llx
  ", (unsigned long long)
  			get_zone(bio->bi_iter.bi_sector, pd));
  		if (get_zone(bio->bi_iter.bi_sector, pd) != zone)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1165
1166
1167
  			break;
  		pkt_rbtree_erase(pd, node);
  		spin_lock(&pkt->lock);
c5ecc484c   Akinobu Mita   pktcdvd: use BIO ...
1168
  		bio_list_add(&pkt->orig_bios, bio);
4f024f379   Kent Overstreet   block: Abstract o...
1169
  		pkt->write_size += bio->bi_iter.bi_size / CD_FRAMESIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1170
1171
  		spin_unlock(&pkt->lock);
  	}
0a0fc9601   Thomas Maier   [PATCH] pktcdvd: ...
1172
1173
1174
1175
  	/* 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
1176
  	spin_unlock(&pd->lock);
8aa7e847d   Jens Axboe   Fix congestion_wa...
1177
  	if (wakeup) {
dc3b17cc8   Jan Kara   block: Use pointe...
1178
  		clear_bdi_congested(pd->disk->queue->backing_dev_info,
8aa7e847d   Jens Axboe   Fix congestion_wa...
1179
1180
  					BLK_RW_ASYNC);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
  
  	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)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1199
  	int f;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1200

ffb25dc60   Kent Overstreet   pktcdvd: use bio_...
1201
  	bio_reset(pkt->w_bio);
4f024f379   Kent Overstreet   block: Abstract o...
1202
  	pkt->w_bio->bi_iter.bi_sector = pkt->sector;
74d46992e   Christoph Hellwig   block: replace bi...
1203
  	bio_set_dev(pkt->w_bio, pd->bdev);
ffb25dc60   Kent Overstreet   pktcdvd: use bio_...
1204
1205
1206
1207
  	pkt->w_bio->bi_end_io = pkt_end_io_packet_write;
  	pkt->w_bio->bi_private = pkt;
  
  	/* XXX: locking? */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1208
  	for (f = 0; f < pkt->frames; f++) {
feebd5687   Christoph Hellwig   pktcdvd: don't sc...
1209
1210
1211
1212
  		struct page *page = pkt->pages[(f * CD_FRAMESIZE) / PAGE_SIZE];
  		unsigned offset = (f * CD_FRAMESIZE) % PAGE_SIZE;
  
  		if (!bio_add_page(pkt->w_bio, page, CD_FRAMESIZE, offset))
ffb25dc60   Kent Overstreet   pktcdvd: use bio_...
1213
  			BUG();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1214
  	}
844aa7974   Joe Perches   pktcdvd: add stru...
1215
1216
  	pkt_dbg(2, pd, "vcnt=%d
  ", pkt->w_bio->bi_vcnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1217
1218
  
  	/*
727723237   Peter Osterlund   [PATCH] pktcdvd: ...
1219
  	 * Fill-in bvec with data from orig_bios.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1220
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1221
  	spin_lock(&pkt->lock);
45db54d58   Kent Overstreet   block: Split out ...
1222
  	bio_list_copy_data(pkt->w_bio, pkt->orig_bios.head);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1223

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1224
1225
  	pkt_set_state(pkt, PACKET_WRITE_WAIT_STATE);
  	spin_unlock(&pkt->lock);
844aa7974   Joe Perches   pktcdvd: add stru...
1226
1227
  	pkt_dbg(2, pd, "Writing %d frames for zone %llx
  ",
ffb25dc60   Kent Overstreet   pktcdvd: use bio_...
1228
  		pkt->write_size, (unsigned long long)pkt->sector);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1229

feebd5687   Christoph Hellwig   pktcdvd: don't sc...
1230
  	if (test_bit(PACKET_MERGE_SEGS, &pd->flags) || (pkt->write_size < pkt->frames))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1231
  		pkt->cache_valid = 1;
feebd5687   Christoph Hellwig   pktcdvd: don't sc...
1232
  	else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1233
  		pkt->cache_valid = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1234
1235
  
  	/* Start the write request */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1236
  	atomic_set(&pkt->io_wait, 1);
95fe6c1a2   Mike Christie   block, fs, mm, dr...
1237
  	bio_set_op_attrs(pkt->w_bio, REQ_OP_WRITE, 0);
46c271bed   Peter Osterlund   [PATCH] Improve C...
1238
  	pkt_queue_bio(pd, pkt->w_bio);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1239
  }
4e4cbee93   Christoph Hellwig   block: switch bio...
1240
  static void pkt_finish_packet(struct packet_data *pkt, blk_status_t status)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1241
  {
c5ecc484c   Akinobu Mita   pktcdvd: use BIO ...
1242
  	struct bio *bio;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1243

4e4cbee93   Christoph Hellwig   block: switch bio...
1244
  	if (status)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1245
1246
1247
  		pkt->cache_valid = 0;
  
  	/* Finish all bios corresponding to this packet */
4246a0b63   Christoph Hellwig   block: add a bi_e...
1248
  	while ((bio = bio_list_pop(&pkt->orig_bios))) {
4e4cbee93   Christoph Hellwig   block: switch bio...
1249
  		bio->bi_status = status;
4246a0b63   Christoph Hellwig   block: add a bi_e...
1250
1251
  		bio_endio(bio);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1252
1253
1254
1255
  }
  
  static void pkt_run_state_machine(struct pktcdvd_device *pd, struct packet_data *pkt)
  {
844aa7974   Joe Perches   pktcdvd: add stru...
1256
1257
  	pkt_dbg(2, pd, "pkt %d
  ", pkt->id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
  
  	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;
4e4cbee93   Christoph Hellwig   block: switch bio...
1284
  			if (!pkt->w_bio->bi_status) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1285
1286
1287
1288
1289
1290
1291
  				pkt_set_state(pkt, PACKET_FINISHED_STATE);
  			} else {
  				pkt_set_state(pkt, PACKET_RECOVERY_STATE);
  			}
  			break;
  
  		case PACKET_RECOVERY_STATE:
2d9e28a9a   Christoph Hellwig   pktcdvd: remove t...
1292
1293
1294
  			pkt_dbg(2, pd, "No recovery possible
  ");
  			pkt_set_state(pkt, PACKET_FINISHED_STATE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1295
1296
1297
  			break;
  
  		case PACKET_FINISHED_STATE:
4e4cbee93   Christoph Hellwig   block: switch bio...
1298
  			pkt_finish_packet(pkt, pkt->w_bio->bi_status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
  			return;
  
  		default:
  			BUG();
  			break;
  		}
  	}
  }
  
  static void pkt_handle_packets(struct pktcdvd_device *pd)
  {
  	struct packet_data *pkt, *next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
  	/*
  	 * 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...
1340
  	for (i = 0; i < PACKET_NUM_STATES; i++)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
  		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;
8698a745d   Dongsheng Yang   sched, treewide: ...
1359
  	set_user_nice(current, MIN_NICE);
831441862   Rafael J. Wysocki   Freezer: make ker...
1360
  	set_freezable();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
  
  	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);
844aa7974   Joe Perches   pktcdvd: add stru...
1390
1391
  				pkt_dbg(2, pd, "i:%d ow:%d rw:%d ww:%d rec:%d fin:%d
  ",
cd3f2cd05   Joe Perches   pktcdvd: consolid...
1392
1393
  					states[0], states[1], states[2],
  					states[3], states[4], states[5]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1394
1395
1396
1397
1398
1399
1400
  			}
  
  			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;
  			}
844aa7974   Joe Perches   pktcdvd: add stru...
1401
1402
  			pkt_dbg(2, pd, "sleeping
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1403
  			residue = schedule_timeout(min_sleep_time);
844aa7974   Joe Perches   pktcdvd: add stru...
1404
1405
  			pkt_dbg(2, pd, "wake up
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1406
1407
  
  			/* make swsusp happy with our thread */
3e1d1d28d   Christoph Lameter   [PATCH] Cleanup p...
1408
  			try_to_freeze();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
  
  			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
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
  			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)
  {
0c075d64d   Joe Perches   pktcdvd: convert ...
1452
1453
1454
1455
1456
  	pkt_info(pd, "%s packets, %u blocks, Mode-%c disc
  ",
  		 pd->settings.fp ? "Fixed" : "Variable",
  		 pd->settings.size >> 2,
  		 pd->settings.block_mode == 8 ? '1' : '2');
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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
  }
  
  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;
ada94973f   RAGHU Halharvi   pktcdvd: remove a...
1493
1494
  	ret = pkt_generic_packet(pd, &cgc);
  	if (ret)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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
  		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;
ada94973f   RAGHU Halharvi   pktcdvd: remove a...
1522
1523
  	ret = pkt_generic_packet(pd, &cgc);
  	if (ret)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
  		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...
1535
1536
  static noinline_for_stack int pkt_get_last_written(struct pktcdvd_device *pd,
  						long *last_written)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1537
1538
1539
1540
  {
  	disc_information di;
  	track_information ti;
  	__u32 last_track;
8d20319e2   Colin Ian King   pktcdvd: remove r...
1541
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1542

ada94973f   RAGHU Halharvi   pktcdvd: remove a...
1543
1544
  	ret = pkt_get_disc_info(pd, &di);
  	if (ret)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1545
1546
1547
  		return ret;
  
  	last_track = (di.last_track_msb << 8) | di.last_track_lsb;
ada94973f   RAGHU Halharvi   pktcdvd: remove a...
1548
1549
  	ret = pkt_get_track_info(pd, last_track, 1, &ti);
  	if (ret)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1550
1551
1552
1553
1554
  		return ret;
  
  	/* if this track is blank, try the previous. */
  	if (ti.blank) {
  		last_track--;
ada94973f   RAGHU Halharvi   pktcdvd: remove a...
1555
1556
  		ret = pkt_get_track_info(pd, last_track, 1, &ti);
  		if (ret)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
  			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...
1576
  static noinline_for_stack int pkt_set_write_settings(struct pktcdvd_device *pd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1577
1578
  {
  	struct packet_command cgc;
e7d0748dd   Kees Cook   block: Switch str...
1579
  	struct scsi_sense_hdr sshdr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
  	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);
e7d0748dd   Kees Cook   block: Switch str...
1590
  	cgc.sshdr = &sshdr;
ada94973f   RAGHU Halharvi   pktcdvd: remove a...
1591
1592
  	ret = pkt_mode_sense(pd, &cgc, GPMODE_WRITE_PARMS_PAGE, 0);
  	if (ret) {
f3ded788b   Joe Perches   pktcdvd: add stru...
1593
  		pkt_dump_sense(pd, &cgc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
  		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);
e7d0748dd   Kees Cook   block: Switch str...
1606
  	cgc.sshdr = &sshdr;
ada94973f   RAGHU Halharvi   pktcdvd: remove a...
1607
1608
  	ret = pkt_mode_sense(pd, &cgc, GPMODE_WRITE_PARMS_PAGE, 0);
  	if (ret) {
f3ded788b   Joe Perches   pktcdvd: add stru...
1609
  		pkt_dump_sense(pd, &cgc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
  		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
  		 */
fa63c0ab8   Joe Perches   pktcdvd: add stru...
1644
1645
  		pkt_err(pd, "write mode wrong %d
  ", wp->data_block_type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1646
1647
1648
1649
1650
  		return 1;
  	}
  	wp->packet_size = cpu_to_be32(pd->settings.size >> 2);
  
  	cgc.buflen = cgc.cmd[8] = size;
ada94973f   RAGHU Halharvi   pktcdvd: remove a...
1651
1652
  	ret = pkt_mode_select(pd, &cgc);
  	if (ret) {
f3ded788b   Joe Perches   pktcdvd: add stru...
1653
  		pkt_dump_sense(pd, &cgc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1654
1655
1656
1657
1658
1659
1660
1661
  		return ret;
  	}
  
  	pkt_print_settings(pd);
  	return 0;
  }
  
  /*
7c613d593   Peter Osterlund   [PATCH] pktcdvd: ...
1662
   * 1 -- we can write to this track, 0 -- we can't
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1663
   */
ab863ec34   Peter Osterlund   [PATCH] pktcdvd: ...
1664
  static int pkt_writable_track(struct pktcdvd_device *pd, track_information *ti)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1665
  {
ab863ec34   Peter Osterlund   [PATCH] pktcdvd: ...
1666
1667
1668
1669
1670
1671
1672
1673
  	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
1674

ab863ec34   Peter Osterlund   [PATCH] pktcdvd: ...
1675
1676
  	if (!ti->packet || !ti->fp)
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1677
1678
1679
1680
  
  	/*
  	 * "good" settings as per Mt Fuji.
  	 */
ab863ec34   Peter Osterlund   [PATCH] pktcdvd: ...
1681
  	if (ti->rt == 0 && ti->blank == 0)
7c613d593   Peter Osterlund   [PATCH] pktcdvd: ...
1682
  		return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1683

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

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

fa63c0ab8   Joe Perches   pktcdvd: add stru...
1690
1691
  	pkt_err(pd, "bad state %d-%d-%d
  ", ti->rt, ti->blank, ti->packet);
7c613d593   Peter Osterlund   [PATCH] pktcdvd: ...
1692
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1693
1694
1695
  }
  
  /*
7c613d593   Peter Osterlund   [PATCH] pktcdvd: ...
1696
   * 1 -- we can write to this disc, 0 -- we can't
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1697
   */
7c613d593   Peter Osterlund   [PATCH] pktcdvd: ...
1698
  static int pkt_writable_disc(struct pktcdvd_device *pd, disc_information *di)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1699
1700
1701
1702
1703
1704
1705
1706
  {
  	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: ...
1707
  			return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1708
  		default:
844aa7974   Joe Perches   pktcdvd: add stru...
1709
1710
  			pkt_dbg(2, pd, "Wrong disc profile (%x)
  ",
cd3f2cd05   Joe Perches   pktcdvd: consolid...
1711
  				pd->mmc3_profile);
7c613d593   Peter Osterlund   [PATCH] pktcdvd: ...
1712
  			return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1713
1714
1715
1716
1717
1718
1719
  	}
  
  	/*
  	 * 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) {
ca73dabc3   Joe Perches   pktcdvd: convert ...
1720
1721
  		pkt_notice(pd, "unknown disc - no track?
  ");
7c613d593   Peter Osterlund   [PATCH] pktcdvd: ...
1722
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1723
1724
1725
  	}
  
  	if (di->disc_type != 0x20 && di->disc_type != 0) {
fa63c0ab8   Joe Perches   pktcdvd: add stru...
1726
1727
  		pkt_err(pd, "wrong disc type (%x)
  ", di->disc_type);
7c613d593   Peter Osterlund   [PATCH] pktcdvd: ...
1728
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1729
1730
1731
  	}
  
  	if (di->erasable == 0) {
ca73dabc3   Joe Perches   pktcdvd: convert ...
1732
1733
  		pkt_notice(pd, "disc not erasable
  ");
7c613d593   Peter Osterlund   [PATCH] pktcdvd: ...
1734
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1735
1736
1737
  	}
  
  	if (di->border_status == PACKET_SESSION_RESERVED) {
fa63c0ab8   Joe Perches   pktcdvd: add stru...
1738
1739
  		pkt_err(pd, "can't write to last track (reserved)
  ");
7c613d593   Peter Osterlund   [PATCH] pktcdvd: ...
1740
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1741
  	}
7c613d593   Peter Osterlund   [PATCH] pktcdvd: ...
1742
  	return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1743
  }
05680d86d   Peter Osterlund   pktcdvd: reduce s...
1744
  static noinline_for_stack int pkt_probe_settings(struct pktcdvd_device *pd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
  {
  	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));
ada94973f   RAGHU Halharvi   pktcdvd: remove a...
1760
1761
  	ret = pkt_get_disc_info(pd, &di);
  	if (ret) {
fa63c0ab8   Joe Perches   pktcdvd: add stru...
1762
1763
  		pkt_err(pd, "failed get_disc
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1764
1765
  		return ret;
  	}
7c613d593   Peter Osterlund   [PATCH] pktcdvd: ...
1766
  	if (!pkt_writable_disc(pd, &di))
9db915465   Peter Osterlund   [PATCH] pktcdvd: ...
1767
  		return -EROFS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1768

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1769
1770
1771
  	pd->type = di.erasable ? PACKET_CDRW : PACKET_CDR;
  
  	track = 1; /* (di.last_track_msb << 8) | di.last_track_lsb; */
ada94973f   RAGHU Halharvi   pktcdvd: remove a...
1772
1773
  	ret = pkt_get_track_info(pd, track, 1, &ti);
  	if (ret) {
fa63c0ab8   Joe Perches   pktcdvd: add stru...
1774
1775
  		pkt_err(pd, "failed get_track
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1776
1777
  		return ret;
  	}
ab863ec34   Peter Osterlund   [PATCH] pktcdvd: ...
1778
  	if (!pkt_writable_track(pd, &ti)) {
fa63c0ab8   Joe Perches   pktcdvd: add stru...
1779
1780
  		pkt_err(pd, "can't write to this track
  ");
9db915465   Peter Osterlund   [PATCH] pktcdvd: ...
1781
  		return -EROFS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1782
1783
1784
1785
1786
1787
1788
1789
  	}
  
  	/*
  	 * 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) {
ca73dabc3   Joe Perches   pktcdvd: convert ...
1790
1791
  		pkt_notice(pd, "detected zero packet size!
  ");
a460ad622   Phillip Susi   [PATCH] pktcdvd: ...
1792
  		return -ENXIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1793
  	}
d0272e78e   Peter Osterlund   [PATCH] pktcdvd: ...
1794
  	if (pd->settings.size > PACKET_MAX_SECTORS) {
fa63c0ab8   Joe Perches   pktcdvd: add stru...
1795
1796
  		pkt_err(pd, "packet size is too big
  ");
9db915465   Peter Osterlund   [PATCH] pktcdvd: ...
1797
  		return -EROFS;
d0272e78e   Peter Osterlund   [PATCH] pktcdvd: ...
1798
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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
  	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:
fa63c0ab8   Joe Perches   pktcdvd: add stru...
1838
1839
  			pkt_err(pd, "unknown data mode
  ");
9db915465   Peter Osterlund   [PATCH] pktcdvd: ...
1840
  			return -EROFS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1841
1842
1843
1844
1845
1846
1847
  	}
  	return 0;
  }
  
  /*
   * enable/disable write caching on drive
   */
05680d86d   Peter Osterlund   pktcdvd: reduce s...
1848
1849
  static noinline_for_stack int pkt_write_caching(struct pktcdvd_device *pd,
  						int set)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1850
1851
  {
  	struct packet_command cgc;
e7d0748dd   Kees Cook   block: Switch str...
1852
  	struct scsi_sense_hdr sshdr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1853
1854
  	unsigned char buf[64];
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1855
  	init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ);
e7d0748dd   Kees Cook   block: Switch str...
1856
  	cgc.sshdr = &sshdr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1857
1858
1859
1860
1861
1862
  	cgc.buflen = pd->mode_offset + 12;
  
  	/*
  	 * caching mode page might not be there, so quiet this command
  	 */
  	cgc.quiet = 1;
ada94973f   RAGHU Halharvi   pktcdvd: remove a...
1863
1864
  	ret = pkt_mode_sense(pd, &cgc, GPMODE_WCACHING_PAGE, 0);
  	if (ret)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1865
1866
1867
1868
1869
1870
1871
  		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) {
fa63c0ab8   Joe Perches   pktcdvd: add stru...
1872
1873
  		pkt_err(pd, "write caching control failed
  ");
f3ded788b   Joe Perches   pktcdvd: add stru...
1874
  		pkt_dump_sense(pd, &cgc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1875
  	} else if (!ret && set)
ca73dabc3   Joe Perches   pktcdvd: convert ...
1876
1877
  		pkt_notice(pd, "enabled write caching
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
  	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...
1894
1895
  static noinline_for_stack int pkt_get_max_speed(struct pktcdvd_device *pd,
  						unsigned *write_speed)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1896
1897
  {
  	struct packet_command cgc;
e7d0748dd   Kees Cook   block: Switch str...
1898
  	struct scsi_sense_hdr sshdr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1899
1900
1901
  	unsigned char buf[256+18];
  	unsigned char *cap_buf;
  	int ret, offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1902
1903
  	cap_buf = &buf[sizeof(struct mode_page_header) + pd->mode_offset];
  	init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_UNKNOWN);
e7d0748dd   Kees Cook   block: Switch str...
1904
  	cgc.sshdr = &sshdr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1905
1906
1907
1908
1909
1910
1911
  
  	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) {
f3ded788b   Joe Perches   pktcdvd: add stru...
1912
  			pkt_dump_sense(pd, &cgc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
  			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...
1954
1955
  static noinline_for_stack int pkt_media_speed(struct pktcdvd_device *pd,
  						unsigned *speed)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1956
1957
  {
  	struct packet_command cgc;
e7d0748dd   Kees Cook   block: Switch str...
1958
  	struct scsi_sense_hdr sshdr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1959
1960
1961
1962
1963
  	unsigned char buf[64];
  	unsigned int size, st, sp;
  	int ret;
  
  	init_cdrom_command(&cgc, buf, 2, CGC_DATA_READ);
e7d0748dd   Kees Cook   block: Switch str...
1964
  	cgc.sshdr = &sshdr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1965
1966
1967
1968
1969
1970
  	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) {
f3ded788b   Joe Perches   pktcdvd: add stru...
1971
  		pkt_dump_sense(pd, &cgc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1972
1973
1974
1975
1976
1977
1978
  		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);
e7d0748dd   Kees Cook   block: Switch str...
1979
  	cgc.sshdr = &sshdr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1980
1981
1982
1983
1984
1985
  	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) {
f3ded788b   Joe Perches   pktcdvd: add stru...
1986
  		pkt_dump_sense(pd, &cgc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1987
1988
  		return ret;
  	}
eaa0ff15c   Alexey Dobriyan   fix ! versus & pr...
1989
  	if (!(buf[6] & 0x40)) {
ca73dabc3   Joe Perches   pktcdvd: convert ...
1990
1991
  		pkt_notice(pd, "disc type is not CD-RW
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1992
1993
  		return 1;
  	}
eaa0ff15c   Alexey Dobriyan   fix ! versus & pr...
1994
  	if (!(buf[6] & 0x4)) {
ca73dabc3   Joe Perches   pktcdvd: convert ...
1995
1996
  		pkt_notice(pd, "A1 values on media are not valid, maybe not CDRW?
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
  		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:
ca73dabc3   Joe Perches   pktcdvd: convert ...
2016
2017
  			pkt_notice(pd, "unknown disc sub-type %d
  ", st);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2018
2019
2020
  			return 1;
  	}
  	if (*speed) {
0c075d64d   Joe Perches   pktcdvd: convert ...
2021
2022
  		pkt_info(pd, "maximum media speed: %d
  ", *speed);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2023
2024
  		return 0;
  	} else {
ca73dabc3   Joe Perches   pktcdvd: convert ...
2025
2026
  		pkt_notice(pd, "unknown speed %d for sub-type %d
  ", sp, st);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2027
2028
2029
  		return 1;
  	}
  }
05680d86d   Peter Osterlund   pktcdvd: reduce s...
2030
  static noinline_for_stack int pkt_perform_opc(struct pktcdvd_device *pd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2031
2032
  {
  	struct packet_command cgc;
e7d0748dd   Kees Cook   block: Switch str...
2033
  	struct scsi_sense_hdr sshdr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2034
  	int ret;
844aa7974   Joe Perches   pktcdvd: add stru...
2035
2036
  	pkt_dbg(2, pd, "Performing OPC
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2037
2038
  
  	init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
e7d0748dd   Kees Cook   block: Switch str...
2039
  	cgc.sshdr = &sshdr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2040
2041
2042
  	cgc.timeout = 60*HZ;
  	cgc.cmd[0] = GPCMD_SEND_OPC;
  	cgc.cmd[1] = 1;
ada94973f   RAGHU Halharvi   pktcdvd: remove a...
2043
2044
  	ret = pkt_generic_packet(pd, &cgc);
  	if (ret)
f3ded788b   Joe Perches   pktcdvd: add stru...
2045
  		pkt_dump_sense(pd, &cgc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2046
2047
2048
2049
2050
2051
2052
  	return ret;
  }
  
  static int pkt_open_write(struct pktcdvd_device *pd)
  {
  	int ret;
  	unsigned int write_speed, media_write_speed, read_speed;
ada94973f   RAGHU Halharvi   pktcdvd: remove a...
2053
2054
  	ret = pkt_probe_settings(pd);
  	if (ret) {
844aa7974   Joe Perches   pktcdvd: add stru...
2055
2056
  		pkt_dbg(2, pd, "failed probe
  ");
9db915465   Peter Osterlund   [PATCH] pktcdvd: ...
2057
  		return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2058
  	}
ada94973f   RAGHU Halharvi   pktcdvd: remove a...
2059
2060
  	ret = pkt_set_write_settings(pd);
  	if (ret) {
844aa7974   Joe Perches   pktcdvd: add stru...
2061
2062
  		pkt_dbg(1, pd, "failed saving write settings
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2063
2064
2065
2066
  		return -EIO;
  	}
  
  	pkt_write_caching(pd, USE_WCACHING);
ada94973f   RAGHU Halharvi   pktcdvd: remove a...
2067
2068
  	ret = pkt_get_max_speed(pd, &write_speed);
  	if (ret)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2069
2070
2071
2072
2073
  		write_speed = 16 * 177;
  	switch (pd->mmc3_profile) {
  		case 0x13: /* DVD-RW */
  		case 0x1a: /* DVD+RW */
  		case 0x12: /* DVD-RAM */
844aa7974   Joe Perches   pktcdvd: add stru...
2074
2075
  			pkt_dbg(1, pd, "write speed %ukB/s
  ", write_speed);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2076
2077
  			break;
  		default:
ada94973f   RAGHU Halharvi   pktcdvd: remove a...
2078
2079
  			ret = pkt_media_speed(pd, &media_write_speed);
  			if (ret)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2080
2081
  				media_write_speed = 16;
  			write_speed = min(write_speed, media_write_speed * 177);
844aa7974   Joe Perches   pktcdvd: add stru...
2082
2083
  			pkt_dbg(1, pd, "write speed %ux
  ", write_speed / 176);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2084
2085
2086
  			break;
  	}
  	read_speed = write_speed;
ada94973f   RAGHU Halharvi   pktcdvd: remove a...
2087
2088
  	ret = pkt_set_speed(pd, write_speed, read_speed);
  	if (ret) {
844aa7974   Joe Perches   pktcdvd: add stru...
2089
2090
  		pkt_dbg(1, pd, "couldn't set write speed
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2091
2092
2093
2094
  		return -EIO;
  	}
  	pd->write_speed = write_speed;
  	pd->read_speed = read_speed;
ada94973f   RAGHU Halharvi   pktcdvd: remove a...
2095
2096
  	ret = pkt_perform_opc(pd);
  	if (ret) {
844aa7974   Joe Perches   pktcdvd: add stru...
2097
2098
  		pkt_dbg(1, pd, "Optimum Power Calibration failed
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2099
2100
2101
2102
2103
2104
2105
2106
  	}
  
  	return 0;
  }
  
  /*
   * called at open time.
   */
aeb5d7270   Al Viro   [PATCH] introduce...
2107
  static int pkt_open_dev(struct pktcdvd_device *pd, fmode_t write)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2108
2109
2110
  {
  	int ret;
  	long lba;
165125e1e   Jens Axboe   [BLOCK] Get rid o...
2111
  	struct request_queue *q;
b8d954849   Christoph Hellwig   pktcdvd: use blkd...
2112
  	struct block_device *bdev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2113
2114
2115
2116
  
  	/*
  	 * 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
b8d954849   Christoph Hellwig   pktcdvd: use blkd...
2117
  	 * so open should not fail.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2118
  	 */
b8d954849   Christoph Hellwig   pktcdvd: use blkd...
2119
2120
2121
  	bdev = blkdev_get_by_dev(pd->bdev->bd_dev, FMODE_READ | FMODE_EXCL, pd);
  	if (IS_ERR(bdev)) {
  		ret = PTR_ERR(bdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2122
  		goto out;
b8d954849   Christoph Hellwig   pktcdvd: use blkd...
2123
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2124

ada94973f   RAGHU Halharvi   pktcdvd: remove a...
2125
2126
  	ret = pkt_get_last_written(pd, &lba);
  	if (ret) {
fa63c0ab8   Joe Perches   pktcdvd: add stru...
2127
2128
  		pkt_err(pd, "pkt_get_last_written failed
  ");
e525fd89d   Tejun Heo   block: make blkde...
2129
  		goto out_putdev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2130
2131
2132
2133
  	}
  
  	set_capacity(pd->disk, lba << 2);
  	set_capacity(pd->bdev->bd_disk, lba << 2);
611bee526   Christoph Hellwig   block: replace bd...
2134
  	bd_set_nr_sectors(pd->bdev, lba << 2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2135
2136
2137
  
  	q = bdev_get_queue(pd->bdev);
  	if (write) {
ada94973f   RAGHU Halharvi   pktcdvd: remove a...
2138
2139
  		ret = pkt_open_write(pd);
  		if (ret)
e525fd89d   Tejun Heo   block: make blkde...
2140
  			goto out_putdev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2141
2142
2143
2144
  		/*
  		 * Some CDRW drives can not handle writes larger than one packet,
  		 * even if the size is a multiple of the packet size.
  		 */
086fa5ff0   Martin K. Petersen   block: Rename blk...
2145
  		blk_queue_max_hw_sectors(q, pd->settings.size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2146
2147
2148
2149
2150
  		set_bit(PACKET_WRITABLE, &pd->flags);
  	} else {
  		pkt_set_speed(pd, MAX_SPEED, MAX_SPEED);
  		clear_bit(PACKET_WRITABLE, &pd->flags);
  	}
ada94973f   RAGHU Halharvi   pktcdvd: remove a...
2151
2152
  	ret = pkt_set_segment_merging(pd, q);
  	if (ret)
e525fd89d   Tejun Heo   block: make blkde...
2153
  		goto out_putdev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2154

e1bc89bc9   Peter Osterlund   [PATCH] pktcdvd: ...
2155
2156
  	if (write) {
  		if (!pkt_grow_pktlist(pd, CONFIG_CDROM_PKTCDVD_BUFFERS)) {
fa63c0ab8   Joe Perches   pktcdvd: add stru...
2157
2158
  			pkt_err(pd, "not enough memory for buffers
  ");
e1bc89bc9   Peter Osterlund   [PATCH] pktcdvd: ...
2159
  			ret = -ENOMEM;
e525fd89d   Tejun Heo   block: make blkde...
2160
  			goto out_putdev;
e1bc89bc9   Peter Osterlund   [PATCH] pktcdvd: ...
2161
  		}
0c075d64d   Joe Perches   pktcdvd: convert ...
2162
2163
  		pkt_info(pd, "%lukB available on disc
  ", lba << 1);
e1bc89bc9   Peter Osterlund   [PATCH] pktcdvd: ...
2164
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2165
2166
2167
2168
  
  	return 0;
  
  out_putdev:
b8d954849   Christoph Hellwig   pktcdvd: use blkd...
2169
  	blkdev_put(bdev, FMODE_READ | FMODE_EXCL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
  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))
844aa7974   Joe Perches   pktcdvd: add stru...
2181
2182
  		pkt_dbg(1, pd, "not flushing cache
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2183
2184
2185
2186
  
  	pkt_lock_door(pd, 0);
  
  	pkt_set_speed(pd, MAX_SPEED, MAX_SPEED);
e525fd89d   Tejun Heo   block: make blkde...
2187
  	blkdev_put(pd->bdev, FMODE_READ | FMODE_EXCL);
e1bc89bc9   Peter Osterlund   [PATCH] pktcdvd: ...
2188
2189
  
  	pkt_shrink_pktlist(pd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2190
  }
252a52aa4   Dan Rosenberg   Fix pktcdvd ioctl...
2191
  static struct pktcdvd_device *pkt_find_dev_from_minor(unsigned int dev_minor)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2192
2193
2194
  {
  	if (dev_minor >= MAX_WRITERS)
  		return NULL;
55690c07b   Jinbum Park   pktcdvd: Fix poss...
2195
2196
  
  	dev_minor = array_index_nospec(dev_minor, MAX_WRITERS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2197
2198
  	return pkt_devs[dev_minor];
  }
5e5e007c2   Al Viro   [PATCH] switch pk...
2199
  static int pkt_open(struct block_device *bdev, fmode_t mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2200
2201
2202
  {
  	struct pktcdvd_device *pd = NULL;
  	int ret;
2a48fc0ab   Arnd Bergmann   block: autoconver...
2203
  	mutex_lock(&pktcdvd_mutex);
1657f824e   Jes Sorensen   [PATCH] sem2mutex...
2204
  	mutex_lock(&ctl_mutex);
5e5e007c2   Al Viro   [PATCH] switch pk...
2205
  	pd = pkt_find_dev_from_minor(MINOR(bdev->bd_dev));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2206
2207
2208
2209
2210
2211
2212
  	if (!pd) {
  		ret = -ENODEV;
  		goto out;
  	}
  	BUG_ON(pd->refcnt < 0);
  
  	pd->refcnt++;
46f4e1b7d   Peter Osterlund   [PATCH] packet dr...
2213
  	if (pd->refcnt > 1) {
5e5e007c2   Al Viro   [PATCH] switch pk...
2214
  		if ((mode & FMODE_WRITE) &&
46f4e1b7d   Peter Osterlund   [PATCH] packet dr...
2215
2216
2217
2218
2219
  		    !test_bit(PACKET_WRITABLE, &pd->flags)) {
  			ret = -EBUSY;
  			goto out_dec;
  		}
  	} else {
5e5e007c2   Al Viro   [PATCH] switch pk...
2220
  		ret = pkt_open_dev(pd, mode & FMODE_WRITE);
01fd9fda2   Peter Osterlund   [PATCH] pktcdvd: ...
2221
  		if (ret)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2222
  			goto out_dec;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2223
2224
2225
2226
  		/*
  		 * needed here as well, since ext2 (among others) may change
  		 * the blocksize at mount time
  		 */
5e5e007c2   Al Viro   [PATCH] switch pk...
2227
  		set_blocksize(bdev, CD_FRAMESIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2228
  	}
1657f824e   Jes Sorensen   [PATCH] sem2mutex...
2229
  	mutex_unlock(&ctl_mutex);
2a48fc0ab   Arnd Bergmann   block: autoconver...
2230
  	mutex_unlock(&pktcdvd_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2231
2232
2233
2234
2235
  	return 0;
  
  out_dec:
  	pd->refcnt--;
  out:
1657f824e   Jes Sorensen   [PATCH] sem2mutex...
2236
  	mutex_unlock(&ctl_mutex);
2a48fc0ab   Arnd Bergmann   block: autoconver...
2237
  	mutex_unlock(&pktcdvd_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2238
2239
  	return ret;
  }
db2a144be   Al Viro   block_device_oper...
2240
  static void pkt_close(struct gendisk *disk, fmode_t mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2241
  {
5e5e007c2   Al Viro   [PATCH] switch pk...
2242
  	struct pktcdvd_device *pd = disk->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2243

2a48fc0ab   Arnd Bergmann   block: autoconver...
2244
  	mutex_lock(&pktcdvd_mutex);
1657f824e   Jes Sorensen   [PATCH] sem2mutex...
2245
  	mutex_lock(&ctl_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2246
2247
2248
2249
2250
2251
  	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...
2252
  	mutex_unlock(&ctl_mutex);
2a48fc0ab   Arnd Bergmann   block: autoconver...
2253
  	mutex_unlock(&pktcdvd_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2254
  }
4246a0b63   Christoph Hellwig   block: add a bi_e...
2255
  static void pkt_end_io_read_cloned(struct bio *bio)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2256
2257
2258
  {
  	struct packet_stacked_data *psd = bio->bi_private;
  	struct pktcdvd_device *pd = psd->pd;
4e4cbee93   Christoph Hellwig   block: switch bio...
2259
  	psd->bio->bi_status = bio->bi_status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2260
  	bio_put(bio);
4246a0b63   Christoph Hellwig   block: add a bi_e...
2261
  	bio_endio(psd->bio);
64c4bc4de   Kent Overstreet   pktcdvd: convert ...
2262
  	mempool_free(psd, &psd_pool);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2263
  	pkt_bio_finished(pd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2264
  }
20d0189b1   Kent Overstreet   block: Introduce ...
2265
  static void pkt_make_request_read(struct pktcdvd_device *pd, struct bio *bio)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2266
  {
64c4bc4de   Kent Overstreet   pktcdvd: convert ...
2267
2268
  	struct bio *cloned_bio = bio_clone_fast(bio, GFP_NOIO, &pkt_bio_set);
  	struct packet_stacked_data *psd = mempool_alloc(&psd_pool, GFP_NOIO);
20d0189b1   Kent Overstreet   block: Introduce ...
2269
2270
2271
  
  	psd->pd = pd;
  	psd->bio = bio;
74d46992e   Christoph Hellwig   block: replace bi...
2272
  	bio_set_dev(cloned_bio, pd->bdev);
20d0189b1   Kent Overstreet   block: Introduce ...
2273
2274
2275
2276
2277
2278
2279
2280
2281
  	cloned_bio->bi_private = psd;
  	cloned_bio->bi_end_io = pkt_end_io_read_cloned;
  	pd->stats.secs_r += bio_sectors(bio);
  	pkt_queue_bio(pd, cloned_bio);
  }
  
  static void pkt_make_request_write(struct request_queue *q, struct bio *bio)
  {
  	struct pktcdvd_device *pd = q->queuedata;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2282
2283
2284
2285
  	sector_t zone;
  	struct packet_data *pkt;
  	int was_empty, blocked_bio;
  	struct pkt_rb_node *node;
4f024f379   Kent Overstreet   block: Abstract o...
2286
  	zone = get_zone(bio->bi_iter.bi_sector, pd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
  
  	/*
  	 * 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 ...
2299
  				bio_list_add(&pkt->orig_bios, bio);
4f024f379   Kent Overstreet   block: Abstract o...
2300
2301
  				pkt->write_size +=
  					bio->bi_iter.bi_size / CD_FRAMESIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2302
2303
2304
2305
2306
2307
2308
  				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...
2309
  				return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2310
2311
2312
2313
2314
2315
2316
  			} else {
  				blocked_bio = 1;
  			}
  			spin_unlock(&pkt->lock);
  		}
  	}
  	spin_unlock(&pd->cdrw.active_list_lock);
0a0fc9601   Thomas Maier   [PATCH] pktcdvd: ...
2317
2318
2319
2320
2321
2322
2323
2324
   	/*
  	 * 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) {
dc3b17cc8   Jan Kara   block: Use pointe...
2325
  		set_bdi_congested(q->backing_dev_info, BLK_RW_ASYNC);
0a0fc9601   Thomas Maier   [PATCH] pktcdvd: ...
2326
2327
  		do {
  			spin_unlock(&pd->lock);
8aa7e847d   Jens Axboe   Fix congestion_wa...
2328
  			congestion_wait(BLK_RW_ASYNC, HZ);
0a0fc9601   Thomas Maier   [PATCH] pktcdvd: ...
2329
2330
2331
2332
  			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
2333
2334
2335
  	/*
  	 * No matching packet found. Store the bio in the work queue.
  	 */
64c4bc4de   Kent Overstreet   pktcdvd: convert ...
2336
  	node = mempool_alloc(&pd->rb_pool, GFP_NOIO);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
  	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);
  	}
20d0189b1   Kent Overstreet   block: Introduce ...
2358
  }
c62b37d96   Christoph Hellwig   block: move ->mak...
2359
  static blk_qc_t pkt_submit_bio(struct bio *bio)
20d0189b1   Kent Overstreet   block: Introduce ...
2360
2361
2362
2363
  {
  	struct pktcdvd_device *pd;
  	char b[BDEVNAME_SIZE];
  	struct bio *split;
f695ca388   Christoph Hellwig   block: remove the...
2364
  	blk_queue_split(&bio);
54efd50bf   Kent Overstreet   block: make gener...
2365

c62b37d96   Christoph Hellwig   block: move ->mak...
2366
  	pd = bio->bi_disk->queue->queuedata;
20d0189b1   Kent Overstreet   block: Introduce ...
2367
  	if (!pd) {
74d46992e   Christoph Hellwig   block: replace bi...
2368
2369
  		pr_err("%s incorrect request queue
  ", bio_devname(bio, b));
20d0189b1   Kent Overstreet   block: Introduce ...
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
  		goto end_io;
  	}
  
  	pkt_dbg(2, pd, "start = %6llx stop = %6llx
  ",
  		(unsigned long long)bio->bi_iter.bi_sector,
  		(unsigned long long)bio_end_sector(bio));
  
  	/*
  	 * Clone READ bios so we can have our own bi_end_io callback.
  	 */
  	if (bio_data_dir(bio) == READ) {
  		pkt_make_request_read(pd, bio);
dece16353   Jens Axboe   block: change ->m...
2383
  		return BLK_QC_T_NONE;
20d0189b1   Kent Overstreet   block: Introduce ...
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
  	}
  
  	if (!test_bit(PACKET_WRITABLE, &pd->flags)) {
  		pkt_notice(pd, "WRITE for ro device (%llu)
  ",
  			   (unsigned long long)bio->bi_iter.bi_sector);
  		goto end_io;
  	}
  
  	if (!bio->bi_iter.bi_size || (bio->bi_iter.bi_size % CD_FRAMESIZE)) {
  		pkt_err(pd, "wrong bio size
  ");
  		goto end_io;
  	}
20d0189b1   Kent Overstreet   block: Introduce ...
2398
2399
2400
2401
2402
2403
2404
2405
2406
  	do {
  		sector_t zone = get_zone(bio->bi_iter.bi_sector, pd);
  		sector_t last_zone = get_zone(bio_end_sector(bio) - 1, pd);
  
  		if (last_zone != zone) {
  			BUG_ON(last_zone != zone + pd->settings.size);
  
  			split = bio_split(bio, last_zone -
  					  bio->bi_iter.bi_sector,
64c4bc4de   Kent Overstreet   pktcdvd: convert ...
2407
  					  GFP_NOIO, &pkt_bio_set);
20d0189b1   Kent Overstreet   block: Introduce ...
2408
2409
2410
2411
  			bio_chain(split, bio);
  		} else {
  			split = bio;
  		}
c62b37d96   Christoph Hellwig   block: move ->mak...
2412
  		pkt_make_request_write(bio->bi_disk->queue, split);
20d0189b1   Kent Overstreet   block: Introduce ...
2413
  	} while (split != bio);
dece16353   Jens Axboe   block: change ->m...
2414
  	return BLK_QC_T_NONE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2415
  end_io:
6712ecf8f   NeilBrown   Drop 'size' argum...
2416
  	bio_io_error(bio);
dece16353   Jens Axboe   block: change ->m...
2417
  	return BLK_QC_T_NONE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2418
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2419
2420
  static void pkt_init_queue(struct pktcdvd_device *pd)
  {
165125e1e   Jens Axboe   [BLOCK] Get rid o...
2421
  	struct request_queue *q = pd->disk->queue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2422

e1defc4ff   Martin K. Petersen   block: Do away wi...
2423
  	blk_queue_logical_block_size(q, CD_FRAMESIZE);
086fa5ff0   Martin K. Petersen   block: Rename blk...
2424
  	blk_queue_max_hw_sectors(q, PACKET_MAX_SECTORS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
  	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: ...
2513
2514
2515
2516
  	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
2517
2518
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2519
2520
2521
  static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev)
  {
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2522
  	char b[BDEVNAME_SIZE];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2523
2524
2525
  	struct block_device *bdev;
  
  	if (pd->pkt_dev == dev) {
fa63c0ab8   Joe Perches   pktcdvd: add stru...
2526
2527
  		pkt_err(pd, "recursive setup not allowed
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2528
2529
2530
2531
2532
2533
2534
  		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) {
fa63c0ab8   Joe Perches   pktcdvd: add stru...
2535
2536
2537
  			pkt_err(pd, "%s already setup
  ",
  				bdevname(pd2->bdev, b));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2538
2539
2540
  			return -EBUSY;
  		}
  		if (pd2->pkt_dev == dev) {
fa63c0ab8   Joe Perches   pktcdvd: add stru...
2541
2542
  			pkt_err(pd, "can't chain pktcdvd devices
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2543
2544
2545
  			return -EBUSY;
  		}
  	}
b8d954849   Christoph Hellwig   pktcdvd: use blkd...
2546
2547
2548
  	bdev = blkdev_get_by_dev(dev, FMODE_READ | FMODE_NDELAY, NULL);
  	if (IS_ERR(bdev))
  		return PTR_ERR(bdev);
ec2be6a98   Bart Van Assche   pktcdvd: Check qu...
2549
  	if (!blk_queue_scsi_passthrough(bdev_get_queue(bdev))) {
882d4171a   Bart Van Assche   pktcdvd: Fix a re...
2550
  		blkdev_put(bdev, FMODE_READ | FMODE_NDELAY);
ec2be6a98   Bart Van Assche   pktcdvd: Check qu...
2551
2552
  		return -EINVAL;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2553
2554
2555
  
  	/* This is safe, since we have a reference from open(). */
  	__module_get(THIS_MODULE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2556
2557
2558
2559
2560
2561
2562
2563
  	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)) {
fa63c0ab8   Joe Perches   pktcdvd: add stru...
2564
2565
  		pkt_err(pd, "can't start kernel thread
  ");
e1bc89bc9   Peter Osterlund   [PATCH] pktcdvd: ...
2566
  		goto out_mem;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2567
  	}
3f3942aca   Christoph Hellwig   proc: introduce p...
2568
  	proc_create_single_data(pd->name, 0, pkt_proc, pkt_seq_show, pd);
844aa7974   Joe Perches   pktcdvd: add stru...
2569
2570
  	pkt_dbg(1, pd, "writer mapped to %s
  ", bdevname(bdev, b));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2571
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2572
  out_mem:
2cbed8906   Al Viro   [PATCH] fix bogus...
2573
  	blkdev_put(bdev, FMODE_READ | FMODE_NDELAY);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2574
2575
  	/* This is safe: open() is still holding a reference. */
  	module_put(THIS_MODULE);
b8d954849   Christoph Hellwig   pktcdvd: use blkd...
2576
  	return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2577
  }
5e5e007c2   Al Viro   [PATCH] switch pk...
2578
  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
2579
  {
5e5e007c2   Al Viro   [PATCH] switch pk...
2580
  	struct pktcdvd_device *pd = bdev->bd_disk->private_data;
8a6cfeb6d   Arnd Bergmann   block: push down ...
2581
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2582

844aa7974   Joe Perches   pktcdvd: add stru...
2583
2584
  	pkt_dbg(2, pd, "cmd %x, dev %d:%d
  ",
cd3f2cd05   Joe Perches   pktcdvd: consolid...
2585
  		cmd, MAJOR(bdev->bd_dev), MINOR(bdev->bd_dev));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2586

2a48fc0ab   Arnd Bergmann   block: autoconver...
2587
  	mutex_lock(&pktcdvd_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2588
  	switch (cmd) {
a0eb62a0a   Al Viro   [PATCH] switch pk...
2589
2590
2591
2592
2593
2594
2595
  	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);
df561f668   Gustavo A. R. Silva   treewide: Use fal...
2596
  		fallthrough;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2597
2598
2599
2600
2601
2602
2603
2604
  	/*
  	 * 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 ...
2605
2606
  		ret = __blkdev_driver_ioctl(pd->bdev, mode, cmd, arg);
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2607
2608
  
  	default:
844aa7974   Joe Perches   pktcdvd: add stru...
2609
2610
  		pkt_dbg(2, pd, "Unknown ioctl (%x)
  ", cmd);
8a6cfeb6d   Arnd Bergmann   block: push down ...
2611
  		ret = -ENOTTY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2612
  	}
2a48fc0ab   Arnd Bergmann   block: autoconver...
2613
  	mutex_unlock(&pktcdvd_mutex);
8560c650f   Linus Torvalds   Revert "pktcdvd: ...
2614

8a6cfeb6d   Arnd Bergmann   block: push down ...
2615
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2616
  }
3c0d20609   Tejun Heo   pktcdvd: Convert ...
2617
2618
  static unsigned int pkt_check_events(struct gendisk *disk,
  				     unsigned int clearing)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2619
2620
2621
2622
2623
2624
2625
2626
2627
  {
  	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 ...
2628
  	if (!attached_disk || !attached_disk->fops->check_events)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2629
  		return 0;
3c0d20609   Tejun Heo   pktcdvd: Convert ...
2630
  	return attached_disk->fops->check_events(attached_disk, clearing);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2631
  }
348e114bb   Christoph Hellwig   block: move the -...
2632
2633
2634
2635
  static char *pkt_devnode(struct gendisk *disk, umode_t *mode)
  {
  	return kasprintf(GFP_KERNEL, "pktcdvd/%s", disk->disk_name);
  }
83d5cde47   Alexey Dobriyan   const: make block...
2636
  static const struct block_device_operations pktcdvd_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2637
  	.owner =		THIS_MODULE,
c62b37d96   Christoph Hellwig   block: move ->mak...
2638
  	.submit_bio =		pkt_submit_bio,
5e5e007c2   Al Viro   [PATCH] switch pk...
2639
2640
  	.open =			pkt_open,
  	.release =		pkt_close,
8a6cfeb6d   Arnd Bergmann   block: push down ...
2641
  	.ioctl =		pkt_ioctl,
ab8bc5417   Arnd Bergmann   compat_ioctl: cdr...
2642
  	.compat_ioctl =		blkdev_compat_ptr_ioctl,
3c0d20609   Tejun Heo   pktcdvd: Convert ...
2643
  	.check_events =		pkt_check_events,
348e114bb   Christoph Hellwig   block: move the -...
2644
  	.devnode =		pkt_devnode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2645
2646
2647
2648
2649
  };
  
  /*
   * Set up mapping from pktcdvd device to CD-ROM device.
   */
adb9250a0   Thomas Maier   [PATCH] pktcdvd: ...
2650
  static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2651
2652
2653
2654
2655
  {
  	int idx;
  	int ret = -ENOMEM;
  	struct pktcdvd_device *pd;
  	struct gendisk *disk;
adb9250a0   Thomas Maier   [PATCH] pktcdvd: ...
2656
2657
  
  	mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2658
2659
2660
2661
2662
  
  	for (idx = 0; idx < MAX_WRITERS; idx++)
  		if (!pkt_devs[idx])
  			break;
  	if (idx == MAX_WRITERS) {
99481334b   Joe Perches   pktcdvd: convert ...
2663
2664
  		pr_err("max %d writers supported
  ", MAX_WRITERS);
adb9250a0   Thomas Maier   [PATCH] pktcdvd: ...
2665
2666
  		ret = -EBUSY;
  		goto out_mutex;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2667
  	}
1107d2e03   Peter Osterlund   [PATCH] pktcdvd: ...
2668
  	pd = kzalloc(sizeof(struct pktcdvd_device), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2669
  	if (!pd)
adb9250a0   Thomas Maier   [PATCH] pktcdvd: ...
2670
  		goto out_mutex;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2671

64c4bc4de   Kent Overstreet   pktcdvd: convert ...
2672
2673
2674
  	ret = mempool_init_kmalloc_pool(&pd->rb_pool, PKT_RB_POOL_SIZE,
  					sizeof(struct pkt_rb_node));
  	if (ret)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2675
  		goto out_mem;
e1bc89bc9   Peter Osterlund   [PATCH] pktcdvd: ...
2676
2677
2678
  	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
2679
2680
  	spin_lock_init(&pd->lock);
  	spin_lock_init(&pd->iosched.lock);
c5ecc484c   Akinobu Mita   pktcdvd: use BIO ...
2681
2682
  	bio_list_init(&pd->iosched.read_queue);
  	bio_list_init(&pd->iosched.write_queue);
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
2683
  	sprintf(pd->name, DRIVER_NAME"%d", idx);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2684
2685
  	init_waitqueue_head(&pd->wqueue);
  	pd->bio_queue = RB_ROOT;
0a0fc9601   Thomas Maier   [PATCH] pktcdvd: ...
2686
2687
  	pd->write_congestion_on  = write_congestion_on;
  	pd->write_congestion_off = write_congestion_off;
566484a9e   Jens Axboe   pktcdvd: fix sett...
2688
  	ret = -ENOMEM;
adb9250a0   Thomas Maier   [PATCH] pktcdvd: ...
2689
2690
2691
2692
  	disk = alloc_disk(1);
  	if (!disk)
  		goto out_mem;
  	pd->disk = disk;
add216608   Thomas Maier   [PATCH] pktcdvd: ...
2693
  	disk->major = pktdev_major;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2694
2695
2696
  	disk->first_minor = idx;
  	disk->fops = &pktcdvd_ops;
  	disk->flags = GENHD_FL_REMOVABLE;
adb9250a0   Thomas Maier   [PATCH] pktcdvd: ...
2697
  	strcpy(disk->disk_name, pd->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2698
  	disk->private_data = pd;
c62b37d96   Christoph Hellwig   block: move ->mak...
2699
  	disk->queue = blk_alloc_queue(NUMA_NO_NODE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2700
2701
  	if (!disk->queue)
  		goto out_mem2;
f331c0296   Tejun Heo   block: don't depe...
2702
  	pd->pkt_dev = MKDEV(pktdev_major, idx);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2703
2704
  	ret = pkt_new_dev(pd, dev);
  	if (ret)
5a0ec388e   Bart Van Assche   pktcdvd: Fix pkt_...
2705
  		goto out_mem2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2706

3c0d20609   Tejun Heo   pktcdvd: Convert ...
2707
2708
  	/* inherit events of the host device */
  	disk->events = pd->bdev->bd_disk->events;
3c0d20609   Tejun Heo   pktcdvd: Convert ...
2709

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2710
  	add_disk(disk);
adb9250a0   Thomas Maier   [PATCH] pktcdvd: ...
2711

32694850a   Thomas Maier   [PATCH] pktcdvd: ...
2712
2713
  	pkt_sysfs_dev_new(pd);
  	pkt_debugfs_dev_new(pd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2714
  	pkt_devs[idx] = pd;
adb9250a0   Thomas Maier   [PATCH] pktcdvd: ...
2715
2716
2717
2718
  	if (pkt_dev)
  		*pkt_dev = pd->pkt_dev;
  
  	mutex_unlock(&ctl_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2719
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2720
2721
2722
  out_mem2:
  	put_disk(disk);
  out_mem:
64c4bc4de   Kent Overstreet   pktcdvd: convert ...
2723
  	mempool_exit(&pd->rb_pool);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2724
  	kfree(pd);
adb9250a0   Thomas Maier   [PATCH] pktcdvd: ...
2725
2726
  out_mutex:
  	mutex_unlock(&ctl_mutex);
99481334b   Joe Perches   pktcdvd: convert ...
2727
2728
  	pr_err("setup of pktcdvd device failed
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2729
2730
2731
2732
2733
2734
  	return ret;
  }
  
  /*
   * Tear down mapping from pktcdvd device to CD-ROM device.
   */
adb9250a0   Thomas Maier   [PATCH] pktcdvd: ...
2735
  static int pkt_remove_dev(dev_t pkt_dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2736
2737
2738
  {
  	struct pktcdvd_device *pd;
  	int idx;
adb9250a0   Thomas Maier   [PATCH] pktcdvd: ...
2739
2740
2741
  	int ret = 0;
  
  	mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2742
2743
2744
2745
2746
2747
2748
  
  	for (idx = 0; idx < MAX_WRITERS; idx++) {
  		pd = pkt_devs[idx];
  		if (pd && (pd->pkt_dev == pkt_dev))
  			break;
  	}
  	if (idx == MAX_WRITERS) {
666dc7c90   Joe Perches   pktcdvd: fix defe...
2749
2750
  		pr_debug("dev not setup
  ");
adb9250a0   Thomas Maier   [PATCH] pktcdvd: ...
2751
2752
  		ret = -ENXIO;
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2753
  	}
adb9250a0   Thomas Maier   [PATCH] pktcdvd: ...
2754
2755
2756
2757
  	if (pd->refcnt > 0) {
  		ret = -EBUSY;
  		goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2758
2759
  	if (!IS_ERR(pd->cdrw.thread))
  		kthread_stop(pd->cdrw.thread);
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
2760
2761
2762
2763
  	pkt_devs[idx] = NULL;
  
  	pkt_debugfs_dev_remove(pd);
  	pkt_sysfs_dev_remove(pd);
2cbed8906   Al Viro   [PATCH] fix bogus...
2764
  	blkdev_put(pd->bdev, FMODE_READ | FMODE_NDELAY);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2765

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2766
  	remove_proc_entry(pd->name, pkt_proc);
844aa7974   Joe Perches   pktcdvd: add stru...
2767
2768
  	pkt_dbg(1, pd, "writer unmapped
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2769
2770
  
  	del_gendisk(pd->disk);
1312f40e1   Al Viro   [PATCH] regulariz...
2771
  	blk_cleanup_queue(pd->disk->queue);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2772
  	put_disk(pd->disk);
64c4bc4de   Kent Overstreet   pktcdvd: convert ...
2773
  	mempool_exit(&pd->rb_pool);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2774
2775
2776
2777
  	kfree(pd);
  
  	/* This is safe: open() is still holding a reference. */
  	module_put(THIS_MODULE);
adb9250a0   Thomas Maier   [PATCH] pktcdvd: ...
2778
2779
2780
2781
  
  out:
  	mutex_unlock(&ctl_mutex);
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2782
2783
2784
2785
  }
  
  static void pkt_get_status(struct pkt_ctrl_command *ctrl_cmd)
  {
adb9250a0   Thomas Maier   [PATCH] pktcdvd: ...
2786
2787
2788
2789
2790
  	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
2791
2792
2793
2794
2795
2796
2797
2798
  	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: ...
2799
2800
  
  	mutex_unlock(&ctl_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2801
  }
f80a0ca6a   Arnd Bergmann   pktcdvd: improve ...
2802
  static long pkt_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2803
2804
2805
2806
  {
  	void __user *argp = (void __user *)arg;
  	struct pkt_ctrl_command ctrl_cmd;
  	int ret = 0;
adb9250a0   Thomas Maier   [PATCH] pktcdvd: ...
2807
  	dev_t pkt_dev = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
  
  	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: ...
2819
2820
  		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
2821
2822
2823
2824
  		break;
  	case PKT_CTRL_CMD_TEARDOWN:
  		if (!capable(CAP_SYS_ADMIN))
  			return -EPERM;
adb9250a0   Thomas Maier   [PATCH] pktcdvd: ...
2825
  		ret = pkt_remove_dev(new_decode_dev(ctrl_cmd.pkt_dev));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2826
2827
  		break;
  	case PKT_CTRL_CMD_STATUS:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2828
  		pkt_get_status(&ctrl_cmd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2829
2830
2831
2832
2833
2834
2835
2836
2837
  		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 ...
2838
2839
2840
2841
2842
2843
  #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
2844

2b8693c06   Arjan van de Ven   [PATCH] mark stru...
2845
  static const struct file_operations pkt_ctl_fops = {
f80a0ca6a   Arnd Bergmann   pktcdvd: improve ...
2846
2847
2848
2849
2850
2851
  	.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...
2852
  	.llseek		= no_llseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2853
2854
2855
2856
  };
  
  static struct miscdevice pkt_misc = {
  	.minor 		= MISC_DYNAMIC_MINOR,
7822082d4   Thomas Maier   [PATCH] pktcdvd: ...
2857
  	.name  		= DRIVER_NAME,
e454cea20   Kay Sievers   Driver-Core: exte...
2858
  	.nodename	= "pktcdvd/control",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2859
2860
2861
2862
2863
2864
  	.fops  		= &pkt_ctl_fops
  };
  
  static int __init pkt_init(void)
  {
  	int ret;
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
2865
  	mutex_init(&ctl_mutex);
64c4bc4de   Kent Overstreet   pktcdvd: convert ...
2866
2867
2868
2869
2870
2871
2872
2873
  	ret = mempool_init_kmalloc_pool(&psd_pool, PSD_POOL_SIZE,
  				    sizeof(struct packet_stacked_data));
  	if (ret)
  		return ret;
  	ret = bioset_init(&pkt_bio_set, BIO_POOL_SIZE, 0, 0);
  	if (ret) {
  		mempool_exit(&psd_pool);
  		return ret;
a1d91404c   NeilBrown   pktcdvd: use bio_...
2874
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2875

add216608   Thomas Maier   [PATCH] pktcdvd: ...
2876
  	ret = register_blkdev(pktdev_major, DRIVER_NAME);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2877
  	if (ret < 0) {
99481334b   Joe Perches   pktcdvd: convert ...
2878
2879
  		pr_err("unable to register block device
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2880
2881
  		goto out2;
  	}
add216608   Thomas Maier   [PATCH] pktcdvd: ...
2882
2883
  	if (!pktdev_major)
  		pktdev_major = ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2884

32694850a   Thomas Maier   [PATCH] pktcdvd: ...
2885
2886
2887
2888
2889
  	ret = pkt_sysfs_init();
  	if (ret)
  		goto out;
  
  	pkt_debugfs_init();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2890
2891
  	ret = misc_register(&pkt_misc);
  	if (ret) {
99481334b   Joe Perches   pktcdvd: convert ...
2892
2893
  		pr_err("unable to register misc device
  ");
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
2894
  		goto out_misc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2895
  	}
928b4d8c8   Alexey Dobriyan   proc: remove proc...
2896
  	pkt_proc = proc_mkdir("driver/"DRIVER_NAME, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2897

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2898
  	return 0;
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
2899
2900
2901
  out_misc:
  	pkt_debugfs_cleanup();
  	pkt_sysfs_cleanup();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2902
  out:
add216608   Thomas Maier   [PATCH] pktcdvd: ...
2903
  	unregister_blkdev(pktdev_major, DRIVER_NAME);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2904
  out2:
64c4bc4de   Kent Overstreet   pktcdvd: convert ...
2905
2906
  	mempool_exit(&psd_pool);
  	bioset_exit(&pkt_bio_set);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2907
2908
2909
2910
2911
  	return ret;
  }
  
  static void __exit pkt_exit(void)
  {
928b4d8c8   Alexey Dobriyan   proc: remove proc...
2912
  	remove_proc_entry("driver/"DRIVER_NAME, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2913
  	misc_deregister(&pkt_misc);
32694850a   Thomas Maier   [PATCH] pktcdvd: ...
2914
2915
2916
  
  	pkt_debugfs_cleanup();
  	pkt_sysfs_cleanup();
add216608   Thomas Maier   [PATCH] pktcdvd: ...
2917
  	unregister_blkdev(pktdev_major, DRIVER_NAME);
64c4bc4de   Kent Overstreet   pktcdvd: convert ...
2918
2919
  	mempool_exit(&psd_pool);
  	bioset_exit(&pkt_bio_set);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2920
2921
2922
2923
2924
2925
2926
2927
  }
  
  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);