OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [s390/] [block/] [dasd_diag.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * File...........: linux/drivers/s390/block/dasd_diag.c
3
 * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
4
 * Based on.......: linux/drivers/s390/block/mdisk.c
5
 * ...............: by Hartmunt Penner <hpenner@de.ibm.com>
6
 * Bugreports.to..: <Linux390@de.ibm.com>
7
 * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
8
 *
9
 * $Revision: 1.1.1.1 $
10
 *
11
 * History of changes
12
 * 07/13/00 Added fixup sections for diagnoses ans saved some registers
13
 * 07/14/00 fixed constraints in newly generated inline asm
14
 * 10/05/00 adapted to 'new' DASD driver
15
 *          fixed return codes of dia250()
16
 *          fixed partition handling and HDIO_GETGEO
17
 * 10/01/02 fixed Bugzilla 1341
18
 */
19
 
20
#include <linux/config.h>
21
#include <linux/stddef.h>
22
#include <linux/kernel.h>
23
#include <asm/debug.h>
24
 
25
#include <linux/slab.h>
26
#include <linux/hdreg.h>
27
#include <linux/blk.h>
28
#include <asm/ccwcache.h>
29
#include <asm/dasd.h>
30
 
31
#include <asm/ebcdic.h>
32
#include <asm/io.h>
33
#include <asm/irq.h>
34
#include <asm/s390dyn.h>
35
#include <asm/s390_ext.h>
36
 
37
#include "dasd_int.h"
38
#include "dasd_diag.h"
39
 
40
#ifdef PRINTK_HEADER
41
#undef PRINTK_HEADER
42
#endif                          /* PRINTK_HEADER */
43
#define PRINTK_HEADER DASD_NAME"(diag):"
44
 
45
#ifdef MODULE
46
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,12))
47
MODULE_LICENSE("GPL");
48
#endif
49
#endif
50
 
51
dasd_discipline_t dasd_diag_discipline;
52
 
53
typedef struct
54
    dasd_diag_private_t {
55
        diag210_t rdc_data;
56
        diag_rw_io_t iob;
57
        diag_init_io_t iib;
58
        unsigned long *label;
59
} dasd_diag_private_t;
60
 
61
static __inline__ int
62
dia250 (void *iob, int cmd)
63
{
64
        unsigned long addr;
65
        int rc;
66
 
67
        addr = __pa(iob);
68
        __asm__ __volatile__ ("    lhi   %0,11\n"
69
                              "    lr    0,%2\n"
70
                              "    diag  0,%1,0x250\n"
71
                              "0:  ipm   %0\n"
72
                              "    srl   %0,28\n"
73
                              "    or    %0,1\n"
74
                              "1:\n"
75
#ifndef CONFIG_ARCH_S390X
76
                              ".section __ex_table,\"a\"\n"
77
                              "    .align 4\n"
78
                              "    .long 0b,1b\n"
79
                              ".previous\n"
80
#else
81
                              ".section __ex_table,\"a\"\n"
82
                              "    .align 8\n"
83
                              "    .quad  0b,1b\n"
84
                              ".previous\n"
85
#endif
86
                              : "=&d" (rc)
87
                              : "d" (cmd), "d" (addr) : "0", "1", "cc");
88
        return rc;
89
}
90
 
91
static __inline__ int
92
mdsk_init_io (dasd_device_t * device, int blocksize, int offset, int size)
93
{
94
        dasd_diag_private_t *private = (dasd_diag_private_t *) device->private;
95
        diag_init_io_t *iib = &private->iib;
96
        int rc;
97
 
98
        memset (iib, 0, sizeof (diag_init_io_t));
99
 
100
        iib->dev_nr = device->devinfo.devno;
101
        iib->block_size = blocksize;
102
        iib->offset = offset;
103
        iib->start_block = 0;
104
        iib->end_block = size;
105
 
106
        rc = dia250 (iib, INIT_BIO);
107
 
108
        return rc & 3;
109
}
110
 
111
static __inline__ int
112
mdsk_term_io (dasd_device_t * device)
113
{
114
        dasd_diag_private_t *private = (dasd_diag_private_t *) device->private;
115
        diag_init_io_t *iib = &private->iib;
116
        int rc;
117
 
118
        memset (iib, 0, sizeof (diag_init_io_t));
119
        iib->dev_nr = device->devinfo.devno;
120
        rc = dia250 (iib, TERM_BIO);
121
        return rc & 3;
122
}
123
 
124
int
125
dasd_start_diag (ccw_req_t * cqr)
126
{
127
        int rc;
128
        dasd_device_t *device = cqr->device;
129
        dasd_diag_private_t *private;
130
        diag_rw_io_t *iob;
131
 
132
        private = (dasd_diag_private_t *) device->private;
133
        iob = &private->iob;
134
 
135
        iob->dev_nr = device->devinfo.devno;
136
        iob->key = 0;
137
        iob->flags = 2;
138
        iob->block_count = cqr->cplength >> 1;
139
        iob->interrupt_params = (u32)(addr_t) cqr;
140
        iob->bio_list = __pa (cqr->cpaddr);
141
 
142
        cqr->startclk = get_clock ();
143
 
144
        rc = dia250 (iob, RW_BIO);
145
        if (rc > 8) {
146
 
147
                MESSAGE (KERN_WARNING,
148
                         "dia250 returned CC %d",
149
                         rc);
150
 
151
                check_then_set (&cqr->status,
152
                                CQR_STATUS_QUEUED, CQR_STATUS_ERROR);
153
        } else if (rc == 0) {
154
                check_then_set (&cqr->status,
155
                                CQR_STATUS_QUEUED, CQR_STATUS_DONE);
156
                dasd_schedule_bh (device);
157
        } else {
158
                check_then_set (&cqr->status,
159
                                CQR_STATUS_QUEUED, CQR_STATUS_IN_IO);
160
                rc = 0;
161
        }
162
        return rc;
163
}
164
 
165
void
166
dasd_ext_handler (struct pt_regs *regs, __u16 code)
167
{
168
        int cpu = smp_processor_id();
169
        ccw_req_t *cqr;
170
        int ip = S390_lowcore.ext_params;
171
        char status = *((char *) &S390_lowcore.ext_params + 5);
172
        dasd_device_t *device;
173
        int done_fast_io = 0;
174
        int devno;
175
        unsigned long flags;
176
        int subcode;
177
 
178
        /*
179
         * Get the external interruption subcode. VM stores
180
         * this in the 'cpu address' field associated with
181
         * the external interrupt. For diag 250 the subcode
182
         * needs to be 3.
183
         */
184
        subcode = S390_lowcore.cpu_addr;
185
        if ((subcode & 0xff00) != 0x0300)
186
                return;
187
 
188
        irq_enter(cpu, -1);
189
 
190
        if (!ip) {              /* no intparm: unsolicited interrupt */
191
 
192
                MESSAGE (KERN_DEBUG, "%s",
193
                         "caught unsolicited interrupt");
194
 
195
                irq_exit(cpu, -1);
196
                return;
197
        }
198
        if (ip & 0x80000001) {
199
 
200
                MESSAGE (KERN_DEBUG,
201
                         "caught spurious interrupt with parm %08x",
202
                         ip);
203
 
204
                irq_exit(cpu, -1);
205
                return;
206
        }
207
        cqr = (ccw_req_t *)(addr_t) ip;
208
        device = (dasd_device_t *) cqr->device;
209
 
210
        devno = device->devinfo.devno;
211
 
212
        if (device == NULL) {
213
 
214
                DEV_MESSAGE (KERN_WARNING, device, "%s",
215
                             " belongs to NULL device");
216
        }
217
 
218
        if (strncmp (device->discipline->ebcname, (char *) &cqr->magic, 4)) {
219
 
220
                DEV_MESSAGE (KERN_WARNING, device,
221
                             " magic number of ccw_req_t 0x%08X doesn't match"
222
                             " discipline 0x%08X",
223
                             cqr->magic,
224
                             *(int *) (&device->discipline->name));
225
 
226
                irq_exit(cpu, -1);
227
                return;
228
        }
229
 
230
        /* get irq lock to modify request queue */
231
        s390irq_spin_lock_irqsave (device->devinfo.irq,
232
                                   flags);
233
 
234
        cqr->stopclk = get_clock ();
235
 
236
        switch (status) {
237
        case 0x00:
238
                check_then_set (&cqr->status,
239
                                CQR_STATUS_IN_IO, CQR_STATUS_DONE);
240
                if (cqr->next && (cqr->next->status == CQR_STATUS_QUEUED)) {
241
                        if (dasd_start_diag (cqr->next) == 0) {
242
                                done_fast_io = 1;
243
                        }
244
                }
245
                break;
246
        case 0x01:
247
        case 0x02:
248
        case 0x03:
249
        default:
250
                check_then_set (&cqr->status,
251
                                CQR_STATUS_IN_IO, CQR_STATUS_FAILED);
252
                break;
253
        }
254
 
255
        s390irq_spin_unlock_irqrestore (device->devinfo.irq,
256
                                        flags);
257
 
258
        wake_up (&device->wait_q);
259
        dasd_schedule_bh (device);
260
        irq_exit(cpu, -1);
261
 
262
}
263
 
264
static int
265
dasd_diag_check_characteristics (struct dasd_device_t *device)
266
{
267
        int rc = 0;
268
        int bsize;
269
        dasd_diag_private_t *private;
270
        diag210_t *rdc_data;
271
        ccw_req_t *cqr;
272
        unsigned long *label;
273
        int sb;
274
 
275
        if (device == NULL) {
276
 
277
                MESSAGE (KERN_WARNING, "%s",
278
                         "Null device pointer passed to characteristics "
279
                         "checker");
280
 
281
                return -ENODEV;
282
        }
283
 
284
        label = NULL;
285
        device->private = kmalloc (sizeof (dasd_diag_private_t), GFP_KERNEL);
286
 
287
        if (device->private == NULL) {
288
 
289
                MESSAGE (KERN_WARNING, "%s",
290
                         "memory allocation failed for private data");
291
 
292
                rc = -ENOMEM;
293
                goto fail;
294
        }
295
        private = (dasd_diag_private_t *) device->private;
296
        memset (private, 0, sizeof(dasd_diag_private_t));
297
        rdc_data = (void *) &(private->rdc_data);
298
 
299
        rdc_data->vrdcdvno = device->devinfo.devno;
300
        rdc_data->vrdclen = sizeof (diag210_t);
301
 
302
        rc = diag210 (rdc_data);
303
        if ( rc != 0) {
304
                goto fail;
305
        }
306
        if (rdc_data->vrdcvcla != DEV_CLASS_FBA &&
307
            rdc_data->vrdcvcla != DEV_CLASS_ECKD &&
308
            rdc_data->vrdcvcla != DEV_CLASS_CKD) {
309
                rc = -ENOTSUPP;
310
                goto fail;
311
        }
312
 
313
        DBF_EVENT (DBF_INFO,
314
                   "%04X: %04X on real %04X/%02X",
315
                   rdc_data->vrdcdvno,
316
                   rdc_data->vrdcvtyp,
317
                   rdc_data->vrdccrty,
318
                   rdc_data->vrdccrmd);
319
 
320
 
321
        /* Figure out position of label block */
322
        if (private->rdc_data.vrdcvcla == DEV_CLASS_FBA) {
323
                device->sizes.pt_block = 1;
324
        } else if (private->rdc_data.vrdcvcla == DEV_CLASS_ECKD ||
325
                   private->rdc_data.vrdcvcla == DEV_CLASS_CKD) {
326
                device->sizes.pt_block = 2;
327
        } else {
328
                BUG();
329
        }
330
        label = (unsigned long *) get_free_page (GFP_KERNEL);
331
        if (!label) {
332
                MESSAGE (KERN_WARNING, "%s",
333
                         "No memory to allocate label struct");
334
                rc = -ENOMEM;
335
                goto fail;
336
        }
337
        mdsk_term_io (device);  /* first terminate all outstanding operations */
338
        /* figure out blocksize of device */
339
        for (bsize = 512; bsize <= PAGE_SIZE; bsize <<= 1) {
340
                diag_bio_t *bio;
341
                diag_rw_io_t *iob = &private->iob;
342
 
343
                rc = mdsk_init_io (device, bsize, 0, 64);
344
                if (rc > 4) {
345
                        continue;
346
                }
347
                cqr = dasd_alloc_request (dasd_diag_discipline.name,
348
                                         sizeof (diag_bio_t) / sizeof (ccw1_t),
349
                                         0, device);
350
 
351
                if (cqr == NULL) {
352
 
353
                        MESSAGE (KERN_WARNING, "%s",
354
                                 "No memory to allocate initialization request");
355
 
356
                        rc = -ENOMEM;
357
                        goto fail;
358
                }
359
                bio = (diag_bio_t *) (cqr->cpaddr);
360
                memset (bio, 0, sizeof (diag_bio_t));
361
                bio->type = MDSK_READ_REQ;
362
                bio->block_number = device->sizes.pt_block + 1;
363
                bio->buffer = __pa (label);
364
                cqr->device = device;
365
                cqr->status = CQR_STATUS_FILLED;
366
                memset (iob, 0, sizeof (diag_rw_io_t));
367
                iob->dev_nr = rdc_data->vrdcdvno;
368
                iob->block_count = 1;
369
                iob->interrupt_params = (u32)(addr_t) cqr;
370
                iob->bio_list = __pa (bio);
371
                rc = dia250 (iob, RW_BIO);
372
                dasd_free_request(cqr, device);
373
                if (rc == 0) {
374
                        if (label[3] != bsize ||
375
                            label[0] != 0xc3d4e2f1 ||    /* != CMS1 */
376
                            label[13] == 0 ){
377
                                rc = -EMEDIUMTYPE;
378
                                goto fail;
379
                        }
380
                        break;
381
                }
382
                mdsk_term_io (device);
383
        }
384
        if (bsize > PAGE_SIZE) {
385
                rc = -EMEDIUMTYPE;
386
                goto fail;
387
        }
388
        device->sizes.blocks = label[7];
389
        device->sizes.bp_block = bsize;
390
        device->sizes.s2b_shift = 0;     /* bits to shift 512 to get a block */
391
 
392
        for (sb = 512; sb < bsize; sb = sb << 1)
393
 
394
                device->sizes.s2b_shift++;
395
 
396
        DEV_MESSAGE (KERN_INFO, device,
397
                     "capacity (%dkB blks): %ldkB",
398
                     (device->sizes.bp_block >> 10),
399
                     (device->sizes.blocks << device->sizes.s2b_shift) >> 1);
400
 
401
        rc = 0;
402
        goto out;
403
 fail:
404
        if (device->private) {
405
                kfree (device->private);
406
                device->private = NULL;
407
        }
408
 out:
409
        if (label) {
410
                free_page ((unsigned long) label);
411
        }
412
        return rc;
413
}
414
 
415
static int
416
dasd_diag_fill_geometry (struct dasd_device_t *device, struct hd_geometry *geo)
417
{
418
        int rc = 0;
419
        unsigned long sectors = device->sizes.blocks << device->sizes.s2b_shift;
420
        unsigned long tracks = sectors >> 6;
421
        unsigned long cyls = tracks >> 4;
422
 
423
        switch (device->sizes.bp_block) {
424
        case 512:
425
        case 1024:
426
        case 2048:
427
        case 4096:
428
                break;
429
        default:
430
                return -EINVAL;
431
        }
432
        geo->cylinders = cyls;
433
        geo->heads = 16;
434
        geo->sectors = 128 >> device->sizes.s2b_shift;
435
        return rc;
436
}
437
 
438
static dasd_era_t
439
dasd_diag_examine_error (ccw_req_t * cqr, devstat_t * stat)
440
{
441
        return dasd_era_fatal;
442
}
443
 
444
static ccw_req_t *
445
dasd_diag_build_cp_from_req (dasd_device_t * device, struct request *req)
446
{
447
        ccw_req_t *rw_cp = NULL;
448
        struct buffer_head *bh;
449
        int rw_cmd;
450
        int noblk = req->nr_sectors >> device->sizes.s2b_shift;
451
        int byt_per_blk = device->sizes.bp_block;
452
        int block;
453
        diag_bio_t *bio;
454
        int bhct;
455
        long size;
456
        unsigned long reloc_sector = req->sector +
457
                device->major_info->gendisk.part[MINOR (req->rq_dev)].start_sect;
458
 
459
        if (!noblk) {
460
 
461
                MESSAGE (KERN_ERR, "%s",
462
                         "No blocks to read/write...returning");
463
 
464
                return ERR_PTR(-EINVAL);
465
        }
466
        if (req->cmd == READ) {
467
                rw_cmd = MDSK_READ_REQ;
468
        } else {
469
                rw_cmd = MDSK_WRITE_REQ;
470
        }
471
        bhct = 0;
472
        for (bh = req->bh; bh; bh = bh->b_reqnext) {
473
                if (bh->b_size < byt_per_blk)
474
                        BUG();
475
                bhct += bh->b_size >> (device->sizes.s2b_shift+9);
476
        }
477
        /* Build the request */
478
        rw_cp = dasd_alloc_request (dasd_diag_discipline.name, bhct << 1, 0, device);
479
        if (!rw_cp) {
480
                return  ERR_PTR(-ENOMEM);
481
        }
482
        bio = (diag_bio_t *) (rw_cp->cpaddr);
483
 
484
        block = reloc_sector >> device->sizes.s2b_shift;
485
        for (bh = req->bh; bh; bh = bh->b_reqnext) {
486
                memset (bio, 0, sizeof (diag_bio_t));
487
                for (size = 0; size < bh->b_size; size += byt_per_blk) {
488
                        bio->type = rw_cmd;
489
                        bio->block_number = block + 1;
490
                        bio->buffer = __pa (bh->b_data + size);
491
                        bio++;
492
                        block++;
493
                }
494
        }
495
 
496
        rw_cp->buildclk = get_clock ();
497
 
498
        rw_cp->device = device;
499
        rw_cp->expires = 50 * TOD_SEC;  /* 50 seconds */
500
        rw_cp->req = req;
501
        check_then_set (&rw_cp->status, CQR_STATUS_EMPTY, CQR_STATUS_FILLED);
502
        return rw_cp;
503
}
504
 
505
static int
506
dasd_diag_fill_info (dasd_device_t * device, dasd_information2_t * info)
507
{
508
        int rc = 0;
509
        info->FBA_layout = 1;
510
        info->format = DASD_FORMAT_LDL;
511
        info->characteristics_size = sizeof (diag210_t);
512
        memcpy (info->characteristics,
513
                &((dasd_diag_private_t *) device->private)->rdc_data,
514
                sizeof (diag210_t));
515
        info->confdata_size = 0;
516
        return rc;
517
}
518
 
519
 
520
/*
521
 * max_blocks: We want to fit one CP into one page of memory so that we can
522
 * effectively use available resources.
523
 * The ccw_req_t has less than 256 bytes (including safety)
524
 * and diag_bio_t for each block has 16 bytes.
525
 * That makes:
526
 * (4096 - 256) / 16 = 240 blocks at maximum.
527
 */
528
dasd_discipline_t dasd_diag_discipline = {
529
        owner: THIS_MODULE,
530
        name:"DIAG",
531
        ebcname:"DIAG",
532
        max_blocks:240,
533
        check_characteristics:dasd_diag_check_characteristics,
534
        fill_geometry:dasd_diag_fill_geometry,
535
        start_IO:dasd_start_diag,
536
        examine_error:dasd_diag_examine_error,
537
        build_cp_from_req:dasd_diag_build_cp_from_req,
538
        int_handler:(void *) dasd_ext_handler,
539
        fill_info:dasd_diag_fill_info,
540
        list:LIST_HEAD_INIT(dasd_diag_discipline.list),
541
};
542
 
543
int
544
dasd_diag_init (void)
545
{
546
        int rc = 0;
547
 
548
        if (MACHINE_IS_VM) {
549
 
550
                MESSAGE (KERN_INFO,
551
                         "%s discipline initializing",
552
                         dasd_diag_discipline.name);
553
 
554
                ASCEBC (dasd_diag_discipline.ebcname, 4);
555
                ctl_set_bit (0, 9);
556
                register_external_interrupt (0x2603, dasd_ext_handler);
557
                dasd_discipline_add (&dasd_diag_discipline);
558
        } else {
559
 
560
                MESSAGE (KERN_INFO,
561
                        "Machine is not VM: %s discipline not initializing",
562
                         dasd_diag_discipline.name);
563
 
564
                rc = -EINVAL;
565
        }
566
        return rc;
567
}
568
 
569
void
570
dasd_diag_cleanup (void)
571
{
572
        if (MACHINE_IS_VM) {
573
 
574
                MESSAGE (KERN_INFO,
575
                         "%s discipline cleaning up",
576
                         dasd_diag_discipline.name);
577
 
578
                dasd_discipline_del (&dasd_diag_discipline);
579
                unregister_external_interrupt (0x2603, dasd_ext_handler);
580
                ctl_clear_bit (0, 9);
581
        } else {
582
 
583
                MESSAGE (KERN_INFO,
584
                         "Machine is not VM: %s discipline not initializing",
585
                         dasd_diag_discipline.name);
586
        }
587
}
588
 
589
#ifdef MODULE
590
int
591
init_module (void)
592
{
593
        int rc = 0;
594
        rc = dasd_diag_init ();
595
        return rc;
596
}
597
 
598
void
599
cleanup_module (void)
600
{
601
        dasd_diag_cleanup ();
602
        return;
603
}
604
#endif
605
 
606
/*
607
 * Overrides for Emacs so that we follow Linus's tabbing style.
608
 * Emacs will notice this stuff at the end of the file and automatically
609
 * adjust the settings for this buffer only.  This must remain at the end
610
 * of the file.
611
 * ---------------------------------------------------------------------------
612
 * Local variables:
613
 * c-indent-level: 4
614
 * c-brace-imaginary-offset: 0
615
 * c-brace-offset: -4
616
 * c-argdecl-indent: 4
617
 * c-label-offset: -4
618
 * c-continued-statement-offset: 4
619
 * c-continued-brace-offset: 0
620
 * indent-tabs-mode: nil
621
 * tab-width: 8
622
 * End:
623
 */

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.