📄 dasd_fba.c
字号:
/* * File...........: linux/drivers/s390/block/dasd_fba.c * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> * Bugreports.to..: <Linux390@de.ibm.com> * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * * $Revision: 1.40 $ */#include <linux/config.h>#include <linux/stddef.h>#include <linux/kernel.h>#include <asm/debug.h>#include <linux/slab.h>#include <linux/hdreg.h> /* HDIO_GETGEO */#include <linux/bio.h>#include <linux/module.h>#include <linux/init.h>#include <asm/idals.h>#include <asm/ebcdic.h>#include <asm/io.h>#include <asm/todclk.h>#include <asm/ccwdev.h>#include "dasd_int.h"#include "dasd_fba.h"#ifdef PRINTK_HEADER#undef PRINTK_HEADER#endif /* PRINTK_HEADER */#define PRINTK_HEADER "dasd(fba):"#define DASD_FBA_CCW_WRITE 0x41#define DASD_FBA_CCW_READ 0x42#define DASD_FBA_CCW_LOCATE 0x43#define DASD_FBA_CCW_DEFINE_EXTENT 0x63MODULE_LICENSE("GPL");static struct dasd_discipline dasd_fba_discipline;struct dasd_fba_private { struct dasd_fba_characteristics rdc_data;};static struct ccw_device_id dasd_fba_ids[] = { { CCW_DEVICE_DEVTYPE (0x6310, 0, 0x9336, 0), driver_info: 0x1}, { CCW_DEVICE_DEVTYPE (0x3880, 0, 0x3370, 0), driver_info: 0x2}, { /* end of list */ },};MODULE_DEVICE_TABLE(ccw, dasd_fba_ids);static struct ccw_driver dasd_fba_driver; /* see below */static intdasd_fba_probe(struct ccw_device *cdev){ int ret; ret = dasd_generic_probe (cdev, &dasd_fba_discipline); if (ret) return ret; ccw_device_set_options(cdev, CCWDEV_DO_PATHGROUP); return 0;}static intdasd_fba_set_online(struct ccw_device *cdev){ return dasd_generic_set_online (cdev, &dasd_fba_discipline);}static struct ccw_driver dasd_fba_driver = { .name = "dasd-fba", .owner = THIS_MODULE, .ids = dasd_fba_ids, .probe = dasd_fba_probe, .remove = dasd_generic_remove, .set_offline = dasd_generic_set_offline, .set_online = dasd_fba_set_online, .notify = dasd_generic_notify,};static inline voiddefine_extent(struct ccw1 * ccw, struct DE_fba_data *data, int rw, int blksize, int beg, int nr){ ccw->cmd_code = DASD_FBA_CCW_DEFINE_EXTENT; ccw->flags = 0; ccw->count = 16; ccw->cda = (__u32) __pa(data); memset(data, 0, sizeof (struct DE_fba_data)); if (rw == WRITE) (data->mask).perm = 0x0; else if (rw == READ) (data->mask).perm = 0x1; else data->mask.perm = 0x2; data->blk_size = blksize; data->ext_loc = beg; data->ext_end = nr - 1;}static inline voidlocate_record(struct ccw1 * ccw, struct LO_fba_data *data, int rw, int block_nr, int block_ct){ ccw->cmd_code = DASD_FBA_CCW_LOCATE; ccw->flags = 0; ccw->count = 8; ccw->cda = (__u32) __pa(data); memset(data, 0, sizeof (struct LO_fba_data)); if (rw == WRITE) data->operation.cmd = 0x5; else if (rw == READ) data->operation.cmd = 0x6; else data->operation.cmd = 0x8; data->blk_nr = block_nr; data->blk_ct = block_ct;}static intdasd_fba_check_characteristics(struct dasd_device *device){ struct dasd_fba_private *private; struct ccw_device *cdev = device->cdev; void *rdc_data; int rc; private = (struct dasd_fba_private *) device->private; if (private == NULL) { private = kmalloc(sizeof(struct dasd_fba_private), GFP_KERNEL); if (private == NULL) { DEV_MESSAGE(KERN_WARNING, device, "%s", "memory allocation failed for private " "data"); return -ENOMEM; } device->private = (void *) private; } /* Read Device Characteristics */ rdc_data = (void *) &(private->rdc_data); rc = read_dev_chars(device->cdev, &rdc_data, 32); if (rc) { DEV_MESSAGE(KERN_WARNING, device, "Read device characteristics returned error %d", rc); return rc; } DEV_MESSAGE(KERN_INFO, device, "%04X/%02X(CU:%04X/%02X) %dMB at(%d B/blk)", cdev->id.dev_type, cdev->id.dev_model, cdev->id.cu_type, cdev->id.cu_model, ((private->rdc_data.blk_bdsa * (private->rdc_data.blk_size >> 9)) >> 11), private->rdc_data.blk_size); return 0;}static intdasd_fba_do_analysis(struct dasd_device *device){ struct dasd_fba_private *private; int sb, rc; private = (struct dasd_fba_private *) device->private; rc = dasd_check_blocksize(private->rdc_data.blk_size); if (rc) { DEV_MESSAGE(KERN_INFO, device, "unknown blocksize %d", private->rdc_data.blk_size); return rc; } device->blocks = private->rdc_data.blk_bdsa; device->bp_block = private->rdc_data.blk_size; device->s2b_shift = 0; /* bits to shift 512 to get a block */ for (sb = 512; sb < private->rdc_data.blk_size; sb = sb << 1) device->s2b_shift++; return 0;}static intdasd_fba_fill_geometry(struct dasd_device *device, struct hd_geometry *geo){ if (dasd_check_blocksize(device->bp_block) != 0) return -EINVAL; geo->cylinders = (device->blocks << device->s2b_shift) >> 10; geo->heads = 16; geo->sectors = 128 >> device->s2b_shift; return 0;}static dasd_era_tdasd_fba_examine_error(struct dasd_ccw_req * cqr, struct irb * irb){ struct dasd_device *device; struct ccw_device *cdev; device = (struct dasd_device *) cqr->device; if (irb->scsw.cstat == 0x00 && irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) return dasd_era_none; cdev = device->cdev; switch (cdev->id.dev_type) { case 0x3370: return dasd_3370_erp_examine(cqr, irb); case 0x9336: return dasd_9336_erp_examine(cqr, irb); default: return dasd_era_recover; }}static dasd_erp_fn_tdasd_fba_erp_action(struct dasd_ccw_req * cqr){ return dasd_default_erp_action;}static dasd_erp_fn_tdasd_fba_erp_postaction(struct dasd_ccw_req * cqr){ if (cqr->function == dasd_default_erp_action) return dasd_default_erp_postaction; DEV_MESSAGE(KERN_WARNING, cqr->device, "unknown ERP action %p", cqr->function); return NULL;}static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * device, struct request *req){ struct dasd_fba_private *private; unsigned long *idaws; struct LO_fba_data *LO_data; struct dasd_ccw_req *cqr; struct ccw1 *ccw; struct bio *bio; struct bio_vec *bv; char *dst; int count, cidaw, cplength, datasize; sector_t recid, first_rec, last_rec; unsigned int blksize, off; unsigned char cmd; int i; private = (struct dasd_fba_private *) device->private; if (rq_data_dir(req) == READ) { cmd = DASD_FBA_CCW_READ; } else if (rq_data_dir(req) == WRITE) { cmd = DASD_FBA_CCW_WRITE; } else return ERR_PTR(-EINVAL); blksize = device->bp_block; /* Calculate record id of first and last block. */ first_rec = req->sector >> device->s2b_shift; last_rec = (req->sector + req->nr_sectors - 1) >> device->s2b_shift; /* Check struct bio and count the number of blocks for the request. */ count = 0; cidaw = 0; rq_for_each_bio(bio, req) { bio_for_each_segment(bv, bio, i) { if (bv->bv_len & (blksize - 1)) /* Fba can only do full blocks. */ return ERR_PTR(-EINVAL); count += bv->bv_len >> (device->s2b_shift + 9);#if defined(CONFIG_ARCH_S390X) if (idal_is_needed (page_address(bv->bv_page), bv->bv_len)) cidaw += bv->bv_len / blksize;#endif } } /* Paranoia. */ if (count != last_rec - first_rec + 1) return ERR_PTR(-EINVAL); /* 1x define extent + 1x locate record + number of blocks */ cplength = 2 + count; /* 1x define extent + 1x locate record */ datasize = sizeof(struct DE_fba_data) + sizeof(struct LO_fba_data) + cidaw * sizeof(unsigned long); /* * Find out number of additional locate record ccws if the device * can't do data chaining. */ if (private->rdc_data.mode.bits.data_chain == 0) { cplength += count - 1; datasize += (count - 1)*sizeof(struct LO_fba_data); } /* Allocate the ccw request. */ cqr = dasd_smalloc_request(dasd_fba_discipline.name, cplength, datasize, device); if (IS_ERR(cqr)) return cqr; ccw = cqr->cpaddr; /* First ccw is define extent. */ define_extent(ccw++, cqr->data, rq_data_dir(req), device->bp_block, req->sector, req->nr_sectors);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -