📄 i2o_block.c
字号:
/* * Block OSM * * Copyright (C) 1999-2002 Red Hat Software * * 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. * * 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. */#include <linux/module.h>#include <linux/i2o.h>#include <linux/mempool.h>#include <linux/genhd.h>#include <linux/blkdev.h>#include <linux/hdreg.h>#include "i2o_block.h"#define OSM_NAME "block-osm"#define OSM_VERSION "1.287"#define OSM_DESCRIPTION "I2O Block Device OSM"static struct i2o_driver i2o_block_driver;/* global Block OSM request mempool */static struct i2o_block_mempool i2o_blk_req_pool;/* Block OSM class handling definition */static struct i2o_class_id i2o_block_class_id[] = { {I2O_CLASS_RANDOM_BLOCK_STORAGE}, {I2O_CLASS_END}};/** * i2o_block_device_free - free the memory of the I2O Block device * @dev: I2O Block device, which should be cleaned up * * Frees the request queue, gendisk and the i2o_block_device structure. */static void i2o_block_device_free(struct i2o_block_device *dev){ blk_cleanup_queue(dev->gd->queue); put_disk(dev->gd); kfree(dev);};/** * i2o_block_remove - remove the I2O Block device from the system again * @dev: I2O Block device which should be removed * * Remove gendisk from system and free all allocated memory. * * Always returns 0. */static int i2o_block_remove(struct device *dev){ struct i2o_device *i2o_dev = to_i2o_device(dev); struct i2o_block_device *i2o_blk_dev = dev_get_drvdata(dev); osm_info("device removed (TID: %03x): %s\n", i2o_dev->lct_data.tid, i2o_blk_dev->gd->disk_name); i2o_event_register(i2o_dev, &i2o_block_driver, 0, 0); del_gendisk(i2o_blk_dev->gd); dev_set_drvdata(dev, NULL); i2o_device_claim_release(i2o_dev); i2o_block_device_free(i2o_blk_dev); return 0;};/** * i2o_block_device flush - Flush all dirty data of I2O device dev * @dev: I2O device which should be flushed * * Flushes all dirty data on device dev. * * Returns 0 on success or negative error code on failure. */static int i2o_block_device_flush(struct i2o_device *dev){ struct i2o_message __iomem *msg; u32 m; m = i2o_msg_get_wait(dev->iop, &msg, I2O_TIMEOUT_MESSAGE_GET); if (m == I2O_QUEUE_EMPTY) return -ETIMEDOUT; writel(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); writel(I2O_CMD_BLOCK_CFLUSH << 24 | HOST_TID << 12 | dev->lct_data.tid, &msg->u.head[1]); writel(60 << 16, &msg->body[0]); osm_debug("Flushing...\n"); return i2o_msg_post_wait(dev->iop, m, 60);};/** * i2o_block_issue_flush - device-flush interface for block-layer * @queue: the request queue of the device which should be flushed * @disk: gendisk * @error_sector: error offset * * Helper function to provide flush functionality to block-layer. * * Returns 0 on success or negative error code on failure. */static int i2o_block_issue_flush(request_queue_t * queue, struct gendisk *disk, sector_t * error_sector){ struct i2o_block_device *i2o_blk_dev = queue->queuedata; int rc = -ENODEV; if (likely(i2o_blk_dev)) rc = i2o_block_device_flush(i2o_blk_dev->i2o_dev); return rc;}/** * i2o_block_device_mount - Mount (load) the media of device dev * @dev: I2O device which should receive the mount request * @media_id: Media Identifier * * Load a media into drive. Identifier should be set to -1, because the * spec does not support any other value. * * Returns 0 on success or negative error code on failure. */static int i2o_block_device_mount(struct i2o_device *dev, u32 media_id){ struct i2o_message __iomem *msg; u32 m; m = i2o_msg_get_wait(dev->iop, &msg, I2O_TIMEOUT_MESSAGE_GET); if (m == I2O_QUEUE_EMPTY) return -ETIMEDOUT; writel(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); writel(I2O_CMD_BLOCK_MMOUNT << 24 | HOST_TID << 12 | dev->lct_data.tid, &msg->u.head[1]); writel(-1, &msg->body[0]); writel(0, &msg->body[1]); osm_debug("Mounting...\n"); return i2o_msg_post_wait(dev->iop, m, 2);};/** * i2o_block_device_lock - Locks the media of device dev * @dev: I2O device which should receive the lock request * @media_id: Media Identifier * * Lock media of device dev to prevent removal. The media identifier * should be set to -1, because the spec does not support any other value. * * Returns 0 on success or negative error code on failure. */static int i2o_block_device_lock(struct i2o_device *dev, u32 media_id){ struct i2o_message __iomem *msg; u32 m; m = i2o_msg_get_wait(dev->iop, &msg, I2O_TIMEOUT_MESSAGE_GET); if (m == I2O_QUEUE_EMPTY) return -ETIMEDOUT; writel(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); writel(I2O_CMD_BLOCK_MLOCK << 24 | HOST_TID << 12 | dev->lct_data.tid, &msg->u.head[1]); writel(-1, &msg->body[0]); osm_debug("Locking...\n"); return i2o_msg_post_wait(dev->iop, m, 2);};/** * i2o_block_device_unlock - Unlocks the media of device dev * @dev: I2O device which should receive the unlocked request * @media_id: Media Identifier * * Unlocks the media in device dev. The media identifier should be set to * -1, because the spec does not support any other value. * * Returns 0 on success or negative error code on failure. */static int i2o_block_device_unlock(struct i2o_device *dev, u32 media_id){ struct i2o_message __iomem *msg; u32 m; m = i2o_msg_get_wait(dev->iop, &msg, I2O_TIMEOUT_MESSAGE_GET); if (m == I2O_QUEUE_EMPTY) return -ETIMEDOUT; writel(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); writel(I2O_CMD_BLOCK_MUNLOCK << 24 | HOST_TID << 12 | dev->lct_data.tid, &msg->u.head[1]); writel(media_id, &msg->body[0]); osm_debug("Unlocking...\n"); return i2o_msg_post_wait(dev->iop, m, 2);};/** * i2o_block_device_power - Power management for device dev * @dev: I2O device which should receive the power management request * @operation: Operation which should be send * * Send a power management request to the device dev. * * Returns 0 on success or negative error code on failure. */static int i2o_block_device_power(struct i2o_block_device *dev, u8 op){ struct i2o_device *i2o_dev = dev->i2o_dev; struct i2o_controller *c = i2o_dev->iop; struct i2o_message __iomem *msg; u32 m; int rc; m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); if (m == I2O_QUEUE_EMPTY) return -ETIMEDOUT; writel(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); writel(I2O_CMD_BLOCK_POWER << 24 | HOST_TID << 12 | i2o_dev->lct_data. tid, &msg->u.head[1]); writel(op << 24, &msg->body[0]); osm_debug("Power...\n"); rc = i2o_msg_post_wait(c, m, 60); if (!rc) dev->power = op; return rc;};/** * i2o_block_request_alloc - Allocate an I2O block request struct * * Allocates an I2O block request struct and initialize the list. * * Returns a i2o_block_request pointer on success or negative error code * on failure. */static inline struct i2o_block_request *i2o_block_request_alloc(void){ struct i2o_block_request *ireq; ireq = mempool_alloc(i2o_blk_req_pool.pool, GFP_ATOMIC); if (!ireq) return ERR_PTR(-ENOMEM); INIT_LIST_HEAD(&ireq->queue); return ireq;};/** * i2o_block_request_free - Frees a I2O block request * @ireq: I2O block request which should be freed * * Fres the allocated memory (give it back to the request mempool). */static inline void i2o_block_request_free(struct i2o_block_request *ireq){ mempool_free(ireq, i2o_blk_req_pool.pool);};/** * i2o_block_sglist_alloc - Allocate the SG list and map it * @c: I2O controller to which the request belongs * @ireq: I2O block request * * Builds the SG list and map it to be accessable by the controller. * * Returns 0 on failure or 1 on success. */static inline int i2o_block_sglist_alloc(struct i2o_controller *c, struct i2o_block_request *ireq, u32 __iomem ** mptr){ int nents; enum dma_data_direction direction; ireq->dev = &c->pdev->dev; nents = blk_rq_map_sg(ireq->req->q, ireq->req, ireq->sg_table); if (rq_data_dir(ireq->req) == READ) direction = PCI_DMA_FROMDEVICE; else direction = PCI_DMA_TODEVICE; ireq->sg_nents = nents; return i2o_dma_map_sg(c, ireq->sg_table, nents, direction, mptr);};/** * i2o_block_sglist_free - Frees the SG list * @ireq: I2O block request from which the SG should be freed * * Frees the SG list from the I2O block request. */static inline void i2o_block_sglist_free(struct i2o_block_request *ireq){ enum dma_data_direction direction; if (rq_data_dir(ireq->req) == READ) direction = PCI_DMA_FROMDEVICE; else direction = PCI_DMA_TODEVICE; dma_unmap_sg(ireq->dev, ireq->sg_table, ireq->sg_nents, direction);};/** * i2o_block_prep_req_fn - Allocates I2O block device specific struct * @q: request queue for the request * @req: the request to prepare * * Allocate the necessary i2o_block_request struct and connect it to * the request. This is needed that we not loose the SG list later on. * * Returns BLKPREP_OK on success or BLKPREP_DEFER on failure. */static int i2o_block_prep_req_fn(struct request_queue *q, struct request *req){ struct i2o_block_device *i2o_blk_dev = q->queuedata; struct i2o_block_request *ireq; if (unlikely(!i2o_blk_dev)) { osm_err("block device already removed\n"); return BLKPREP_KILL; } /* request is already processed by us, so return */ if (req->flags & REQ_SPECIAL) { osm_debug("REQ_SPECIAL already set!\n"); req->flags |= REQ_DONTPREP; return BLKPREP_OK; } /* connect the i2o_block_request to the request */ if (!req->special) { ireq = i2o_block_request_alloc(); if (unlikely(IS_ERR(ireq))) { osm_debug("unable to allocate i2o_block_request!\n"); return BLKPREP_DEFER; } ireq->i2o_blk_dev = i2o_blk_dev; req->special = ireq; ireq->req = req; } else ireq = req->special; /* do not come back here */ req->flags |= REQ_DONTPREP | REQ_SPECIAL; return BLKPREP_OK;};/** * i2o_block_delayed_request_fn - delayed request queue function
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -