dasd_diag.c
来自「linux-2.4.29操作系统的源码」· C语言 代码 · 共 624 行 · 第 1/2 页
C
624 行
/* * File...........: linux/drivers/s390/block/dasd_diag.c * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> * Based on.......: linux/drivers/s390/block/mdisk.c * ...............: by Hartmunt Penner <hpenner@de.ibm.com> * Bugreports.to..: <Linux390@de.ibm.com> * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * * $Revision: 1.49 $ * * History of changes * 07/13/00 Added fixup sections for diagnoses ans saved some registers * 07/14/00 fixed constraints in newly generated inline asm * 10/05/00 adapted to 'new' DASD driver * fixed return codes of dia250() * fixed partition handling and HDIO_GETGEO * 10/01/02 fixed Bugzilla 1341 */#include <linux/config.h>#include <linux/stddef.h>#include <linux/kernel.h>#include <asm/debug.h>#include <linux/slab.h>#include <linux/hdreg.h>#include <linux/blk.h>#include <asm/ccwcache.h>#include <asm/dasd.h>#include <asm/ebcdic.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/s390dyn.h>#include <asm/s390_ext.h>#include "dasd_int.h"#include "dasd_diag.h"#ifdef PRINTK_HEADER#undef PRINTK_HEADER#endif /* PRINTK_HEADER */#define PRINTK_HEADER DASD_NAME"(diag):"#ifdef MODULE#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,12))MODULE_LICENSE("GPL");#endif#endifdasd_discipline_t dasd_diag_discipline;typedef struct dasd_diag_private_t { diag210_t rdc_data; diag_rw_io_t iob; diag_init_io_t iib; unsigned long *label;} dasd_diag_private_t;static __inline__ intdia250 (void *iob, int cmd){ unsigned long addr; int rc; addr = __pa(iob); __asm__ __volatile__ (" lhi %0,11\n" " lr 0,%2\n" " diag 0,%1,0x250\n" "0: ipm %0\n" " srl %0,28\n" " or %0,1\n" "1:\n"#ifndef CONFIG_ARCH_S390X ".section __ex_table,\"a\"\n" " .align 4\n" " .long 0b,1b\n" ".previous\n"#else ".section __ex_table,\"a\"\n" " .align 8\n" " .quad 0b,1b\n" ".previous\n"#endif : "=&d" (rc) : "d" (cmd), "d" (addr) : "0", "1", "cc"); return rc;}static __inline__ intmdsk_init_io (dasd_device_t * device, int blocksize, int offset, int size){ dasd_diag_private_t *private = (dasd_diag_private_t *) device->private; diag_init_io_t *iib = &private->iib; int rc; memset (iib, 0, sizeof (diag_init_io_t)); iib->dev_nr = device->devinfo.devno; iib->block_size = blocksize; iib->offset = offset; iib->start_block = 0; iib->end_block = size; rc = dia250 (iib, INIT_BIO); return rc & 3;}static __inline__ intmdsk_term_io (dasd_device_t * device){ dasd_diag_private_t *private = (dasd_diag_private_t *) device->private; diag_init_io_t *iib = &private->iib; int rc; memset (iib, 0, sizeof (diag_init_io_t)); iib->dev_nr = device->devinfo.devno; rc = dia250 (iib, TERM_BIO); return rc & 3;}intdasd_start_diag (ccw_req_t * cqr){ int rc; dasd_device_t *device = cqr->device; dasd_diag_private_t *private; diag_rw_io_t *iob; private = (dasd_diag_private_t *) device->private; iob = &private->iob; iob->dev_nr = device->devinfo.devno; iob->key = 0; iob->flags = 2; iob->block_count = cqr->cplength >> 1; iob->interrupt_params = (u32)(addr_t) cqr; iob->bio_list = __pa (cqr->cpaddr); cqr->startclk = get_clock (); rc = dia250 (iob, RW_BIO); if (rc > 8) { MESSAGE (KERN_WARNING, "dia250 returned CC %d", rc); check_then_set (&cqr->status, CQR_STATUS_QUEUED, CQR_STATUS_ERROR); } else if (rc == 0) { check_then_set (&cqr->status, CQR_STATUS_QUEUED, CQR_STATUS_DONE); dasd_schedule_bh (device); } else { check_then_set (&cqr->status, CQR_STATUS_QUEUED, CQR_STATUS_IN_IO); rc = 0; } return rc;}voiddasd_ext_handler (struct pt_regs *regs, __u16 code){ int cpu = smp_processor_id(); ccw_req_t *cqr; int ip = S390_lowcore.ext_params; char status = *((char *) &S390_lowcore.ext_params + 5); dasd_device_t *device; int done_fast_io = 0; int devno; unsigned long flags; int subcode; /* * Get the external interruption subcode. VM stores * this in the 'cpu address' field associated with * the external interrupt. For diag 250 the subcode * needs to be 3. */ subcode = S390_lowcore.cpu_addr; if ((subcode & 0xff00) != 0x0300) return; irq_enter(cpu, -1); if (!ip) { /* no intparm: unsolicited interrupt */ MESSAGE (KERN_DEBUG, "%s", "caught unsolicited interrupt"); irq_exit(cpu, -1); return; } if (ip & 0x80000001) { MESSAGE (KERN_DEBUG, "caught spurious interrupt with parm %08x", ip); irq_exit(cpu, -1); return; } cqr = (ccw_req_t *)(addr_t) ip; device = (dasd_device_t *) cqr->device; devno = device->devinfo.devno; if (device == NULL) { DEV_MESSAGE (KERN_WARNING, device, "%s", " belongs to NULL device"); } if (strncmp (device->discipline->ebcname, (char *) &cqr->magic, 4)) { DEV_MESSAGE (KERN_WARNING, device, " magic number of ccw_req_t 0x%08X doesn't match" " discipline 0x%08X", cqr->magic, *(int *) (&device->discipline->name)); irq_exit(cpu, -1); return; } /* get irq lock to modify request queue */ s390irq_spin_lock_irqsave (device->devinfo.irq, flags); cqr->stopclk = get_clock (); switch (status) { case 0x00: check_then_set (&cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_DONE); if (cqr->next && (cqr->next->status == CQR_STATUS_QUEUED)) { if (dasd_start_diag (cqr->next) == 0) { done_fast_io = 1; } } break; case 0x01: case 0x02: case 0x03: default: check_then_set (&cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_FAILED); break; } s390irq_spin_unlock_irqrestore (device->devinfo.irq, flags); wake_up (&device->wait_q); dasd_schedule_bh (device); irq_exit(cpu, -1);}static intdasd_diag_check_characteristics (struct dasd_device_t *device){ int rc = 0; int bsize; dasd_diag_private_t *private; diag210_t *rdc_data; ccw_req_t *cqr; unsigned long *label; int sb; if (device == NULL) { MESSAGE (KERN_WARNING, "%s", "Null device pointer passed to characteristics " "checker"); return -ENODEV; } label = NULL; device->private = kmalloc (sizeof (dasd_diag_private_t), GFP_KERNEL); if (device->private == NULL) { MESSAGE (KERN_WARNING, "%s", "memory allocation failed for private data"); rc = -ENOMEM; goto fail; } private = (dasd_diag_private_t *) device->private; memset (private, 0, sizeof(dasd_diag_private_t)); rdc_data = (void *) &(private->rdc_data); rdc_data->vrdcdvno = device->devinfo.devno; rdc_data->vrdclen = sizeof (diag210_t); rc = diag210 (rdc_data); if ( rc != 0) { goto fail; } if (rdc_data->vrdcvcla != DEV_CLASS_FBA && rdc_data->vrdcvcla != DEV_CLASS_ECKD && rdc_data->vrdcvcla != DEV_CLASS_CKD) { rc = -ENOTSUPP; goto fail; }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?