diff options
Diffstat (limited to 'drivers/block')
-rw-r--r-- | drivers/block/DAC960.c | 12 | ||||
-rw-r--r-- | drivers/block/Kconfig | 17 | ||||
-rw-r--r-- | drivers/block/Makefile | 1 | ||||
-rw-r--r-- | drivers/block/aoe/aoecmd.c | 23 | ||||
-rw-r--r-- | drivers/block/brd.c | 5 | ||||
-rw-r--r-- | drivers/block/cciss.c | 123 | ||||
-rw-r--r-- | drivers/block/cciss.h | 2 | ||||
-rw-r--r-- | drivers/block/cciss_cmd.h | 23 | ||||
-rw-r--r-- | drivers/block/floppy.c | 8 | ||||
-rw-r--r-- | drivers/block/hd.c | 2 | ||||
-rw-r--r-- | drivers/block/loop.c | 7 | ||||
-rw-r--r-- | drivers/block/mg_disk.c | 1005 | ||||
-rw-r--r-- | drivers/block/nbd.c | 112 | ||||
-rw-r--r-- | drivers/block/sx8.c | 6 | ||||
-rw-r--r-- | drivers/block/ub.c | 20 | ||||
-rw-r--r-- | drivers/block/umem.c | 4 | ||||
-rw-r--r-- | drivers/block/xsysace.c | 34 |
17 files changed, 1297 insertions, 107 deletions
diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c index f6a337c34ac..f22ed6cc69f 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -1169,9 +1169,9 @@ static bool DAC960_V1_EnableMemoryMailboxInterface(DAC960_Controller_T int i; - if (pci_set_dma_mask(Controller->PCIDevice, DMA_32BIT_MASK)) + if (pci_set_dma_mask(Controller->PCIDevice, DMA_BIT_MASK(32))) return DAC960_Failure(Controller, "DMA mask out of range"); - Controller->BounceBufferLimit = DMA_32BIT_MASK; + Controller->BounceBufferLimit = DMA_BIT_MASK(32); if ((hw_type == DAC960_PD_Controller) || (hw_type == DAC960_P_Controller)) { CommandMailboxesSize = 0; @@ -1372,10 +1372,10 @@ static bool DAC960_V2_EnableMemoryMailboxInterface(DAC960_Controller_T dma_addr_t CommandMailboxDMA; DAC960_V2_CommandStatus_T CommandStatus; - if (!pci_set_dma_mask(Controller->PCIDevice, DMA_64BIT_MASK)) - Controller->BounceBufferLimit = DMA_64BIT_MASK; - else if (!pci_set_dma_mask(Controller->PCIDevice, DMA_32BIT_MASK)) - Controller->BounceBufferLimit = DMA_32BIT_MASK; + if (!pci_set_dma_mask(Controller->PCIDevice, DMA_BIT_MASK(64))) + Controller->BounceBufferLimit = DMA_BIT_MASK(64); + else if (!pci_set_dma_mask(Controller->PCIDevice, DMA_BIT_MASK(32))) + Controller->BounceBufferLimit = DMA_BIT_MASK(32); else return DAC960_Failure(Controller, "DMA mask out of range"); diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index e7b8aa0cb47..ddea8e485cc 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -410,6 +410,23 @@ config ATA_OVER_ETH This driver provides Support for ATA over Ethernet block devices like the Coraid EtherDrive (R) Storage Blade. +config MG_DISK + tristate "mGine mflash, gflash support" + depends on ARM && ATA && GPIOLIB + help + mGine mFlash(gFlash) block device driver + +config MG_DISK_RES + int "Size of reserved area before MBR" + depends on MG_DISK + default 0 + help + Define size of reserved area that usually used for boot. Unit is KB. + All of the block device operation will be taken this value as start + offset + Examples: + 1024 => 1 MB + config SUNVDC tristate "Sun Virtual Disk Client support" depends on SUN_LDOMS diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 3145141cef7..7755a5e2a85 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_BLK_CPQ_CISS_DA) += cciss.o obj-$(CONFIG_BLK_DEV_DAC960) += DAC960.o obj-$(CONFIG_XILINX_SYSACE) += xsysace.o obj-$(CONFIG_CDROM_PKTCDVD) += pktcdvd.o +obj-$(CONFIG_MG_DISK) += mg_disk.o obj-$(CONFIG_SUNVDC) += sunvdc.o obj-$(CONFIG_BLK_DEV_UMEM) += umem.o diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 45c5a33daf4..31693bc2444 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -4,6 +4,7 @@ * Filesystem request handling methods */ +#include <linux/ata.h> #include <linux/hdreg.h> #include <linux/blkdev.h> #include <linux/skbuff.h> @@ -267,7 +268,7 @@ aoecmd_ata_rw(struct aoedev *d) writebit = 0; } - ah->cmdstat = WIN_READ | writebit | extbit; + ah->cmdstat = ATA_CMD_PIO_READ | writebit | extbit; /* mark all tracking fields and load out */ buf->nframesout += 1; @@ -362,10 +363,10 @@ resend(struct aoedev *d, struct aoetgt *t, struct frame *f) switch (ah->cmdstat) { default: break; - case WIN_READ: - case WIN_READ_EXT: - case WIN_WRITE: - case WIN_WRITE_EXT: + case ATA_CMD_PIO_READ: + case ATA_CMD_PIO_READ_EXT: + case ATA_CMD_PIO_WRITE: + case ATA_CMD_PIO_WRITE_EXT: put_lba(ah, f->lba); n = f->bcnt; @@ -812,8 +813,8 @@ aoecmd_ata_rsp(struct sk_buff *skb) d->htgt = NULL; n = ahout->scnt << 9; switch (ahout->cmdstat) { - case WIN_READ: - case WIN_READ_EXT: + case ATA_CMD_PIO_READ: + case ATA_CMD_PIO_READ_EXT: if (skb->len - sizeof *hin - sizeof *ahin < n) { printk(KERN_ERR "aoe: %s. skb->len=%d need=%ld\n", @@ -823,8 +824,8 @@ aoecmd_ata_rsp(struct sk_buff *skb) return; } memcpy(f->bufaddr, ahin+1, n); - case WIN_WRITE: - case WIN_WRITE_EXT: + case ATA_CMD_PIO_WRITE: + case ATA_CMD_PIO_WRITE_EXT: ifp = getif(t, skb->dev); if (ifp) { ifp->lost = 0; @@ -838,7 +839,7 @@ aoecmd_ata_rsp(struct sk_buff *skb) goto xmit; } break; - case WIN_IDENTIFY: + case ATA_CMD_ID_ATA: if (skb->len - sizeof *hin - sizeof *ahin < 512) { printk(KERN_INFO "aoe: runt data size in ataid. skb->len=%d\n", @@ -914,7 +915,7 @@ aoecmd_ata_id(struct aoedev *d) /* set up ata header */ ah->scnt = 1; - ah->cmdstat = WIN_IDENTIFY; + ah->cmdstat = ATA_CMD_ID_ATA; ah->lba3 = 0xa0; skb->dev = t->ifp->nd; diff --git a/drivers/block/brd.c b/drivers/block/brd.c index bdd4f5f4557..5f7e64ba87e 100644 --- a/drivers/block/brd.c +++ b/drivers/block/brd.c @@ -275,8 +275,10 @@ static int brd_do_bvec(struct brd_device *brd, struct page *page, if (rw == READ) { copy_from_brd(mem + off, brd, sector, len); flush_dcache_page(page); - } else + } else { + flush_dcache_page(page); copy_to_brd(brd, mem + off, sector, len); + } kunmap_atomic(mem, KM_USER0); out: @@ -436,6 +438,7 @@ static struct brd_device *brd_alloc(int i) if (!brd->brd_queue) goto out_free_dev; blk_queue_make_request(brd->brd_queue, brd_make_request); + blk_queue_ordered(brd->brd_queue, QUEUE_ORDERED_TAG, NULL); blk_queue_max_sectors(brd->brd_queue, 1024); blk_queue_bounce_limit(brd->brd_queue, BLK_BOUNCE_ANY); diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 5d0e135824f..4d4d5e0d3fa 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -51,6 +51,7 @@ #include <scsi/scsi_ioctl.h> #include <linux/cdrom.h> #include <linux/scatterlist.h> +#include <linux/kthread.h> #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin)) #define DRIVER_NAME "HP CISS Driver (v 3.6.20)" @@ -186,6 +187,8 @@ static int sendcmd_withirq(__u8 cmd, int ctlr, void *buff, size_t size, __u8 page_code, int cmd_type); static void fail_all_cmds(unsigned long ctlr); +static int scan_thread(void *data); +static int check_for_unit_attention(ctlr_info_t *h, CommandList_struct *c); #ifdef CONFIG_PROC_FS static void cciss_procinit(int i); @@ -735,6 +738,12 @@ static int cciss_getgeo(struct block_device *bdev, struct hd_geometry *geo) return 0; } +static void check_ioctl_unit_attention(ctlr_info_t *host, CommandList_struct *c) +{ + if (c->err_info->CommandStatus == CMD_TARGET_STATUS && + c->err_info->ScsiStatus != SAM_STAT_CHECK_CONDITION) + (void)check_for_unit_attention(host, c); +} /* * ioctl */ @@ -1029,6 +1038,8 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode, iocommand.buf_size, PCI_DMA_BIDIRECTIONAL); + check_ioctl_unit_attention(host, c); + /* Copy the error information out */ iocommand.error_info = *(c->err_info); if (copy_to_user @@ -1180,6 +1191,7 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode, (dma_addr_t) temp64.val, buff_size[i], PCI_DMA_BIDIRECTIONAL); } + check_ioctl_unit_attention(host, c); /* Copy the error information out */ ioc->error_info = *(c->err_info); if (copy_to_user(argp, ioc, sizeof(*ioc))) { @@ -1287,6 +1299,7 @@ static void cciss_softirq_done(struct request *rq) { CommandList_struct *cmd = rq->completion_data; ctlr_info_t *h = hba[cmd->ctlr]; + unsigned int nr_bytes; unsigned long flags; u64bit temp64; int i, ddir; @@ -1308,7 +1321,14 @@ static void cciss_softirq_done(struct request *rq) printk("Done with %p\n", rq); #endif /* CCISS_DEBUG */ - if (blk_end_request(rq, (rq->errors == 0) ? 0 : -EIO, blk_rq_bytes(rq))) + /* + * Store the full size and set the residual count for pc requests + */ + nr_bytes = blk_rq_bytes(rq); + if (blk_pc_request(rq)) + rq->data_len = cmd->err_info->ResidualCnt; + + if (blk_end_request(rq, (rq->errors == 0) ? 0 : -EIO, nr_bytes)) BUG(); spin_lock_irqsave(&h->lock, flags); @@ -2585,12 +2605,14 @@ static inline unsigned int make_status_bytes(unsigned int scsi_status_byte, ((driver_byte & 0xff) << 24); } -static inline int evaluate_target_status(CommandList_struct *cmd) +static inline int evaluate_target_status(ctlr_info_t *h, + CommandList_struct *cmd, int *retry_cmd) { unsigned char sense_key; unsigned char status_byte, msg_byte, host_byte, driver_byte; int error_value; + *retry_cmd = 0; /* If we get in here, it means we got "target status", that is, scsi status */ status_byte = cmd->err_info->ScsiStatus; driver_byte = DRIVER_OK; @@ -2618,6 +2640,11 @@ static inline int evaluate_target_status(CommandList_struct *cmd) if (((sense_key == 0x0) || (sense_key == 0x1)) && !blk_pc_request(cmd->rq)) error_value = 0; + if (check_for_unit_attention(h, cmd)) { + *retry_cmd = !blk_pc_request(cmd->rq); + return 0; + } + if (!blk_pc_request(cmd->rq)) { /* Not SG_IO or similar? */ if (error_value != 0) printk(KERN_WARNING "cciss: cmd %p has CHECK CONDITION" @@ -2657,7 +2684,7 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd, switch (cmd->err_info->CommandStatus) { case CMD_TARGET_STATUS: - rq->errors = evaluate_target_status(cmd); + rq->errors = evaluate_target_status(h, cmd, &retry_cmd); break; case CMD_DATA_UNDERRUN: if (blk_fs_request(cmd->rq)) { @@ -3008,6 +3035,63 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id) return IRQ_HANDLED; } +static int scan_thread(void *data) +{ + ctlr_info_t *h = data; + int rc; + DECLARE_COMPLETION_ONSTACK(wait); + h->rescan_wait = &wait; + + for (;;) { + rc = wait_for_completion_interruptible(&wait); + if (kthread_should_stop()) + break; + if (!rc) + rebuild_lun_table(h, 0); + } + return 0; +} + +static int check_for_unit_attention(ctlr_info_t *h, CommandList_struct *c) +{ + if (c->err_info->SenseInfo[2] != UNIT_ATTENTION) + return 0; + + switch (c->err_info->SenseInfo[12]) { + case STATE_CHANGED: + printk(KERN_WARNING "cciss%d: a state change " + "detected, command retried\n", h->ctlr); + return 1; + break; + case LUN_FAILED: + printk(KERN_WARNING "cciss%d: LUN failure " + "detected, action required\n", h->ctlr); + return 1; + break; + case REPORT_LUNS_CHANGED: + printk(KERN_WARNING "cciss%d: report LUN data " + "changed\n", h->ctlr); + if (h->rescan_wait) + complete(h->rescan_wait); + return 1; + break; + case POWER_OR_RESET: + printk(KERN_WARNING "cciss%d: a power on " + "or device reset detected\n", h->ctlr); + return 1; + break; + case UNIT_ATTENTION_CLEARED: + printk(KERN_WARNING "cciss%d: unit attention " + "cleared by another initiator\n", h->ctlr); + return 1; + break; + default: + printk(KERN_WARNING "cciss%d: unknown " + "unit attention detected\n", h->ctlr); + return 1; + } +} + /* * We cannot read the structure directly, for portability we must use * the io functions. @@ -3181,12 +3265,21 @@ static int __devinit cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev) */ cciss_interrupt_mode(c, pdev, board_id); - /* - * Memory base addr is first addr , the second points to the config - * table - */ + /* find the memory BAR */ + for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { + if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) + break; + } + if (i == DEVICE_COUNT_RESOURCE) { + printk(KERN_WARNING "cciss: No memory BAR found\n"); + err = -ENODEV; + goto err_out_free_res; + } + + c->paddr = pci_resource_start(pdev, i); /* addressing mode bits + * already removed + */ - c->paddr = pci_resource_start(pdev, 0); /* addressing mode bits already removed */ #ifdef CCISS_DEBUG printk("address 0 = %lx\n", c->paddr); #endif /* CCISS_DEBUG */ @@ -3412,7 +3505,7 @@ static __devinit int cciss_message(struct pci_dev *pdev, unsigned char opcode, u /* The Inbound Post Queue only accepts 32-bit physical addresses for the CCISS commands, so they must be allocated from the lower 4GiB of memory. */ - err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); if (err) { iounmap(vaddr); return -ENOMEM; @@ -3637,9 +3730,9 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, hba[i]->pdev = pdev; /* configure PCI DMA stuff */ - if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) + if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) dac = 1; - else if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK)) + else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) dac = 0; else { printk(KERN_ERR "cciss: no suitable DMA available\n"); @@ -3753,6 +3846,11 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, hba[i]->busy_initializing = 0; rebuild_lun_table(hba[i], 1); + hba[i]->cciss_scan_thread = kthread_run(scan_thread, hba[i], + "cciss_scan%02d", i); + if (IS_ERR(hba[i]->cciss_scan_thread)) + return PTR_ERR(hba[i]->cciss_scan_thread); + return 1; clean4: @@ -3828,6 +3926,7 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev) printk(KERN_ERR "cciss: Unable to remove device \n"); return; } + tmp_ptr = pci_get_drvdata(pdev); i = tmp_ptr->ctlr; if (hba[i] == NULL) { @@ -3836,6 +3935,8 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev) return; } + kthread_stop(hba[i]->cciss_scan_thread); + remove_proc_entry(hba[i]->devname, proc_cciss); unregister_blkdev(hba[i]->major, hba[i]->devname); diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h index 15e2b84734e..703e08038fb 100644 --- a/drivers/block/cciss.h +++ b/drivers/block/cciss.h @@ -121,6 +121,8 @@ struct ctlr_info struct sendcmd_reject_list scsi_rejects; #endif unsigned char alive; + struct completion *rescan_wait; + struct task_struct *cciss_scan_thread; }; /* Defining the diffent access_menthods */ diff --git a/drivers/block/cciss_cmd.h b/drivers/block/cciss_cmd.h index 24e22dea1a9..40b1b92dae7 100644 --- a/drivers/block/cciss_cmd.h +++ b/drivers/block/cciss_cmd.h @@ -25,6 +25,29 @@ #define CMD_TIMEOUT 0x000B #define CMD_UNABORTABLE 0x000C +/* Unit Attentions ASC's as defined for the MSA2012sa */ +#define POWER_OR_RESET 0x29 +#define STATE_CHANGED 0x2a +#define UNIT_ATTENTION_CLEARED 0x2f +#define LUN_FAILED 0x3e +#define REPORT_LUNS_CHANGED 0x3f + +/* Unit Attentions ASCQ's as defined for the MSA2012sa */ + + /* These ASCQ's defined for ASC = POWER_OR_RESET */ +#define POWER_ON_RESET 0x00 +#define POWER_ON_REBOOT 0x01 +#define SCSI_BUS_RESET 0x02 +#define MSA_TARGET_RESET 0x03 +#define CONTROLLER_FAILOVER 0x04 +#define TRANSCEIVER_SE 0x05 +#define TRANSCEIVER_LVD 0x06 + + /* These ASCQ's defined for ASC = STATE_CHANGED */ +#define RESERVATION_PREEMPTED 0x03 +#define ASYM_ACCESS_CHANGED 0x06 +#define LUN_CAPACITY_CHANGED 0x09 + //transfer direction #define XFER_NONE 0x00 #define XFER_WRITE 0x01 diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index c2c95e61450..1300df6f164 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -177,6 +177,7 @@ static int print_unex = 1; #include <linux/interrupt.h> #include <linux/init.h> #include <linux/platform_device.h> +#include <linux/mod_devicetable.h> #include <linux/buffer_head.h> /* for invalidate_buffers() */ #include <linux/mutex.h> @@ -4597,6 +4598,13 @@ MODULE_AUTHOR("Alain L. Knaff"); MODULE_SUPPORTED_DEVICE("fd"); MODULE_LICENSE("GPL"); +/* This doesn't actually get used other than for module information */ +static const struct pnp_device_id floppy_pnpids[] = { + { "PNP0700", 0 }, + { } +}; +MODULE_DEVICE_TABLE(pnp, floppy_pnpids); + #else __setup("floppy=", floppy_setup); diff --git a/drivers/block/hd.c b/drivers/block/hd.c index 482c0c4b964..3c11f062a18 100644 --- a/drivers/block/hd.c +++ b/drivers/block/hd.c @@ -42,6 +42,8 @@ #include <linux/ata.h> #include <linux/hdreg.h> +#define HD_IRQ 14 + #define REALLY_SLOW_IO #include <asm/system.h> #include <asm/io.h> diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 40b17d3b55a..ddae8082589 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -1431,6 +1431,7 @@ static int lo_open(struct block_device *bdev, fmode_t mode) static int lo_release(struct gendisk *disk, fmode_t mode) { struct loop_device *lo = disk->private_data; + int err; mutex_lock(&lo->lo_ctl_mutex); @@ -1442,7 +1443,9 @@ static int lo_release(struct gendisk *disk, fmode_t mode) * In autoclear mode, stop the loop thread * and remove configuration after last close. */ - loop_clr_fd(lo, NULL); + err = loop_clr_fd(lo, NULL); + if (!err) + goto out_unlocked; } else { /* * Otherwise keep thread (if running) and config, @@ -1453,7 +1456,7 @@ static int lo_release(struct gendisk *disk, fmode_t mode) out: mutex_unlock(&lo->lo_ctl_mutex); - +out_unlocked: return 0; } diff --git a/drivers/block/mg_disk.c b/drivers/block/mg_disk.c new file mode 100644 index 00000000000..fb39d9aa3cd --- /dev/null +++ b/drivers/block/mg_disk.c @@ -0,0 +1,1005 @@ +/* + * drivers/block/mg_disk.c + * + * Support for the mGine m[g]flash IO mode. + * Based on legacy hd.c + * + * (c) 2008 mGine Co.,LTD + * (c) 2008 unsik Kim <donari75@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/blkdev.h> +#include <linux/hdreg.h> +#include <linux/libata.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/gpio.h> +#include <linux/mg_disk.h> + +#define MG_RES_SEC (CONFIG_MG_DISK_RES << 1) + +static void mg_request(struct request_queue *); + +static void mg_dump_status(const char *msg, unsigned int stat, + struct mg_host *host) +{ + char *name = MG_DISK_NAME; + struct request *req; + + if (host->breq) { + req = elv_next_request(host->breq); + if (req) + name = req->rq_disk->disk_name; + } + + printk(KERN_ERR "%s: %s: status=0x%02x { ", name, msg, stat & 0xff); + if (stat & MG_REG_STATUS_BIT_BUSY) + printk("Busy "); + if (stat & MG_REG_STATUS_BIT_READY) + printk("DriveReady "); + if (stat & MG_REG_STATUS_BIT_WRITE_FAULT) + printk("WriteFault "); + if (stat & MG_REG_STATUS_BIT_SEEK_DONE) + printk("SeekComplete "); + if (stat & MG_REG_STATUS_BIT_DATA_REQ) + printk("DataRequest "); + if (stat & MG_REG_STATUS_BIT_CORRECTED_ERROR) + printk("CorrectedError "); + if (stat & MG_REG_STATUS_BIT_ERROR) + printk("Error "); + printk("}\n"); + if ((stat & MG_REG_STATUS_BIT_ERROR) == 0) { + host->error = 0; + } else { + host->error = inb((unsigned long)host->dev_base + MG_REG_ERROR); + printk(KERN_ERR "%s: %s: error=0x%02x { ", name, msg, + host->error & 0xff); + if (host->error & MG_REG_ERR_BBK) + printk("BadSector "); + if (host->error & MG_REG_ERR_UNC) + printk("UncorrectableError "); + if (host->error & MG_REG_ERR_IDNF) + printk("SectorIdNotFound "); + if (host->error & MG_REG_ERR_ABRT) + printk("DriveStatusError "); + if (host->error & MG_REG_ERR_AMNF) + printk("AddrMarkNotFound "); + printk("}"); + if (host->error & + (MG_REG_ERR_BBK | MG_REG_ERR_UNC | + MG_REG_ERR_IDNF | MG_REG_ERR_AMNF)) { + if (host->breq) { + req = elv_next_request(host->breq); + if (req) + printk(", sector=%ld", req->sector); + } + + } + printk("\n"); + } +} + +static unsigned int mg_wait(struct mg_host *host, u32 expect, u32 msec) +{ + u8 status; + unsigned long expire, cur_jiffies; + struct mg_drv_data *prv_data = host->dev->platform_data; + + host->error = MG_ERR_NONE; + expire = jiffies + msecs_to_jiffies(msec); + + status = inb((unsigned long)host->dev_base + MG_REG_STATUS); + + do { + cur_jiffies = jiffies; + if (status & MG_REG_STATUS_BIT_BUSY) { + if (expect == MG_REG_STATUS_BIT_BUSY) + break; + } else { + /* Check the error condition! */ + if (status & MG_REG_STATUS_BIT_ERROR) { + mg_dump_status("mg_wait", status, host); + break; + } + + if (expect == MG_STAT_READY) + if (MG_READY_OK(status)) + break; + + if (expect == MG_REG_STATUS_BIT_DATA_REQ) + if (status & MG_REG_STATUS_BIT_DATA_REQ) + break; + } + if (!msec) { + mg_dump_status("not ready", status, host); + return MG_ERR_INV_STAT; + } + if (prv_data->use_polling) + msleep(1); + + status = inb((unsigned long)host->dev_base + MG_REG_STATUS); + } while (time_before(cur_jiffies, expire)); + + if (time_after_eq(cur_jiffies, expire) && msec) + host->error = MG_ERR_TIMEOUT; + + return host->error; +} + +static unsigned int mg_wait_rstout(u32 rstout, u32 msec) +{ + unsigned long expire; + + expire = jiffies + msecs_to_jiffies(msec); + while (time_before(jiffies, expire)) { + if (gpio_get_value(rstout) == 1) + return MG_ERR_NONE; + msleep(10); + } + + return MG_ERR_RSTOUT; +} + +static void mg_unexpected_intr(struct mg_host *host) +{ + u32 status = inb((unsigned long)host->dev_base + MG_REG_STATUS); + + mg_dump_status("mg_unexpected_intr", status, host); +} + +static irqreturn_t mg_irq(int irq, void *dev_id) +{ + struct mg_host *host = dev_id; + void (*handler)(struct mg_host *) = host->mg_do_intr; + + host->mg_do_intr = 0; + del_timer(&host->timer); + if (!handler) + handler = mg_unexpected_intr; + handler(host); + return IRQ_HANDLED; +} + +static int mg_get_disk_id(struct mg_host *host) +{ + u32 i; + s32 err; + const u16 *id = host->id; + struct mg_drv_data *prv_data = host->dev->platform_data; + char fwrev[ATA_ID_FW_REV_LEN + 1]; + char model[ATA_ID_PROD_LEN + 1]; + char serial[ATA_ID_SERNO_LEN + 1]; + + if (!prv_data->use_polling) + outb(MG_REG_CTRL_INTR_DISABLE, + (unsigned long)host->dev_base + + MG_REG_DRV_CTRL); + + outb(MG_CMD_ID, (unsigned long)host->dev_base + MG_REG_COMMAND); + err = mg_wait(host, MG_REG_STATUS_BIT_DATA_REQ, MG_TMAX_WAIT_RD_DRQ); + if (err) + return err; + + for (i = 0; i < (MG_SECTOR_SIZE >> 1); i++) + host->id[i] = le16_to_cpu(inw((unsigned long)host->dev_base + + MG_BUFF_OFFSET + i * 2)); + + outb(MG_CMD_RD_CONF, (unsigned long)host->dev_base + MG_REG_COMMAND); + err = mg_wait(host, MG_STAT_READY, MG_TMAX_CONF_TO_CMD); + if (err) + return err; + + if ((id[ATA_ID_FIELD_VALID] & 1) == 0) + return MG_ERR_TRANSLATION; + + host->n_sectors = ata_id_u32(id, ATA_ID_LBA_CAPACITY); + host->cyls = id[ATA_ID_CYLS]; + host->heads = id[ATA_ID_HEADS]; + host->sectors = id[ATA_ID_SECTORS]; + + if (MG_RES_SEC && host->heads && host->sectors) { + /* modify cyls, n_sectors */ + host->cyls = (host->n_sectors - MG_RES_SEC) / + host->heads / host->sectors; + host->nres_sectors = host->n_sectors - host->cyls * + host->heads * host->sectors; + host->n_sectors -= host->nres_sectors; + } + + ata_id_c_string(id, fwrev, ATA_ID_FW_REV, sizeof(fwrev)); + ata_id_c_string(id, model, ATA_ID_PROD, sizeof(model)); + ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial)); + printk(KERN_INFO "mg_disk: model: %s\n", model); + printk(KERN_INFO "mg_disk: firm: %.8s\n", fwrev); + printk(KERN_INFO "mg_disk: serial: %s\n", serial); + printk(KERN_INFO "mg_disk: %d + reserved %d sectors\n", + host->n_sectors, host->nres_sectors); + + if (!prv_data->use_polling) + outb(MG_REG_CTRL_INTR_ENABLE, (unsigned long)host->dev_base + + MG_REG_DRV_CTRL); + + return err; +} + + +static int mg_disk_init(struct mg_host *host) +{ + struct mg_drv_data *prv_data = host->dev->platform_data; + s32 err; + u8 init_status; + + /* hdd rst low */ + gpio_set_value(host->rst, 0); + err = mg_wait(host, MG_REG_STATUS_BIT_BUSY, MG_TMAX_RST_TO_BUSY); + if (err) + return err; + + /* hdd rst high */ + gpio_set_value(host->rst, 1); + err = mg_wait(host, MG_STAT_READY, MG_TMAX_HDRST_TO_RDY); + if (err) + return err; + + /* soft reset on */ + outb(MG_REG_CTRL_RESET | + (prv_data->use_polling ? MG_REG_CTRL_INTR_DISABLE : + MG_REG_CTRL_INTR_ENABLE), + (unsigned long)host->dev_base + MG_REG_DRV_CTRL); + err = mg_wait(host, MG_REG_STATUS_BIT_BUSY, MG_TMAX_RST_TO_BUSY); + if (err) + return err; + + /* soft reset off */ + outb(prv_data->use_polling ? MG_REG_CTRL_INTR_DISABLE : + MG_REG_CTRL_INTR_ENABLE, + (unsigned long)host->dev_base + MG_REG_DRV_CTRL); + err = mg_wait(host, MG_STAT_READY, MG_TMAX_SWRST_TO_RDY); + if (err) + return err; + + init_status = inb((unsigned long)host->dev_base + MG_REG_STATUS) & 0xf; + + if (init_status == 0xf) + return MG_ERR_INIT_STAT; + + return err; +} + +static void mg_bad_rw_intr(struct mg_host *host) +{ + struct request *req = elv_next_request(host->breq); + if (req != NULL) + if (++req->errors >= MG_MAX_ERRORS || + host->error == MG_ERR_TIMEOUT) + end_request(req, 0); +} + +static unsigned int mg_out(struct mg_host *host, + unsigned int sect_num, + unsigned int sect_cnt, + unsigned int cmd, + void (*intr_addr)(struct mg_host *)) +{ + struct mg_drv_data *prv_data = host->dev->platform_data; + + if (mg_wait(host, MG_STAT_READY, MG_TMAX_CONF_TO_CMD)) + return host->error; + + if (!prv_data->use_polling) { + host->mg_do_intr = intr_addr; + mod_timer(&host->timer, jiffies + 3 * HZ); + } + if (MG_RES_SEC) + sect_num += MG_RES_SEC; + outb((u8)sect_cnt, (unsigned long)host->dev_base + MG_REG_SECT_CNT); + outb((u8)sect_num, (unsigned long)host->dev_base + MG_REG_SECT_NUM); + outb((u8)(sect_num >> 8), (unsigned long)host->dev_base + + MG_REG_CYL_LOW); + outb((u8)(sect_num >> 16), (unsigned long)host->dev_base + + MG_REG_CYL_HIGH); + outb((u8)((sect_num >> 24) | MG_REG_HEAD_LBA_MODE), + (unsigned long)host->dev_base + MG_REG_DRV_HEAD); + outb(cmd, (unsigned long)host->dev_base + MG_REG_COMMAND); + return MG_ERR_NONE; +} + +static void mg_read(struct request *req) +{ + u32 remains, j; + struct mg_host *host = req->rq_disk->private_data; + + remains = req->nr_sectors; + + if (mg_out(host, req->sector, req->nr_sectors, MG_CMD_RD, 0) != + MG_ERR_NONE) + mg_bad_rw_intr(host); + + MG_DBG("requested %d sects (from %ld), buffer=0x%p\n", + remains, req->sector, req->buffer); + + while (remains) { + if (mg_wait(host, MG_REG_STATUS_BIT_DATA_REQ, + MG_TMAX_WAIT_RD_DRQ) != MG_ERR_NONE) { + mg_bad_rw_intr(host); + return; + } + for (j = 0; j < MG_SECTOR_SIZE >> 1; j++) { + *(u16 *)req->buffer = + inw((unsigned long)host->dev_base + + MG_BUFF_OFFSET + (j << 1)); + req->buffer += 2; + } + + req->sector++; + req->errors = 0; + remains = --req->nr_sectors; + --req->current_nr_sectors; + + if (req->current_nr_sectors <= 0) { + MG_DBG("remain : %d sects\n", remains); + end_request(req, 1); + if (remains > 0) + req = elv_next_request(host->breq); + } + + outb(MG_CMD_RD_CONF, (unsigned long)host->dev_base + + MG_REG_COMMAND); + } +} + +static void mg_write(struct request *req) +{ + u32 remains, j; + struct mg_host *host = req->rq_disk->private_data; + + remains = req->nr_sectors; + + if (mg_out(host, req->sector, req->nr_sectors, MG_CMD_WR, 0) != + MG_ERR_NONE) { + mg_bad_rw_intr(host); + return; + } + + + MG_DBG("requested %d sects (from %ld), buffer=0x%p\n", + remains, req->sector, req->buffer); + while (remains) { + if (mg_wait(host, MG_REG_STATUS_BIT_DATA_REQ, + MG_TMAX_WAIT_WR_DRQ) != MG_ERR_NONE) { + mg_bad_rw_intr(host); + return; + } + for (j = 0; j < MG_SECTOR_SIZE >> 1; j++) { + outw(*(u16 *)req->buffer, + (unsigned long)host->dev_base + + MG_BUFF_OFFSET + (j << 1)); + req->buffer += 2; + } + req->sector++; + remains = --req->nr_sectors; + --req->current_nr_sectors; + + if (req->current_nr_sectors <= 0) { + MG_DBG("remain : %d sects\n", remains); + end_request(req, 1); + if (remains > 0) + req = elv_next_request(host->breq); + } + + outb(MG_CMD_WR_CONF, (unsigned long)host->dev_base + + MG_REG_COMMAND); + } +} + +static void mg_read_intr(struct mg_host *host) +{ + u32 i; + struct request *req; + + /* check status */ + do { + i = inb((unsigned long)host->dev_base + MG_REG_STATUS); + if (i & MG_REG_STATUS_BIT_BUSY) + break; + if (!MG_READY_OK(i)) + break; + if (i & MG_REG_STATUS_BIT_DATA_REQ) + goto ok_to_read; + } while (0); + mg_dump_status("mg_read_intr", i, host); + mg_bad_rw_intr(host); + mg_request(host->breq); + return; + +ok_to_read: + /* get current segment of request */ + req = elv_next_request(host->breq); + + /* read 1 sector */ + for (i = 0; i < MG_SECTOR_SIZE >> 1; i++) { + *(u16 *)req->buffer = + inw((unsigned long)host->dev_base + MG_BUFF_OFFSET + + (i << 1)); + req->buffer += 2; + } + + /* manipulate request */ + MG_DBG("sector %ld, remaining=%ld, buffer=0x%p\n", + req->sector, req->nr_sectors - 1, req->buffer); + + req->sector++; + req->errors = 0; + i = --req->nr_sectors; + --req->current_nr_sectors; + + /* let know if current segment done */ + if (req->current_nr_sectors <= 0) + end_request(req, 1); + + /* set handler if read remains */ + if (i > 0) { + host->mg_do_intr = mg_read_intr; + mod_timer(&host->timer, jiffies + 3 * HZ); + } + + /* send read confirm */ + outb(MG_CMD_RD_CONF, (unsigned long)host->dev_base + MG_REG_COMMAND); + + /* goto next request */ + if (!i) + mg_request(host->breq); +} + +static void mg_write_intr(struct mg_host *host) +{ + u32 i, j; + u16 *buff; + struct request *req; + + /* get current segment of request */ + req = elv_next_request(host->breq); + + /* check status */ + do { + i = inb((unsigned long)host->dev_base + MG_REG_STATUS); + if (i & MG_REG_STATUS_BIT_BUSY) + break; + if (!MG_READY_OK(i)) + break; + if ((req->nr_sectors <= 1) || (i & MG_REG_STATUS_BIT_DATA_REQ)) + goto ok_to_write; + } while (0); + mg_dump_status("mg_write_intr", i, host); + mg_bad_rw_intr(host); + mg_request(host->breq); + return; + +ok_to_write: + /* manipulate request */ + req->sector++; + i = --req->nr_sectors; + --req->current_nr_sectors; + req->buffer += MG_SECTOR_SIZE; + + /* let know if current segment or all done */ + if (!i || (req->bio && req->current_nr_sectors <= 0)) + end_request(req, 1); + + /* write 1 sector and set handler if remains */ + if (i > 0) { + buff = (u16 *)req->buffer; + for (j = 0; j < MG_STORAGE_BUFFER_SIZE >> 1; j++) { + outw(*buff, (unsigned long)host->dev_base + + MG_BUFF_OFFSET + (j << 1)); + buff++; + } + MG_DBG("sector %ld, remaining=%ld, buffer=0x%p\n", + req->sector, req->nr_sectors, req->buffer); + host->mg_do_intr = mg_write_intr; + mod_timer(&host->timer, jiffies + 3 * HZ); + } + + /* send write confirm */ + outb(MG_CMD_WR_CONF, (unsigned long)host->dev_base + MG_REG_COMMAND); + + if (!i) + mg_request(host->breq); +} + +void mg_times_out(unsigned long data) +{ + struct mg_host *host = (struct mg_host *)data; + char *name; + struct request *req; + + req = elv_next_request(host->breq); + if (!req) + return; + + host->mg_do_intr = NULL; + + name = req->rq_disk->disk_name; + printk(KERN_DEBUG "%s: timeout\n", name); + + host->error = MG_ERR_TIMEOUT; + mg_bad_rw_intr(host); + + mg_request(host->breq); +} + +static void mg_request_poll(struct request_queue *q) +{ + struct request *req; + struct mg_host *host; + + while ((req = elv_next_request(q)) != NULL) { + host = req->rq_disk->private_data; + if (blk_fs_request(req)) { + switch (rq_data_dir(req)) { + case READ: + mg_read(req); + break; + case WRITE: + mg_write(req); + break; + default: + printk(KERN_WARNING "%s:%d unknown command\n", + __func__, __LINE__); + end_request(req, 0); + break; + } + } + } +} + +static unsigned int mg_issue_req(struct request *req, + struct mg_host *host, + unsigned int sect_num, + unsigned int sect_cnt) +{ + u16 *buff; + u32 i; + + switch (rq_data_dir(req)) { + case READ: + if (mg_out(host, sect_num, sect_cnt, MG_CMD_RD, &mg_read_intr) + != MG_ERR_NONE) { + mg_bad_rw_intr(host); + return host->error; + } + break; + case WRITE: + /* TODO : handler */ + outb(MG_REG_CTRL_INTR_DISABLE, + (unsigned long)host->dev_base + + MG_REG_DRV_CTRL); + if (mg_out(host, sect_num, sect_cnt, MG_CMD_WR, &mg_write_intr) + != MG_ERR_NONE) { + mg_bad_rw_intr(host); + return host->error; + } + del_timer(&host->timer); + mg_wait(host, MG_REG_STATUS_BIT_DATA_REQ, MG_TMAX_WAIT_WR_DRQ); + outb(MG_REG_CTRL_INTR_ENABLE, (unsigned long)host->dev_base + + MG_REG_DRV_CTRL); + if (host->error) { + mg_bad_rw_intr(host); + return host->error; + } + buff = (u16 *)req->buffer; + for (i = 0; i < MG_SECTOR_SIZE >> 1; i++) { + outw(*buff, (unsigned long)host->dev_base + + MG_BUFF_OFFSET + (i << 1)); + buff++; + } + mod_timer(&host->timer, jiffies + 3 * HZ); + outb(MG_CMD_WR_CONF, (unsigned long)host->dev_base + + MG_REG_COMMAND); + break; + default: + printk(KERN_WARNING "%s:%d unknown command\n", + __func__, __LINE__); + end_request(req, 0); + break; + } + return MG_ERR_NONE; +} + +/* This function also called from IRQ context */ +static void mg_request(struct request_queue *q) +{ + struct request *req; + struct mg_host *host; + u32 sect_num, sect_cnt; + + while (1) { + req = elv_next_request(q); + if (!req) + return; + + host = req->rq_disk->private_data; + + /* check unwanted request call */ + if (host->mg_do_intr) + return; + + del_timer(&host->timer); + + sect_num = req->sector; + /* deal whole segments */ + sect_cnt = req->nr_sectors; + + /* sanity check */ + if (sect_num >= get_capacity(req->rq_disk) || + ((sect_num + sect_cnt) > + get_capacity(req->rq_disk))) { + printk(KERN_WARNING + "%s: bad access: sector=%d, count=%d\n", + req->rq_disk->disk_name, + sect_num, sect_cnt); + end_request(req, 0); + continue; + } + + if (!blk_fs_request(req)) + return; + + if (!mg_issue_req(req, host, sect_num, sect_cnt)) + return; + } +} + +static int mg_getgeo(struct block_device *bdev, struct hd_geometry *geo) +{ + struct mg_host *host = bdev->bd_disk->private_data; + + geo->cylinders = (unsigned short)host->cyls; + geo->heads = (unsigned char)host->heads; + geo->sectors = (unsigned char)host->sectors; + return 0; +} + +static struct block_device_operations mg_disk_ops = { + .getgeo = mg_getgeo +}; + +static int mg_suspend(struct platform_device *plat_dev, pm_message_t state) +{ + struct mg_drv_data *prv_data = plat_dev->dev.platform_data; + struct mg_host *host = prv_data->host; + + if (mg_wait(host, MG_STAT_READY, MG_TMAX_CONF_TO_CMD)) + return -EIO; + + if (!prv_data->use_polling) + outb(MG_REG_CTRL_INTR_DISABLE, + (unsigned long)host->dev_base + + MG_REG_DRV_CTRL); + + outb(MG_CMD_SLEEP, (unsigned long)host->dev_base + MG_REG_COMMAND); + /* wait until mflash deep sleep */ + msleep(1); + + if (mg_wait(host, MG_STAT_READY, MG_TMAX_CONF_TO_CMD)) { + if (!prv_data->use_polling) + outb(MG_REG_CTRL_INTR_ENABLE, + (unsigned long)host->dev_base + + MG_REG_DRV_CTRL); + return -EIO; + } + + return 0; +} + +static int mg_resume(struct platform_device *plat_dev) +{ + struct mg_drv_data *prv_data = plat_dev->dev.platform_data; + struct mg_host *host = prv_data->host; + + if (mg_wait(host, MG_STAT_READY, MG_TMAX_CONF_TO_CMD)) + return -EIO; + + outb(MG_CMD_WAKEUP, (unsigned long)host->dev_base + MG_REG_COMMAND); + /* wait until mflash wakeup */ + msleep(1); + + if (mg_wait(host, MG_STAT_READY, MG_TMAX_CONF_TO_CMD)) + return -EIO; + + if (!prv_data->use_polling) + outb(MG_REG_CTRL_INTR_ENABLE, (unsigned long)host->dev_base + + MG_REG_DRV_CTRL); + + return 0; +} + +static int mg_probe(struct platform_device *plat_dev) +{ + struct mg_host *host; + struct resource *rsc; + struct mg_drv_data *prv_data = plat_dev->dev.platform_data; + int err = 0; + + if (!prv_data) { + printk(KERN_ERR "%s:%d fail (no driver_data)\n", + __func__, __LINE__); + err = -EINVAL; + goto probe_err; + } + + /* alloc mg_host */ + host = kzalloc(sizeof(struct mg_host), GFP_KERNEL); + if (!host) { + printk(KERN_ERR "%s:%d fail (no memory for mg_host)\n", + __func__, __LINE__); + err = -ENOMEM; + goto probe_err; + } + host->major = MG_DISK_MAJ; + + /* link each other */ + prv_data->host = host; + host->dev = &plat_dev->dev; + + /* io remap */ + rsc = platform_get_resource(plat_dev, IORESOURCE_MEM, 0); + if (!rsc) { + printk(KERN_ERR "%s:%d platform_get_resource fail\n", + __func__, __LINE__); + err = -EINVAL; + goto probe_err_2; + } + host->dev_base = ioremap(rsc->start , rsc->end + 1); + if (!host->dev_base) { + printk(KERN_ERR "%s:%d ioremap fail\n", + __func__, __LINE__); + err = -EIO; + goto probe_err_2; + } + MG_DBG("dev_base = 0x%x\n", (u32)host->dev_base); + + /* get reset pin */ + rsc = platform_get_resource_byname(plat_dev, IORESOURCE_IO, + MG_RST_PIN); + if (!rsc) { + printk(KERN_ERR "%s:%d get reset pin fail\n", + __func__, __LINE__); + err = -EIO; + goto probe_err_3; + } + host->rst = rsc->start; + + /* init rst pin */ + err = gpio_request(host->rst, MG_RST_PIN); + if (err) + goto probe_err_3; + gpio_direction_output(host->rst, 1); + + /* reset out pin */ + if (!(prv_data->dev_attr & MG_DEV_MASK)) + goto probe_err_3a; + + if (prv_data->dev_attr != MG_BOOT_DEV) { + rsc = platform_get_resource_byname(plat_dev, IORESOURCE_IO, + MG_RSTOUT_PIN); + if (!rsc) { + printk(KERN_ERR "%s:%d get reset-out pin fail\n", + __func__, __LINE__); + err = -EIO; + goto probe_err_3a; + } + host->rstout = rsc->start; + err = gpio_request(host->rstout, MG_RSTOUT_PIN); + if (err) + goto probe_err_3a; + gpio_direction_input(host->rstout); + } + + /* disk reset */ + if (prv_data->dev_attr == MG_STORAGE_DEV) { + /* If POR seq. not yet finised, wait */ + err = mg_wait_rstout(host->rstout, MG_TMAX_RSTOUT); + if (err) + goto probe_err_3b; + err = mg_disk_init(host); + if (err) { + printk(KERN_ERR "%s:%d fail (err code : %d)\n", + __func__, __LINE__, err); + err = -EIO; + goto probe_err_3b; + } + } + + /* get irq resource */ + if (!prv_data->use_polling) { + host->irq = platform_get_irq(plat_dev, 0); + if (host->irq == -ENXIO) { + err = host->irq; + goto probe_err_3b; + } + err = request_irq(host->irq, mg_irq, + IRQF_DISABLED | IRQF_TRIGGER_RISING, + MG_DEV_NAME, host); + if (err) { + printk(KERN_ERR "%s:%d fail (request_irq err=%d)\n", + __func__, __LINE__, err); + goto probe_err_3b; + } + + } + + /* get disk id */ + err = mg_get_disk_id(host); + if (err) { + printk(KERN_ERR "%s:%d fail (err code : %d)\n", + __func__, __LINE__, err); + err = -EIO; + goto probe_err_4; + } + + err = register_blkdev(host->major, MG_DISK_NAME); + if (err < 0) { + printk(KERN_ERR "%s:%d register_blkdev fail (err code : %d)\n", + __func__, __LINE__, err); + goto probe_err_4; + } + if (!host->major) + host->major = err; + + spin_lock_init(&host->lock); + + if (prv_data->use_polling) + host->breq = blk_init_queue(mg_request_poll, &host->lock); + else + host->breq = blk_init_queue(mg_request, &host->lock); + + if (!host->breq) { + err = -ENOMEM; + printk(KERN_ERR "%s:%d (blk_init_queue) fail\n", + __func__, __LINE__); + goto probe_err_5; + } + + /* mflash is random device, thanx for the noop */ + elevator_exit(host->breq->elevator); + err = elevator_init(host->breq, "noop"); + if (err) { + printk(KERN_ERR "%s:%d (elevator_init) fail\n", + __func__, __LINE__); + goto probe_err_6; + } + blk_queue_max_sectors(host->breq, MG_MAX_SECTS); + blk_queue_hardsect_size(host->breq, MG_SECTOR_SIZE); + + init_timer(&host->timer); + host->timer.function = mg_times_out; + host->timer.data = (unsigned long)host; + + host->gd = alloc_disk(MG_DISK_MAX_PART); + if (!host->gd) { + printk(KERN_ERR "%s:%d (alloc_disk) fail\n", + __func__, __LINE__); + err = -ENOMEM; + goto probe_err_7; + } + host->gd->major = host->major; + host->gd->first_minor = 0; + host->gd->fops = &mg_disk_ops; + host->gd->queue = host->breq; + host->gd->private_data = host; + sprintf(host->gd->disk_name, MG_DISK_NAME"a"); + + set_capacity(host->gd, host->n_sectors); + + add_disk(host->gd); + + return err; + +probe_err_7: + del_timer_sync(&host->timer); +probe_err_6: + blk_cleanup_queue(host->breq); +probe_err_5: + unregister_blkdev(MG_DISK_MAJ, MG_DISK_NAME); +probe_err_4: + if (!prv_data->use_polling) + free_irq(host->irq, host); +probe_err_3b: + gpio_free(host->rstout); +probe_err_3a: + gpio_free(host->rst); +probe_err_3: + iounmap(host->dev_base); +probe_err_2: + kfree(host); +probe_err: + return err; +} + +static int mg_remove(struct platform_device *plat_dev) +{ + struct mg_drv_data *prv_data = plat_dev->dev.platform_data; + struct mg_host *host = prv_data->host; + int err = 0; + + /* delete timer */ + del_timer_sync(&host->timer); + + /* remove disk */ + if (host->gd) { + del_gendisk(host->gd); + put_disk(host->gd); + } + /* remove queue */ + if (host->breq) + blk_cleanup_queue(host->breq); + + /* unregister blk device */ + unregister_blkdev(host->major, MG_DISK_NAME); + + /* free irq */ + if (!prv_data->use_polling) + free_irq(host->irq, host); + + /* free reset-out pin */ + if (prv_data->dev_attr != MG_BOOT_DEV) + gpio_free(host->rstout); + + /* free rst pin */ + if (host->rst) + gpio_free(host->rst); + + /* unmap io */ + if (host->dev_base) + iounmap(host->dev_base); + + /* free mg_host */ + kfree(host); + + return err; +} + +static struct platform_driver mg_disk_driver = { + .probe = mg_probe, + .remove = mg_remove, + .suspend = mg_suspend, + .resume = mg_resume, + .driver = { + .name = MG_DEV_NAME, + .owner = THIS_MODULE, + } +}; + +/**************************************************************************** + * + * Module stuff + * + ****************************************************************************/ + +static int __init mg_init(void) +{ + printk(KERN_INFO "mGine mflash driver, (c) 2008 mGine Co.\n"); + return platform_driver_register(&mg_disk_driver); +} + +static void __exit mg_exit(void) +{ + printk(KERN_INFO "mflash driver : bye bye\n"); + platform_driver_unregister(&mg_disk_driver); +} + +module_init(mg_init); +module_exit(mg_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("unsik Kim <donari75@gmail.com>"); +MODULE_DESCRIPTION("mGine m[g]flash device driver"); diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 8299e2d3b61..4d6de4f15cc 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -4,7 +4,7 @@ * Note that you can not swap over this thing, yet. Seems to work but * deadlocks sometimes - you can not swap over TCP in general. * - * Copyright 1997-2000 Pavel Machek <pavel@ucw.cz> + * Copyright 1997-2000, 2008 Pavel Machek <pavel@suse.cz> * Parts copyright 2001 Steven Whitehouse <steve@chygwyn.com> * * This file is released under GPLv2 or later. @@ -276,7 +276,7 @@ static int nbd_send_req(struct nbd_device *lo, struct request *req) return 0; error_out: - return 1; + return -EIO; } static struct request *nbd_find_request(struct nbd_device *lo, @@ -467,9 +467,7 @@ static void nbd_handle_req(struct nbd_device *lo, struct request *req) mutex_unlock(&lo->tx_lock); printk(KERN_ERR "%s: Attempted send on closed socket\n", lo->disk->disk_name); - req->errors++; - nbd_end_request(req); - return; + goto error_out; } lo->active_req = req; @@ -531,7 +529,7 @@ static int nbd_thread(void *data) * { printk( "Warning: Ignoring result!\n"); nbd_end_request( req ); } */ -static void do_nbd_request(struct request_queue * q) +static void do_nbd_request(struct request_queue *q) { struct request *req; @@ -568,27 +566,17 @@ static void do_nbd_request(struct request_queue * q) } } -static int nbd_ioctl(struct block_device *bdev, fmode_t mode, - unsigned int cmd, unsigned long arg) -{ - struct nbd_device *lo = bdev->bd_disk->private_data; - struct file *file; - int error; - struct request sreq ; - struct task_struct *thread; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - BUG_ON(lo->magic != LO_MAGIC); - - /* Anyone capable of this syscall can do *real bad* things */ - dprintk(DBG_IOCTL, "%s: nbd_ioctl cmd=%s(0x%x) arg=%lu\n", - lo->disk->disk_name, ioctl_cmd_to_ascii(cmd), cmd, arg); +/* Must be called with tx_lock held */ +static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *lo, + unsigned int cmd, unsigned long arg) +{ switch (cmd) { - case NBD_DISCONNECT: + case NBD_DISCONNECT: { + struct request sreq; + printk(KERN_INFO "%s: NBD_DISCONNECT\n", lo->disk->disk_name); + blk_rq_init(NULL, &sreq); sreq.cmd_type = REQ_TYPE_SPECIAL; nbd_cmd(&sreq) = NBD_CMD_DISC; @@ -599,29 +587,29 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode, */ sreq.sector = 0; sreq.nr_sectors = 0; - if (!lo->sock) + if (!lo->sock) return -EINVAL; - mutex_lock(&lo->tx_lock); - nbd_send_req(lo, &sreq); - mutex_unlock(&lo->tx_lock); + nbd_send_req(lo, &sreq); return 0; + } - case NBD_CLEAR_SOCK: - error = 0; - mutex_lock(&lo->tx_lock); + case NBD_CLEAR_SOCK: { + struct file *file; + lo->sock = NULL; - mutex_unlock(&lo->tx_lock); file = lo->file; lo->file = NULL; nbd_clear_que(lo); BUG_ON(!list_empty(&lo->queue_head)); if (file) fput(file); - return error; - case NBD_SET_SOCK: + return 0; + } + + case NBD_SET_SOCK: { + struct file *file; if (lo->file) return -EBUSY; - error = -EINVAL; file = fget(arg); if (file) { struct inode *inode = file->f_path.dentry->d_inode; @@ -630,12 +618,14 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode, lo->sock = SOCKET_I(inode); if (max_part > 0) bdev->bd_invalidated = 1; - error = 0; + return 0; } else { fput(file); } } - return error; + return -EINVAL; + } + case NBD_SET_BLKSIZE: lo->blksize = arg; lo->bytesize &= ~(lo->blksize-1); @@ -643,35 +633,50 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode, set_blocksize(bdev, lo->blksize); set_capacity(lo->disk, lo->bytesize >> 9); return 0; + case NBD_SET_SIZE: lo->bytesize = arg & ~(lo->blksize-1); bdev->bd_inode->i_size = lo->bytesize; set_blocksize(bdev, lo->blksize); set_capacity(lo->disk, lo->bytesize >> 9); return 0; + case NBD_SET_TIMEOUT: lo->xmit_timeout = arg * HZ; return 0; + case NBD_SET_SIZE_BLOCKS: lo->bytesize = ((u64) arg) * lo->blksize; bdev->bd_inode->i_size = lo->bytesize; set_blocksize(bdev, lo->blksize); set_capacity(lo->disk, lo->bytesize >> 9); return 0; - case NBD_DO_IT: + + case NBD_DO_IT: { + struct task_struct *thread; + struct file *file; + int error; + if (lo->pid) return -EBUSY; if (!lo->file) return -EINVAL; + + mutex_unlock(&lo->tx_lock); + thread = kthread_create(nbd_thread, lo, lo->disk->disk_name); - if (IS_ERR(thread)) + if (IS_ERR(thread)) { + mutex_lock(&lo->tx_lock); return PTR_ERR(thread); + } wake_up_process(thread); error = nbd_do_it(lo); kthread_stop(thread); + + mutex_lock(&lo->tx_lock); if (error) return error; - sock_shutdown(lo, 1); + sock_shutdown(lo, 0); file = lo->file; lo->file = NULL; nbd_clear_que(lo); @@ -684,6 +689,8 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode, if (max_part > 0) ioctl_by_bdev(bdev, BLKRRPART, 0); return lo->harderror; + } + case NBD_CLEAR_QUE: /* * This is for compatibility only. The queue is always cleared @@ -691,6 +698,7 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode, */ BUG_ON(!lo->sock && !list_empty(&lo->queue_head)); return 0; + case NBD_PRINT_DEBUG: printk(KERN_INFO "%s: next = %p, prev = %p, head = %p\n", bdev->bd_disk->disk_name, @@ -698,7 +706,29 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode, &lo->queue_head); return 0; } - return -EINVAL; + return -ENOTTY; +} + +static int nbd_ioctl(struct block_device *bdev, fmode_t mode, + unsigned int cmd, unsigned long arg) +{ + struct nbd_device *lo = bdev->bd_disk->private_data; + int error; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + BUG_ON(lo->magic != LO_MAGIC); + + /* Anyone capable of this syscall can do *real bad* things */ + dprintk(DBG_IOCTL, "%s: nbd_ioctl cmd=%s(0x%x) arg=%lu\n", + lo->disk->disk_name, ioctl_cmd_to_ascii(cmd), cmd, arg); + + mutex_lock(&lo->tx_lock); + error = __nbd_ioctl(bdev, lo, cmd, arg); + mutex_unlock(&lo->tx_lock); + + return error; } static struct block_device_operations nbd_fops = diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c index a18e1ca0f76..ff0448e4bf0 100644 --- a/drivers/block/sx8.c +++ b/drivers/block/sx8.c @@ -1586,9 +1586,9 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out; #ifdef IF_64BIT_DMA_IS_POSSIBLE /* grrrr... */ - rc = pci_set_dma_mask(pdev, DMA_64BIT_MASK); + rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); if (!rc) { - rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); + rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); if (rc) { printk(KERN_ERR DRV_NAME "(%s): consistent DMA mask failure\n", pci_name(pdev)); @@ -1597,7 +1597,7 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) pci_dac = 1; } else { #endif - rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); if (rc) { printk(KERN_ERR DRV_NAME "(%s): DMA mask failure\n", pci_name(pdev)); diff --git a/drivers/block/ub.c b/drivers/block/ub.c index 69b7f8e7759..689cd27ac89 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c @@ -1025,6 +1025,7 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd) { struct urb *urb = &sc->work_urb; struct bulk_cs_wrap *bcs; + int endp; int len; int rc; @@ -1033,6 +1034,10 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd) return; } + endp = usb_pipeendpoint(sc->last_pipe); + if (usb_pipein(sc->last_pipe)) + endp |= USB_DIR_IN; + if (cmd->state == UB_CMDST_CLEAR) { if (urb->status == -EPIPE) { /* @@ -1048,9 +1053,7 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd) * We ignore the result for the halt clear. */ - /* reset the endpoint toggle */ - usb_settoggle(sc->dev, usb_pipeendpoint(sc->last_pipe), - usb_pipeout(sc->last_pipe), 0); + usb_reset_endpoint(sc->dev, endp); ub_state_sense(sc, cmd); @@ -1065,9 +1068,7 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd) * We ignore the result for the halt clear. */ - /* reset the endpoint toggle */ - usb_settoggle(sc->dev, usb_pipeendpoint(sc->last_pipe), - usb_pipeout(sc->last_pipe), 0); + usb_reset_endpoint(sc->dev, endp); ub_state_stat(sc, cmd); @@ -1082,9 +1083,7 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd) * We ignore the result for the halt clear. */ - /* reset the endpoint toggle */ - usb_settoggle(sc->dev, usb_pipeendpoint(sc->last_pipe), - usb_pipeout(sc->last_pipe), 0); + usb_reset_endpoint(sc->dev, endp); ub_state_stat_counted(sc, cmd); @@ -2119,8 +2118,7 @@ static int ub_probe_clear_stall(struct ub_dev *sc, int stalled_pipe) del_timer_sync(&timer); usb_kill_urb(&sc->work_urb); - /* reset the endpoint toggle */ - usb_settoggle(sc->dev, endp, usb_pipeout(sc->last_pipe), 0); + usb_reset_endpoint(sc->dev, endp); return 0; } diff --git a/drivers/block/umem.c b/drivers/block/umem.c index c24e1bdbad4..9744d59a69f 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -829,8 +829,8 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, dev_printk(KERN_INFO, &dev->dev, "Micro Memory(tm) controller found (PCI Mem Module (Battery Backup))\n"); - if (pci_set_dma_mask(dev, DMA_64BIT_MASK) && - pci_set_dma_mask(dev, DMA_32BIT_MASK)) { + if (pci_set_dma_mask(dev, DMA_BIT_MASK(64)) && + pci_set_dma_mask(dev, DMA_BIT_MASK(32))) { dev_printk(KERN_WARNING, &dev->dev, "NO suitable DMA found\n"); return -ENOMEM; } diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index 119be3442f2..4aecf5dc6a9 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -89,6 +89,7 @@ #include <linux/delay.h> #include <linux/slab.h> #include <linux/blkdev.h> +#include <linux/ata.h> #include <linux/hdreg.h> #include <linux/platform_device.h> #if defined(CONFIG_OF) @@ -208,7 +209,7 @@ struct ace_device { struct gendisk *gd; /* Inserted CF card parameters */ - struct hd_driveid cf_id; + u16 cf_id[ATA_ID_WORDS]; }; static int ace_major; @@ -402,21 +403,14 @@ static void ace_dump_regs(struct ace_device *ace) ace_in32(ace, ACE_CFGLBA), ace_in(ace, ACE_FATSTAT)); } -void ace_fix_driveid(struct hd_driveid *id) +void ace_fix_driveid(u16 *id) { #if defined(__BIG_ENDIAN) - u16 *buf = (void *)id; int i; /* All half words have wrong byte order; swap the bytes */ - for (i = 0; i < sizeof(struct hd_driveid); i += 2, buf++) - *buf = le16_to_cpu(*buf); - - /* Some of the data values are 32bit; swap the half words */ - id->lba_capacity = ((id->lba_capacity >> 16) & 0x0000FFFF) | - ((id->lba_capacity << 16) & 0xFFFF0000); - id->spg = ((id->spg >> 16) & 0x0000FFFF) | - ((id->spg << 16) & 0xFFFF0000); + for (i = 0; i < ATA_ID_WORDS; i++, id++) + *id = le16_to_cpu(*id); #endif } @@ -569,7 +563,7 @@ static void ace_fsm_dostate(struct ace_device *ace) case ACE_FSM_STATE_IDENTIFY_PREPARE: /* Send identify command */ ace->fsm_task = ACE_TASK_IDENTIFY; - ace->data_ptr = &ace->cf_id; + ace->data_ptr = ace->cf_id; ace->data_count = ACE_BUF_PER_SECTOR; ace_out(ace, ACE_SECCNTCMD, ACE_SECCNTCMD_IDENTIFY); @@ -614,8 +608,8 @@ static void ace_fsm_dostate(struct ace_device *ace) break; case ACE_FSM_STATE_IDENTIFY_COMPLETE: - ace_fix_driveid(&ace->cf_id); - ace_dump_mem(&ace->cf_id, 512); /* Debug: Dump out disk ID */ + ace_fix_driveid(ace->cf_id); + ace_dump_mem(ace->cf_id, 512); /* Debug: Dump out disk ID */ if (ace->data_result) { /* Error occured, disable the disk */ @@ -627,9 +621,10 @@ static void ace_fsm_dostate(struct ace_device *ace) ace->media_change = 0; /* Record disk parameters */ - set_capacity(ace->gd, ace->cf_id.lba_capacity); + set_capacity(ace->gd, + ata_id_u32(ace->cf_id, ATA_ID_LBA_CAPACITY)); dev_info(ace->dev, "capacity: %i sectors\n", - ace->cf_id.lba_capacity); + ata_id_u32(ace->cf_id, ATA_ID_LBA_CAPACITY)); } /* We're done, drop to IDLE state and notify waiters */ @@ -928,12 +923,13 @@ static int ace_release(struct gendisk *disk, fmode_t mode) static int ace_getgeo(struct block_device *bdev, struct hd_geometry *geo) { struct ace_device *ace = bdev->bd_disk->private_data; + u16 *cf_id = ace->cf_id; dev_dbg(ace->dev, "ace_getgeo()\n"); - geo->heads = ace->cf_id.heads; - geo->sectors = ace->cf_id.sectors; - geo->cylinders = ace->cf_id.cyls; + geo->heads = cf_id[ATA_ID_HEADS]; + geo->sectors = cf_id[ATA_ID_SECTORS]; + geo->cylinders = cf_id[ATA_ID_CYLS]; return 0; } |