diff options
Diffstat (limited to 'drivers/block')
-rw-r--r-- | drivers/block/Kconfig | 21 | ||||
-rw-r--r-- | drivers/block/Makefile | 1 | ||||
-rw-r--r-- | drivers/block/acsi_slm.c | 4 | ||||
-rw-r--r-- | drivers/block/aoe/aoecmd.c | 13 | ||||
-rw-r--r-- | drivers/block/cciss.c | 33 | ||||
-rw-r--r-- | drivers/block/cpqarray.c | 10 | ||||
-rw-r--r-- | drivers/block/loop.c | 4 | ||||
-rw-r--r-- | drivers/block/nbd.c | 2 | ||||
-rw-r--r-- | drivers/block/pktcdvd.c | 596 | ||||
-rw-r--r-- | drivers/block/swim_iop.c | 578 | ||||
-rw-r--r-- | drivers/block/viodasd.c | 6 |
11 files changed, 586 insertions, 682 deletions
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 85072446d772..58c1debf86f1 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -28,13 +28,6 @@ config ATARI_FLOPPY tristate "Atari floppy support" depends on ATARI -config BLK_DEV_SWIM_IOP - bool "Macintosh IIfx/Quadra 900/Quadra 950 floppy support (EXPERIMENTAL)" - depends on MAC && EXPERIMENTAL && BROKEN - help - Say Y here to support the SWIM (Super Woz Integrated Machine) IOP - floppy controller on the Macintosh IIfx and Quadra 900/950. - config MAC_FLOPPY tristate "Support for PowerMac floppy" depends on PPC_PMAC && !PPC_PMAC64 @@ -431,14 +424,18 @@ config CDROM_PKTCDVD tristate "Packet writing on CD/DVD media" depends on !UML help - If you have a CDROM drive that supports packet writing, say Y to - include preliminary support. It should work with any MMC/Mt Fuji - compliant ATAPI or SCSI drive, which is just about any newer CD - writer. + If you have a CDROM/DVD drive that supports packet writing, say + Y to include support. It should work with any MMC/Mt Fuji + compliant ATAPI or SCSI drive, which is just about any newer + DVD/CD writer. - Currently only writing to CD-RW, DVD-RW and DVD+RW discs is possible. + Currently only writing to CD-RW, DVD-RW, DVD+RW and DVDRAM discs + is possible. DVD-RW disks must be in restricted overwrite mode. + See the file <file:Documentation/cdrom/packet-writing.txt> + for further information on the use of this driver. + To compile this driver as a module, choose M here: the module will be called pktcdvd. diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 410f259a8031..dd88e33c1eb1 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -9,7 +9,6 @@ obj-$(CONFIG_MAC_FLOPPY) += swim3.o obj-$(CONFIG_BLK_DEV_FD) += floppy.o obj-$(CONFIG_AMIGA_FLOPPY) += amiflop.o obj-$(CONFIG_ATARI_FLOPPY) += ataflop.o -obj-$(CONFIG_BLK_DEV_SWIM_IOP) += swim_iop.o obj-$(CONFIG_ATARI_ACSI) += acsi.o obj-$(CONFIG_ATARI_SLM) += acsi_slm.o obj-$(CONFIG_AMIGA_Z2RAM) += z2ram.o diff --git a/drivers/block/acsi_slm.c b/drivers/block/acsi_slm.c index 8e41c87b026e..e04be94d195c 100644 --- a/drivers/block/acsi_slm.c +++ b/drivers/block/acsi_slm.c @@ -363,7 +363,7 @@ static ssize_t slm_read( struct file *file, char *buf, size_t count, loff_t *ppos ) { - struct inode *node = file->f_dentry->d_inode; + struct inode *node = file->f_path.dentry->d_inode; unsigned long page; int length; int end; @@ -618,7 +618,7 @@ static ssize_t slm_write( struct file *file, const char *buf, size_t count, loff_t *ppos ) { - struct inode *node = file->f_dentry->d_inode; + struct inode *node = file->f_path.dentry->d_inode; int device = iminor(node); int n, filled, w, h; diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 97f7f535f412..bb022ed4a866 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -30,8 +30,6 @@ new_skb(ulong len) skb->nh.raw = skb->mac.raw = skb->data; skb->protocol = __constant_htons(ETH_P_AOE); skb->priority = 0; - skb_put(skb, len); - memset(skb->head, 0, len); skb->next = skb->prev = NULL; /* tell the network layer not to perform IP checksums @@ -122,8 +120,8 @@ aoecmd_ata_rw(struct aoedev *d, struct frame *f) skb = f->skb; h = (struct aoe_hdr *) skb->mac.raw; ah = (struct aoe_atahdr *) (h+1); - skb->len = sizeof *h + sizeof *ah; - memset(h, 0, ETH_ZLEN); + skb_put(skb, sizeof *h + sizeof *ah); + memset(h, 0, skb->len); f->tag = aoehdr_atainit(d, h); f->waited = 0; f->buf = buf; @@ -149,7 +147,6 @@ aoecmd_ata_rw(struct aoedev *d, struct frame *f) skb->len += bcnt; skb->data_len = bcnt; } else { - skb->len = ETH_ZLEN; writebit = 0; } @@ -206,6 +203,7 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff **tail) printk(KERN_INFO "aoe: skb alloc failure\n"); continue; } + skb_put(skb, sizeof *h + sizeof *ch); skb->dev = ifp; if (sl_tail == NULL) sl_tail = skb; @@ -243,6 +241,7 @@ freeframe(struct aoedev *d) continue; if (atomic_read(&skb_shinfo(f->skb)->dataref) == 1) { skb_shinfo(f->skb)->nr_frags = f->skb->data_len = 0; + skb_trim(f->skb, 0); return f; } n++; @@ -698,8 +697,8 @@ aoecmd_ata_id(struct aoedev *d) skb = f->skb; h = (struct aoe_hdr *) skb->mac.raw; ah = (struct aoe_atahdr *) (h+1); - skb->len = ETH_ZLEN; - memset(h, 0, ETH_ZLEN); + skb_put(skb, sizeof *h + sizeof *ah); + memset(h, 0, skb->len); f->tag = aoehdr_atainit(d, h); f->waited = 0; diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 892e092afe9a..05dfe357527c 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -225,6 +225,8 @@ static inline CommandList_struct *removeQ(CommandList_struct **Qptr, #include "cciss_scsi.c" /* For SCSI tape support */ +#define RAID_UNKNOWN 6 + #ifdef CONFIG_PROC_FS /* @@ -232,7 +234,6 @@ static inline CommandList_struct *removeQ(CommandList_struct **Qptr, */ #define ENG_GIG 1000000000 #define ENG_GIG_FACTOR (ENG_GIG/512) -#define RAID_UNKNOWN 6 static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG", "UNKNOWN" }; @@ -535,7 +536,7 @@ static int do_ioctl(struct file *f, unsigned cmd, unsigned long arg) { int ret; lock_kernel(); - ret = cciss_ioctl(f->f_dentry->d_inode, f, cmd, arg); + ret = cciss_ioctl(f->f_path.dentry->d_inode, f, cmd, arg); unlock_kernel(); return ret; } @@ -1039,7 +1040,7 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, status = -ENOMEM; goto cleanup1; } - buff_size = (int *)kmalloc(MAXSGENTRIES * sizeof(int), + buff_size = kmalloc(MAXSGENTRIES * sizeof(int), GFP_KERNEL); if (!buff_size) { status = -ENOMEM; @@ -1907,6 +1908,7 @@ static void cciss_geometry_inquiry(int ctlr, int logvol, "does not support reading geometry\n"); drv->heads = 255; drv->sectors = 32; // Sectors per track + drv->raid_level = RAID_UNKNOWN; } else { drv->heads = inq_buff->data_byte[6]; drv->sectors = inq_buff->data_byte[7]; @@ -2491,7 +2493,7 @@ static void do_cciss_request(request_queue_t *q) c->Request.Type.Type = TYPE_CMD; // It is a command. c->Request.Type.Attribute = ATTR_SIMPLE; c->Request.Type.Direction = - (rq_data_dir(creq) == READ) ? h->cciss_read : h->cciss_write; + (rq_data_dir(creq) == READ) ? XFER_READ : XFER_WRITE; c->Request.Timeout = 0; // Don't time out c->Request.CDB[0] = (rq_data_dir(creq) == READ) ? h->cciss_read : h->cciss_write; @@ -2837,7 +2839,7 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev) if (err) { printk(KERN_ERR "cciss: Cannot obtain PCI resources, " "aborting\n"); - goto err_out_disable_pdev; + return err; } subsystem_vendor_id = pdev->subsystem_vendor; @@ -2865,7 +2867,7 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev) #ifdef CCISS_DEBUG printk("address 0 = %x\n", c->paddr); #endif /* CCISS_DEBUG */ - c->vaddr = remap_pci_mem(c->paddr, 200); + c->vaddr = remap_pci_mem(c->paddr, 0x250); /* Wait for the board to become ready. (PCI hotplug needs this.) * We poll for up to 120 secs, once per 100ms. */ @@ -3004,11 +3006,12 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev) } return 0; - err_out_free_res: +err_out_free_res: + /* + * Deliberately omit pci_disable_device(): it does something nasty to + * Smart Array controllers that pci_enable_device does not undo + */ pci_release_regions(pdev); - - err_out_disable_pdev: - pci_disable_device(pdev); return err; } @@ -3382,8 +3385,11 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, if (drv->queue) blk_cleanup_queue(drv->queue); } + /* + * Deliberately omit pci_disable_device(): it does something nasty to + * Smart Array controllers that pci_enable_device does not undo + */ pci_release_regions(pdev); - pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); free_hba(i); return -1; @@ -3452,8 +3458,11 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev) #ifdef CONFIG_CISS_SCSI_TAPE kfree(hba[i]->scsi_rejects.complete); #endif + /* + * Deliberately omit pci_disable_device(): it does something nasty to + * Smart Array controllers that pci_enable_device does not undo + */ pci_release_regions(pdev); - pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); free_hba(i); } diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index d5f519ebbc08..b94cd1c32131 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -1625,7 +1625,7 @@ static void start_fwbk(int ctlr) " processing\n"); /* Command does not return anything, but idasend command needs a buffer */ - id_ctlr_buf = (id_ctlr_t *)kmalloc(sizeof(id_ctlr_t), GFP_KERNEL); + id_ctlr_buf = kmalloc(sizeof(id_ctlr_t), GFP_KERNEL); if(id_ctlr_buf==NULL) { printk(KERN_WARNING "cpqarray: Out of memory. " @@ -1660,14 +1660,14 @@ static void getgeometry(int ctlr) info_p->log_drv_map = 0; - id_ldrive = (id_log_drv_t *)kmalloc(sizeof(id_log_drv_t), GFP_KERNEL); + id_ldrive = kmalloc(sizeof(id_log_drv_t), GFP_KERNEL); if(id_ldrive == NULL) { printk( KERN_ERR "cpqarray: out of memory.\n"); return; } - id_ctlr_buf = (id_ctlr_t *)kmalloc(sizeof(id_ctlr_t), GFP_KERNEL); + id_ctlr_buf = kmalloc(sizeof(id_ctlr_t), GFP_KERNEL); if(id_ctlr_buf == NULL) { kfree(id_ldrive); @@ -1675,7 +1675,7 @@ static void getgeometry(int ctlr) return; } - id_lstatus_buf = (sense_log_drv_stat_t *)kmalloc(sizeof(sense_log_drv_stat_t), GFP_KERNEL); + id_lstatus_buf = kmalloc(sizeof(sense_log_drv_stat_t), GFP_KERNEL); if(id_lstatus_buf == NULL) { kfree(id_ctlr_buf); @@ -1684,7 +1684,7 @@ static void getgeometry(int ctlr) return; } - sense_config_buf = (config_t *)kmalloc(sizeof(config_t), GFP_KERNEL); + sense_config_buf = kmalloc(sizeof(config_t), GFP_KERNEL); if(sense_config_buf == NULL) { kfree(id_lstatus_buf); diff --git a/drivers/block/loop.c b/drivers/block/loop.c index beab6d2643cb..6b5b64207407 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -1000,7 +1000,7 @@ loop_get_status(struct loop_device *lo, struct loop_info64 *info) if (lo->lo_state != Lo_bound) return -ENXIO; - error = vfs_getattr(file->f_vfsmnt, file->f_dentry, &stat); + error = vfs_getattr(file->f_path.mnt, file->f_path.dentry, &stat); if (error) return error; memset(info, 0, sizeof(*info)); @@ -1287,7 +1287,7 @@ loop_get_status_compat(struct loop_device *lo, static long lo_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - struct inode *inode = file->f_dentry->d_inode; + struct inode *inode = file->f_path.dentry->d_inode; struct loop_device *lo = inode->i_bdev->bd_disk->private_data; int err; diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 7bf2cfbd6285..090796bef78f 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -537,7 +537,7 @@ static int nbd_ioctl(struct inode *inode, struct file *file, error = -EINVAL; file = fget(arg); if (file) { - inode = file->f_dentry->d_inode; + inode = file->f_path.dentry->d_inode; if (S_ISSOCK(inode->i_mode)) { lo->file = file; lo->sock = SOCKET_I(inode); diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index e45eaa264119..62462190e07e 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2000 Jens Axboe <axboe@suse.de> * Copyright (C) 2001-2004 Peter Osterlund <petero2@telia.com> + * Copyright (C) 2006 Thomas Maier <balagi@justmail.de> * * May be copied or modified under the terms of the GNU General Public * License. See linux/COPYING for more information. @@ -59,6 +60,8 @@ #include <scsi/scsi_cmnd.h> #include <scsi/scsi_ioctl.h> #include <scsi/scsi.h> +#include <linux/debugfs.h> +#include <linux/device.h> #include <asm/uaccess.h> @@ -83,9 +86,424 @@ static struct pktcdvd_device *pkt_devs[MAX_WRITERS]; static struct proc_dir_entry *pkt_proc; static int pktdev_major; +static int write_congestion_on = PKT_WRITE_CONGESTION_ON; +static int write_congestion_off = PKT_WRITE_CONGESTION_OFF; static struct mutex ctl_mutex; /* Serialize open/close/setup/teardown */ static mempool_t *psd_pool; +static struct class *class_pktcdvd = NULL; /* /sys/class/pktcdvd */ +static struct dentry *pkt_debugfs_root = NULL; /* /debug/pktcdvd */ + +/* forward declaration */ +static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev); +static int pkt_remove_dev(dev_t pkt_dev); +static int pkt_seq_show(struct seq_file *m, void *p); + + + +/* + * create and register a pktcdvd kernel object. + */ +static struct pktcdvd_kobj* pkt_kobj_create(struct pktcdvd_device *pd, + const char* name, + struct kobject* parent, + struct kobj_type* ktype) +{ + struct pktcdvd_kobj *p; + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (!p) + return NULL; + kobject_set_name(&p->kobj, "%s", name); + p->kobj.parent = parent; + p->kobj.ktype = ktype; + p->pd = pd; + if (kobject_register(&p->kobj) != 0) + return NULL; + return p; +} +/* + * remove a pktcdvd kernel object. + */ +static void pkt_kobj_remove(struct pktcdvd_kobj *p) +{ + if (p) + kobject_unregister(&p->kobj); +} +/* + * default release function for pktcdvd kernel objects. + */ +static void pkt_kobj_release(struct kobject *kobj) +{ + kfree(to_pktcdvdkobj(kobj)); +} + + +/********************************************************** + * + * sysfs interface for pktcdvd + * by (C) 2006 Thomas Maier <balagi@justmail.de> + * + **********************************************************/ + +#define DEF_ATTR(_obj,_name,_mode) \ + static struct attribute _obj = { \ + .name = _name, .owner = THIS_MODULE, .mode = _mode } + +/********************************************************** + /sys/class/pktcdvd/pktcdvd[0-7]/ + stat/reset + stat/packets_started + stat/packets_finished + stat/kb_written + stat/kb_read + stat/kb_read_gather + write_queue/size + write_queue/congestion_off + write_queue/congestion_on + **********************************************************/ + +DEF_ATTR(kobj_pkt_attr_st1, "reset", 0200); +DEF_ATTR(kobj_pkt_attr_st2, "packets_started", 0444); +DEF_ATTR(kobj_pkt_attr_st3, "packets_finished", 0444); +DEF_ATTR(kobj_pkt_attr_st4, "kb_written", 0444); +DEF_ATTR(kobj_pkt_attr_st5, "kb_read", 0444); +DEF_ATTR(kobj_pkt_attr_st6, "kb_read_gather", 0444); + +static struct attribute *kobj_pkt_attrs_stat[] = { + &kobj_pkt_attr_st1, + &kobj_pkt_attr_st2, + &kobj_pkt_attr_st3, + &kobj_pkt_attr_st4, + &kobj_pkt_attr_st5, + &kobj_pkt_attr_st6, + NULL +}; + +DEF_ATTR(kobj_pkt_attr_wq1, "size", 0444); +DEF_ATTR(kobj_pkt_attr_wq2, "congestion_off", 0644); +DEF_ATTR(kobj_pkt_attr_wq3, "congestion_on", 0644); + +static struct attribute *kobj_pkt_attrs_wqueue[] = { + &kobj_pkt_attr_wq1, + &kobj_pkt_attr_wq2, + &kobj_pkt_attr_wq3, + NULL +}; + +/* declares a char buffer[64] _dbuf, copies data from + * _b with length _l into it and ensures that _dbuf ends + * with a \0 character. + */ +#define DECLARE_BUF_AS_STRING(_dbuf, _b, _l) \ + char _dbuf[64]; int dlen = (_l) < 0 ? 0 : (_l); \ + if (dlen >= sizeof(_dbuf)) dlen = sizeof(_dbuf)-1; \ + memcpy(_dbuf, _b, dlen); _dbuf[dlen] = 0 + +static ssize_t kobj_pkt_show(struct kobject *kobj, + struct attribute *attr, char *data) +{ + struct pktcdvd_device *pd = to_pktcdvdkobj(kobj)->pd; + int n = 0; + int v; + if (strcmp(attr->name, "packets_started") == 0) { + n = sprintf(data, "%lu\n", pd->stats.pkt_started); + + } else if (strcmp(attr->name, "packets_finished") == 0) { + n = sprintf(data, "%lu\n", pd->stats.pkt_ended); + + } else if (strcmp(attr->name, "kb_written") == 0) { + n = sprintf(data, "%lu\n", pd->stats.secs_w >> 1); + + } else if (strcmp(attr->name, "kb_read") == 0) { + n = sprintf(data, "%lu\n", pd->stats.secs_r >> 1); + + } else if (strcmp(attr->name, "kb_read_gather") == 0) { + n = sprintf(data, "%lu\n", pd->stats.secs_rg >> 1); + + } else if (strcmp(attr->name, "size") == 0) { + spin_lock(&pd->lock); + v = pd->bio_queue_size; + spin_unlock(&pd->lock); + n = sprintf(data, "%d\n", v); + + } else if (strcmp(attr->name, "congestion_off") == 0) { + spin_lock(&pd->lock); + v = pd->write_congestion_off; + spin_unlock(&pd->lock); + n = sprintf(data, "%d\n", v); + + } else if (strcmp(attr->name, "congestion_on") == 0) { + spin_lock(&pd->lock); + v = pd->write_congestion_on; + spin_unlock(&pd->lock); + n = sprintf(data, "%d\n", v); + } + return n; +} + +static void init_write_congestion_marks(int* lo, int* hi) +{ + if (*hi > 0) { + *hi = max(*hi, 500); + *hi = min(*hi, 1000000); + if (*lo <= 0) + *lo = *hi - 100; + else { + *lo = min(*lo, *hi - 100); + *lo = max(*lo, 100); + } + } else { + *hi = -1; + *lo = -1; + } +} + +static ssize_t kobj_pkt_store(struct kobject *kobj, + struct attribute *attr, + const char *data, size_t len) +{ + struct pktcdvd_device *pd = to_pktcdvdkobj(kobj)->pd; + int val; + DECLARE_BUF_AS_STRING(dbuf, data, len); /* ensure sscanf scans a string */ + + if (strcmp(attr->name, "reset") == 0 && dlen > 0) { + pd->stats.pkt_started = 0; + pd->stats.pkt_ended = 0; + pd->stats.secs_w = 0; + pd->stats.secs_rg = 0; + pd->stats.secs_r = 0; + + } else if (strcmp(attr->name, "congestion_off") == 0 + && sscanf(dbuf, "%d", &val) == 1) { + spin_lock(&pd->lock); + pd->write_congestion_off = val; + init_write_congestion_marks(&pd->write_congestion_off, + &pd->write_congestion_on); + spin_unlock(&pd->lock); + + } else if (strcmp(attr->name, "congestion_on") == 0 + && sscanf(dbuf, "%d", &val) == 1) { + spin_lock(&pd->lock); + pd->write_congestion_on = val; + init_write_congestion_marks(&pd->write_congestion_off, + &pd->write_congestion_on); + spin_unlock(&pd->lock); + } + return len; +} + +static struct sysfs_ops kobj_pkt_ops = { + .show = kobj_pkt_show, + .store = kobj_pkt_store +}; +static struct kobj_type kobj_pkt_type_stat = { + .release = pkt_kobj_release, + .sysfs_ops = &kobj_pkt_ops, + .default_attrs = kobj_pkt_attrs_stat +}; +static struct kobj_type kobj_pkt_type_wqueue = { + .release = pkt_kobj_release, + .sysfs_ops = &kobj_pkt_ops, + .default_attrs = kobj_pkt_attrs_wqueue +}; + +static void pkt_sysfs_dev_new(struct pktcdvd_device *pd) +{ + if (class_pktcdvd) { + pd->clsdev = class_device_create(class_pktcdvd, + NULL, pd->pkt_dev, + NULL, "%s", pd->name); + if (IS_ERR(pd->clsdev)) + pd->clsdev = NULL; + } + if (pd->clsdev) { + pd->kobj_stat = pkt_kobj_create(pd, "stat", + &pd->clsdev->kobj, + &kobj_pkt_type_stat); + pd->kobj_wqueue = pkt_kobj_create(pd, "write_queue", + &pd->clsdev->kobj, + &kobj_pkt_type_wqueue); + } +} + +static void pkt_sysfs_dev_remove(struct pktcdvd_device *pd) +{ + pkt_kobj_remove(pd->kobj_stat); + pkt_kobj_remove(pd->kobj_wqueue); + if (class_pktcdvd) + class_device_destroy(class_pktcdvd, pd->pkt_dev); +} + + +/******************************************************************** + /sys/class/pktcdvd/ + add map block device + remove unmap packet dev + device_map show mappings + *******************************************************************/ + +static void class_pktcdvd_release(struct class *cls) +{ + kfree(cls); +} +static ssize_t class_pktcdvd_show_map(struct class *c, char *data) +{ + int n = 0; + int idx; + mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); + for (idx = 0; idx < MAX_WRITERS; idx++) { + struct pktcdvd_device *pd = pkt_devs[idx]; + if (!pd) + continue; + n += sprintf(data+n, "%s %u:%u %u:%u\n", + pd->name, + MAJOR(pd->pkt_dev), MINOR(pd->pkt_dev), + MAJOR(pd->bdev->bd_dev), + MINOR(pd->bdev->bd_dev)); + } + mutex_unlock(&ctl_mutex); + return n; +} + +static ssize_t class_pktcdvd_store_add(struct class *c, const char *buf, + size_t count) +{ + unsigned int major, minor; + DECLARE_BUF_AS_STRING(dbuf, buf, count); + if (sscanf(dbuf, "%u:%u", &major, &minor) == 2) { + pkt_setup_dev(MKDEV(major, minor), NULL); + return count; + } + return -EINVAL; +} + +static ssize_t class_pktcdvd_store_remove(struct class *c, const char *buf, + size_t count) +{ + unsigned int major, minor; + DECLARE_BUF_AS_STRING(dbuf, buf, count); + if (sscanf(dbuf, "%u:%u", &major, &minor) == 2) { + pkt_remove_dev(MKDEV(major, minor)); + return count; + } + return -EINVAL; +} + +static struct class_attribute class_pktcdvd_attrs[] = { + __ATTR(add, 0200, NULL, class_pktcdvd_store_add), + __ATTR(remove, 0200, NULL, class_pktcdvd_store_remove), + __ATTR(device_map, 0444, class_pktcdvd_show_map, NULL), + __ATTR_NULL +}; + + +static int pkt_sysfs_init(void) +{ + int ret = 0; + + /* + * create control files in sysfs + * /sys/class/pktcdvd/... + */ + class_pktcdvd = kzalloc(sizeof(*class_pktcdvd), GFP_KERNEL); + if (!class_pktcdvd) + return -ENOMEM; + class_pktcdvd->name = DRIVER_NAME; + class_pktcdvd->owner = THIS_MODULE; + class_pktcdvd->class_release = class_pktcdvd_release; + class_pktcdvd->class_attrs = class_pktcdvd_attrs; + ret = class_register(class_pktcdvd); + if (ret) { + kfree(class_pktcdvd); + class_pktcdvd = NULL; + printk(DRIVER_NAME": failed to create class pktcdvd\n"); + return ret; + } + return 0; +} + +static void pkt_sysfs_cleanup(void) +{ + if (class_pktcdvd) + class_destroy(class_pktcdvd); + class_pktcdvd = NULL; +} + +/******************************************************************** + entries in debugfs + + /debugfs/pktcdvd[0-7]/ + info + + *******************************************************************/ + +static int pkt_debugfs_seq_show(struct seq_file *m, void *p) +{ + return pkt_seq_show(m, p); +} + +static int pkt_debugfs_fops_open(struct inode *inode, struct file *file) +{ + return single_open(file, pkt_debugfs_seq_show, inode->i_private); +} + +static struct file_operations debug_fops = { + .open = pkt_debugfs_fops_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static void pkt_debugfs_dev_new(struct pktcdvd_device *pd) +{ + if (!pkt_debugfs_root) + return; + pd->dfs_f_info = NULL; + pd->dfs_d_root = debugfs_create_dir(pd->name, pkt_debugfs_root); + if (IS_ERR(pd->dfs_d_root)) { + pd->dfs_d_root = NULL; + return; + } + pd->dfs_f_info = debugfs_create_file("info", S_IRUGO, + pd->dfs_d_root, pd, &debug_fops); + if (IS_ERR(pd->dfs_f_info)) { + pd->dfs_f_info = NULL; + return; + } +} + +static void pkt_debugfs_dev_remove(struct pktcdvd_device *pd) +{ + if (!pkt_debugfs_root) + return; + if (pd->dfs_f_info) + debugfs_remove(pd->dfs_f_info); + pd->dfs_f_info = NULL; + if (pd->dfs_d_root) + debugfs_remove(pd->dfs_d_root); + pd->dfs_d_root = NULL; +} + +static void pkt_debugfs_init(void) +{ + pkt_debugfs_root = debugfs_create_dir(DRIVER_NAME, NULL); + if (IS_ERR(pkt_debugfs_root)) { + pkt_debugfs_root = NULL; + return; + } +} + +static void pkt_debugfs_cleanup(void) +{ + if (!pkt_debugfs_root) + return; + debugfs_remove(pkt_debugfs_root); + pkt_debugfs_root = NULL; +} + +/* ----------------------------------------------------------*/ + static void pkt_bio_finished(struct pktcdvd_device *pd) { @@ -347,47 +765,34 @@ static inline struct bio *pkt_get_list_first(struct bio **list_head, struct bio */ static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command *cgc) { - char sense[SCSI_SENSE_BUFFERSIZE]; - request_queue_t *q; + request_queue_t *q = bdev_get_queue(pd->bdev); struct request *rq; - DECLARE_COMPLETION_ONSTACK(wait); - int err = 0; + int ret = 0; - q = bdev_get_queue(pd->bdev); + rq = blk_get_request(q, (cgc->data_direction == CGC_DATA_WRITE) ? + WRITE : READ, __GFP_WAIT); + + if (cgc->buflen) { + if (blk_rq_map_kern(q, rq, cgc->buffer, cgc->buflen, __GFP_WAIT)) + goto out; + } + + rq->cmd_len = COMMAND_SIZE(rq->cmd[0]); + memcpy(rq->cmd, cgc->cmd, CDROM_PACKET_SIZE); + if (sizeof(rq->cmd) > CDROM_PACKET_SIZE) + memset(rq->cmd + CDROM_PACKET_SIZE, 0, sizeof(rq->cmd) - CDROM_PACKET_SIZE); - rq = blk_get_request(q, (cgc->data_direction == CGC_DATA_WRITE) ? WRITE : READ, - __GFP_WAIT); - rq->errors = 0; - rq->rq_disk = pd->bdev->bd_disk; - rq->bio = NULL; - rq->buffer = NULL; rq->timeout = 60*HZ; - rq->data = cgc->buffer; - rq->data_len = cgc->buflen; - rq->sense = sense; - memset(sense, 0, sizeof(sense)); - rq->sense_len = 0; rq->cmd_type = REQ_TYPE_BLOCK_PC; rq->cmd_flags |= REQ_HARDBARRIER; if (cgc->quiet) rq->cmd_flags |= REQ_QUIET; - memcpy(rq->cmd, cgc->cmd, CDROM_PACKET_SIZE); - if (sizeof(rq->cmd) > CDROM_PACKET_SIZE) - memset(rq->cmd + CDROM_PACKET_SIZE, 0, sizeof(rq->cmd) - CDROM_PACKET_SIZE); - rq->cmd_len = COMMAND_SIZE(rq->cmd[0]); - - rq->ref_count++; - rq->end_io_data = &wait; - rq->end_io = blk_end_sync_rq; - elv_add_request(q, rq, ELEVATOR_INSERT_BACK, 1); - generic_unplug_device(q); - wait_for_completion(&wait); - - if (rq->errors) - err = -EIO; + blk_execute_rq(rq->q, pd->bdev->bd_disk, rq, 0); + ret = rq->errors; +out: blk_put_request(rq); - return err; + return ret; } /* @@ -893,6 +1298,7 @@ static int pkt_handle_queue(struct pktcdvd_device *pd) sector_t zone = 0; /* Suppress gcc warning */ struct pkt_rb_node *node, *first_node; struct rb_node *n; + int wakeup; VPRINTK("handle_queue\n"); @@ -965,7 +1371,13 @@ try_next_bio: pkt->write_size += bio->bi_size / CD_FRAMESIZE; spin_unlock(&pkt->lock); } + /* check write congestion marks, and if bio_queue_size is + below, wake up any waiters */ + wakeup = (pd->write_congestion_on > 0 + && pd->bio_queue_size <= pd->write_congestion_off); spin_unlock(&pd->lock); + if (wakeup) + blk_clear_queue_congested(pd->disk->queue, WRITE); pkt->sleep_time = max(PACKET_WAIT_TIME, 1); pkt_set_state(pkt, PACKET_WAITING_STATE); @@ -2178,6 +2590,23 @@ static int pkt_make_request(request_queue_t *q, struct bio *bio) } spin_unlock(&pd->cdrw.active_list_lock); + /* + * Test if there is enough room left in the bio work queue + * (queue size >= congestion on mark). + * If not, wait till the work queue size is below the congestion off mark. + */ + spin_lock(&pd->lock); + if (pd->write_congestion_on > 0 + && pd->bio_queue_size >= pd->write_congestion_on) { + blk_set_queue_congested(q, WRITE); + do { + spin_unlock(&pd->lock); + congestion_wait(WRITE, HZ); + spin_lock(&pd->lock); + } while(pd->bio_queue_size > pd->write_congestion_off); + } + spin_unlock(&pd->lock); + /* * No matching packet found. Store the bio in the work queue. */ @@ -2297,6 +2726,9 @@ static int pkt_seq_show(struct seq_file *m, void *p) seq_printf(m, "\tstate:\t\t\ti:%d ow:%d rw:%d ww:%d rec:%d fin:%d\n", states[0], states[1], states[2], states[3], states[4], states[5]); + seq_printf(m, "\twrite congestion marks:\toff=%d on=%d\n", + pd->write_congestion_off, + pd->write_congestion_on); return 0; } @@ -2436,36 +2868,33 @@ static struct block_device_operations pktcdvd_ops = { /* * Set up mapping from pktcdvd device to CD-ROM device. */ -static int pkt_setup_dev(struct pkt_ctrl_command *ctrl_cmd) +static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev) { int idx; int ret = -ENOMEM; struct pktcdvd_device *pd; struct gendisk *disk; - dev_t dev = new_decode_dev(ctrl_cmd->dev); + + mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); for (idx = 0; idx < MAX_WRITERS; idx++) if (!pkt_devs[idx]) break; if (idx == MAX_WRITERS) { printk(DRIVER_NAME": max %d writers supported\n", MAX_WRITERS); - return -EBUSY; + ret = -EBUSY; + goto out_mutex; } pd = kzalloc(sizeof(struct pktcdvd_device), GFP_KERNEL); if (!pd) - return ret; + goto out_mutex; pd->rb_pool = mempool_create_kmalloc_pool(PKT_RB_POOL_SIZE, sizeof(struct pkt_rb_node)); if (!pd->rb_pool) goto out_mem; - disk = alloc_disk(1); - if (!disk) - goto out_mem; - pd->disk = disk; - INIT_LIST_HEAD(&pd->cdrw.pkt_free_list); INIT_LIST_HEAD(&pd->cdrw.pkt_active_list); spin_lock_init(&pd->cdrw.active_list_lock); @@ -2476,11 +2905,18 @@ static int pkt_setup_dev(struct pkt_ctrl_command *ctrl_cmd) init_waitqueue_head(&pd->wqueue); pd->bio_queue = RB_ROOT; + pd->write_congestion_on = write_congestion_on; + pd->write_congestion_off = write_congestion_off; + + disk = alloc_disk(1); + if (!disk) + goto out_mem; + pd->disk = disk; disk->major = pktdev_major; disk->first_minor = idx; disk->fops = &pktcdvd_ops; disk->flags = GENHD_FL_REMOVABLE; - sprintf(disk->disk_name, DRIVER_NAME"%d", idx); + strcpy(disk->disk_name, pd->name); disk->private_data = pd; disk->queue = blk_alloc_queue(GFP_KERNEL); if (!disk->queue) @@ -2492,8 +2928,15 @@ static int pkt_setup_dev(struct pkt_ctrl_command *ctrl_cmd) goto out_new_dev; add_disk(disk); + + pkt_sysfs_dev_new(pd); + pkt_debugfs_dev_new(pd); + pkt_devs[idx] = pd; - ctrl_cmd->pkt_dev = new_encode_dev(pd->pkt_dev); + if (pkt_dev) + *pkt_dev = pd->pkt_dev; + + mutex_unlock(&ctl_mutex); return 0; out_new_dev: @@ -2504,17 +2947,22 @@ out_mem: if (pd->rb_pool) mempool_destroy(pd->rb_pool); kfree(pd); +out_mutex: + mutex_unlock(&ctl_mutex); + printk(DRIVER_NAME": setup of pktcdvd device failed\n"); return ret; } /* * Tear down mapping from pktcdvd device to CD-ROM device. */ -static int pkt_remove_dev(struct pkt_ctrl_command *ctrl_cmd) +static int pkt_remove_dev(dev_t pkt_dev) { struct pktcdvd_device *pd; int idx; - dev_t pkt_dev = new_decode_dev(ctrl_cmd->pkt_dev); + int ret = 0; + + mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); for (idx = 0; idx < MAX_WRITERS; idx++) { pd = pkt_devs[idx]; @@ -2523,15 +2971,22 @@ static int pkt_remove_dev(struct pkt_ctrl_command *ctrl_cmd) } if (idx == MAX_WRITERS) { DPRINTK(DRIVER_NAME": dev not setup\n"); - return -ENXIO; + ret = -ENXIO; + goto out; } - if (pd->refcnt > 0) - return -EBUSY; - + if (pd->refcnt > 0) { + ret = -EBUSY; + goto out; + } if (!IS_ERR(pd->cdrw.thread)) kthread_stop(pd->cdrw.thread); + pkt_devs[idx] = NULL; + + pkt_debugfs_dev_remove(pd); + pkt_sysfs_dev_remove(pd); + blkdev_put(pd->bdev); remove_proc_entry(pd->name, pkt_proc); @@ -2541,18 +2996,24 @@ static int pkt_remove_dev(struct pkt_ctrl_command *ctrl_cmd) blk_cleanup_queue(pd->disk->queue); put_disk(pd->disk); - pkt_devs[idx] = NULL; mempool_destroy(pd->rb_pool); kfree(pd); /* This is safe: open() is still holding a reference. */ module_put(THIS_MODULE); - return 0; + +out: + mutex_unlock(&ctl_mutex); + return ret; } static void pkt_get_status(struct pkt_ctrl_command *ctrl_cmd) { - struct pktcdvd_device *pd = pkt_find_dev_from_minor(ctrl_cmd->dev_index); + struct pktcdvd_device *pd; + + mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); + + pd = pkt_find_dev_from_minor(ctrl_cmd->dev_index); if (pd) { ctrl_cmd->dev = new_encode_dev(pd->bdev->bd_dev); ctrl_cmd->pkt_dev = new_encode_dev(pd->pkt_dev); @@ -2561,6 +3022,8 @@ static void pkt_get_status(struct pkt_ctrl_command *ctrl_cmd) ctrl_cmd->pkt_dev = 0; } ctrl_cmd->num_devices = MAX_WRITERS; + + mutex_unlock(&ctl_mutex); } static int pkt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) @@ -2568,6 +3031,7 @@ static int pkt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cm void __user *argp = (void __user *)arg; struct pkt_ctrl_command ctrl_cmd; int ret = 0; + dev_t pkt_dev = 0; if (cmd != PACKET_CTRL_CMD) return -ENOTTY; @@ -2579,21 +3043,16 @@ static int pkt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cm case PKT_CTRL_CMD_SETUP: if (!capable(CAP_SYS_ADMIN)) return -EPERM; - mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); - ret = pkt_setup_dev(&ctrl_cmd); - mutex_unlock(&ctl_mutex); + ret = pkt_setup_dev(new_decode_dev(ctrl_cmd.dev), &pkt_dev); + ctrl_cmd.pkt_dev = new_encode_dev(pkt_dev); break; case PKT_CTRL_CMD_TEARDOWN: if (!capable(CAP_SYS_ADMIN)) return -EPERM; - mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); - ret = pkt_remove_dev(&ctrl_cmd); - mutex_unlock(&ctl_mutex); + ret = pkt_remove_dev(new_decode_dev(ctrl_cmd.pkt_dev)); break; case PKT_CTRL_CMD_STATUS: - mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); pkt_get_status(&ctrl_cmd); - mutex_unlock(&ctl_mutex); break; default: return -ENOTTY; @@ -2620,6 +3079,8 @@ static int __init pkt_init(void) { int ret; + mutex_init(&ctl_mutex); + psd_pool = mempool_create_kmalloc_pool(PSD_POOL_SIZE, sizeof(struct packet_stacked_data)); if (!psd_pool) @@ -2633,18 +3094,25 @@ static int __init pkt_init(void) if (!pktdev_major) pktdev_major = ret; + ret = pkt_sysfs_init(); + if (ret) + goto out; + + pkt_debugfs_init(); + ret = misc_register(&pkt_misc); if (ret) { printk(DRIVER_NAME": Unable to register misc device\n"); - goto out; + goto out_misc; } - mutex_init(&ctl_mutex); - pkt_proc = proc_mkdir(DRIVER_NAME, proc_root_driver); return 0; +out_misc: + pkt_debugfs_cleanup(); + pkt_sysfs_cleanup(); out: unregister_blkdev(pktdev_major, DRIVER_NAME); out2: @@ -2656,6 +3124,10 @@ static void __exit pkt_exit(void) { remove_proc_entry(DRIVER_NAME, proc_root_driver); misc_deregister(&pkt_misc); + + pkt_debugfs_cleanup(); + pkt_sysfs_cleanup(); + unregister_blkdev(pktdev_major, DRIVER_NAME); mempool_destroy(psd_pool); } diff --git a/drivers/block/swim_iop.c b/drivers/block/swim_iop.c deleted file mode 100644 index ed7b06cf3e68..000000000000 --- a/drivers/block/swim_iop.c +++ /dev/null @@ -1,578 +0,0 @@ -/* - * Driver for the SWIM (Super Woz Integrated Machine) IOP - * floppy controller on the Macintosh IIfx and Quadra 900/950 - * - * Written by Joshua M. Thompson (funaho@jurai.org) - * based on the SWIM3 driver (c) 1996 by Paul Mackerras. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * 1999-06-12 (jmt) - Initial implementation. - */ - -/* - * ------------------- - * Theory of Operation - * ------------------- - * - * Since the SWIM IOP is message-driven we implement a simple request queue - * system. One outstanding request may be queued at any given time (this is - * an IOP limitation); only when that request has completed can a new request - * be sent. - */ - -#include <linux/stddef.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/timer.h> -#include <linux/delay.h> -#include <linux/fd.h> -#include <linux/ioctl.h> -#include <linux/blkdev.h> -#include <asm/io.h> -#include <asm/uaccess.h> -#include <asm/mac_iop.h> -#include <asm/swim_iop.h> - -#define DRIVER_VERSION "Version 0.1 (1999-06-12)" - -#define MAX_FLOPPIES 4 - -enum swim_state { - idle, - available, - revalidating, - transferring, - ejecting -}; - -struct floppy_state { - enum swim_state state; - int drive_num; /* device number */ - int secpercyl; /* disk geometry information */ - int secpertrack; - int total_secs; - int write_prot; /* 1 if write-protected, 0 if not, -1 dunno */ - int ref_count; - struct timer_list timeout; - int ejected; - struct wait_queue *wait; - int wanted; - int timeout_pending; -}; - -struct swim_iop_req { - int sent; - int complete; - __u8 command[32]; - struct floppy_state *fs; - void (*done)(struct swim_iop_req *); -}; - -static struct swim_iop_req *current_req; -static int floppy_count; - -static struct floppy_state floppy_states[MAX_FLOPPIES]; -static DEFINE_SPINLOCK(swim_iop_lock); - -#define CURRENT elv_next_request(swim_queue) - -static char *drive_names[7] = { - "not installed", /* DRV_NONE */ - "unknown (1)", /* DRV_UNKNOWN */ - "a 400K drive", /* DRV_400K */ - "an 800K drive" /* DRV_800K */ - "unknown (4)", /* ???? */ - "an FDHD", /* DRV_FDHD */ - "unknown (6)", /* ???? */ - "an Apple HD20" /* DRV_HD20 */ -}; - -int swimiop_init(void); -static void swimiop_init_request(struct swim_iop_req *); -static int swimiop_send_request(struct swim_iop_req *); -static void swimiop_receive(struct iop_msg *); -static void swimiop_status_update(int, struct swim_drvstatus *); -static int swimiop_eject(struct floppy_state *fs); - -static int floppy_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long param); -static int floppy_open(struct inode *inode, struct file *filp); -static int floppy_release(struct inode *inode, struct file *filp); -static int floppy_check_change(struct gendisk *disk); -static int floppy_revalidate(struct gendisk *disk); -static int grab_drive(struct floppy_state *fs, enum swim_state state, - int interruptible); -static void release_drive(struct floppy_state *fs); -static void set_timeout(struct floppy_state *fs, int nticks, - void (*proc)(unsigned long)); -static void fd_request_timeout(unsigned long); -static void do_fd_request(request_queue_t * q); -static void start_request(struct floppy_state *fs); - -static struct block_device_operations floppy_fops = { - .open = floppy_open, - .release = floppy_release, - .ioctl = floppy_ioctl, - .media_changed = floppy_check_change, - .revalidate_disk= floppy_revalidate, -}; - -static struct request_queue *swim_queue; -/* - * SWIM IOP initialization - */ - -int swimiop_init(void) -{ - volatile struct swim_iop_req req; - struct swimcmd_status *cmd = (struct swimcmd_status *) &req.command[0]; - struct swim_drvstatus *ds = &cmd->status; - struct floppy_state *fs; - int i; - - current_req = NULL; - floppy_count = 0; - - if (!iop_ism_present) - return -ENODEV; - - if (register_blkdev(FLOPPY_MAJOR, "fd")) - return -EBUSY; - - swim_queue = blk_init_queue(do_fd_request, &swim_iop_lock); - if (!swim_queue) { - unregister_blkdev(FLOPPY_MAJOR, "fd"); - return -ENOMEM; - } - - printk("SWIM-IOP: %s by Joshua M. Thompson (funaho@jurai.org)\n", - DRIVER_VERSION); - - if (iop_listen(SWIM_IOP, SWIM_CHAN, swimiop_receive, "SWIM") != 0) { - printk(KERN_ERR "SWIM-IOP: IOP channel already in use; can't initialize.\n"); - unregister_blkdev(FLOPPY_MAJOR, "fd"); - blk_cleanup_queue(swim_queue); - return -EBUSY; - } - - printk(KERN_ERR "SWIM_IOP: probing for installed drives.\n"); - - for (i = 0 ; i < MAX_FLOPPIES ; i++) { - memset(&floppy_states[i], 0, sizeof(struct floppy_state)); - fs = &floppy_states[floppy_count]; - - swimiop_init_request(&req); - cmd->code = CMD_STATUS; - cmd->drive_num = i + 1; - if (swimiop_send_request(&req) != 0) continue; - while (!req.complete); - if (cmd->error != 0) { - printk(KERN_ERR "SWIM-IOP: probe on drive %d returned error %d\n", i, (uint) cmd->error); - continue; - } - if (ds->installed != 0x01) continue; - printk("SWIM-IOP: drive %d is %s (%s, %s, %s, %s)\n", i, - drive_names[ds->info.type], - ds->info.external? "ext" : "int", - ds->info.scsi? "scsi" : "floppy", - ds->info.fixed? "fixed" : "removable", - ds->info.secondary? "secondary" : "primary"); - swimiop_status_update(floppy_count, ds); - fs->state = idle; - - init_timer(&fs->timeout); - floppy_count++; - } - printk("SWIM-IOP: detected %d installed drives.\n", floppy_count); - - for (i = 0; i < floppy_count; i++) { - struct gendisk *disk = alloc_disk(1); - if (!disk) - continue; - disk->major = FLOPPY_MAJOR; - disk->first_minor = i; - disk->fops = &floppy_fops; - sprintf(disk->disk_name, "fd%d", i); - disk->private_data = &floppy_states[i]; - disk->queue = swim_queue; - set_capacity(disk, 2880 * 2); - add_disk(disk); - } - - return 0; -} - -static void swimiop_init_request(struct swim_iop_req *req) -{ - req->sent = 0; - req->complete = 0; - req->done = NULL; -} - -static int swimiop_send_request(struct swim_iop_req *req) -{ - unsigned long flags; - int err; - - /* It's doubtful an interrupt routine would try to send */ - /* a SWIM request, but I'd rather play it safe here. */ - - local_irq_save(flags); - - if (current_req != NULL) { - local_irq_restore(flags); - return -ENOMEM; - } - - current_req = req; - - /* Interrupts should be back on for iop_send_message() */ - - local_irq_restore(flags); - - err = iop_send_message(SWIM_IOP, SWIM_CHAN, (void *) req, - sizeof(req->command), (__u8 *) &req->command[0], - swimiop_receive); - - /* No race condition here; we own current_req at this point */ - - if (err) { - current_req = NULL; - } else { - req->sent = 1; - } - return err; -} - -/* - * Receive a SWIM message from the IOP. - * - * This will be called in two cases: - * - * 1. A message has been successfully sent to the IOP. - * 2. An unsolicited message was received from the IOP. - */ - -void swimiop_receive(struct iop_msg *msg) -{ - struct swim_iop_req *req; - struct swimmsg_status *sm; - struct swim_drvstatus *ds; - - req = current_req; - - switch(msg->status) { - case IOP_MSGSTATUS_COMPLETE: - memcpy(&req->command[0], &msg->reply[0], sizeof(req->command)); - req->complete = 1; - if (req->done) (*req->done)(req); - current_req = NULL; - break; - case IOP_MSGSTATUS_UNSOL: - sm = (struct swimmsg_status *) &msg->message[0]; - ds = &sm->status; - swimiop_status_update(sm->drive_num, ds); - iop_complete_message(msg); - break; - } -} - -static void swimiop_status_update(int drive_num, struct swim_drvstatus *ds) -{ - struct floppy_state *fs = &floppy_states[drive_num]; - - fs->write_prot = (ds->write_prot == 0x80); - if ((ds->disk_in_drive != 0x01) && (ds->disk_in_drive != 0x02)) { - fs->ejected = 1; - } else { - fs->ejected = 0; - } - switch(ds->info.type) { - case DRV_400K: - fs->secpercyl = 10; - fs->secpertrack = 10; - fs->total_secs = 800; - break; - case DRV_800K: - fs->secpercyl = 20; - fs->secpertrack = 10; - fs->total_secs = 1600; - break; - case DRV_FDHD: - fs->secpercyl = 36; - fs->secpertrack = 18; - fs->total_secs = 2880; - break; - default: - fs->secpercyl = 0; - fs->secpertrack = 0; - fs->total_secs = 0; - break; - } -} - -static int swimiop_eject(struct floppy_state *fs) -{ - int err, n; - struct swim_iop_req req; - struct swimcmd_eject *cmd = (struct swimcmd_eject *) &req.command[0]; - - err = grab_drive(fs, ejecting, 1); - if (err) return err; - - swimiop_init_request(&req); - cmd->code = CMD_EJECT; - cmd->drive_num = fs->drive_num; - err = swimiop_send_request(&req); - if (err) { - release_drive(fs); - return err; - } - for (n = 2*HZ; n > 0; --n) { - if (req.complete) break; - if (signal_pending(current)) { - err = -EINTR; - break; - } - schedule_timeout_interruptible(1); - } - release_drive(fs); - return cmd->error; -} - -static struct floppy_struct floppy_type = - { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,NULL }; /* 7 1.44MB 3.5" */ - -static int floppy_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long param) -{ - struct floppy_state *fs = inode->i_bdev->bd_disk->private_data; - int err; - - if ((cmd & 0x80) && !capable(CAP_SYS_ADMIN)) - return -EPERM; - - switch (cmd) { - case FDEJECT: - if (fs->ref_count != 1) - return -EBUSY; - err = swimiop_eject(fs); - return err; - case FDGETPRM: - if (copy_to_user((void *) param, (void *) &floppy_type, - sizeof(struct floppy_struct))) - return -EFAULT; - return 0; - } - return -ENOTTY; -} - -static int floppy_open(struct inode *inode, struct file *filp) -{ - struct floppy_state *fs = inode->i_bdev->bd_disk->private_data; - - if (fs->ref_count == -1 || filp->f_flags & O_EXCL) - return -EBUSY; - - if ((filp->f_flags & O_NDELAY) == 0 && (filp->f_mode & 3)) { - check_disk_change(inode->i_bdev); - if (fs->ejected) - return -ENXIO; - } - - if ((filp->f_mode & 2) && fs->write_prot) - return -EROFS; - - if (filp->f_flags & O_EXCL) - fs->ref_count = -1; - else - ++fs->ref_count; - - return 0; -} - -static int floppy_release(struct inode *inode, struct file *filp) -{ - struct floppy_state *fs = inode->i_bdev->bd_disk->private_data; - if (fs->ref_count > 0) - fs->ref_count--; - return 0; -} - -static int floppy_check_change(struct gendisk *disk) -{ - struct floppy_state *fs = disk->private_data; - return fs->ejected; -} - -static int floppy_revalidate(struct gendisk *disk) -{ - struct floppy_state *fs = disk->private_data; - grab_drive(fs, revalidating, 0); - /* yadda, yadda */ - release_drive(fs); - return 0; -} - -static void floppy_off(unsigned int nr) -{ -} - -static int grab_drive(struct floppy_state *fs, enum swim_state state, - int interruptible) -{ - unsigned long flags; - - local_irq_save(flags); - if (fs->state != idle) { - ++fs->wanted; - while (fs->state != available) { - if (interruptible && signal_pending(current)) { - --fs->wanted; - local_irq_restore(flags); - return -EINTR; - } - interruptible_sleep_on(&fs->wait); - } - --fs->wanted; - } - fs->state = state; - local_irq_restore(flags); - return 0; -} - -static void release_drive(struct floppy_state *fs) -{ - unsigned long flags; - - local_irq_save(flags); - fs->state = idle; - start_request(fs); - local_irq_restore(flags); -} - -static void set_timeout(struct floppy_state *fs, int nticks, - void (*proc)(unsigned long)) -{ - unsigned long flags; - - local_irq_save(flags); - if (fs->timeout_pending) - del_timer(&fs->timeout); - init_timer(&fs->timeout); - fs->timeout.expires = jiffies + nticks; - fs->timeout.function = proc; - fs->timeout.data = (unsigned long) fs; - add_timer(&fs->timeout); - fs->timeout_pending = 1; - local_irq_restore(flags); -} - -static void do_fd_request(request_queue_t * q) -{ - int i; - - for (i = 0 ; i < floppy_count ; i++) { - start_request(&floppy_states[i]); - } -} - -static void fd_request_complete(struct swim_iop_req *req) -{ - struct floppy_state *fs = req->fs; - struct swimcmd_rw *cmd = (struct swimcmd_rw *) &req->command[0]; - - del_timer(&fs->timeout); - fs->timeout_pending = 0; - fs->state = idle; - if (cmd->error) { - printk(KERN_ERR "SWIM-IOP: error %d on read/write request.\n", cmd->error); - end_request(CURRENT, 0); - } else { - CURRENT->sector += cmd->num_blocks; - CURRENT->current_nr_sectors -= cmd->num_blocks; - if (CURRENT->current_nr_sectors <= 0) { - end_request(CURRENT, 1); - return; - } - } - start_request(fs); -} - -static void fd_request_timeout(unsigned long data) -{ - struct floppy_state *fs = (struct floppy_state *) data; - - fs->timeout_pending = 0; - end_request(CURRENT, 0); - fs->state = idle; -} - -static void start_request(struct floppy_state *fs) -{ - volatile struct swim_iop_req req; - struct swimcmd_rw *cmd = (struct swimcmd_rw *) &req.command[0]; - - if (fs->state == idle && fs->wanted) { - fs->state = available; - wake_up(&fs->wait); - return; - } - while (CURRENT && fs->state == idle) { - if (CURRENT->bh && !buffer_locked(CURRENT->bh)) - panic("floppy: block not locked"); -#if 0 - printk("do_fd_req: dev=%s cmd=%d sec=%ld nr_sec=%ld buf=%p\n", - CURRENT->rq_disk->disk_name, CURRENT->cmd, - CURRENT->sector, CURRENT->nr_sectors, CURRENT->buffer); - printk(" errors=%d current_nr_sectors=%ld\n", - CURRENT->errors, CURRENT->current_nr_sectors); -#endif - - if (CURRENT->sector < 0 || CURRENT->sector >= fs->total_secs) { - end_request(CURRENT, 0); - continue; - } - if (CURRENT->current_nr_sectors == 0) { - end_request(CURRENT, 1); - continue; - } - if (fs->ejected) { - end_request(CURRENT, 0); - continue; - } - - swimiop_init_request(&req); - req.fs = fs; - req.done = fd_request_complete; - - if (CURRENT->cmd == WRITE) { - if (fs->write_prot) { - end_request(CURRENT, 0); - continue; - } - cmd->code = CMD_WRITE; - } else { - cmd->code = CMD_READ; - - } - cmd->drive_num = fs->drive_num; - cmd->buffer = CURRENT->buffer; - cmd->first_block = CURRENT->sector; - cmd->num_blocks = CURRENT->current_nr_sectors; - - if (swimiop_send_request(&req)) { - end_request(CURRENT, 0); - continue; - } - - set_timeout(fs, HZ*CURRENT->current_nr_sectors, - fd_request_timeout); - - fs->state = transferring; - } -} diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c index e19ba4ebcd4e..68592c336011 100644 --- a/drivers/block/viodasd.c +++ b/drivers/block/viodasd.c @@ -49,6 +49,7 @@ #include <asm/iseries/hv_lp_event.h> #include <asm/iseries/hv_lp_config.h> #include <asm/iseries/vio.h> +#include <asm/firmware.h> MODULE_DESCRIPTION("iSeries Virtual DASD"); MODULE_AUTHOR("Dave Boutcher"); @@ -769,6 +770,11 @@ static int __init viodasd_init(void) { int rc; + if (!firmware_has_feature(FW_FEATURE_ISERIES)) { + rc = -ENODEV; + goto early_fail; + } + /* Try to open to our host lp */ if (viopath_hostLp == HvLpIndexInvalid) vio_set_hostlp(); |