i2o_block.c
来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 1,694 行 · 第 1/3 页
C
1,694 行
else ireq->req->errors = 0; /* * Dequeue the request. We use irqsave locks as one day we * may be running polled controllers from a BH... */ i2ob_free_sglist(dev, ireq); spin_lock_irqsave(dev->req_queue->queue_lock, flags); i2ob_unhook_request(ireq, c->unit); i2ob_end_request(ireq->req); i2ob_queues[c->unit]->queue_depth --; /* * We may be able to do more I/O */ i2ob_request(dev->gd->queue); spin_unlock_irqrestore(dev->req_queue->queue_lock, flags);}/* * Event handler. Needs to be a separate thread b/c we may have * to do things like scan a partition table, or query parameters * which cannot be done from an interrupt or from a bottom half. */static int i2ob_evt(void *dummy){ unsigned int evt; unsigned long flags; struct i2ob_device *dev; int unit; //The only event that has data is the SCSI_SMART event. struct i2o_reply { u32 header[4]; u32 evt_indicator; u8 ASC; u8 ASCQ; u16 pad; u8 data[16]; } *evt_local; daemonize("i2oblock"); allow_signal(SIGKILL); evt_running = 1; while(1) { if(down_interruptible(&i2ob_evt_sem)) { evt_running = 0; printk("exiting..."); break; } /* * Keep another CPU/interrupt from overwriting the * message while we're reading it * * We stuffed the unit in the TxContext and grab the event mask * None of the BSA we care about events have EventData */ spin_lock_irqsave(&i2ob_evt_lock, flags); evt_local = (struct i2o_reply *)evt_msg; spin_unlock_irqrestore(&i2ob_evt_lock, flags); unit = le32_to_cpu(evt_local->header[3]); evt = le32_to_cpu(evt_local->evt_indicator); dev = &i2ob_dev[unit]; switch(evt) { /* * New volume loaded on same TID, so we just re-install. * The TID/controller don't change as it is the same * I2O device. It's just new media that we have to * rescan. */ case I2O_EVT_IND_BSA_VOLUME_LOAD: { i2ob_install_device(dev->i2odev->controller, dev->i2odev, unit); add_disk(dev->gd); break; } /* * No media, so set all parameters to 0 and set the media * change flag. The I2O device is still valid, just doesn't * have media, so we don't want to clear the controller or * device pointer. */ case I2O_EVT_IND_BSA_VOLUME_UNLOAD: { struct gendisk *p = dev->gd; blk_queue_max_sectors(dev->gd->queue, 0); del_gendisk(p); put_disk(p); dev->gd = NULL; dev->media_change_flag = 1; break; } case I2O_EVT_IND_BSA_VOLUME_UNLOAD_REQ: printk(KERN_WARNING "%s: Attempt to eject locked media\n", dev->i2odev->dev_name); break; /* * The capacity has changed and we are going to be * updating the max_sectors and other information * about this disk. We try a revalidate first. If * the block device is in use, we don't want to * do that as there may be I/Os bound for the disk * at the moment. In that case we read the size * from the device and update the information ourselves * and the user can later force a partition table * update through an ioctl. */ case I2O_EVT_IND_BSA_CAPACITY_CHANGE: { u64 size; if(i2ob_query_device(dev, 0x0004, 0, &size, 8) !=0 ) i2ob_query_device(dev, 0x0000, 4, &size, 8); spin_lock_irqsave(dev->req_queue->queue_lock, flags); set_capacity(dev->gd, size>>9); spin_unlock_irqrestore(dev->req_queue->queue_lock, flags); break; } /* * We got a SCSI SMART event, we just log the relevant * information and let the user decide what they want * to do with the information. */ case I2O_EVT_IND_BSA_SCSI_SMART: { char buf[16]; printk(KERN_INFO "I2O Block: %s received a SCSI SMART Event\n",dev->i2odev->dev_name); evt_local->data[16]='\0'; sprintf(buf,"%s",&evt_local->data[0]); printk(KERN_INFO " Disk Serial#:%s\n",buf); printk(KERN_INFO " ASC 0x%02x \n",evt_local->ASC); printk(KERN_INFO " ASCQ 0x%02x \n",evt_local->ASCQ); break; } /* * Non event */ case 0: break; /* * An event we didn't ask for. Call the card manufacturer * and tell them to fix their firmware :) */ case 0x20: /* * If a promise card reports 0x20 event then the brown stuff * hit the fan big time. The card seems to recover but loses * the pending writes. Deeply ungood except for testing fsck */ if(dev->i2odev->controller->promise) panic("I2O controller firmware failed. Reboot and force a filesystem check.\n"); default: printk(KERN_INFO "%s: Received event 0x%X we didn't register for\n" KERN_INFO " Blame the I2O card manufacturer 8)\n", dev->i2odev->dev_name, evt); break; } }; complete_and_exit(&i2ob_thread_dead,0); return 0;}/* * The I2O block driver is listed as one of those that pulls the * front entry off the queue before processing it. This is important * to remember here. If we drop the io lock then CURRENT will change * on us. We must unlink CURRENT in this routine before we return, if * we use it. */static void i2ob_request(request_queue_t *q){ struct request *req; struct i2ob_request *ireq; struct i2ob_device *dev; u32 m; while ((req = elv_next_request(q)) != NULL) { dev = req->rq_disk->private_data; /* * Queue depths probably belong with some kind of * generic IOP commit control. Certainly it's not right * its global! */ if(i2ob_queues[dev->unit]->queue_depth >= dev->depth) break; /* Get a message */ m = i2ob_get(dev); if(m==0xFFFFFFFF) { if(i2ob_queues[dev->unit]->queue_depth == 0) printk(KERN_ERR "i2o_block: message queue and request queue empty!!\n"); break; } /* * Everything ok, so pull from kernel queue onto our queue */ req->errors = 0; blkdev_dequeue_request(req); ireq = i2ob_queues[dev->unit]->i2ob_qhead; i2ob_queues[dev->unit]->i2ob_qhead = ireq->next; ireq->req = req; i2ob_send(m, dev, ireq, dev->index); }}/* * SCSI-CAM for ioctl geometry mapping * Duplicated with SCSI - this should be moved into somewhere common * perhaps genhd ? * * LBA -> CHS mapping table taken from: * * "Incorporating the I2O Architecture into BIOS for Intel Architecture * Platforms" * * This is an I2O document that is only available to I2O members, * not developers. * * From my understanding, this is how all the I2O cards do this * * Disk Size | Sectors | Heads | Cylinders * ---------------+---------+-------+------------------- * 1 < X <= 528M | 63 | 16 | X/(63 * 16 * 512) * 528M < X <= 1G | 63 | 32 | X/(63 * 32 * 512) * 1 < X <528M | 63 | 16 | X/(63 * 16 * 512) * 1 < X <528M | 63 | 16 | X/(63 * 16 * 512) * */#define BLOCK_SIZE_528M 1081344#define BLOCK_SIZE_1G 2097152#define BLOCK_SIZE_21G 4403200#define BLOCK_SIZE_42G 8806400#define BLOCK_SIZE_84G 17612800static void i2o_block_biosparam( unsigned long capacity, unsigned short *cyls, unsigned char *hds, unsigned char *secs) { unsigned long heads, sectors, cylinders; sectors = 63L; /* Maximize sectors per track */ if(capacity <= BLOCK_SIZE_528M) heads = 16; else if(capacity <= BLOCK_SIZE_1G) heads = 32; else if(capacity <= BLOCK_SIZE_21G) heads = 64; else if(capacity <= BLOCK_SIZE_42G) heads = 128; else heads = 255; cylinders = (unsigned long)capacity / (heads * sectors); *cyls = (unsigned short) cylinders; /* Stuff return values */ *secs = (unsigned char) sectors; *hds = (unsigned char) heads; }/* * Issue device specific ioctl calls. */static int i2ob_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ struct gendisk *disk = inode->i_bdev->bd_disk; struct i2ob_device *dev = disk->private_data; void __user *argp = (void __user *)arg; /* Anyone capable of this syscall can do *real bad* things */ if (!capable(CAP_SYS_ADMIN)) return -EPERM; switch (cmd) { case HDIO_GETGEO: { struct hd_geometry g; i2o_block_biosparam(get_capacity(disk), &g.cylinders, &g.heads, &g.sectors); g.start = get_start_sect(inode->i_bdev); return copy_to_user(argp, &g, sizeof(g))?-EFAULT:0; } case BLKI2OGRSTRAT: return put_user(dev->rcache, (int __user *)argp); case BLKI2OGWSTRAT: return put_user(dev->wcache, (int __user *)argp); case BLKI2OSRSTRAT: if(arg<0||arg>CACHE_SMARTFETCH) return -EINVAL; dev->rcache = arg; break; case BLKI2OSWSTRAT: if(arg!=0 && (arg<CACHE_WRITETHROUGH || arg>CACHE_SMARTBACK)) return -EINVAL; dev->wcache = arg; break; } return -ENOTTY;}/* * Close the block device down */ static int i2ob_release(struct inode *inode, struct file *file){ struct gendisk *disk = inode->i_bdev->bd_disk; struct i2ob_device *dev = disk->private_data; /* * This is to deail with the case of an application * opening a device and then the device dissapears while * it's in use, and then the application tries to release * it. ex: Unmounting a deleted RAID volume at reboot. * If we send messages, it will just cause FAILs since * the TID no longer exists. */ if(!dev->i2odev) return 0; if (dev->refcnt <= 0) printk(KERN_ALERT "i2ob_release: refcount(%d) <= 0\n", dev->refcnt); dev->refcnt--; if(dev->refcnt==0) { /* * Flush the onboard cache on unmount */ u32 msg[5]; int *query_done = &dev->done_flag; msg[0] = (FIVE_WORD_MSG_SIZE|SGL_OFFSET_0); msg[1] = I2O_CMD_BLOCK_CFLUSH<<24|HOST_TID<<12|dev->tid; msg[2] = i2ob_context|0x40000000; msg[3] = (u32)query_done; msg[4] = 60<<16; DEBUG("Flushing..."); i2o_post_wait(dev->controller, msg, 20, 60); /* * Unlock the media */ msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; msg[1] = I2O_CMD_BLOCK_MUNLOCK<<24|HOST_TID<<12|dev->tid; msg[2] = i2ob_context|0x40000000; msg[3] = (u32)query_done; msg[4] = -1; DEBUG("Unlocking..."); i2o_post_wait(dev->controller, msg, 20, 2); DEBUG("Unlocked.\n"); msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; msg[1] = I2O_CMD_BLOCK_POWER<<24 | HOST_TID << 12 | dev->tid; if(dev->flags & (1<<3|1<<4)) /* Removable */ msg[4] = 0x21 << 24; else msg[4] = 0x24 << 24; if(i2o_post_wait(dev->controller, msg, 20, 60)==0) dev->power = 0x24; /* * Now unclaim the device. */ if (i2o_release_device(dev->i2odev, &i2o_block_handler)) printk(KERN_ERR "i2ob_release: controller rejected unclaim.\n"); DEBUG("Unclaim\n"); } return 0;}/* * Open the block device. */ static int i2ob_open(struct inode *inode, struct file *file){ struct gendisk *disk = inode->i_bdev->bd_disk; struct i2ob_device *dev = disk->private_data; if(!dev->i2odev) return -ENODEV; if(dev->refcnt++==0) { u32 msg[6]; DEBUG("Claim "); if(i2o_claim_device(dev->i2odev, &i2o_block_handler)) { dev->refcnt--; printk(KERN_INFO "I2O Block: Could not open device\n"); return -EBUSY; } DEBUG("Claimed "); /* * Power up if needed */ if(dev->power > 0x1f) { msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; msg[1] = I2O_CMD_BLOCK_POWER<<24 | HOST_TID << 12 | dev->tid; msg[4] = 0x02 << 24; if(i2o_post_wait(dev->controller, msg, 20, 60) == 0) dev->power = 0x02; } /* * Mount the media if needed. Note that we don't use * the lock bit. Since we have to issue a lock if it * refuses a mount (quite possible) then we might as * well just send two messages out. */ msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; msg[1] = I2O_CMD_BLOCK_MMOUNT<<24|HOST_TID<<12|dev->tid; msg[4] = -1; msg[5] = 0; DEBUG("Mount "); i2o_post_wait(dev->controller, msg, 24, 2); /* * Lock the media */ msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; msg[1] = I2O_CMD_BLOCK_MLOCK<<24|HOST_TID<<12|dev->tid; msg[4] = -1; DEBUG("Lock "); i2o_post_wait(dev->controller, msg, 20, 2); DEBUG("Ready.\n"); } return 0;}/* * Issue a device query */ static int i2ob_query_device(struct i2ob_device *dev, int table, int field, void *buf, int buflen){ return i2o_query_scalar(dev->controller, dev->tid, table, field, buf, buflen);}/* * Install the I2O block device we found. */ static int i2ob_install_device(struct i2o_controller *c, struct i2o_device *d, int unit){ u64 size; u32 blocksize; u8 type; u16 power; u32 flags, status; struct i2ob_device *dev=&i2ob_dev[unit]; struct gendisk *disk; request_queue_t *q; int segments; /* * For logging purposes... */ printk(KERN_INFO "i2ob: Installing tid %d device at unit %d\n", d->lct_data.tid, unit); /* * If this is the first I2O block device found on this IOP, * we need to initialize all the queue data structures * before any I/O can be performed. If it fails, this * device is useless. */ if(!i2ob_queues[c->unit]) { if(i2ob_init_iop(c->unit)) return 1; } q = i2ob_queues[c->unit]->req_queue; /* * This will save one level of lookup/indirection in critical * code so that we can directly get the queue ptr from the * device instead of having to go the IOP data structure. */ dev->req_queue = q; /* * Allocate a gendisk structure and initialize it */ disk = alloc_disk(16); if (!disk) return 1; dev->gd = disk; /* initialize gendik structure */ disk->major = MAJOR_NR; disk->first_minor = unit<<4; disk->queue = q; disk->fops = &i2ob_fops; sprintf(disk->disk_name, "i2o/hd%c", 'a' + unit); disk->private_data = dev; /* * Ask for the current media data. If that isn't supported * then we ask for the device capacity data */ if(i2ob_query_device(dev, 0x0004, 1, &blocksize, 4) != 0 || i2ob_query_device(dev, 0x0004, 0, &size, 8) !=0 ) { i2ob_query_device(dev, 0x0000, 3, &blocksize, 4); i2ob_query_device(dev, 0x0000, 4, &size, 8); } if(i2ob_query_device(dev, 0x0000, 2, &power, 2)!=0) power = 0; i2ob_query_device(dev, 0x0000, 5, &flags, 4); i2ob_query_device(dev, 0x0000, 6, &status, 4); set_capacity(disk, size>>9); /* * Max number of Scatter-Gather Elements */ dev->power = power; /* Save power state in device proper */ dev->flags = flags; segments = (d->controller->status_block->inbound_frame_size - 7) / 2; if(segments > 16)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?