📄 dasd_eckd.c
字号:
cqr->cpaddr->flags |= CCW_FLAG_SLI; cqr->cpaddr->count = 32; cqr->cpaddr->cda = (__u32)(addr_t) cqr->data; cqr->device = device; clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); cqr->retries = 0; cqr->expires = 2 * HZ; cqr->buildclk = get_clock(); cqr->status = DASD_CQR_FILLED; rc = dasd_sleep_on_immediatly(cqr); dasd_sfree_request(cqr, cqr->device); return rc;}/* * Steal lock ioctl - unconditional reserve device. * Buils a channel programm to break a device's reservation. * (unconditional reserve) */static intdasd_eckd_steal_lock(struct block_device *bdev, int no, long args){ struct dasd_device *device; struct dasd_ccw_req *cqr; int rc; if (!capable(CAP_SYS_ADMIN)) return -EACCES; device = bdev->bd_disk->private_data; if (device == NULL) return -ENODEV; cqr = dasd_smalloc_request(dasd_eckd_discipline.name, 1, 32, device); if (IS_ERR(cqr)) { DEV_MESSAGE(KERN_WARNING, device, "%s", "Could not allocate initialization request"); return PTR_ERR(cqr); } cqr->cpaddr->cmd_code = DASD_ECKD_CCW_SLCK; cqr->cpaddr->flags |= CCW_FLAG_SLI; cqr->cpaddr->count = 32; cqr->cpaddr->cda = (__u32)(addr_t) cqr->data; cqr->device = device; clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); cqr->retries = 0; cqr->expires = 2 * HZ; cqr->buildclk = get_clock(); cqr->status = DASD_CQR_FILLED; rc = dasd_sleep_on_immediatly(cqr); dasd_sfree_request(cqr, cqr->device); return rc;}/* * Read performance statistics */static intdasd_eckd_performance(struct block_device *bdev, int no, long args){ struct dasd_device *device; struct dasd_psf_prssd_data *prssdp; struct dasd_rssd_perf_stats_t *stats; struct dasd_ccw_req *cqr; struct ccw1 *ccw; int rc; device = bdev->bd_disk->private_data; if (device == NULL) return -ENODEV; cqr = dasd_smalloc_request(dasd_eckd_discipline.name, 1 /* PSF */ + 1 /* RSSD */ , (sizeof (struct dasd_psf_prssd_data) + sizeof (struct dasd_rssd_perf_stats_t)), device); if (IS_ERR(cqr)) { DEV_MESSAGE(KERN_WARNING, device, "%s", "Could not allocate initialization request"); return PTR_ERR(cqr); } cqr->device = device; cqr->retries = 0; cqr->expires = 10 * HZ; /* Prepare for Read Subsystem Data */ prssdp = (struct dasd_psf_prssd_data *) cqr->data; memset(prssdp, 0, sizeof (struct dasd_psf_prssd_data)); prssdp->order = PSF_ORDER_PRSSD; prssdp->suborder = 0x01; /* Perfomance Statistics */ prssdp->varies[1] = 0x01; /* Perf Statistics for the Subsystem */ ccw = cqr->cpaddr; ccw->cmd_code = DASD_ECKD_CCW_PSF; ccw->count = sizeof (struct dasd_psf_prssd_data); ccw->flags |= CCW_FLAG_CC; ccw->cda = (__u32)(addr_t) prssdp; /* Read Subsystem Data - Performance Statistics */ stats = (struct dasd_rssd_perf_stats_t *) (prssdp + 1); memset(stats, 0, sizeof (struct dasd_rssd_perf_stats_t)); ccw++; ccw->cmd_code = DASD_ECKD_CCW_RSSD; ccw->count = sizeof (struct dasd_rssd_perf_stats_t); ccw->cda = (__u32)(addr_t) stats; cqr->buildclk = get_clock(); cqr->status = DASD_CQR_FILLED; rc = dasd_sleep_on(cqr); if (rc == 0) { /* Prepare for Read Subsystem Data */ prssdp = (struct dasd_psf_prssd_data *) cqr->data; stats = (struct dasd_rssd_perf_stats_t *) (prssdp + 1); rc = copy_to_user((long __user *) args, (long *) stats, sizeof(struct dasd_rssd_perf_stats_t)); } dasd_sfree_request(cqr, cqr->device); return rc;}/* * Get attributes (cache operations) * Returnes the cache attributes used in Define Extend (DE). */static intdasd_eckd_get_attrib (struct block_device *bdev, int no, long args){ struct dasd_device *device; struct dasd_eckd_private *private; struct attrib_data_t attrib; int rc; if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (!args) return -EINVAL; device = bdev->bd_disk->private_data; if (device == NULL) return -ENODEV; private = (struct dasd_eckd_private *) device->private; attrib = private->attrib; rc = copy_to_user((long __user *) args, (long *) &attrib, sizeof (struct attrib_data_t)); return rc;}/* * Set attributes (cache operations) * Stores the attributes for cache operation to be used in Define Extend (DE). */static intdasd_eckd_set_attrib(struct block_device *bdev, int no, long args){ struct dasd_device *device; struct dasd_eckd_private *private; struct attrib_data_t attrib; if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (!args) return -EINVAL; device = bdev->bd_disk->private_data; if (device == NULL) return -ENODEV; if (copy_from_user(&attrib, (void __user *) args, sizeof (struct attrib_data_t))) { return -EFAULT; } private = (struct dasd_eckd_private *) device->private; private->attrib = attrib; DEV_MESSAGE(KERN_INFO, device, "cache operation mode set to %x (%i cylinder prestage)", private->attrib.operation, private->attrib.nr_cyl); return 0;}/* * Print sense data and related channel program. * Parts are printed because printk buffer is only 1024 bytes. */static voiddasd_eckd_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req, struct irb *irb){ char *page; struct ccw1 *act, *end, *last; int len, sl, sct, count; page = (char *) get_zeroed_page(GFP_ATOMIC); if (page == NULL) { DEV_MESSAGE(KERN_ERR, device, " %s", "No memory to dump sense data"); return; } len = sprintf(page, KERN_ERR PRINTK_HEADER " I/O status report for device %s:\n", device->cdev->dev.bus_id); len += sprintf(page + len, KERN_ERR PRINTK_HEADER " in req: %p CS: 0x%02X DS: 0x%02X\n", req, irb->scsw.cstat, irb->scsw.dstat); len += sprintf(page + len, KERN_ERR PRINTK_HEADER " device %s: Failing CCW: %p\n", device->cdev->dev.bus_id, (void *) (addr_t) irb->scsw.cpa); if (irb->esw.esw0.erw.cons) { for (sl = 0; sl < 4; sl++) { len += sprintf(page + len, KERN_ERR PRINTK_HEADER " Sense(hex) %2d-%2d:", (8 * sl), ((8 * sl) + 7)); for (sct = 0; sct < 8; sct++) { len += sprintf(page + len, " %02x", irb->ecw[8 * sl + sct]); } len += sprintf(page + len, "\n"); } if (irb->ecw[27] & DASD_SENSE_BIT_0) { /* 24 Byte Sense Data */ len += sprintf(page + len, KERN_ERR PRINTK_HEADER " 24 Byte: %x MSG %x, " "%s MSGb to SYSOP\n", irb->ecw[7] >> 4, irb->ecw[7] & 0x0f, irb->ecw[1] & 0x10 ? "" : "no"); } else { /* 32 Byte Sense Data */ len += sprintf(page + len, KERN_ERR PRINTK_HEADER " 32 Byte: Format: %x " "Exception class %x\n", irb->ecw[6] & 0x0f, irb->ecw[22] >> 4); } } else { len += sprintf(page + len, KERN_ERR PRINTK_HEADER " SORRY - NO VALID SENSE AVAILABLE\n"); } MESSAGE_LOG(KERN_ERR, "%s", page + sizeof(KERN_ERR PRINTK_HEADER)); /* dump the Channel Program */ /* print first CCWs (maximum 8) */ act = req->cpaddr; for (last = act; last->flags & (CCW_FLAG_CC | CCW_FLAG_DC); last++); end = min(act + 8, last); len = sprintf(page, KERN_ERR PRINTK_HEADER " Related CP in req: %p\n", req); while (act <= end) { len += sprintf(page + len, KERN_ERR PRINTK_HEADER " CCW %p: %08X %08X DAT:", act, ((int *) act)[0], ((int *) act)[1]); for (count = 0; count < 32 && count < act->count; count += sizeof(int)) len += sprintf(page + len, " %08X", ((int *) (addr_t) act->cda) [(count>>2)]); len += sprintf(page + len, "\n"); act++; } MESSAGE_LOG(KERN_ERR, "%s", page + sizeof(KERN_ERR PRINTK_HEADER)); /* print failing CCW area */ len = 0; if (act < ((struct ccw1 *)(addr_t) irb->scsw.cpa) - 2) { act = ((struct ccw1 *)(addr_t) irb->scsw.cpa) - 2; len += sprintf(page + len, KERN_ERR PRINTK_HEADER "......\n"); } end = min((struct ccw1 *)(addr_t) irb->scsw.cpa + 2, last); while (act <= end) { len += sprintf(page + len, KERN_ERR PRINTK_HEADER " CCW %p: %08X %08X DAT:", act, ((int *) act)[0], ((int *) act)[1]); for (count = 0; count < 32 && count < act->count; count += sizeof(int)) len += sprintf(page + len, " %08X", ((int *) (addr_t) act->cda) [(count>>2)]); len += sprintf(page + len, "\n"); act++; } /* print last CCWs */ if (act < last - 2) { act = last - 2; len += sprintf(page + len, KERN_ERR PRINTK_HEADER "......\n"); } while (act <= last) { len += sprintf(page + len, KERN_ERR PRINTK_HEADER " CCW %p: %08X %08X DAT:", act, ((int *) act)[0], ((int *) act)[1]); for (count = 0; count < 32 && count < act->count; count += sizeof(int)) len += sprintf(page + len, " %08X", ((int *) (addr_t) act->cda) [(count>>2)]); len += sprintf(page + len, "\n"); act++; } if (len > 0) MESSAGE_LOG(KERN_ERR, "%s", page + sizeof(KERN_ERR PRINTK_HEADER)); free_page((unsigned long) page);}/* * max_blocks is dependent on the amount of storage that is available * in the static io buffer for each device. Currently each device has * 8192 bytes (=2 pages). For 64 bit one dasd_mchunkt_t structure has * 24 bytes, the struct dasd_ccw_req has 136 bytes and each block can use * up to 16 bytes (8 for the ccw and 8 for the idal pointer). In * addition we have one define extent ccw + 16 bytes of data and one * locate record ccw + 16 bytes of data. That makes: * (8192 - 24 - 136 - 8 - 16 - 8 - 16) / 16 = 499 blocks at maximum. * We want to fit two into the available memory so that we can immediately * start the next request if one finishes off. That makes 249.5 blocks * for one request. Give a little safety and the result is 240. */static struct dasd_discipline dasd_eckd_discipline = { .owner = THIS_MODULE, .name = "ECKD", .ebcname = "ECKD", .max_blocks = 240, .check_device = dasd_eckd_check_characteristics, .do_analysis = dasd_eckd_do_analysis, .fill_geometry = dasd_eckd_fill_geometry, .start_IO = dasd_start_IO, .term_IO = dasd_term_IO, .format_device = dasd_eckd_format_device, .examine_error = dasd_eckd_examine_error, .erp_action = dasd_eckd_erp_action, .erp_postaction = dasd_eckd_erp_postaction, .build_cp = dasd_eckd_build_cp, .free_cp = dasd_eckd_free_cp, .dump_sense = dasd_eckd_dump_sense, .fill_info = dasd_eckd_fill_info,};static int __initdasd_eckd_init(void){ int ret; dasd_ioctl_no_register(THIS_MODULE, BIODASDGATTR, dasd_eckd_get_attrib); dasd_ioctl_no_register(THIS_MODULE, BIODASDSATTR, dasd_eckd_set_attrib); dasd_ioctl_no_register(THIS_MODULE, BIODASDPSRD, dasd_eckd_performance); dasd_ioctl_no_register(THIS_MODULE, BIODASDRLSE, dasd_eckd_release); dasd_ioctl_no_register(THIS_MODULE, BIODASDRSRV, dasd_eckd_reserve); dasd_ioctl_no_register(THIS_MODULE, BIODASDSLCK, dasd_eckd_steal_lock); ASCEBC(dasd_eckd_discipline.ebcname, 4); ret = ccw_driver_register(&dasd_eckd_driver); if (ret) { dasd_ioctl_no_unregister(THIS_MODULE, BIODASDGATTR, dasd_eckd_get_attrib); dasd_ioctl_no_unregister(THIS_MODULE, BIODASDSATTR, dasd_eckd_set_attrib); dasd_ioctl_no_unregister(THIS_MODULE, BIODASDPSRD, dasd_eckd_performance); dasd_ioctl_no_unregister(THIS_MODULE, BIODASDRLSE, dasd_eckd_release); dasd_ioctl_no_unregister(THIS_MODULE, BIODASDRSRV, dasd_eckd_reserve); dasd_ioctl_no_unregister(THIS_MODULE, BIODASDSLCK, dasd_eckd_steal_lock); return ret; } dasd_generic_auto_online(&dasd_eckd_driver); return 0;}static void __exitdasd_eckd_cleanup(void){ ccw_driver_unregister(&dasd_eckd_driver); dasd_ioctl_no_unregister(THIS_MODULE, BIODASDGATTR, dasd_eckd_get_attrib); dasd_ioctl_no_unregister(THIS_MODULE, BIODASDSATTR, dasd_eckd_set_attrib); dasd_ioctl_no_unregister(THIS_MODULE, BIODASDPSRD, dasd_eckd_performance); dasd_ioctl_no_unregister(THIS_MODULE, BIODASDRLSE, dasd_eckd_release); dasd_ioctl_no_unregister(THIS_MODULE, BIODASDRSRV, dasd_eckd_reserve); dasd_ioctl_no_unregister(THIS_MODULE, BIODASDSLCK, dasd_eckd_steal_lock);}module_init(dasd_eckd_init);module_exit(dasd_eckd_cleanup);/* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically * adjust the settings for this buffer only. This must remain at the end * of the file. * --------------------------------------------------------------------------- * Local variables: * c-indent-level: 4 * c-brace-imaginary-offset: 0 * c-brace-offset: -4 * c-argdecl-indent: 4 * c-label-offset: -4 * c-continued-statement-offset: 4 * c-continued-brace-offset: 0 * indent-tabs-mode: 1 * tab-width: 8 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -