i2o_block.c
来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 1,694 行 · 第 1/3 页
C
1,694 行
/* * I2O Random Block Storage Class OSM * * (C) Copyright 1999-2002 Red Hat * * Written by Alan Cox, Building Number Three Ltd * * 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. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * For the purpose of avoiding doubt the preferred form of the work * for making modifications shall be a standards compliant form such * gzipped tar and not one requiring a proprietary or patent encumbered * tool to unpack. * * This is a beta test release. Most of the good code was taken * from the nbd driver by Pavel Machek, who in turn took some of it * from loop.c. Isn't free software great for reusability 8) * * Fixes/additions: * Steve Ralston: * Multiple device handling error fixes, * Added a queue depth. * Alan Cox: * FC920 has an rmw bug. Dont or in the end marker. * Removed queue walk, fixed for 64bitness. * Rewrote much of the code over time * Added indirect block lists * Handle 64K limits on many controllers * Don't use indirects on the Promise (breaks) * Heavily chop down the queue depths * Deepak Saxena: * Independent queues per IOP * Support for dynamic device creation/deletion * Code cleanup * Support for larger I/Os through merge* functions * (taken from DAC960 driver) * Boji T Kannanthanam: * Set the I2O Block devices to be detected in increasing * order of TIDs during boot. * Search and set the I2O block device that we boot off from as * the first device to be claimed (as /dev/i2o/hda) * Properly attach/detach I2O gendisk structure from the system * gendisk list. The I2O block devices now appear in * /proc/partitions. * Markus Lidel <Markus.Lidel@shadowconnect.com>: * Minor bugfixes for 2.6. * * To do: * Serial number scanning to find duplicates for FC multipathing */#include <linux/major.h>#include <linux/module.h>#include <linux/init.h>#include <linux/sched.h>#include <linux/fs.h>#include <linux/stat.h>#include <linux/pci.h>#include <linux/errno.h>#include <linux/file.h>#include <linux/ioctl.h>#include <linux/i2o.h>#include <linux/blkdev.h>#include <linux/blkpg.h>#include <linux/slab.h>#include <linux/hdreg.h>#include <linux/spinlock.h>#include <linux/bio.h>#include <linux/notifier.h>#include <linux/reboot.h>#include <asm/uaccess.h>#include <asm/semaphore.h>#include <linux/completion.h>#include <asm/io.h>#include <linux/smp_lock.h>#include <linux/wait.h>#define MAJOR_NR I2O_MAJOR#define MAX_I2OB 16#define MAX_I2OB_DEPTH 8#define MAX_I2OB_RETRIES 4//#define DRIVERDEBUG#ifdef DRIVERDEBUG#define DEBUG( s ) printk( s )#else#define DEBUG( s )#endif/* * Events that this OSM is interested in */#define I2OB_EVENT_MASK (I2O_EVT_IND_BSA_VOLUME_LOAD | \ I2O_EVT_IND_BSA_VOLUME_UNLOAD | \ I2O_EVT_IND_BSA_VOLUME_UNLOAD_REQ | \ I2O_EVT_IND_BSA_CAPACITY_CHANGE | \ I2O_EVT_IND_BSA_SCSI_SMART )/* * Some of these can be made smaller later */static int i2ob_context;static struct block_device_operations i2ob_fops;/* * I2O Block device descriptor */struct i2ob_device{ struct i2o_controller *controller; struct i2o_device *i2odev; int unit; int tid; int flags; int refcnt; struct request *head, *tail; request_queue_t *req_queue; int max_segments; int max_direct; /* Not yet used properly */ int done_flag; int depth; int rcache; int wcache; int power; int index; int media_change_flag; u32 max_sectors; struct gendisk *gd;};/* * FIXME: * We should cache align these to avoid ping-ponging lines on SMP * boxes under heavy I/O load... */struct i2ob_request{ struct i2ob_request *next; struct request *req; int num; int sg_dma_direction; int sg_nents; struct scatterlist sg_table[16];};/* * Per IOP request queue information * * We have a separate request_queue_t per IOP so that a heavilly * loaded I2O block device on an IOP does not starve block devices * across all I2O controllers. * */struct i2ob_iop_queue{ unsigned int queue_depth; struct i2ob_request request_queue[MAX_I2OB_DEPTH]; struct i2ob_request *i2ob_qhead; request_queue_t *req_queue; spinlock_t lock;};static struct i2ob_iop_queue *i2ob_queues[MAX_I2O_CONTROLLERS];/* * Each I2O disk is one of these. */static struct i2ob_device i2ob_dev[MAX_I2OB];static int i2ob_dev_count = 0;/* * Mutex and spin lock for event handling synchronization * evt_msg contains the last event. */static DECLARE_MUTEX_LOCKED(i2ob_evt_sem);static DECLARE_COMPLETION(i2ob_thread_dead);static spinlock_t i2ob_evt_lock = SPIN_LOCK_UNLOCKED;static u32 evt_msg[MSG_FRAME_SIZE];static void i2o_block_reply(struct i2o_handler *, struct i2o_controller *, struct i2o_message *);static void i2ob_new_device(struct i2o_controller *, struct i2o_device *);static void i2ob_del_device(struct i2o_controller *, struct i2o_device *);static void i2ob_reboot_event(void);static int i2ob_install_device(struct i2o_controller *, struct i2o_device *, int);static void i2ob_end_request(struct request *);static void i2ob_request(request_queue_t *);static int i2ob_init_iop(unsigned int);static int i2ob_query_device(struct i2ob_device *, int, int, void*, int);static int i2ob_evt(void *);static int evt_pid = 0;static int evt_running = 0;static int scan_unit = 0;/* * I2O OSM registration structure...keeps getting bigger and bigger :) */static struct i2o_handler i2o_block_handler ={ i2o_block_reply, i2ob_new_device, i2ob_del_device, i2ob_reboot_event, "I2O Block OSM", 0, I2O_CLASS_RANDOM_BLOCK_STORAGE};/** * i2ob_get - Get an I2O message * @dev: I2O block device * * Get a message from the FIFO used for this block device. The message is returned * or the I2O 'no message' value of 0xFFFFFFFF if nothing is available. */static u32 i2ob_get(struct i2ob_device *dev){ struct i2o_controller *c=dev->controller; return I2O_POST_READ32(c);}static int i2ob_build_sglist(struct i2ob_device *dev, struct i2ob_request *ireq){ struct scatterlist *sg = ireq->sg_table; int nents; nents = blk_rq_map_sg(dev->req_queue, ireq->req, ireq->sg_table); if (rq_data_dir(ireq->req) == READ) ireq->sg_dma_direction = PCI_DMA_FROMDEVICE; else ireq->sg_dma_direction = PCI_DMA_TODEVICE; ireq->sg_nents = pci_map_sg(dev->controller->pdev, sg, nents, ireq->sg_dma_direction); return ireq->sg_nents;}void i2ob_free_sglist(struct i2ob_device *dev, struct i2ob_request *ireq){ struct pci_dev *pdev = dev->controller->pdev; struct scatterlist *sg = ireq->sg_table; int nents = ireq->sg_nents; pci_unmap_sg(pdev, sg, nents, ireq->sg_dma_direction);} /** * i2ob_send - Turn a request into a message and send it * @m: Message offset * @dev: I2O device * @ireq: Request structure * @unit: Device identity * * Generate an I2O BSAREAD request. This interface function is called for devices that * appear to explode when they are fed indirect chain pointers (notably right now this * appears to afflict Promise hardwre, so be careful what you feed the hardware * * No cleanup is done by this interface. It is done on the interrupt side when the * reply arrives */ static int i2ob_send(u32 m, struct i2ob_device *dev, struct i2ob_request *ireq, int unit){ struct i2o_controller *c = dev->controller; int tid = dev->tid; void *msg; void *mptr; u64 offset; struct request *req = ireq->req; int count = req->nr_sectors<<9; struct scatterlist *sg; int sgnum; int i; // printk(KERN_INFO "i2ob_send called\n"); /* Map the message to a virtual address */ msg = c->msg_virt + m; sgnum = i2ob_build_sglist(dev, ireq); /* FIXME: if we have no resources how should we get out of this */ if(sgnum == 0) BUG(); /* * Build the message based on the request. */ i2o_raw_writel(i2ob_context|(unit<<8), msg+8); i2o_raw_writel(ireq->num, msg+12); i2o_raw_writel(req->nr_sectors << 9, msg+20); /* * Mask out partitions from now on */ /* This can be optimised later - just want to be sure its right for starters */ offset = ((u64)req->sector) << 9; i2o_raw_writel( offset & 0xFFFFFFFF, msg+24); i2o_raw_writel(offset>>32, msg+28); mptr=msg+32; sg = ireq->sg_table; if(rq_data_dir(req) == READ) { DEBUG("READ\n"); i2o_raw_writel(I2O_CMD_BLOCK_READ<<24|HOST_TID<<12|tid, msg+4); for(i = sgnum; i > 0; i--) { if(i != 1) i2o_raw_writel(0x10000000|sg_dma_len(sg), mptr); else i2o_raw_writel(0xD0000000|sg_dma_len(sg), mptr); i2o_raw_writel(sg_dma_address(sg), mptr+4); mptr += 8; count -= sg_dma_len(sg); sg++; } switch(dev->rcache) { case CACHE_NULL: i2o_raw_writel(0, msg+16);break; case CACHE_PREFETCH: i2o_raw_writel(0x201F0008, msg+16);break; case CACHE_SMARTFETCH: if(req->nr_sectors > 16) i2o_raw_writel(0x201F0008, msg+16); else i2o_raw_writel(0x001F0000, msg+16); break; } // printk("Reading %d entries %d bytes.\n",// mptr-msg-8, req->nr_sectors<<9); } else if(rq_data_dir(req) == WRITE) { DEBUG("WRITE\n"); i2o_raw_writel(I2O_CMD_BLOCK_WRITE<<24|HOST_TID<<12|tid, msg+4); for(i = sgnum; i > 0; i--) { if(i != 1) i2o_raw_writel(0x14000000|sg_dma_len(sg), mptr); else i2o_raw_writel(0xD4000000|sg_dma_len(sg), mptr); i2o_raw_writel(sg_dma_address(sg), mptr+4); mptr += 8; count -= sg_dma_len(sg); sg++; } switch(dev->wcache) { case CACHE_NULL: i2o_raw_writel(0, msg+16);break; case CACHE_WRITETHROUGH: i2o_raw_writel(0x001F0008, msg+16);break; case CACHE_WRITEBACK: i2o_raw_writel(0x001F0010, msg+16);break; case CACHE_SMARTBACK: if(req->nr_sectors > 16) i2o_raw_writel(0x001F0004, msg+16); else i2o_raw_writel(0x001F0010, msg+16); break; case CACHE_SMARTTHROUGH: if(req->nr_sectors > 16) i2o_raw_writel(0x001F0004, msg+16); else i2o_raw_writel(0x001F0010, msg+16); } // printk("Writing %d entries %d bytes.\n",// mptr-msg-8, req->nr_sectors<<9); } i2o_raw_writel(I2O_MESSAGE_SIZE(mptr-msg)>>2 | SGL_OFFSET_8, msg); if(count != 0) { printk(KERN_ERR "Request count botched by %d.\n", count); } i2o_post_message(c,m); i2ob_queues[c->unit]->queue_depth ++; return 0;}/* * Remove a request from the _locked_ request list. We update both the * list chain and if this is the last item the tail pointer. Caller * must hold the lock. */ static inline void i2ob_unhook_request(struct i2ob_request *ireq, unsigned int iop){ ireq->next = i2ob_queues[iop]->i2ob_qhead; i2ob_queues[iop]->i2ob_qhead = ireq;}/* * Request completion handler */ static inline void i2ob_end_request(struct request *req){ /* FIXME - pci unmap the request */ /* * Loop until all of the buffers that are linked * to this request have been marked updated and * unlocked. */ while (end_that_request_first( req, !req->errors, req->hard_cur_sectors )); /* * It is now ok to complete the request. */ end_that_request_last( req ); DEBUG("IO COMPLETED\n");}/* * OSM reply handler. This gets all the message replies */static void i2o_block_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *msg){ unsigned long flags; struct i2ob_request *ireq = NULL; u8 st; u32 *m = (u32 *)msg; u8 unit = m[2]>>8; struct i2ob_device *dev = &i2ob_dev[unit]; /* * FAILed message */ if(m[0] & (1<<13)) { DEBUG("FAIL"); /* * FAILed message from controller * We increment the error count and abort it * * In theory this will never happen. The I2O block class * specification states that block devices never return * FAILs but instead use the REQ status field...but * better be on the safe side since no one really follows * the spec to the book :) */ ireq=&i2ob_queues[c->unit]->request_queue[m[3]]; ireq->req->errors++; spin_lock_irqsave(dev->req_queue->queue_lock, flags); i2ob_unhook_request(ireq, c->unit); i2ob_end_request(ireq->req); spin_unlock_irqrestore(dev->req_queue->queue_lock, flags); /* Now flush the message by making it a NOP */ m[0]&=0x00FFFFFF; m[0]|=(I2O_CMD_UTIL_NOP)<<24; i2o_post_message(c, (unsigned long) m - (unsigned long) c->msg_virt); return; } if(msg->function == I2O_CMD_UTIL_EVT_REGISTER) { spin_lock(&i2ob_evt_lock); memcpy(evt_msg, msg, (m[0]>>16)<<2); spin_unlock(&i2ob_evt_lock); up(&i2ob_evt_sem); return; } if(!dev->i2odev) { /* * This is HACK, but Intel Integrated RAID allows user * to delete a volume that is claimed, locked, and in use * by the OS. We have to check for a reply from a * non-existent device and flag it as an error or the system * goes kaput... */ ireq=&i2ob_queues[c->unit]->request_queue[m[3]]; ireq->req->errors++; printk(KERN_WARNING "I2O Block: Data transfer to deleted device!\n"); spin_lock_irqsave(dev->req_queue->queue_lock, flags); i2ob_unhook_request(ireq, c->unit); i2ob_end_request(ireq->req); spin_unlock_irqrestore(dev->req_queue->queue_lock, flags); return; } /* * Lets see what is cooking. We stuffed the * request in the context. */ ireq=&i2ob_queues[c->unit]->request_queue[m[3]]; st=m[4]>>24; if(st!=0) { int err; char *bsa_errors[] = { "Success", "Media Error", "Failure communicating to device", "Device Failure", "Device is not ready", "Media not present", "Media is locked by another user", "Media has failed", "Failure communicating to device", "Device bus failure", "Device is locked by another user", "Device is write protected", "Device has reset", "Volume has changed, waiting for acknowledgement" }; err = m[4]&0xFFFF; /* * Device not ready means two things. One is that the * the thing went offline (but not a removal media) * * The second is that you have a SuperTrak 100 and the * firmware got constipated. Unlike standard i2o card * setups the supertrak returns an error rather than * blocking for the timeout in these cases. * * Don't stick a supertrak100 into cache aggressive modes */ printk(KERN_ERR "\n/dev/%s error: %s", dev->i2odev->dev_name, bsa_errors[m[4]&0XFFFF]); if(m[4]&0x00FF0000) printk(" - DDM attempted %d retries", (m[4]>>16)&0x00FF ); printk(".\n"); ireq->req->errors++; }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?