pktcdvd.c revision adb9250a07edb7d41a17ba3b96fcb84c4d8e4260
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2000 Jens Axboe <axboe@suse.de> 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2001-2004 Peter Osterlund <petero2@telia.com> 4adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maier * Copyright (C) 2006 Thomas Maier <balagi@justmail.de> 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * May be copied or modified under the terms of the GNU General Public 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * License. See linux/COPYING for more information. 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 9a676f8d092f2a3aff419cacae79c80c3b7f6c0f5Peter Osterlund * Packet writing layer for ATAPI and SCSI CD-RW, DVD+RW, DVD-RW and 10a676f8d092f2a3aff419cacae79c80c3b7f6c0f5Peter Osterlund * DVD-RAM devices. 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Theory of operation: 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 14a676f8d092f2a3aff419cacae79c80c3b7f6c0f5Peter Osterlund * At the lowest level, there is the standard driver for the CD/DVD device, 15a676f8d092f2a3aff419cacae79c80c3b7f6c0f5Peter Osterlund * typically ide-cd.c or sr.c. This driver can handle read and write requests, 16a676f8d092f2a3aff419cacae79c80c3b7f6c0f5Peter Osterlund * but it doesn't know anything about the special restrictions that apply to 17a676f8d092f2a3aff419cacae79c80c3b7f6c0f5Peter Osterlund * packet writing. One restriction is that write requests must be aligned to 18a676f8d092f2a3aff419cacae79c80c3b7f6c0f5Peter Osterlund * packet boundaries on the physical media, and the size of a write request 19a676f8d092f2a3aff419cacae79c80c3b7f6c0f5Peter Osterlund * must be equal to the packet size. Another restriction is that a 20a676f8d092f2a3aff419cacae79c80c3b7f6c0f5Peter Osterlund * GPCMD_FLUSH_CACHE command has to be issued to the drive before a read 21a676f8d092f2a3aff419cacae79c80c3b7f6c0f5Peter Osterlund * command, if the previous command was a write. 22a676f8d092f2a3aff419cacae79c80c3b7f6c0f5Peter Osterlund * 23a676f8d092f2a3aff419cacae79c80c3b7f6c0f5Peter Osterlund * The purpose of the packet writing driver is to hide these restrictions from 24a676f8d092f2a3aff419cacae79c80c3b7f6c0f5Peter Osterlund * higher layers, such as file systems, and present a block device that can be 25a676f8d092f2a3aff419cacae79c80c3b7f6c0f5Peter Osterlund * randomly read and written using 2kB-sized blocks. 26a676f8d092f2a3aff419cacae79c80c3b7f6c0f5Peter Osterlund * 27a676f8d092f2a3aff419cacae79c80c3b7f6c0f5Peter Osterlund * The lowest layer in the packet writing driver is the packet I/O scheduler. 28a676f8d092f2a3aff419cacae79c80c3b7f6c0f5Peter Osterlund * Its data is defined by the struct packet_iosched and includes two bio 29a676f8d092f2a3aff419cacae79c80c3b7f6c0f5Peter Osterlund * queues with pending read and write requests. These queues are processed 30a676f8d092f2a3aff419cacae79c80c3b7f6c0f5Peter Osterlund * by the pkt_iosched_process_queue() function. The write requests in this 31a676f8d092f2a3aff419cacae79c80c3b7f6c0f5Peter Osterlund * queue are already properly aligned and sized. This layer is responsible for 32a676f8d092f2a3aff419cacae79c80c3b7f6c0f5Peter Osterlund * issuing the flush cache commands and scheduling the I/O in a good order. 33a676f8d092f2a3aff419cacae79c80c3b7f6c0f5Peter Osterlund * 34a676f8d092f2a3aff419cacae79c80c3b7f6c0f5Peter Osterlund * The next layer transforms unaligned write requests to aligned writes. This 35a676f8d092f2a3aff419cacae79c80c3b7f6c0f5Peter Osterlund * transformation requires reading missing pieces of data from the underlying 36a676f8d092f2a3aff419cacae79c80c3b7f6c0f5Peter Osterlund * block device, assembling the pieces to full packets and queuing them to the 37a676f8d092f2a3aff419cacae79c80c3b7f6c0f5Peter Osterlund * packet I/O scheduler. 38a676f8d092f2a3aff419cacae79c80c3b7f6c0f5Peter Osterlund * 39a676f8d092f2a3aff419cacae79c80c3b7f6c0f5Peter Osterlund * At the top layer there is a custom make_request_fn function that forwards 40a676f8d092f2a3aff419cacae79c80c3b7f6c0f5Peter Osterlund * read requests directly to the iosched queue and puts write requests in the 41a676f8d092f2a3aff419cacae79c80c3b7f6c0f5Peter Osterlund * unaligned write queue. A kernel thread performs the necessary read 42a676f8d092f2a3aff419cacae79c80c3b7f6c0f5Peter Osterlund * gathering to convert the unaligned writes to aligned writes and then feeds 43a676f8d092f2a3aff419cacae79c80c3b7f6c0f5Peter Osterlund * them to the packet I/O scheduler. 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *************************************************************************/ 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pktcdvd.h> 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h> 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kthread.h> 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h> 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/file.h> 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/proc_fs.h> 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/seq_file.h> 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/miscdevice.h> 587dfb71030f7636a0d65200158113c37764552f93Nigel Cunningham#include <linux/freezer.h> 591657f824e880a9bd239a3436b820d1a2986f763dJes Sorensen#include <linux/mutex.h> 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <scsi/scsi_cmnd.h> 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <scsi/scsi_ioctl.h> 62cef289633a9321cd99dd5f6cc935657dc487e9f0Peter Osterlund#include <scsi/scsi.h> 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h> 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 667822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier#define DRIVER_NAME "pktcdvd" 677822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if PACKET_DEBUG 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DPRINTK(fmt, args...) printk(KERN_NOTICE fmt, ##args) 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DPRINTK(fmt, args...) 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if PACKET_DEBUG > 1 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VPRINTK(fmt, args...) printk(KERN_NOTICE fmt, ##args) 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VPRINTK(fmt, args...) 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MAX_SPEED 0xffff 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ZONE(sector, pd) (((sector) + (pd)->offset) & ~((pd)->settings.size - 1)) 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pktcdvd_device *pkt_devs[MAX_WRITERS]; 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct proc_dir_entry *pkt_proc; 86add216608a63713b8a2c4545698d5ae02e27ac3bThomas Maierstatic int pktdev_major; 871657f824e880a9bd239a3436b820d1a2986f763dJes Sorensenstatic struct mutex ctl_mutex; /* Serialize open/close/setup/teardown */ 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic mempool_t *psd_pool; 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pkt_bio_finished(struct pktcdvd_device *pd) 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(atomic_read(&pd->cdrw.pending_bios) <= 0); 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (atomic_dec_and_test(&pd->cdrw.pending_bios)) { 957822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier VPRINTK(DRIVER_NAME": queue empty\n"); 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_set(&pd->iosched.attention, 1); 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up(&pd->wqueue); 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pkt_bio_destructor(struct bio *bio) 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(bio->bi_io_vec); 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(bio); 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct bio *pkt_bio_alloc(int nr_iovecs) 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct bio_vec *bvl = NULL; 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct bio *bio; 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bio = kmalloc(sizeof(struct bio), GFP_KERNEL); 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!bio) 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto no_bio; 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bio_init(bio); 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1171107d2e0352769b9bde6a4877c295b9309cdb877Peter Osterlund bvl = kcalloc(nr_iovecs, sizeof(struct bio_vec), GFP_KERNEL); 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!bvl) 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto no_bvl; 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bio->bi_max_vecs = nr_iovecs; 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bio->bi_io_vec = bvl; 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bio->bi_destructor = pkt_bio_destructor; 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return bio; 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds no_bvl: 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(bio); 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds no_bio: 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Allocate a packet_data struct 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 136e1bc89bc9991e994f2b3c60d9ad2fdb5ad9b10fcPeter Osterlundstatic struct packet_data *pkt_alloc_packet_data(int frames) 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct packet_data *pkt; 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1411107d2e0352769b9bde6a4877c295b9309cdb877Peter Osterlund pkt = kzalloc(sizeof(struct packet_data), GFP_KERNEL); 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!pkt) 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto no_pkt; 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 145e1bc89bc9991e994f2b3c60d9ad2fdb5ad9b10fcPeter Osterlund pkt->frames = frames; 146e1bc89bc9991e994f2b3c60d9ad2fdb5ad9b10fcPeter Osterlund pkt->w_bio = pkt_bio_alloc(frames); 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!pkt->w_bio) 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto no_bio; 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 150e1bc89bc9991e994f2b3c60d9ad2fdb5ad9b10fcPeter Osterlund for (i = 0; i < frames / FRAMES_PER_PAGE; i++) { 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt->pages[i] = alloc_page(GFP_KERNEL|__GFP_ZERO); 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!pkt->pages[i]) 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto no_page; 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&pkt->lock); 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 158e1bc89bc9991e994f2b3c60d9ad2fdb5ad9b10fcPeter Osterlund for (i = 0; i < frames; i++) { 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct bio *bio = pkt_bio_alloc(1); 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!bio) 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto no_rd_bio; 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt->r_bios[i] = bio; 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return pkt; 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsno_rd_bio: 168e1bc89bc9991e994f2b3c60d9ad2fdb5ad9b10fcPeter Osterlund for (i = 0; i < frames; i++) { 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct bio *bio = pkt->r_bios[i]; 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bio) 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bio_put(bio); 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsno_page: 175e1bc89bc9991e994f2b3c60d9ad2fdb5ad9b10fcPeter Osterlund for (i = 0; i < frames / FRAMES_PER_PAGE; i++) 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pkt->pages[i]) 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __free_page(pkt->pages[i]); 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bio_put(pkt->w_bio); 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsno_bio: 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(pkt); 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsno_pkt: 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Free a packet_data struct 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pkt_free_packet_data(struct packet_data *pkt) 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 192e1bc89bc9991e994f2b3c60d9ad2fdb5ad9b10fcPeter Osterlund for (i = 0; i < pkt->frames; i++) { 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct bio *bio = pkt->r_bios[i]; 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bio) 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bio_put(bio); 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 197e1bc89bc9991e994f2b3c60d9ad2fdb5ad9b10fcPeter Osterlund for (i = 0; i < pkt->frames / FRAMES_PER_PAGE; i++) 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __free_page(pkt->pages[i]); 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bio_put(pkt->w_bio); 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(pkt); 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pkt_shrink_pktlist(struct pktcdvd_device *pd) 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct packet_data *pkt, *next; 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(!list_empty(&pd->cdrw.pkt_active_list)); 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_entry_safe(pkt, next, &pd->cdrw.pkt_free_list, list) { 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_free_packet_data(pkt); 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 212e1bc89bc9991e994f2b3c60d9ad2fdb5ad9b10fcPeter Osterlund INIT_LIST_HEAD(&pd->cdrw.pkt_free_list); 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pkt_grow_pktlist(struct pktcdvd_device *pd, int nr_packets) 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct packet_data *pkt; 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 219e1bc89bc9991e994f2b3c60d9ad2fdb5ad9b10fcPeter Osterlund BUG_ON(!list_empty(&pd->cdrw.pkt_free_list)); 220e1bc89bc9991e994f2b3c60d9ad2fdb5ad9b10fcPeter Osterlund 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (nr_packets > 0) { 222e1bc89bc9991e994f2b3c60d9ad2fdb5ad9b10fcPeter Osterlund pkt = pkt_alloc_packet_data(pd->settings.size >> 2); 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!pkt) { 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_shrink_pktlist(pd); 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt->id = nr_packets; 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt->pd = pd; 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_add(&pkt->list, &pd->cdrw.pkt_free_list); 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nr_packets--; 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct pkt_rb_node *pkt_rbtree_next(struct pkt_rb_node *node) 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct rb_node *n = rb_next(&node->rb_node); 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!n) 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rb_entry(n, struct pkt_rb_node, rb_node); 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 243ac893963030ad70e528dc23270d499d650546a38Peter Osterlundstatic void pkt_rbtree_erase(struct pktcdvd_device *pd, struct pkt_rb_node *node) 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rb_erase(&node->rb_node, &pd->bio_queue); 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mempool_free(node, pd->rb_pool); 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd->bio_queue_size--; 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(pd->bio_queue_size < 0); 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Find the first node in the pd->bio_queue rb tree with a starting sector >= s. 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pkt_rb_node *pkt_rbtree_find(struct pktcdvd_device *pd, sector_t s) 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct rb_node *n = pd->bio_queue.rb_node; 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct rb_node *next; 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pkt_rb_node *tmp; 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!n) { 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(pd->bio_queue_size > 0); 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (;;) { 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = rb_entry(n, struct pkt_rb_node, rb_node); 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (s <= tmp->bio->bi_sector) 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds next = n->rb_left; 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds next = n->rb_right; 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!next) 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds n = next; 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (s > tmp->bio->bi_sector) { 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = pkt_rbtree_next(tmp); 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!tmp) 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(s > tmp->bio->bi_sector); 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return tmp; 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Insert a node into the pd->bio_queue rb tree. 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pkt_rbtree_insert(struct pktcdvd_device *pd, struct pkt_rb_node *node) 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct rb_node **p = &pd->bio_queue.rb_node; 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct rb_node *parent = NULL; 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sector_t s = node->bio->bi_sector; 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pkt_rb_node *tmp; 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (*p) { 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds parent = *p; 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = rb_entry(parent, struct pkt_rb_node, rb_node); 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (s < tmp->bio->bi_sector) 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p = &(*p)->rb_left; 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p = &(*p)->rb_right; 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rb_link_node(&node->rb_node, parent, p); 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rb_insert_color(&node->rb_node, &pd->bio_queue); 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd->bio_queue_size++; 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Add a bio to a single linked list defined by its head and tail pointers. 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 311ac893963030ad70e528dc23270d499d650546a38Peter Osterlundstatic void pkt_add_list_last(struct bio *bio, struct bio **list_head, struct bio **list_tail) 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bio->bi_next = NULL; 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (*list_tail) { 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON((*list_head) == NULL); 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (*list_tail)->bi_next = bio; 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (*list_tail) = bio; 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON((*list_head) != NULL); 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (*list_head) = bio; 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (*list_tail) = bio; 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Remove and return the first bio from a single linked list defined by its 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * head and tail pointers. 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct bio *pkt_get_list_first(struct bio **list_head, struct bio **list_tail) 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct bio *bio; 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (*list_head == NULL) 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bio = *list_head; 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *list_head = bio->bi_next; 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (*list_head == NULL) 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *list_tail = NULL; 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bio->bi_next = NULL; 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return bio; 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Send a packet_command to the underlying block device and 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * wait for completion. 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command *cgc) 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char sense[SCSI_SENSE_BUFFERSIZE]; 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds request_queue_t *q; 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct request *rq; 3546e9a4738c9fadb7cbdcabc1e3b415159f3741ed9Peter Zijlstra DECLARE_COMPLETION_ONSTACK(wait); 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err = 0; 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q = bdev_get_queue(pd->bdev); 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rq = blk_get_request(q, (cgc->data_direction == CGC_DATA_WRITE) ? WRITE : READ, 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __GFP_WAIT); 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rq->errors = 0; 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rq->rq_disk = pd->bdev->bd_disk; 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rq->bio = NULL; 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rq->buffer = NULL; 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rq->timeout = 60*HZ; 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rq->data = cgc->buffer; 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rq->data_len = cgc->buflen; 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rq->sense = sense; 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(sense, 0, sizeof(sense)); 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rq->sense_len = 0; 3714aff5e2333c9a1609662f2091f55c3f6fffdad36Jens Axboe rq->cmd_type = REQ_TYPE_BLOCK_PC; 3724aff5e2333c9a1609662f2091f55c3f6fffdad36Jens Axboe rq->cmd_flags |= REQ_HARDBARRIER; 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cgc->quiet) 3744aff5e2333c9a1609662f2091f55c3f6fffdad36Jens Axboe rq->cmd_flags |= REQ_QUIET; 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(rq->cmd, cgc->cmd, CDROM_PACKET_SIZE); 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sizeof(rq->cmd) > CDROM_PACKET_SIZE) 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(rq->cmd + CDROM_PACKET_SIZE, 0, sizeof(rq->cmd) - CDROM_PACKET_SIZE); 378cef289633a9321cd99dd5f6cc935657dc487e9f0Peter Osterlund rq->cmd_len = COMMAND_SIZE(rq->cmd[0]); 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rq->ref_count++; 381c00895ab2f08df7044e58ee01c38bf0a661ea0ebJens Axboe rq->end_io_data = &wait; 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rq->end_io = blk_end_sync_rq; 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds elv_add_request(q, rq, ELEVATOR_INSERT_BACK, 1); 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds generic_unplug_device(q); 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wait_for_completion(&wait); 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rq->errors) 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -EIO; 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds blk_put_request(rq); 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A generic sense dump / resolve mechanism should be implemented across 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * all ATAPI + SCSI devices. 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pkt_dump_sense(struct packet_command *cgc) 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static char *info[9] = { "No sense", "Recovered error", "Not ready", 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Medium error", "Hardware error", "Illegal request", 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Unit attention", "Data protect", "Blank check" }; 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct request_sense *sense = cgc->sense; 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4067822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier printk(DRIVER_NAME":"); 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < CDROM_PACKET_SIZE; i++) 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(" %02x", cgc->cmd[i]); 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(" - "); 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sense == NULL) { 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("no sense\n"); 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("sense %02x.%02x.%02x", sense->sense_key, sense->asc, sense->ascq); 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sense->sense_key > 8) { 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(" (INVALID)\n"); 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(" (%s)\n", info[sense->sense_key]); 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * flush the drive cache to media 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pkt_flush_cache(struct pktcdvd_device *pd) 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct packet_command cgc; 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.cmd[0] = GPCMD_FLUSH_CACHE; 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.quiet = 1; 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the IMMED bit -- we default to not setting it, although that 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * would allow a much faster close, this is safer 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.cmd[1] = 1 << 1; 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return pkt_generic_packet(pd, &cgc); 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * speed is given as the normal factor, e.g. 4 for 4x 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pkt_set_speed(struct pktcdvd_device *pd, unsigned write_speed, unsigned read_speed) 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct packet_command cgc; 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct request_sense sense; 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.sense = &sense; 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.cmd[0] = GPCMD_SET_SPEED; 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.cmd[2] = (read_speed >> 8) & 0xff; 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.cmd[3] = read_speed & 0xff; 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.cmd[4] = (write_speed >> 8) & 0xff; 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.cmd[5] = write_speed & 0xff; 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ret = pkt_generic_packet(pd, &cgc))) 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_dump_sense(&cgc); 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Queue a bio for processing by the low-level CD device. Must be called 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * from process context. 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 47446c271bedd2c8444b1d05bc44928beec0c07debcPeter Osterlundstatic void pkt_queue_bio(struct pktcdvd_device *pd, struct bio *bio) 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&pd->iosched.lock); 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bio_data_dir(bio) == READ) { 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_add_list_last(bio, &pd->iosched.read_queue, 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &pd->iosched.read_queue_tail); 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_add_list_last(bio, &pd->iosched.write_queue, 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &pd->iosched.write_queue_tail); 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&pd->iosched.lock); 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_set(&pd->iosched.attention, 1); 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up(&pd->wqueue); 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Process the queued read/write requests. This function handles special 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * requirements for CDRW drives: 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - A cache flush command must be inserted before a read request if the 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * previous request was a write. 49546c271bedd2c8444b1d05bc44928beec0c07debcPeter Osterlund * - Switching between reading and writing is slow, so don't do it more often 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * than necessary. 49746c271bedd2c8444b1d05bc44928beec0c07debcPeter Osterlund * - Optimize for throughput at the expense of latency. This means that streaming 49846c271bedd2c8444b1d05bc44928beec0c07debcPeter Osterlund * writes will never be interrupted by a read, but if the drive has to seek 49946c271bedd2c8444b1d05bc44928beec0c07debcPeter Osterlund * before the next write, switch to reading instead if there are any pending 50046c271bedd2c8444b1d05bc44928beec0c07debcPeter Osterlund * read requests. 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - Set the read speed according to current usage pattern. When only reading 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * from the device, it's best to use the highest possible read speed, but 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * when switching often between reading and writing, it's better to have the 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * same read and write speeds. 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pkt_iosched_process_queue(struct pktcdvd_device *pd) 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (atomic_read(&pd->iosched.attention) == 0) 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_set(&pd->iosched.attention, 0); 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (;;) { 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct bio *bio; 51546c271bedd2c8444b1d05bc44928beec0c07debcPeter Osterlund int reads_queued, writes_queued; 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&pd->iosched.lock); 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reads_queued = (pd->iosched.read_queue != NULL); 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writes_queued = (pd->iosched.write_queue != NULL); 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&pd->iosched.lock); 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!reads_queued && !writes_queued) 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pd->iosched.writing) { 52646c271bedd2c8444b1d05bc44928beec0c07debcPeter Osterlund int need_write_seek = 1; 52746c271bedd2c8444b1d05bc44928beec0c07debcPeter Osterlund spin_lock(&pd->iosched.lock); 52846c271bedd2c8444b1d05bc44928beec0c07debcPeter Osterlund bio = pd->iosched.write_queue; 52946c271bedd2c8444b1d05bc44928beec0c07debcPeter Osterlund spin_unlock(&pd->iosched.lock); 53046c271bedd2c8444b1d05bc44928beec0c07debcPeter Osterlund if (bio && (bio->bi_sector == pd->iosched.last_write)) 53146c271bedd2c8444b1d05bc44928beec0c07debcPeter Osterlund need_write_seek = 0; 53246c271bedd2c8444b1d05bc44928beec0c07debcPeter Osterlund if (need_write_seek && reads_queued) { 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (atomic_read(&pd->cdrw.pending_bios) > 0) { 5347822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier VPRINTK(DRIVER_NAME": write, waiting\n"); 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_flush_cache(pd); 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd->iosched.writing = 0; 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!reads_queued && writes_queued) { 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (atomic_read(&pd->cdrw.pending_bios) > 0) { 5437822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier VPRINTK(DRIVER_NAME": read, waiting\n"); 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd->iosched.writing = 1; 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&pd->iosched.lock); 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pd->iosched.writing) { 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bio = pkt_get_list_first(&pd->iosched.write_queue, 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &pd->iosched.write_queue_tail); 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bio = pkt_get_list_first(&pd->iosched.read_queue, 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &pd->iosched.read_queue_tail); 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&pd->iosched.lock); 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!bio) 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bio_data_dir(bio) == READ) 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd->iosched.successive_reads += bio->bi_size >> 10; 56546c271bedd2c8444b1d05bc44928beec0c07debcPeter Osterlund else { 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd->iosched.successive_reads = 0; 56746c271bedd2c8444b1d05bc44928beec0c07debcPeter Osterlund pd->iosched.last_write = bio->bi_sector + bio_sectors(bio); 56846c271bedd2c8444b1d05bc44928beec0c07debcPeter Osterlund } 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pd->iosched.successive_reads >= HI_SPEED_SWITCH) { 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pd->read_speed == pd->write_speed) { 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd->read_speed = MAX_SPEED; 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_set_speed(pd, pd->write_speed, pd->read_speed); 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pd->read_speed != pd->write_speed) { 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd->read_speed = pd->write_speed; 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_set_speed(pd, pd->write_speed, pd->read_speed); 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_inc(&pd->cdrw.pending_bios); 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds generic_make_request(bio); 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Special care is needed if the underlying block device has a small 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * max_phys_segments value. 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pkt_set_segment_merging(struct pktcdvd_device *pd, request_queue_t *q) 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((pd->settings.size << 9) / CD_FRAMESIZE <= q->max_phys_segments) { 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The cdrom device can handle one segment/frame 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_bit(PACKET_MERGE_SEGS, &pd->flags); 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if ((pd->settings.size << 9) / PAGE_SIZE <= q->max_phys_segments) { 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We can handle this case at the expense of some extra memory 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * copies during write operations 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_bit(PACKET_MERGE_SEGS, &pd->flags); 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 6067822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier printk(DRIVER_NAME": cdrom max_phys_segments too small\n"); 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copy CD_FRAMESIZE bytes from src_bio into a destination page 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pkt_copy_bio_data(struct bio *src_bio, int seg, int offs, struct page *dst_page, int dst_offs) 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int copy_size = CD_FRAMESIZE; 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (copy_size > 0) { 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct bio_vec *src_bvl = bio_iovec_idx(src_bio, seg); 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void *vfrom = kmap_atomic(src_bvl->bv_page, KM_USER0) + 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds src_bvl->bv_offset + offs; 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void *vto = page_address(dst_page) + dst_offs; 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int len = min_t(int, copy_size, src_bvl->bv_len - offs); 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(len < 0); 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(vto, vfrom, len); 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kunmap_atomic(vfrom, KM_USER0); 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds seg++; 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offs = 0; 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dst_offs += len; 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds copy_size -= len; 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copy all data for this packet to pkt->pages[], so that 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a) The number of required segments for the write bio is minimized, which 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is necessary for some scsi controllers. 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * b) The data can be used as cache to avoid read requests if we receive a 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * new write request for the same zone. 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6437277232374680595cdbc774fd246b206f56db015Peter Osterlundstatic void pkt_make_local_copy(struct packet_data *pkt, struct bio_vec *bvec) 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int f, p, offs; 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Copy all data to pkt->pages[] */ 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p = 0; 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offs = 0; 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (f = 0; f < pkt->frames; f++) { 6517277232374680595cdbc774fd246b206f56db015Peter Osterlund if (bvec[f].bv_page != pkt->pages[p]) { 6527277232374680595cdbc774fd246b206f56db015Peter Osterlund void *vfrom = kmap_atomic(bvec[f].bv_page, KM_USER0) + bvec[f].bv_offset; 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void *vto = page_address(pkt->pages[p]) + offs; 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(vto, vfrom, CD_FRAMESIZE); 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kunmap_atomic(vfrom, KM_USER0); 6567277232374680595cdbc774fd246b206f56db015Peter Osterlund bvec[f].bv_page = pkt->pages[p]; 6577277232374680595cdbc774fd246b206f56db015Peter Osterlund bvec[f].bv_offset = offs; 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 6597277232374680595cdbc774fd246b206f56db015Peter Osterlund BUG_ON(bvec[f].bv_offset != offs); 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offs += CD_FRAMESIZE; 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (offs >= PAGE_SIZE) { 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offs = 0; 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p++; 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pkt_end_io_read(struct bio *bio, unsigned int bytes_done, int err) 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct packet_data *pkt = bio->bi_private; 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pktcdvd_device *pd = pkt->pd; 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(!pd); 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bio->bi_size) 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VPRINTK("pkt_end_io_read: bio=%p sec0=%llx sec=%llx err=%d\n", bio, 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned long long)pkt->sector, (unsigned long long)bio->bi_sector, err); 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_inc(&pkt->io_errors); 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (atomic_dec_and_test(&pkt->io_wait)) { 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_inc(&pkt->run_sm); 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up(&pd->wqueue); 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_bio_finished(pd); 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pkt_end_io_packet_write(struct bio *bio, unsigned int bytes_done, int err) 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct packet_data *pkt = bio->bi_private; 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pktcdvd_device *pd = pkt->pd; 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(!pd); 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bio->bi_size) 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VPRINTK("pkt_end_io_packet_write: id=%d, err=%d\n", pkt->id, err); 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd->stats.pkt_ended++; 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_bio_finished(pd); 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_dec(&pkt->io_wait); 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_inc(&pkt->run_sm); 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up(&pd->wqueue); 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Schedule reads for the holes in a packet 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt) 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int frames_read = 0; 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct bio *bio; 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int f; 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char written[PACKET_MAX_SIZE]; 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(!pkt->orig_bios); 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_set(&pkt->io_wait, 0); 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_set(&pkt->io_errors, 0); 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Figure out which frames we need to read before we can write. 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(written, 0, sizeof(written)); 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&pkt->lock); 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (bio = pkt->orig_bios; bio; bio = bio->bi_next) { 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int first_frame = (bio->bi_sector - pkt->sector) / (CD_FRAMESIZE >> 9); 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int num_frames = bio->bi_size / CD_FRAMESIZE; 73506e7ab53f4a1e8bbf66c3985968468949d74d006Peter Osterlund pd->stats.secs_w += num_frames * (CD_FRAMESIZE >> 9); 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(first_frame < 0); 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(first_frame + num_frames > pkt->frames); 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (f = first_frame; f < first_frame + num_frames; f++) 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds written[f] = 1; 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&pkt->lock); 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 74306e7ab53f4a1e8bbf66c3985968468949d74d006Peter Osterlund if (pkt->cache_valid) { 74406e7ab53f4a1e8bbf66c3985968468949d74d006Peter Osterlund VPRINTK("pkt_gather_data: zone %llx cached\n", 74506e7ab53f4a1e8bbf66c3985968468949d74d006Peter Osterlund (unsigned long long)pkt->sector); 74606e7ab53f4a1e8bbf66c3985968468949d74d006Peter Osterlund goto out_account; 74706e7ab53f4a1e8bbf66c3985968468949d74d006Peter Osterlund } 74806e7ab53f4a1e8bbf66c3985968468949d74d006Peter Osterlund 7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Schedule reads for missing parts of the packet. 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (f = 0; f < pkt->frames; f++) { 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int p, offset; 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (written[f]) 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bio = pkt->r_bios[f]; 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bio_init(bio); 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bio->bi_max_vecs = 1; 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bio->bi_sector = pkt->sector + f * (CD_FRAMESIZE >> 9); 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bio->bi_bdev = pd->bdev; 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bio->bi_end_io = pkt_end_io_read; 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bio->bi_private = pkt; 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p = (f * CD_FRAMESIZE) / PAGE_SIZE; 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset = (f * CD_FRAMESIZE) % PAGE_SIZE; 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VPRINTK("pkt_gather_data: Adding frame %d, page:%p offs:%d\n", 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds f, pkt->pages[p], offset); 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!bio_add_page(bio, pkt->pages[p], CD_FRAMESIZE, offset)) 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG(); 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_inc(&pkt->io_wait); 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bio->bi_rw = READ; 77346c271bedd2c8444b1d05bc44928beec0c07debcPeter Osterlund pkt_queue_bio(pd, bio); 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds frames_read++; 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_account: 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VPRINTK("pkt_gather_data: need %d frames for zone %llx\n", 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds frames_read, (unsigned long long)pkt->sector); 7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd->stats.pkt_started++; 7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd->stats.secs_rg += frames_read * (CD_FRAMESIZE >> 9); 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Find a packet matching zone, or the least recently used packet if 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * there is no match. 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct packet_data *pkt_get_packet_data(struct pktcdvd_device *pd, int zone) 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct packet_data *pkt; 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_entry(pkt, &pd->cdrw.pkt_free_list, list) { 7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pkt->sector == zone || pkt->list.next == &pd->cdrw.pkt_free_list) { 7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del_init(&pkt->list); 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pkt->sector != zone) 7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt->cache_valid = 0; 797610827dee82731c7be5a135d750d194ac56881a9Peter Osterlund return pkt; 7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 800610827dee82731c7be5a135d750d194ac56881a9Peter Osterlund BUG(); 801610827dee82731c7be5a135d750d194ac56881a9Peter Osterlund return NULL; 8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pkt_put_packet_data(struct pktcdvd_device *pd, struct packet_data *pkt) 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pkt->cache_valid) { 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_add(&pkt->list, &pd->cdrw.pkt_free_list); 8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_add_tail(&pkt->list, &pd->cdrw.pkt_free_list); 8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * recover a failed write, query for relocation if possible 8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns 1 if recovery is possible, or 0 if not 8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pkt_start_recovery(struct packet_data *pkt) 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * FIXME. We need help from the file system to implement 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * recovery handling. 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct request *rq = pkt->rq; 8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pktcdvd_device *pd = rq->rq_disk->private_data; 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct block_device *pkt_bdev; 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct super_block *sb = NULL; 8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long old_block, new_block; 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sector_t new_sector; 8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_bdev = bdget(kdev_t_to_nr(pd->pkt_dev)); 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pkt_bdev) { 8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sb = get_super(pkt_bdev); 8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bdput(pkt_bdev); 8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!sb) 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!sb->s_op || !sb->s_op->relocate_blocks) 8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds old_block = pkt->sector / (CD_FRAMESIZE >> 9); 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sb->s_op->relocate_blocks(sb, old_block, &new_block)) 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_sector = new_block * (CD_FRAMESIZE >> 9); 8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt->sector = new_sector; 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt->bio->bi_sector = new_sector; 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt->bio->bi_next = NULL; 8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt->bio->bi_flags = 1 << BIO_UPTODATE; 8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt->bio->bi_idx = 0; 8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(pkt->bio->bi_rw != (1 << BIO_RW)); 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(pkt->bio->bi_vcnt != pkt->frames); 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(pkt->bio->bi_size != pkt->frames * CD_FRAMESIZE); 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(pkt->bio->bi_end_io != pkt_end_io_packet_write); 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(pkt->bio->bi_private != pkt); 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds drop_super(sb); 8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds drop_super(sb); 8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void pkt_set_state(struct packet_data *pkt, enum packet_data_state state) 8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if PACKET_DEBUG > 1 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static const char *state_name[] = { 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "IDLE", "WAITING", "READ_WAIT", "WRITE_WAIT", "RECOVERY", "FINISHED" 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }; 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enum packet_data_state old_state = pkt->state; 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VPRINTK("pkt %2d : s=%6llx %s -> %s\n", pkt->id, (unsigned long long)pkt->sector, 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds state_name[old_state], state_name[state]); 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt->state = state; 8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Scan the work queue to see if we can start a new packet. 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returns non-zero if any work was done. 8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pkt_handle_queue(struct pktcdvd_device *pd) 8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct packet_data *pkt, *p; 8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct bio *bio = NULL; 8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sector_t zone = 0; /* Suppress gcc warning */ 8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pkt_rb_node *node, *first_node; 8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct rb_node *n; 8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VPRINTK("handle_queue\n"); 8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_set(&pd->scan_queue, 0); 9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (list_empty(&pd->cdrw.pkt_free_list)) { 9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VPRINTK("handle_queue: no pkt\n"); 9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Try to find a zone we are not already working on. 9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&pd->lock); 9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds first_node = pkt_rbtree_find(pd, pd->current_sector); 9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!first_node) { 9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds n = rb_first(&pd->bio_queue); 9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (n) 9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds first_node = rb_entry(n, struct pkt_rb_node, rb_node); 9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds node = first_node; 9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (node) { 9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bio = node->bio; 9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zone = ZONE(bio->bi_sector, pd); 9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_entry(p, &pd->cdrw.pkt_active_list, list) { 9227baeb6a5ccab2d472679a053e64a63ac423c3a42Peter Osterlund if (p->sector == zone) { 9237baeb6a5ccab2d472679a053e64a63ac423c3a42Peter Osterlund bio = NULL; 9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto try_next_bio; 9257baeb6a5ccab2d472679a053e64a63ac423c3a42Peter Osterlund } 9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstry_next_bio: 9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds node = pkt_rbtree_next(node); 9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!node) { 9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds n = rb_first(&pd->bio_queue); 9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (n) 9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds node = rb_entry(n, struct pkt_rb_node, rb_node); 9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (node == first_node) 9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds node = NULL; 9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&pd->lock); 9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!bio) { 9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VPRINTK("handle_queue: no bio\n"); 9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt = pkt_get_packet_data(pd, zone); 9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd->current_sector = zone + pd->settings.size; 9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt->sector = zone; 948e1bc89bc9991e994f2b3c60d9ad2fdb5ad9b10fcPeter Osterlund BUG_ON(pkt->frames != pd->settings.size >> 2); 9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt->write_size = 0; 9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Scan work queue for bios in the same zone and link them 9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to this packet. 9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&pd->lock); 9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VPRINTK("pkt_handle_queue: looking for zone %llx\n", (unsigned long long)zone); 9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ((node = pkt_rbtree_find(pd, zone)) != NULL) { 9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bio = node->bio; 9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VPRINTK("pkt_handle_queue: found zone=%llx\n", 9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned long long)ZONE(bio->bi_sector, pd)); 9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ZONE(bio->bi_sector, pd) != zone) 9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_rbtree_erase(pd, node); 9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&pkt->lock); 9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_add_list_last(bio, &pkt->orig_bios, &pkt->orig_bios_tail); 9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt->write_size += bio->bi_size / CD_FRAMESIZE; 9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&pkt->lock); 9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&pd->lock); 9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt->sleep_time = max(PACKET_WAIT_TIME, 1); 9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_set_state(pkt, PACKET_WAITING_STATE); 9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_set(&pkt->run_sm, 1); 9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&pd->cdrw.active_list_lock); 9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_add(&pkt->list, &pd->cdrw.pkt_active_list); 9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&pd->cdrw.active_list_lock); 9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Assemble a bio to write one packet and queue the bio for processing 9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * by the underlying block device. 9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pkt_start_write(struct pktcdvd_device *pd, struct packet_data *pkt) 9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct bio *bio; 9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int f; 9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int frames_write; 9917277232374680595cdbc774fd246b206f56db015Peter Osterlund struct bio_vec *bvec = pkt->w_bio->bi_io_vec; 9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (f = 0; f < pkt->frames; f++) { 9947277232374680595cdbc774fd246b206f56db015Peter Osterlund bvec[f].bv_page = pkt->pages[(f * CD_FRAMESIZE) / PAGE_SIZE]; 9957277232374680595cdbc774fd246b206f56db015Peter Osterlund bvec[f].bv_offset = (f * CD_FRAMESIZE) % PAGE_SIZE; 9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 9997277232374680595cdbc774fd246b206f56db015Peter Osterlund * Fill-in bvec with data from orig_bios. 10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds frames_write = 0; 10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&pkt->lock); 10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (bio = pkt->orig_bios; bio; bio = bio->bi_next) { 10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int segment = bio->bi_idx; 10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int src_offs = 0; 10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int first_frame = (bio->bi_sector - pkt->sector) / (CD_FRAMESIZE >> 9); 10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int num_frames = bio->bi_size / CD_FRAMESIZE; 10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(first_frame < 0); 10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(first_frame + num_frames > pkt->frames); 10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (f = first_frame; f < first_frame + num_frames; f++) { 10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct bio_vec *src_bvl = bio_iovec_idx(bio, segment); 10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (src_offs >= src_bvl->bv_len) { 10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds src_offs -= src_bvl->bv_len; 10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds segment++; 10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(segment >= bio->bi_vcnt); 10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds src_bvl = bio_iovec_idx(bio, segment); 10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (src_bvl->bv_len - src_offs >= CD_FRAMESIZE) { 10217277232374680595cdbc774fd246b206f56db015Peter Osterlund bvec[f].bv_page = src_bvl->bv_page; 10227277232374680595cdbc774fd246b206f56db015Peter Osterlund bvec[f].bv_offset = src_bvl->bv_offset + src_offs; 10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_copy_bio_data(bio, segment, src_offs, 10257277232374680595cdbc774fd246b206f56db015Peter Osterlund bvec[f].bv_page, bvec[f].bv_offset); 10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds src_offs += CD_FRAMESIZE; 10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds frames_write++; 10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_set_state(pkt, PACKET_WRITE_WAIT_STATE); 10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&pkt->lock); 10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VPRINTK("pkt_start_write: Writing %d frames for zone %llx\n", 10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds frames_write, (unsigned long long)pkt->sector); 10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(frames_write != pkt->write_size); 10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (test_bit(PACKET_MERGE_SEGS, &pd->flags) || (pkt->write_size < pkt->frames)) { 10397277232374680595cdbc774fd246b206f56db015Peter Osterlund pkt_make_local_copy(pkt, bvec); 10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt->cache_valid = 1; 10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt->cache_valid = 0; 10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Start the write request */ 10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bio_init(pkt->w_bio); 10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt->w_bio->bi_max_vecs = PACKET_MAX_SIZE; 10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt->w_bio->bi_sector = pkt->sector; 10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt->w_bio->bi_bdev = pd->bdev; 10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt->w_bio->bi_end_io = pkt_end_io_packet_write; 10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt->w_bio->bi_private = pkt; 10527277232374680595cdbc774fd246b206f56db015Peter Osterlund for (f = 0; f < pkt->frames; f++) 10537277232374680595cdbc774fd246b206f56db015Peter Osterlund if (!bio_add_page(pkt->w_bio, bvec[f].bv_page, CD_FRAMESIZE, bvec[f].bv_offset)) 10547277232374680595cdbc774fd246b206f56db015Peter Osterlund BUG(); 10557822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier VPRINTK(DRIVER_NAME": vcnt=%d\n", pkt->w_bio->bi_vcnt); 10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_set(&pkt->io_wait, 1); 10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt->w_bio->bi_rw = WRITE; 105946c271bedd2c8444b1d05bc44928beec0c07debcPeter Osterlund pkt_queue_bio(pd, pkt->w_bio); 10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pkt_finish_packet(struct packet_data *pkt, int uptodate) 10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct bio *bio, *next; 10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!uptodate) 10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt->cache_valid = 0; 10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Finish all bios corresponding to this packet */ 10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bio = pkt->orig_bios; 10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (bio) { 10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds next = bio->bi_next; 10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bio->bi_next = NULL; 10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bio_endio(bio, bio->bi_size, uptodate ? 0 : -EIO); 10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bio = next; 10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt->orig_bios = pkt->orig_bios_tail = NULL; 10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pkt_run_state_machine(struct pktcdvd_device *pd, struct packet_data *pkt) 10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int uptodate; 10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VPRINTK("run_state_machine: pkt %d\n", pkt->id); 10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (;;) { 10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (pkt->state) { 10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PACKET_WAITING_STATE: 10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((pkt->write_size < pkt->frames) && (pkt->sleep_time > 0)) 10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt->sleep_time = 0; 10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_gather_data(pd, pkt); 10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_set_state(pkt, PACKET_READ_WAIT_STATE); 10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PACKET_READ_WAIT_STATE: 10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (atomic_read(&pkt->io_wait) > 0) 10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (atomic_read(&pkt->io_errors) > 0) { 11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_set_state(pkt, PACKET_RECOVERY_STATE); 11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_start_write(pd, pkt); 11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PACKET_WRITE_WAIT_STATE: 11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (atomic_read(&pkt->io_wait) > 0) 11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (test_bit(BIO_UPTODATE, &pkt->w_bio->bi_flags)) { 11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_set_state(pkt, PACKET_FINISHED_STATE); 11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_set_state(pkt, PACKET_RECOVERY_STATE); 11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PACKET_RECOVERY_STATE: 11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pkt_start_recovery(pkt)) { 11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_start_write(pd, pkt); 11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VPRINTK("No recovery possible\n"); 11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_set_state(pkt, PACKET_FINISHED_STATE); 11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PACKET_FINISHED_STATE: 11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uptodate = test_bit(BIO_UPTODATE, &pkt->w_bio->bi_flags); 11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_finish_packet(pkt, uptodate); 11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG(); 11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pkt_handle_packets(struct pktcdvd_device *pd) 11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct packet_data *pkt, *next; 11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VPRINTK("pkt_handle_packets\n"); 11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Run state machine for active packets 11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_entry(pkt, &pd->cdrw.pkt_active_list, list) { 11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (atomic_read(&pkt->run_sm) > 0) { 11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_set(&pkt->run_sm, 0); 11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_run_state_machine(pd, pkt); 11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Move no longer active packets to the free list 11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&pd->cdrw.active_list_lock); 11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_entry_safe(pkt, next, &pd->cdrw.pkt_active_list, list) { 11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pkt->state == PACKET_FINISHED_STATE) { 11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del(&pkt->list); 11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_put_packet_data(pd, pkt); 11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_set_state(pkt, PACKET_IDLE_STATE); 11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_set(&pd->scan_queue, 1); 11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&pd->cdrw.active_list_lock); 11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pkt_count_states(struct pktcdvd_device *pd, int *states) 11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct packet_data *pkt; 11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1176ae7642bb05623988d8ca82b332dad1ed7bdb8cebPeter Osterlund for (i = 0; i < PACKET_NUM_STATES; i++) 11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds states[i] = 0; 11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&pd->cdrw.active_list_lock); 11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_entry(pkt, &pd->cdrw.pkt_active_list, list) { 11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds states[pkt->state]++; 11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&pd->cdrw.active_list_lock); 11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * kcdrwd is woken up when writes have been queued for one of our 11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * registered devices 11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int kcdrwd(void *foobar) 11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pktcdvd_device *pd = foobar; 11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct packet_data *pkt; 11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds long min_sleep_time, residue; 11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_user_nice(current, -20); 11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (;;) { 11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DECLARE_WAITQUEUE(wait, current); 12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wait until there is something to do 12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds add_wait_queue(&pd->wqueue, &wait); 12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (;;) { 12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_current_state(TASK_INTERRUPTIBLE); 12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check if we need to run pkt_handle_queue */ 12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (atomic_read(&pd->scan_queue) > 0) 12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto work_to_do; 12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check if we need to run the state machine for some packet */ 12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_entry(pkt, &pd->cdrw.pkt_active_list, list) { 12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (atomic_read(&pkt->run_sm) > 0) 12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto work_to_do; 12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check if we need to process the iosched queues */ 12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (atomic_read(&pd->iosched.attention) != 0) 12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto work_to_do; 12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Otherwise, go to sleep */ 12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (PACKET_DEBUG > 1) { 12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int states[PACKET_NUM_STATES]; 12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_count_states(pd, states); 12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VPRINTK("kcdrwd: i:%d ow:%d rw:%d ww:%d rec:%d fin:%d\n", 12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds states[0], states[1], states[2], states[3], 12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds states[4], states[5]); 12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds min_sleep_time = MAX_SCHEDULE_TIMEOUT; 12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_entry(pkt, &pd->cdrw.pkt_active_list, list) { 12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pkt->sleep_time && pkt->sleep_time < min_sleep_time) 12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds min_sleep_time = pkt->sleep_time; 12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds generic_unplug_device(bdev_get_queue(pd->bdev)); 12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VPRINTK("kcdrwd: sleeping\n"); 12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds residue = schedule_timeout(min_sleep_time); 12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VPRINTK("kcdrwd: wake up\n"); 12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* make swsusp happy with our thread */ 12443e1d1d28d99dabe63c64f7f40f1ca1d646de1f73Christoph Lameter try_to_freeze(); 12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_entry(pkt, &pd->cdrw.pkt_active_list, list) { 12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!pkt->sleep_time) 12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt->sleep_time -= min_sleep_time - residue; 12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pkt->sleep_time <= 0) { 12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt->sleep_time = 0; 12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_inc(&pkt->run_sm); 12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (signal_pending(current)) { 12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flush_signals(current); 12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (kthread_should_stop()) 12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldswork_to_do: 12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_current_state(TASK_RUNNING); 12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds remove_wait_queue(&pd->wqueue, &wait); 12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (kthread_should_stop()) 12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if pkt_handle_queue returns true, we can queue 12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * another request. 12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (pkt_handle_queue(pd)) 12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ; 12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Handle packet state machine 12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_handle_packets(pd); 12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Handle iosched queues 12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_iosched_process_queue(pd); 12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pkt_print_settings(struct pktcdvd_device *pd) 12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12927822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier printk(DRIVER_NAME": %s packets, ", pd->settings.fp ? "Fixed" : "Variable"); 12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%u blocks, ", pd->settings.size >> 2); 12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("Mode-%c disc\n", pd->settings.block_mode == 8 ? '1' : '2'); 12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pkt_mode_sense(struct pktcdvd_device *pd, struct packet_command *cgc, int page_code, int page_control) 12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(cgc->cmd, 0, sizeof(cgc->cmd)); 13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc->cmd[0] = GPCMD_MODE_SENSE_10; 13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc->cmd[2] = page_code | (page_control << 6); 13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc->cmd[7] = cgc->buflen >> 8; 13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc->cmd[8] = cgc->buflen & 0xff; 13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc->data_direction = CGC_DATA_READ; 13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return pkt_generic_packet(pd, cgc); 13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pkt_mode_select(struct pktcdvd_device *pd, struct packet_command *cgc) 13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(cgc->cmd, 0, sizeof(cgc->cmd)); 13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(cgc->buffer, 0, 2); 13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc->cmd[0] = GPCMD_MODE_SELECT_10; 13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc->cmd[1] = 0x10; /* PF */ 13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc->cmd[7] = cgc->buflen >> 8; 13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc->cmd[8] = cgc->buflen & 0xff; 13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc->data_direction = CGC_DATA_WRITE; 13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return pkt_generic_packet(pd, cgc); 13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pkt_get_disc_info(struct pktcdvd_device *pd, disc_information *di) 13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct packet_command cgc; 13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* set up command and get the disc info */ 13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_cdrom_command(&cgc, di, sizeof(*di), CGC_DATA_READ); 13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.cmd[0] = GPCMD_READ_DISC_INFO; 13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.cmd[8] = cgc.buflen = 2; 13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.quiet = 1; 13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ret = pkt_generic_packet(pd, &cgc))) 13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* not all drives have the same disc_info length, so requeue 13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * packet with the length the drive tells us it can supply 13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.buflen = be16_to_cpu(di->disc_information_length) + 13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(di->disc_information_length); 13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cgc.buflen > sizeof(disc_information)) 13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.buflen = sizeof(disc_information); 13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.cmd[8] = cgc.buflen; 13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return pkt_generic_packet(pd, &cgc); 13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pkt_get_track_info(struct pktcdvd_device *pd, __u16 track, __u8 type, track_information *ti) 13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct packet_command cgc; 13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_cdrom_command(&cgc, ti, 8, CGC_DATA_READ); 13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.cmd[0] = GPCMD_READ_TRACK_RZONE_INFO; 13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.cmd[1] = type & 3; 13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.cmd[4] = (track & 0xff00) >> 8; 13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.cmd[5] = track & 0xff; 13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.cmd[8] = 8; 13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.quiet = 1; 13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ret = pkt_generic_packet(pd, &cgc))) 13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.buflen = be16_to_cpu(ti->track_information_length) + 13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(ti->track_information_length); 13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cgc.buflen > sizeof(track_information)) 13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.buflen = sizeof(track_information); 13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.cmd[8] = cgc.buflen; 13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return pkt_generic_packet(pd, &cgc); 13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pkt_get_last_written(struct pktcdvd_device *pd, long *last_written) 13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds disc_information di; 13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds track_information ti; 13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u32 last_track; 13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = -1; 13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ret = pkt_get_disc_info(pd, &di))) 13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds last_track = (di.last_track_msb << 8) | di.last_track_lsb; 13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ret = pkt_get_track_info(pd, last_track, 1, &ti))) 13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if this track is blank, try the previous. */ 13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ti.blank) { 13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds last_track--; 13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ret = pkt_get_track_info(pd, last_track, 1, &ti))) 13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if last recorded field is valid, return it. */ 13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ti.lra_v) { 13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *last_written = be32_to_cpu(ti.last_rec_address); 13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* make it up instead */ 14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *last_written = be32_to_cpu(ti.track_start) + 14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds be32_to_cpu(ti.track_size); 14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ti.free_blocks) 14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *last_written -= (be32_to_cpu(ti.free_blocks) + 7); 14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * write mode select package based on pd->settings 14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pkt_set_write_settings(struct pktcdvd_device *pd) 14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct packet_command cgc; 14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct request_sense sense; 14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_param_page *wp; 14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char buffer[128]; 14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret, size; 14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* doesn't apply to DVD+RW or DVD-RAM */ 14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((pd->mmc3_profile == 0x1a) || (pd->mmc3_profile == 0x12)) 14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(buffer, 0, sizeof(buffer)); 14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_cdrom_command(&cgc, buffer, sizeof(*wp), CGC_DATA_READ); 14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.sense = &sense; 14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ret = pkt_mode_sense(pd, &cgc, GPMODE_WRITE_PARMS_PAGE, 0))) { 14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_dump_sense(&cgc); 14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size = 2 + ((buffer[0] << 8) | (buffer[1] & 0xff)); 14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd->mode_offset = (buffer[6] << 8) | (buffer[7] & 0xff); 14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (size > sizeof(buffer)) 14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size = sizeof(buffer); 14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * now get it all 14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_cdrom_command(&cgc, buffer, size, CGC_DATA_READ); 14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.sense = &sense; 14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ret = pkt_mode_sense(pd, &cgc, GPMODE_WRITE_PARMS_PAGE, 0))) { 14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_dump_sense(&cgc); 14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * write page is offset header + block descriptor length 14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wp = (write_param_page *) &buffer[sizeof(struct mode_page_header) + pd->mode_offset]; 14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wp->fp = pd->settings.fp; 14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wp->track_mode = pd->settings.track_mode; 14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wp->write_type = pd->settings.write_type; 14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wp->data_block_type = pd->settings.block_mode; 14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wp->multi_session = 0; 14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef PACKET_USE_LS 14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wp->link_size = 7; 14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wp->ls_v = 1; 14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (wp->data_block_type == PACKET_BLOCK_MODE1) { 14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wp->session_format = 0; 14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wp->subhdr2 = 0x20; 14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (wp->data_block_type == PACKET_BLOCK_MODE2) { 14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wp->session_format = 0x20; 14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wp->subhdr2 = 8; 14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wp->mcn[0] = 0x80; 14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(&wp->mcn[1], PACKET_MCN, sizeof(wp->mcn) - 1); 14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * paranoia 14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14777822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier printk(DRIVER_NAME": write mode wrong %d\n", wp->data_block_type); 14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wp->packet_size = cpu_to_be32(pd->settings.size >> 2); 14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.buflen = cgc.cmd[8] = size; 14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ret = pkt_mode_select(pd, &cgc))) { 14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_dump_sense(&cgc); 14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_print_settings(pd); 14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 14937c613d593370292d1685f5794c743a2323be3a09Peter Osterlund * 1 -- we can write to this track, 0 -- we can't 14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1495ab863ec342cf148d02ed180b8ecf3a71a024e4bePeter Osterlundstatic int pkt_writable_track(struct pktcdvd_device *pd, track_information *ti) 14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1497ab863ec342cf148d02ed180b8ecf3a71a024e4bePeter Osterlund switch (pd->mmc3_profile) { 1498ab863ec342cf148d02ed180b8ecf3a71a024e4bePeter Osterlund case 0x1a: /* DVD+RW */ 1499ab863ec342cf148d02ed180b8ecf3a71a024e4bePeter Osterlund case 0x12: /* DVD-RAM */ 1500ab863ec342cf148d02ed180b8ecf3a71a024e4bePeter Osterlund /* The track is always writable on DVD+RW/DVD-RAM */ 1501ab863ec342cf148d02ed180b8ecf3a71a024e4bePeter Osterlund return 1; 1502ab863ec342cf148d02ed180b8ecf3a71a024e4bePeter Osterlund default: 1503ab863ec342cf148d02ed180b8ecf3a71a024e4bePeter Osterlund break; 1504ab863ec342cf148d02ed180b8ecf3a71a024e4bePeter Osterlund } 15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1506ab863ec342cf148d02ed180b8ecf3a71a024e4bePeter Osterlund if (!ti->packet || !ti->fp) 1507ab863ec342cf148d02ed180b8ecf3a71a024e4bePeter Osterlund return 0; 15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * "good" settings as per Mt Fuji. 15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1512ab863ec342cf148d02ed180b8ecf3a71a024e4bePeter Osterlund if (ti->rt == 0 && ti->blank == 0) 15137c613d593370292d1685f5794c743a2323be3a09Peter Osterlund return 1; 15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1515ab863ec342cf148d02ed180b8ecf3a71a024e4bePeter Osterlund if (ti->rt == 0 && ti->blank == 1) 15167c613d593370292d1685f5794c743a2323be3a09Peter Osterlund return 1; 15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1518ab863ec342cf148d02ed180b8ecf3a71a024e4bePeter Osterlund if (ti->rt == 1 && ti->blank == 0) 15197c613d593370292d1685f5794c743a2323be3a09Peter Osterlund return 1; 15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15217822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier printk(DRIVER_NAME": bad state %d-%d-%d\n", ti->rt, ti->blank, ti->packet); 15227c613d593370292d1685f5794c743a2323be3a09Peter Osterlund return 0; 15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 15267c613d593370292d1685f5794c743a2323be3a09Peter Osterlund * 1 -- we can write to this disc, 0 -- we can't 15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15287c613d593370292d1685f5794c743a2323be3a09Peter Osterlundstatic int pkt_writable_disc(struct pktcdvd_device *pd, disc_information *di) 15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (pd->mmc3_profile) { 15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x0a: /* CD-RW */ 15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0xffff: /* MMC3 not supported */ 15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x1a: /* DVD+RW */ 15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x13: /* DVD-RW */ 15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x12: /* DVD-RAM */ 15377c613d593370292d1685f5794c743a2323be3a09Peter Osterlund return 1; 15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 15397822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier VPRINTK(DRIVER_NAME": Wrong disc profile (%x)\n", pd->mmc3_profile); 15407c613d593370292d1685f5794c743a2323be3a09Peter Osterlund return 0; 15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for disc type 0xff we should probably reserve a new track. 15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but i'm not sure, should we leave this to user apps? probably. 15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (di->disc_type == 0xff) { 15487822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier printk(DRIVER_NAME": Unknown disc. No track?\n"); 15497c613d593370292d1685f5794c743a2323be3a09Peter Osterlund return 0; 15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (di->disc_type != 0x20 && di->disc_type != 0) { 15537822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier printk(DRIVER_NAME": Wrong disc type (%x)\n", di->disc_type); 15547c613d593370292d1685f5794c743a2323be3a09Peter Osterlund return 0; 15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (di->erasable == 0) { 15587822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier printk(DRIVER_NAME": Disc not erasable\n"); 15597c613d593370292d1685f5794c743a2323be3a09Peter Osterlund return 0; 15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (di->border_status == PACKET_SESSION_RESERVED) { 15637822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier printk(DRIVER_NAME": Can't write to last track (reserved)\n"); 15647c613d593370292d1685f5794c743a2323be3a09Peter Osterlund return 0; 15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15677c613d593370292d1685f5794c743a2323be3a09Peter Osterlund return 1; 15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pkt_probe_settings(struct pktcdvd_device *pd) 15711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct packet_command cgc; 15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char buf[12]; 15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds disc_information di; 15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds track_information ti; 15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret, track; 15771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ); 15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.cmd[0] = GPCMD_GET_CONFIGURATION; 15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.cmd[8] = 8; 15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = pkt_generic_packet(pd, &cgc); 15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd->mmc3_profile = ret ? 0xffff : buf[6] << 8 | buf[7]; 15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(&di, 0, sizeof(disc_information)); 15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(&ti, 0, sizeof(track_information)); 15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ret = pkt_get_disc_info(pd, &di))) { 15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("failed get_disc\n"); 15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15927c613d593370292d1685f5794c743a2323be3a09Peter Osterlund if (!pkt_writable_disc(pd, &di)) 15939db91546570ca1b3bc90b4c2d25d5bb74a44be24Peter Osterlund return -EROFS; 15941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd->type = di.erasable ? PACKET_CDRW : PACKET_CDR; 15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds track = 1; /* (di.last_track_msb << 8) | di.last_track_lsb; */ 15981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ret = pkt_get_track_info(pd, track, 1, &ti))) { 15997822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier printk(DRIVER_NAME": failed get_track\n"); 16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1603ab863ec342cf148d02ed180b8ecf3a71a024e4bePeter Osterlund if (!pkt_writable_track(pd, &ti)) { 16047822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier printk(DRIVER_NAME": can't write to this track\n"); 16059db91546570ca1b3bc90b4c2d25d5bb74a44be24Peter Osterlund return -EROFS; 16061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we keep packet size in 512 byte units, makes it easier to 16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * deal with request calculations. 16111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd->settings.size = be32_to_cpu(ti.fixed_packet_size) << 2; 16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pd->settings.size == 0) { 16147822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier printk(DRIVER_NAME": detected zero packet size!\n"); 1615a460ad62260def15c42130de253d6cfc32528a2fPhillip Susi return -ENXIO; 16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1617d0272e78eee4dc53c887fd132e9035daf037d423Peter Osterlund if (pd->settings.size > PACKET_MAX_SECTORS) { 16187822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier printk(DRIVER_NAME": packet size is too big\n"); 16199db91546570ca1b3bc90b4c2d25d5bb74a44be24Peter Osterlund return -EROFS; 1620d0272e78eee4dc53c887fd132e9035daf037d423Peter Osterlund } 16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd->settings.fp = ti.fp; 16221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd->offset = (be32_to_cpu(ti.track_start) << 2) & (pd->settings.size - 1); 16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ti.nwa_v) { 16251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd->nwa = be32_to_cpu(ti.next_writable); 16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_bit(PACKET_NWA_VALID, &pd->flags); 16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in theory we could use lra on -RW media as well and just zero 16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * blocks that haven't been written yet, but in practice that 16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is just a no-go. we'll use that for -R, naturally. 16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ti.lra_v) { 16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd->lra = be32_to_cpu(ti.last_rec_address); 16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_bit(PACKET_LRA_VALID, &pd->flags); 16371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd->lra = 0xffffffff; 16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_bit(PACKET_LRA_VALID, &pd->flags); 16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * fine for now 16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd->settings.link_loss = 7; 16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd->settings.write_type = 0; /* packet */ 16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd->settings.track_mode = ti.track_mode; 16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * mode1 or mode2 disc 16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (ti.data_mode) { 16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PACKET_MODE1: 16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd->settings.block_mode = PACKET_BLOCK_MODE1; 16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PACKET_MODE2: 16571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd->settings.block_mode = PACKET_BLOCK_MODE2; 16581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 16607822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier printk(DRIVER_NAME": unknown data mode\n"); 16619db91546570ca1b3bc90b4c2d25d5bb74a44be24Peter Osterlund return -EROFS; 16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * enable/disable write caching on drive 16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pkt_write_caching(struct pktcdvd_device *pd, int set) 16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct packet_command cgc; 16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct request_sense sense; 16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char buf[64]; 16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(buf, 0, sizeof(buf)); 16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ); 16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.sense = &sense; 16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.buflen = pd->mode_offset + 12; 16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 16821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * caching mode page might not be there, so quiet this command 16831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.quiet = 1; 16851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ret = pkt_mode_sense(pd, &cgc, GPMODE_WCACHING_PAGE, 0))) 16871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[pd->mode_offset + 10] |= (!!set << 2); 16901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.buflen = cgc.cmd[8] = 2 + ((buf[0] << 8) | (buf[1] & 0xff)); 16921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = pkt_mode_select(pd, &cgc); 16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) { 16947822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier printk(DRIVER_NAME": write caching control failed\n"); 16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_dump_sense(&cgc); 16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (!ret && set) 16977822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier printk(DRIVER_NAME": enabled write caching on %s\n", pd->name); 16981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 16991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pkt_lock_door(struct pktcdvd_device *pd, int lockflag) 17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct packet_command cgc; 17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); 17061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.cmd[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL; 17071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.cmd[4] = lockflag ? 1 : 0; 17081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return pkt_generic_packet(pd, &cgc); 17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 17121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns drive maximum write speed 17131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 17141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pkt_get_max_speed(struct pktcdvd_device *pd, unsigned *write_speed) 17151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct packet_command cgc; 17171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct request_sense sense; 17181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char buf[256+18]; 17191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *cap_buf; 17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret, offset; 17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(buf, 0, sizeof(buf)); 17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cap_buf = &buf[sizeof(struct mode_page_header) + pd->mode_offset]; 17241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_UNKNOWN); 17251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.sense = &sense; 17261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = pkt_mode_sense(pd, &cgc, GPMODE_CAPABILITIES_PAGE, 0); 17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) { 17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.buflen = pd->mode_offset + cap_buf[1] + 2 + 17301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(struct mode_page_header); 17311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = pkt_mode_sense(pd, &cgc, GPMODE_CAPABILITIES_PAGE, 0); 17321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) { 17331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_dump_sense(&cgc); 17341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 17351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset = 20; /* Obsoleted field, used by older drives */ 17391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cap_buf[1] >= 28) 17401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset = 28; /* Current write speed selected */ 17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cap_buf[1] >= 30) { 17421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If the drive reports at least one "Logical Unit Write 17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Speed Performance Descriptor Block", use the information 17441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in the first block. (contains the highest speed) 17451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 17461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int num_spdb = (cap_buf[30] << 8) + cap_buf[31]; 17471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (num_spdb > 0) 17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset = 34; 17491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *write_speed = (cap_buf[offset] << 8) | cap_buf[offset + 1]; 17521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 17531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* These tables from cdrecord - I don't have orange book */ 17561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* standard speed CD-RW (1-4x) */ 17571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char clv_to_speed[16] = { 17581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */ 17591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0, 2, 4, 6, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 17601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 17611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* high speed CD-RW (-10x) */ 17621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char hs_clv_to_speed[16] = { 17631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */ 17641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0, 2, 4, 6, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 17651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 17661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ultra high speed CD-RW */ 17671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char us_clv_to_speed[16] = { 17681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */ 17691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0, 2, 4, 8, 0, 0,16, 0,24,32,40,48, 0, 0, 0, 0 17701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 17711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 17731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * reads the maximum media speed from ATIP 17741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 17751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pkt_media_speed(struct pktcdvd_device *pd, unsigned *speed) 17761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct packet_command cgc; 17781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct request_sense sense; 17791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char buf[64]; 17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int size, st, sp; 17811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 17821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_cdrom_command(&cgc, buf, 2, CGC_DATA_READ); 17841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.sense = &sense; 17851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.cmd[0] = GPCMD_READ_TOC_PMA_ATIP; 17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.cmd[1] = 2; 17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.cmd[2] = 4; /* READ ATIP */ 17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.cmd[8] = 2; 17891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = pkt_generic_packet(pd, &cgc); 17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) { 17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_dump_sense(&cgc); 17921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 17931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size = ((unsigned int) buf[0]<<8) + buf[1] + 2; 17951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (size > sizeof(buf)) 17961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size = sizeof(buf); 17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_cdrom_command(&cgc, buf, size, CGC_DATA_READ); 17991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.sense = &sense; 18001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.cmd[0] = GPCMD_READ_TOC_PMA_ATIP; 18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.cmd[1] = 2; 18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.cmd[2] = 4; 18031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.cmd[8] = size; 18041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = pkt_generic_packet(pd, &cgc); 18051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) { 18061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_dump_sense(&cgc); 18071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 18081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!buf[6] & 0x40) { 18117822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier printk(DRIVER_NAME": Disc type is not CD-RW\n"); 18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 18131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!buf[6] & 0x4) { 18157822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier printk(DRIVER_NAME": A1 values on media are not valid, maybe not CDRW?\n"); 18161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds st = (buf[6] >> 3) & 0x7; /* disc sub-type */ 18201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sp = buf[16] & 0xf; /* max speed from ATIP A1 field */ 18221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Info from cdrecord */ 18241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (st) { 18251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0: /* standard speed */ 18261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *speed = clv_to_speed[sp]; 18271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 18281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 1: /* high speed */ 18291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *speed = hs_clv_to_speed[sp]; 18301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 18311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 2: /* ultra high speed */ 18321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *speed = us_clv_to_speed[sp]; 18331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 18341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 18357822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier printk(DRIVER_NAME": Unknown disc sub-type %d\n",st); 18361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 18371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (*speed) { 18397822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier printk(DRIVER_NAME": Max. media speed: %d\n",*speed); 18401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 18411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 18427822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier printk(DRIVER_NAME": Unknown speed %d for sub-type %d\n",sp,st); 18431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 18441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pkt_perform_opc(struct pktcdvd_device *pd) 18481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 18491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct packet_command cgc; 18501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct request_sense sense; 18511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 18521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18537822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier VPRINTK(DRIVER_NAME": Performing OPC\n"); 18541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); 18561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.sense = &sense; 18571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.timeout = 60*HZ; 18581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.cmd[0] = GPCMD_SEND_OPC; 18591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cgc.cmd[1] = 1; 18601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ret = pkt_generic_packet(pd, &cgc))) 18611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_dump_sense(&cgc); 18621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 18631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pkt_open_write(struct pktcdvd_device *pd) 18661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 18671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 18681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int write_speed, media_write_speed, read_speed; 18691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ret = pkt_probe_settings(pd))) { 18717822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier VPRINTK(DRIVER_NAME": %s failed probe\n", pd->name); 18729db91546570ca1b3bc90b4c2d25d5bb74a44be24Peter Osterlund return ret; 18731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ret = pkt_set_write_settings(pd))) { 18767822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier DPRINTK(DRIVER_NAME": %s failed saving write settings\n", pd->name); 18771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 18781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_write_caching(pd, USE_WCACHING); 18811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ret = pkt_get_max_speed(pd, &write_speed))) 18831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_speed = 16 * 177; 18841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (pd->mmc3_profile) { 18851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x13: /* DVD-RW */ 18861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x1a: /* DVD+RW */ 18871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x12: /* DVD-RAM */ 18887822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier DPRINTK(DRIVER_NAME": write speed %ukB/s\n", write_speed); 18891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 18901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 18911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ret = pkt_media_speed(pd, &media_write_speed))) 18921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds media_write_speed = 16; 18931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write_speed = min(write_speed, media_write_speed * 177); 18947822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier DPRINTK(DRIVER_NAME": write speed %ux\n", write_speed / 176); 18951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 18961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read_speed = write_speed; 18981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ret = pkt_set_speed(pd, write_speed, read_speed))) { 19007822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier DPRINTK(DRIVER_NAME": %s couldn't set write speed\n", pd->name); 19011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 19021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd->write_speed = write_speed; 19041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd->read_speed = read_speed; 19051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ret = pkt_perform_opc(pd))) { 19077822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier DPRINTK(DRIVER_NAME": %s Optimum Power Calibration failed\n", pd->name); 19081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 19111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 19121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 19141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * called at open time. 19151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 19161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pkt_open_dev(struct pktcdvd_device *pd, int write) 19171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 19181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 19191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds long lba; 19201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds request_queue_t *q; 19211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 19231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We need to re-open the cdrom device without O_NONBLOCK to be able 19241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to read/write from/to it. It is already opened in O_NONBLOCK mode 19251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * so bdget() can't fail. 19261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 19271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bdget(pd->bdev->bd_dev); 19281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ret = blkdev_get(pd->bdev, FMODE_READ, O_RDONLY))) 19291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 19301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19318382bf2e72d16d0532e351299121ccd3bca0fdd8Peter Osterlund if ((ret = bd_claim(pd->bdev, pd))) 19328382bf2e72d16d0532e351299121ccd3bca0fdd8Peter Osterlund goto out_putdev; 19338382bf2e72d16d0532e351299121ccd3bca0fdd8Peter Osterlund 19341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ret = pkt_get_last_written(pd, &lba))) { 19357822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier printk(DRIVER_NAME": pkt_get_last_written failed\n"); 19368382bf2e72d16d0532e351299121ccd3bca0fdd8Peter Osterlund goto out_unclaim; 19371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_capacity(pd->disk, lba << 2); 19401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_capacity(pd->bdev->bd_disk, lba << 2); 19411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bd_set_size(pd->bdev, (loff_t)lba << 11); 19421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q = bdev_get_queue(pd->bdev); 19441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (write) { 19451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ret = pkt_open_write(pd))) 19468382bf2e72d16d0532e351299121ccd3bca0fdd8Peter Osterlund goto out_unclaim; 19471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 19481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Some CDRW drives can not handle writes larger than one packet, 19491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * even if the size is a multiple of the packet size. 19501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 19511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(q->queue_lock); 19521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds blk_queue_max_sectors(q, pd->settings.size); 19531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(q->queue_lock); 19541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_bit(PACKET_WRITABLE, &pd->flags); 19551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 19561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_set_speed(pd, MAX_SPEED, MAX_SPEED); 19571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_bit(PACKET_WRITABLE, &pd->flags); 19581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ret = pkt_set_segment_merging(pd, q))) 19618382bf2e72d16d0532e351299121ccd3bca0fdd8Peter Osterlund goto out_unclaim; 19621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1963e1bc89bc9991e994f2b3c60d9ad2fdb5ad9b10fcPeter Osterlund if (write) { 1964e1bc89bc9991e994f2b3c60d9ad2fdb5ad9b10fcPeter Osterlund if (!pkt_grow_pktlist(pd, CONFIG_CDROM_PKTCDVD_BUFFERS)) { 19657822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier printk(DRIVER_NAME": not enough memory for buffers\n"); 1966e1bc89bc9991e994f2b3c60d9ad2fdb5ad9b10fcPeter Osterlund ret = -ENOMEM; 1967e1bc89bc9991e994f2b3c60d9ad2fdb5ad9b10fcPeter Osterlund goto out_unclaim; 1968e1bc89bc9991e994f2b3c60d9ad2fdb5ad9b10fcPeter Osterlund } 19697822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier printk(DRIVER_NAME": %lukB available on disc\n", lba << 1); 1970e1bc89bc9991e994f2b3c60d9ad2fdb5ad9b10fcPeter Osterlund } 19711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 19731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19748382bf2e72d16d0532e351299121ccd3bca0fdd8Peter Osterlundout_unclaim: 19758382bf2e72d16d0532e351299121ccd3bca0fdd8Peter Osterlund bd_release(pd->bdev); 19761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_putdev: 19771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds blkdev_put(pd->bdev); 19781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 19791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 19801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 19811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 19831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * called when the device is closed. makes sure that the device flushes 19841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the internal cache before we close. 19851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 19861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pkt_release_dev(struct pktcdvd_device *pd, int flush) 19871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 19881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (flush && pkt_flush_cache(pd)) 19897822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier DPRINTK(DRIVER_NAME": %s not flushing cache\n", pd->name); 19901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_lock_door(pd, 0); 19921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_set_speed(pd, MAX_SPEED, MAX_SPEED); 19948382bf2e72d16d0532e351299121ccd3bca0fdd8Peter Osterlund bd_release(pd->bdev); 19951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds blkdev_put(pd->bdev); 1996e1bc89bc9991e994f2b3c60d9ad2fdb5ad9b10fcPeter Osterlund 1997e1bc89bc9991e994f2b3c60d9ad2fdb5ad9b10fcPeter Osterlund pkt_shrink_pktlist(pd); 19981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 19991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pktcdvd_device *pkt_find_dev_from_minor(int dev_minor) 20011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 20021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev_minor >= MAX_WRITERS) 20031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 20041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return pkt_devs[dev_minor]; 20051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 20061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pkt_open(struct inode *inode, struct file *file) 20081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 20091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pktcdvd_device *pd = NULL; 20101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 20111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20127822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier VPRINTK(DRIVER_NAME": entering open\n"); 20131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20141657f824e880a9bd239a3436b820d1a2986f763dJes Sorensen mutex_lock(&ctl_mutex); 20151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd = pkt_find_dev_from_minor(iminor(inode)); 20161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!pd) { 20171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -ENODEV; 20181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 20191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(pd->refcnt < 0); 20211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd->refcnt++; 202346f4e1b7d5fa3ddf2486bf69716c404147e38ebfPeter Osterlund if (pd->refcnt > 1) { 202446f4e1b7d5fa3ddf2486bf69716c404147e38ebfPeter Osterlund if ((file->f_mode & FMODE_WRITE) && 202546f4e1b7d5fa3ddf2486bf69716c404147e38ebfPeter Osterlund !test_bit(PACKET_WRITABLE, &pd->flags)) { 202646f4e1b7d5fa3ddf2486bf69716c404147e38ebfPeter Osterlund ret = -EBUSY; 202746f4e1b7d5fa3ddf2486bf69716c404147e38ebfPeter Osterlund goto out_dec; 202846f4e1b7d5fa3ddf2486bf69716c404147e38ebfPeter Osterlund } 202946f4e1b7d5fa3ddf2486bf69716c404147e38ebfPeter Osterlund } else { 203001fd9fda2ce462b44bafdac2fe6aacacf23531f2Peter Osterlund ret = pkt_open_dev(pd, file->f_mode & FMODE_WRITE); 203101fd9fda2ce462b44bafdac2fe6aacacf23531f2Peter Osterlund if (ret) 20321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_dec; 20331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 20341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * needed here as well, since ext2 (among others) may change 20351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the blocksize at mount time 20361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 20371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_blocksize(inode->i_bdev, CD_FRAMESIZE); 20381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20401657f824e880a9bd239a3436b820d1a2986f763dJes Sorensen mutex_unlock(&ctl_mutex); 20411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 20421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_dec: 20441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd->refcnt--; 20451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 20467822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier VPRINTK(DRIVER_NAME": failed open (%d)\n", ret); 20471657f824e880a9bd239a3436b820d1a2986f763dJes Sorensen mutex_unlock(&ctl_mutex); 20481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 20491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 20501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pkt_close(struct inode *inode, struct file *file) 20521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 20531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pktcdvd_device *pd = inode->i_bdev->bd_disk->private_data; 20541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = 0; 20551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20561657f824e880a9bd239a3436b820d1a2986f763dJes Sorensen mutex_lock(&ctl_mutex); 20571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd->refcnt--; 20581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(pd->refcnt < 0); 20591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pd->refcnt == 0) { 20601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int flush = test_bit(PACKET_WRITABLE, &pd->flags); 20611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_release_dev(pd, flush); 20621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20631657f824e880a9bd239a3436b820d1a2986f763dJes Sorensen mutex_unlock(&ctl_mutex); 20641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 20651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 20661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pkt_end_io_read_cloned(struct bio *bio, unsigned int bytes_done, int err) 20691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 20701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct packet_stacked_data *psd = bio->bi_private; 20711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pktcdvd_device *pd = psd->pd; 20721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bio->bi_size) 20741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 20751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bio_put(bio); 20771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bio_endio(psd->bio, psd->bio->bi_size, err); 20781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mempool_free(psd, psd_pool); 20791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_bio_finished(pd); 20801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 20811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 20821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pkt_make_request(request_queue_t *q, struct bio *bio) 20841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 20851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pktcdvd_device *pd; 20861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char b[BDEVNAME_SIZE]; 20871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sector_t zone; 20881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct packet_data *pkt; 20891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int was_empty, blocked_bio; 20901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pkt_rb_node *node; 20911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd = q->queuedata; 20931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!pd) { 20947822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier printk(DRIVER_NAME": %s incorrect request queue\n", bdevname(bio->bi_bdev, b)); 20951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto end_io; 20961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 20991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Clone READ bios so we can have our own bi_end_io callback. 21001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 21011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bio_data_dir(bio) == READ) { 21021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct bio *cloned_bio = bio_clone(bio, GFP_NOIO); 21031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct packet_stacked_data *psd = mempool_alloc(psd_pool, GFP_NOIO); 21041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psd->pd = pd; 21061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psd->bio = bio; 21071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cloned_bio->bi_bdev = pd->bdev; 21081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cloned_bio->bi_private = psd; 21091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cloned_bio->bi_end_io = pkt_end_io_read_cloned; 21101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd->stats.secs_r += bio->bi_size >> 9; 211146c271bedd2c8444b1d05bc44928beec0c07debcPeter Osterlund pkt_queue_bio(pd, cloned_bio); 21121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 21131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!test_bit(PACKET_WRITABLE, &pd->flags)) { 21167822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier printk(DRIVER_NAME": WRITE for ro device %s (%llu)\n", 21171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd->name, (unsigned long long)bio->bi_sector); 21181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto end_io; 21191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!bio->bi_size || (bio->bi_size % CD_FRAMESIZE)) { 21227822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier printk(DRIVER_NAME": wrong bio size\n"); 21231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto end_io; 21241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds blk_queue_bounce(q, &bio); 21271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zone = ZONE(bio->bi_sector, pd); 21291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VPRINTK("pkt_make_request: start = %6llx stop = %6llx\n", 21301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned long long)bio->bi_sector, 21311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned long long)(bio->bi_sector + bio_sectors(bio))); 21321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check if we have to split the bio */ 21341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 21351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct bio_pair *bp; 21361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sector_t last_zone; 21371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int first_sectors; 21381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds last_zone = ZONE(bio->bi_sector + bio_sectors(bio) - 1, pd); 21401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (last_zone != zone) { 21411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(last_zone != zone + pd->settings.size); 21421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds first_sectors = last_zone - bio->bi_sector; 21431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp = bio_split(bio, bio_split_pool, first_sectors); 21441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(!bp); 21451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_make_request(q, &bp->bio1); 21461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_make_request(q, &bp->bio2); 21471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bio_pair_release(bp); 21481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 21491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 21531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we find a matching packet in state WAITING or READ_WAIT, we can 21541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * just append this bio to that packet. 21551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 21561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&pd->cdrw.active_list_lock); 21571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds blocked_bio = 0; 21581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_entry(pkt, &pd->cdrw.pkt_active_list, list) { 21591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pkt->sector == zone) { 21601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&pkt->lock); 21611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((pkt->state == PACKET_WAITING_STATE) || 21621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (pkt->state == PACKET_READ_WAIT_STATE)) { 21631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_add_list_last(bio, &pkt->orig_bios, 21641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &pkt->orig_bios_tail); 21651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt->write_size += bio->bi_size / CD_FRAMESIZE; 21661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((pkt->write_size >= pkt->frames) && 21671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (pkt->state == PACKET_WAITING_STATE)) { 21681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_inc(&pkt->run_sm); 21691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up(&pd->wqueue); 21701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&pkt->lock); 21721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&pd->cdrw.active_list_lock); 21731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 21741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 21751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds blocked_bio = 1; 21761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&pkt->lock); 21781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&pd->cdrw.active_list_lock); 21811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 21831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * No matching packet found. Store the bio in the work queue. 21841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 21851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds node = mempool_alloc(pd->rb_pool, GFP_NOIO); 21861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds node->bio = bio; 21871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&pd->lock); 21881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(pd->bio_queue_size < 0); 21891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds was_empty = (pd->bio_queue_size == 0); 21901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_rbtree_insert(pd, node); 21911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&pd->lock); 21921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 21941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wake up the worker thread. 21951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 21961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_set(&pd->scan_queue, 1); 21971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (was_empty) { 21981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* This wake_up is required for correct operation */ 21991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up(&pd->wqueue); 22001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (!list_empty(&pd->cdrw.pkt_free_list) && !blocked_bio) { 22011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 22021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This wake up is not required for correct operation, 22031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but improves performance in some cases. 22041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 22051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up(&pd->wqueue); 22061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 22081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsend_io: 22091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bio_io_error(bio, bio->bi_size); 22101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 22111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 22121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pkt_merge_bvec(request_queue_t *q, struct bio *bio, struct bio_vec *bvec) 22161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 22171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pktcdvd_device *pd = q->queuedata; 22181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sector_t zone = ZONE(bio->bi_sector, pd); 22191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int used = ((bio->bi_sector - zone) << 9) + bio->bi_size; 22201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int remaining = (pd->settings.size << 9) - used; 22211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int remaining2; 22221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 22241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A bio <= PAGE_SIZE must be allowed. If it crosses a packet 22251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * boundary, pkt_make_request() will split the bio. 22261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 22271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds remaining2 = PAGE_SIZE - bio->bi_size; 22281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds remaining = max(remaining, remaining2); 22291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(remaining < 0); 22311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return remaining; 22321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 22331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pkt_init_queue(struct pktcdvd_device *pd) 22351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 22361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds request_queue_t *q = pd->disk->queue; 22371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds blk_queue_make_request(q, pkt_make_request); 22391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds blk_queue_hardsect_size(q, CD_FRAMESIZE); 22401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds blk_queue_max_sectors(q, PACKET_MAX_SECTORS); 22411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds blk_queue_merge_bvec(q, pkt_merge_bvec); 22421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q->queuedata = pd; 22431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 22441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pkt_seq_show(struct seq_file *m, void *p) 22461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 22471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pktcdvd_device *pd = m->private; 22481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *msg; 22491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char bdev_buf[BDEVNAME_SIZE]; 22501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int states[PACKET_NUM_STATES]; 22511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds seq_printf(m, "Writer %s mapped to %s:\n", pd->name, 22531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bdevname(pd->bdev, bdev_buf)); 22541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds seq_printf(m, "\nSettings:\n"); 22561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds seq_printf(m, "\tpacket size:\t\t%dkB\n", pd->settings.size / 2); 22571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pd->settings.write_type == 0) 22591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msg = "Packet"; 22601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 22611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msg = "Unknown"; 22621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds seq_printf(m, "\twrite type:\t\t%s\n", msg); 22631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds seq_printf(m, "\tpacket type:\t\t%s\n", pd->settings.fp ? "Fixed" : "Variable"); 22651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds seq_printf(m, "\tlink loss:\t\t%d\n", pd->settings.link_loss); 22661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds seq_printf(m, "\ttrack mode:\t\t%d\n", pd->settings.track_mode); 22681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pd->settings.block_mode == PACKET_BLOCK_MODE1) 22701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msg = "Mode 1"; 22711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (pd->settings.block_mode == PACKET_BLOCK_MODE2) 22721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msg = "Mode 2"; 22731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 22741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msg = "Unknown"; 22751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds seq_printf(m, "\tblock mode:\t\t%s\n", msg); 22761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds seq_printf(m, "\nStatistics:\n"); 22781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds seq_printf(m, "\tpackets started:\t%lu\n", pd->stats.pkt_started); 22791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds seq_printf(m, "\tpackets ended:\t\t%lu\n", pd->stats.pkt_ended); 22801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds seq_printf(m, "\twritten:\t\t%lukB\n", pd->stats.secs_w >> 1); 22811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds seq_printf(m, "\tread gather:\t\t%lukB\n", pd->stats.secs_rg >> 1); 22821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds seq_printf(m, "\tread:\t\t\t%lukB\n", pd->stats.secs_r >> 1); 22831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds seq_printf(m, "\nMisc:\n"); 22851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds seq_printf(m, "\treference count:\t%d\n", pd->refcnt); 22861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds seq_printf(m, "\tflags:\t\t\t0x%lx\n", pd->flags); 22871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds seq_printf(m, "\tread speed:\t\t%ukB/s\n", pd->read_speed); 22881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds seq_printf(m, "\twrite speed:\t\t%ukB/s\n", pd->write_speed); 22891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds seq_printf(m, "\tstart offset:\t\t%lu\n", pd->offset); 22901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds seq_printf(m, "\tmode page offset:\t%u\n", pd->mode_offset); 22911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds seq_printf(m, "\nQueue state:\n"); 22931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds seq_printf(m, "\tbios queued:\t\t%d\n", pd->bio_queue_size); 22941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds seq_printf(m, "\tbios pending:\t\t%d\n", atomic_read(&pd->cdrw.pending_bios)); 22951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds seq_printf(m, "\tcurrent sector:\t\t0x%llx\n", (unsigned long long)pd->current_sector); 22961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_count_states(pd, states); 22981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds seq_printf(m, "\tstate:\t\t\ti:%d ow:%d rw:%d ww:%d rec:%d fin:%d\n", 22991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds states[0], states[1], states[2], states[3], states[4], states[5]); 23001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 23021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 23031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pkt_seq_open(struct inode *inode, struct file *file) 23051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 23061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return single_open(file, pkt_seq_show, PDE(inode)->data); 23071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 23081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct file_operations pkt_proc_fops = { 23101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .open = pkt_seq_open, 23111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .read = seq_read, 23121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .llseek = seq_lseek, 23131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .release = single_release 23141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 23151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev) 23171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 23181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 23191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = 0; 23201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char b[BDEVNAME_SIZE]; 23211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct proc_dir_entry *proc; 23221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct block_device *bdev; 23231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pd->pkt_dev == dev) { 23257822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier printk(DRIVER_NAME": Recursive setup not allowed\n"); 23261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 23271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < MAX_WRITERS; i++) { 23291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pktcdvd_device *pd2 = pkt_devs[i]; 23301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!pd2) 23311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 23321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pd2->bdev->bd_dev == dev) { 23337822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier printk(DRIVER_NAME": %s already setup\n", bdevname(pd2->bdev, b)); 23341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 23351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pd2->pkt_dev == dev) { 23377822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier printk(DRIVER_NAME": Can't chain pktcdvd devices\n"); 23381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 23391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bdev = bdget(dev); 23431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!bdev) 23441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 23451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = blkdev_get(bdev, FMODE_READ, O_RDONLY | O_NONBLOCK); 23461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) 23471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 23481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* This is safe, since we have a reference from open(). */ 23501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __module_get(THIS_MODULE); 23511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd->bdev = bdev; 23531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_blocksize(bdev, CD_FRAMESIZE); 23541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_init_queue(pd); 23561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_set(&pd->cdrw.pending_bios, 0); 23581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd->cdrw.thread = kthread_run(kcdrwd, pd, "%s", pd->name); 23591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_ERR(pd->cdrw.thread)) { 23607822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier printk(DRIVER_NAME": can't start kernel thread\n"); 23611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -ENOMEM; 2362e1bc89bc9991e994f2b3c60d9ad2fdb5ad9b10fcPeter Osterlund goto out_mem; 23631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds proc = create_proc_entry(pd->name, 0, pkt_proc); 23661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (proc) { 23671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds proc->data = pd; 23681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds proc->proc_fops = &pkt_proc_fops; 23691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23707822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier DPRINTK(DRIVER_NAME": writer %s mapped to %s\n", pd->name, bdevname(bdev, b)); 23711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 23721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_mem: 23741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds blkdev_put(bdev); 23751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* This is safe: open() is still holding a reference. */ 23761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds module_put(THIS_MODULE); 23771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 23781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 23791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pkt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) 23811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 23821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pktcdvd_device *pd = inode->i_bdev->bd_disk->private_data; 23831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VPRINTK("pkt_ioctl: cmd %x, dev %d:%d\n", cmd, imajor(inode), iminor(inode)); 23851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 23871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 23881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * forward selected CDROM ioctls to CD-ROM, for UDF 23891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 23901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CDROMMULTISESSION: 23911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CDROMREADTOCENTRY: 23921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CDROM_LAST_WRITTEN: 23931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CDROM_SEND_PACKET: 23941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SCSI_IOCTL_SEND_COMMAND: 2395118326e940bdecef6c459d42ccf05256ba86daa7Peter Osterlund return blkdev_ioctl(pd->bdev->bd_inode, file, cmd, arg); 23961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case CDROMEJECT: 23981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 23991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The door gets locked when the device is opened, so we 24001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * have to unlock it or else the eject command fails. 24011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2402948423e5ccc33bc257384ad4b339214c577bc926Peter Osterlund if (pd->refcnt == 1) 2403948423e5ccc33bc257384ad4b339214c577bc926Peter Osterlund pkt_lock_door(pd, 0); 2404118326e940bdecef6c459d42ccf05256ba86daa7Peter Osterlund return blkdev_ioctl(pd->bdev->bd_inode, file, cmd, arg); 24051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 24077822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier VPRINTK(DRIVER_NAME": Unknown ioctl for %s (%x)\n", pd->name, cmd); 24081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOTTY; 24091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 24121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 24131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pkt_media_changed(struct gendisk *disk) 24151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 24161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pktcdvd_device *pd = disk->private_data; 24171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct gendisk *attached_disk; 24181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!pd) 24201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 24211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!pd->bdev) 24221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 24231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds attached_disk = pd->bdev->bd_disk; 24241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!attached_disk) 24251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 24261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return attached_disk->fops->media_changed(attached_disk); 24271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 24281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct block_device_operations pktcdvd_ops = { 24301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE, 24311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .open = pkt_open, 24321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .release = pkt_close, 24331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .ioctl = pkt_ioctl, 24341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .media_changed = pkt_media_changed, 24351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 24361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 24381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set up mapping from pktcdvd device to CD-ROM device. 24391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2440adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maierstatic int pkt_setup_dev(dev_t dev, dev_t* pkt_dev) 24411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 24421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int idx; 24431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = -ENOMEM; 24441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pktcdvd_device *pd; 24451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct gendisk *disk; 2446adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maier 2447adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maier mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); 24481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (idx = 0; idx < MAX_WRITERS; idx++) 24501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!pkt_devs[idx]) 24511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 24521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (idx == MAX_WRITERS) { 24537822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier printk(DRIVER_NAME": max %d writers supported\n", MAX_WRITERS); 2454adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maier ret = -EBUSY; 2455adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maier goto out_mutex; 24561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24581107d2e0352769b9bde6a4877c295b9309cdb877Peter Osterlund pd = kzalloc(sizeof(struct pktcdvd_device), GFP_KERNEL); 24591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!pd) 2460adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maier goto out_mutex; 24611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24620eaae62abaa1ad1f231932b6cdd9fb1b91df6651Matthew Dobson pd->rb_pool = mempool_create_kmalloc_pool(PKT_RB_POOL_SIZE, 24630eaae62abaa1ad1f231932b6cdd9fb1b91df6651Matthew Dobson sizeof(struct pkt_rb_node)); 24641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!pd->rb_pool) 24651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_mem; 24661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2467e1bc89bc9991e994f2b3c60d9ad2fdb5ad9b10fcPeter Osterlund INIT_LIST_HEAD(&pd->cdrw.pkt_free_list); 2468e1bc89bc9991e994f2b3c60d9ad2fdb5ad9b10fcPeter Osterlund INIT_LIST_HEAD(&pd->cdrw.pkt_active_list); 2469e1bc89bc9991e994f2b3c60d9ad2fdb5ad9b10fcPeter Osterlund spin_lock_init(&pd->cdrw.active_list_lock); 2470e1bc89bc9991e994f2b3c60d9ad2fdb5ad9b10fcPeter Osterlund 24711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&pd->lock); 24721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&pd->iosched.lock); 24737822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier sprintf(pd->name, DRIVER_NAME"%d", idx); 24741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_waitqueue_head(&pd->wqueue); 24751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd->bio_queue = RB_ROOT; 24761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2477adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maier disk = alloc_disk(1); 2478adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maier if (!disk) 2479adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maier goto out_mem; 2480adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maier pd->disk = disk; 2481add216608a63713b8a2c4545698d5ae02e27ac3bThomas Maier disk->major = pktdev_major; 24821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds disk->first_minor = idx; 24831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds disk->fops = &pktcdvd_ops; 24841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds disk->flags = GENHD_FL_REMOVABLE; 2485adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maier strcpy(disk->disk_name, pd->name); 24861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds disk->private_data = pd; 24871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds disk->queue = blk_alloc_queue(GFP_KERNEL); 24881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!disk->queue) 24891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_mem2; 24901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd->pkt_dev = MKDEV(disk->major, disk->first_minor); 24921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = pkt_new_dev(pd, dev); 24931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) 24941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_new_dev; 24951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds add_disk(disk); 2497adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maier 24981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_devs[idx] = pd; 2499adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maier if (pkt_dev) 2500adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maier *pkt_dev = pd->pkt_dev; 2501adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maier 2502adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maier mutex_unlock(&ctl_mutex); 25031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 25041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_new_dev: 25061312f40e11c57edb5c3250f1b782cef8e3efea82Al Viro blk_cleanup_queue(disk->queue); 25071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_mem2: 25081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds put_disk(disk); 25091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_mem: 25101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pd->rb_pool) 25111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mempool_destroy(pd->rb_pool); 25121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(pd); 2513adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maierout_mutex: 2514adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maier mutex_unlock(&ctl_mutex); 2515adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maier printk(DRIVER_NAME": setup of pktcdvd device failed\n"); 25161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 25171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 25181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 25201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Tear down mapping from pktcdvd device to CD-ROM device. 25211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2522adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maierstatic int pkt_remove_dev(dev_t pkt_dev) 25231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 25241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pktcdvd_device *pd; 25251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int idx; 2526adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maier int ret = 0; 2527adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maier 2528adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maier mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); 25291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (idx = 0; idx < MAX_WRITERS; idx++) { 25311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd = pkt_devs[idx]; 25321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pd && (pd->pkt_dev == pkt_dev)) 25331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 25341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (idx == MAX_WRITERS) { 25367822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier DPRINTK(DRIVER_NAME": dev not setup\n"); 2537adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maier ret = -ENXIO; 2538adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maier goto out; 25391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2541adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maier if (pd->refcnt > 0) { 2542adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maier ret = -EBUSY; 2543adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maier goto out; 2544adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maier } 25451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!IS_ERR(pd->cdrw.thread)) 25461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kthread_stop(pd->cdrw.thread); 25471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds blkdev_put(pd->bdev); 25491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds remove_proc_entry(pd->name, pkt_proc); 25517822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier DPRINTK(DRIVER_NAME": writer %s unmapped\n", pd->name); 25521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds del_gendisk(pd->disk); 25541312f40e11c57edb5c3250f1b782cef8e3efea82Al Viro blk_cleanup_queue(pd->disk->queue); 25551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds put_disk(pd->disk); 25561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_devs[idx] = NULL; 25581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mempool_destroy(pd->rb_pool); 25591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(pd); 25601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* This is safe: open() is still holding a reference. */ 25621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds module_put(THIS_MODULE); 2563adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maier 2564adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maierout: 2565adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maier mutex_unlock(&ctl_mutex); 2566adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maier return ret; 25671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 25681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pkt_get_status(struct pkt_ctrl_command *ctrl_cmd) 25701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2571adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maier struct pktcdvd_device *pd; 2572adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maier 2573adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maier mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); 2574adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maier 2575adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maier pd = pkt_find_dev_from_minor(ctrl_cmd->dev_index); 25761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pd) { 25771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ctrl_cmd->dev = new_encode_dev(pd->bdev->bd_dev); 25781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ctrl_cmd->pkt_dev = new_encode_dev(pd->pkt_dev); 25791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 25801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ctrl_cmd->dev = 0; 25811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ctrl_cmd->pkt_dev = 0; 25821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ctrl_cmd->num_devices = MAX_WRITERS; 2584adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maier 2585adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maier mutex_unlock(&ctl_mutex); 25861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 25871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pkt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) 25891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 25901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __user *argp = (void __user *)arg; 25911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pkt_ctrl_command ctrl_cmd; 25921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = 0; 2593adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maier dev_t pkt_dev = 0; 25941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cmd != PACKET_CTRL_CMD) 25961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOTTY; 25971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(&ctrl_cmd, argp, sizeof(struct pkt_ctrl_command))) 25991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 26001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (ctrl_cmd.command) { 26021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PKT_CTRL_CMD_SETUP: 26031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!capable(CAP_SYS_ADMIN)) 26041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPERM; 2605adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maier ret = pkt_setup_dev(new_decode_dev(ctrl_cmd.dev), &pkt_dev); 2606adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maier ctrl_cmd.pkt_dev = new_encode_dev(pkt_dev); 26071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 26081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PKT_CTRL_CMD_TEARDOWN: 26091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!capable(CAP_SYS_ADMIN)) 26101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPERM; 2611adb9250a07edb7d41a17ba3b96fcb84c4d8e4260Thomas Maier ret = pkt_remove_dev(new_decode_dev(ctrl_cmd.pkt_dev)); 26121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 26131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PKT_CTRL_CMD_STATUS: 26141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_get_status(&ctrl_cmd); 26151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 26161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 26171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOTTY; 26181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 26191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_to_user(argp, &ctrl_cmd, sizeof(struct pkt_ctrl_command))) 26211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 26221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 26231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 26241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct file_operations pkt_ctl_fops = { 26271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .ioctl = pkt_ctl_ioctl, 26281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE, 26291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 26301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct miscdevice pkt_misc = { 26321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .minor = MISC_DYNAMIC_MINOR, 26337822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier .name = DRIVER_NAME, 26341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .fops = &pkt_ctl_fops 26351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 26361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init pkt_init(void) 26381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 26391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 26401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26410eaae62abaa1ad1f231932b6cdd9fb1b91df6651Matthew Dobson psd_pool = mempool_create_kmalloc_pool(PSD_POOL_SIZE, 26420eaae62abaa1ad1f231932b6cdd9fb1b91df6651Matthew Dobson sizeof(struct packet_stacked_data)); 26431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!psd_pool) 26441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 26451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2646add216608a63713b8a2c4545698d5ae02e27ac3bThomas Maier ret = register_blkdev(pktdev_major, DRIVER_NAME); 26471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret < 0) { 26487822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier printk(DRIVER_NAME": Unable to register block device\n"); 26491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out2; 26501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2651add216608a63713b8a2c4545698d5ae02e27ac3bThomas Maier if (!pktdev_major) 2652add216608a63713b8a2c4545698d5ae02e27ac3bThomas Maier pktdev_major = ret; 26531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = misc_register(&pkt_misc); 26551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) { 26567822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier printk(DRIVER_NAME": Unable to register misc device\n"); 26571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 26581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 26591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26601657f824e880a9bd239a3436b820d1a2986f763dJes Sorensen mutex_init(&ctl_mutex); 26611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26627822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier pkt_proc = proc_mkdir(DRIVER_NAME, proc_root_driver); 26631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 26651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 2667add216608a63713b8a2c4545698d5ae02e27ac3bThomas Maier unregister_blkdev(pktdev_major, DRIVER_NAME); 26681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout2: 26691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mempool_destroy(psd_pool); 26701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 26711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 26721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit pkt_exit(void) 26741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 26757822082d4e054fbdec8cf26590a350e3496c5cc9Thomas Maier remove_proc_entry(DRIVER_NAME, proc_root_driver); 26761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds misc_deregister(&pkt_misc); 2677add216608a63713b8a2c4545698d5ae02e27ac3bThomas Maier unregister_blkdev(pktdev_major, DRIVER_NAME); 26781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mempool_destroy(psd_pool); 26791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 26801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("Packet writing layer for CD/DVD drives"); 26821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Jens Axboe <axboe@suse.de>"); 26831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 26841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(pkt_init); 26861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(pkt_exit); 2687