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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [s390/] [block/] [dasd_eckd.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_eckd.c
3
 * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
4
 *                  Horst Hummel <Horst.Hummel@de.ibm.com>
5
 *                  Carsten Otte <Cotte@de.ibm.com>
6
 * Bugreports.to..: <Linux390@de.ibm.com>
7
 * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
8
 *
9
 * $Revision $
10
 *
11
 * History of changes (starts July 2000)
12
 * 07/11/00 Enabled rotational position sensing
13
 * 07/14/00 Reorganized the format process for better ERP
14
 * 07/20/00 added experimental support for 2105 control unit (ESS)
15
 * 07/24/00 increased expiration time and added the missing zero
16
 * 08/07/00 added some bits to define_extent for ESS support
17
 * 09/20/00 added reserve and release ioctls
18
 * 10/04/00 changed RW-CCWS to R/W Key and Data
19
 * 10/10/00 reverted last change according to ESS exploitation
20
 * 10/10/00 now dequeuing init_cqr before freeing *ouch*
21
 * 26/10/00 fixed ITPM20144ASC (problems when accesing a device formatted by VIF)
22
 * 01/23/01 fixed kmalloc statement in dump_sense to be GFP_ATOMIC
23
 *          fixed partition handling and HDIO_GETGEO
24
 */
25
 
26
#include <linux/config.h>
27
#include <linux/stddef.h>
28
#include <linux/kernel.h>
29
#include <linux/slab.h>
30
#include <linux/hdreg.h>        /* HDIO_GETGEO                      */
31
#include <linux/blk.h>
32
 
33
#include <asm/debug.h>
34
#include <asm/ccwcache.h>
35
#include <asm/idals.h>
36
#include <asm/ebcdic.h>
37
#include <asm/io.h>
38
#include <asm/irq.h>
39
#include <asm/s390dyn.h>
40
 
41
#include "dasd_int.h"
42
#include "dasd_eckd.h"
43
 
44
#ifdef PRINTK_HEADER
45
#undef PRINTK_HEADER
46
#endif                          /* PRINTK_HEADER */
47
#define PRINTK_HEADER DASD_NAME"(eckd):"
48
 
49
#define ECKD_C0(i) (i->home_bytes)
50
#define ECKD_F(i) (i->formula)
51
#define ECKD_F1(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f1):(i->factors.f_0x02.f1))
52
#define ECKD_F2(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f2):(i->factors.f_0x02.f2))
53
#define ECKD_F3(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f3):(i->factors.f_0x02.f3))
54
#define ECKD_F4(i) (ECKD_F(i)==0x02?(i->factors.f_0x02.f4):0)
55
#define ECKD_F5(i) (ECKD_F(i)==0x02?(i->factors.f_0x02.f5):0)
56
#define ECKD_F6(i) (i->factor6)
57
#define ECKD_F7(i) (i->factor7)
58
#define ECKD_F8(i) (i->factor8)
59
 
60
#ifdef MODULE
61
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,12))
62
MODULE_LICENSE("GPL");
63
#endif
64
#endif
65
 
66
dasd_discipline_t dasd_eckd_discipline;
67
 
68
typedef struct dasd_eckd_private_t {
69
        dasd_eckd_characteristics_t rdc_data;
70
        dasd_eckd_confdata_t        conf_data;
71
        eckd_count_t                count_area[5];
72
        int                         uses_cdl;
73
        attrib_data_t               attrib;     /* e.g. cache operations */
74
} dasd_eckd_private_t;
75
 
76
#ifdef CONFIG_DASD_DYNAMIC
77
static
78
devreg_t dasd_eckd_known_devices[] = {
79
        {
80
                ci: { hc: {ctype:0x3880, dtype: 0x3390}},
81
                flag:(DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE |
82
                      DEVREG_TYPE_DEVCHARS),
83
                oper_func:dasd_oper_handler
84
        },
85
        {
86
                ci: { hc: {ctype:0x3990}},
87
                flag:(DEVREG_MATCH_CU_TYPE | DEVREG_TYPE_DEVCHARS),
88
                oper_func:dasd_oper_handler
89
        },
90
        {
91
                ci: { hc: {ctype:0x2105}},
92
                flag:(DEVREG_MATCH_CU_TYPE | DEVREG_TYPE_DEVCHARS),
93
                oper_func:dasd_oper_handler
94
        },
95
        {
96
                ci: { hc: {ctype:0x9343}},
97
                flag:(DEVREG_MATCH_CU_TYPE | DEVREG_TYPE_DEVCHARS),
98
                oper_func:dasd_oper_handler
99
        }
100
};
101
#endif
102
 
103
int sizes_trk0[] = { 28, 148, 84 };
104
#define LABEL_SIZE 140
105
 
106
static inline unsigned int
107
round_up_multiple (unsigned int no, unsigned int mult)
108
{
109
        int rem = no % mult;
110
        return (rem ? no - rem + mult : no);
111
}
112
 
113
static inline unsigned int
114
ceil_quot (unsigned int d1, unsigned int d2)
115
{
116
        return (d1 + (d2 - 1)) / d2;
117
}
118
 
119
static inline int
120
bytes_per_record (dasd_eckd_characteristics_t * rdc, int kl,    /* key length */
121
                  int dl /* data length */ )
122
{
123
        int bpr = 0;
124
        switch (rdc->formula) {
125
        case 0x01:{
126
                        unsigned int fl1, fl2;
127
                        fl1 = round_up_multiple (ECKD_F2 (rdc) + dl,
128
                                                 ECKD_F1 (rdc));
129
                        fl2 = round_up_multiple (kl ? ECKD_F2 (rdc) + kl : 0,
130
                                                 ECKD_F1 (rdc));
131
                        bpr = fl1 + fl2;
132
                        break;
133
                }
134
        case 0x02:{
135
                        unsigned int fl1, fl2, int1, int2;
136
                        int1 = ceil_quot (dl + ECKD_F6 (rdc),
137
                                          ECKD_F5 (rdc) << 1);
138
                        int2 = ceil_quot (kl + ECKD_F6 (rdc),
139
                                          ECKD_F5 (rdc) << 1);
140
                        fl1 = round_up_multiple (ECKD_F1 (rdc) *
141
                                                 ECKD_F2 (rdc) +
142
                                                 (dl + ECKD_F6 (rdc) +
143
                                                  ECKD_F4 (rdc) * int1),
144
                                                 ECKD_F1 (rdc));
145
                        fl2 = round_up_multiple (ECKD_F1 (rdc) *
146
                                                 ECKD_F3 (rdc) +
147
                                                 (kl + ECKD_F6 (rdc) +
148
                                                  ECKD_F4 (rdc) * int2),
149
                                                 ECKD_F1 (rdc));
150
                        bpr = fl1 + fl2;
151
                        break;
152
                }
153
        default:
154
 
155
                MESSAGE (KERN_ERR,
156
                         "unknown formula%d",
157
                         rdc->formula);
158
        }
159
        return bpr;
160
}
161
 
162
static inline unsigned int
163
bytes_per_track (dasd_eckd_characteristics_t * rdc)
164
{
165
        return *(unsigned int *) (rdc->byte_per_track) >> 8;
166
}
167
 
168
static inline unsigned int
169
recs_per_track (dasd_eckd_characteristics_t * rdc,
170
                unsigned int kl, unsigned int dl)
171
{
172
        int rpt = 0;
173
        int dn;
174
        switch (rdc->dev_type) {
175
        case 0x3380:
176
                if (kl)
177
                        return 1499 / (15 +
178
                                       7 + ceil_quot (kl + 12, 32) +
179
                                       ceil_quot (dl + 12, 32));
180
                else
181
                        return 1499 / (15 + ceil_quot (dl + 12, 32));
182
        case 0x3390:
183
                dn = ceil_quot (dl + 6, 232) + 1;
184
                if (kl) {
185
                        int kn = ceil_quot (kl + 6, 232) + 1;
186
                        return 1729 / (10 +
187
                                       9 + ceil_quot (kl + 6 * kn, 34) +
188
                                       9 + ceil_quot (dl + 6 * dn, 34));
189
                } else
190
                        return 1729 / (10 + 9 + ceil_quot (dl + 6 * dn, 34));
191
        case 0x9345:
192
                dn = ceil_quot (dl + 6, 232) + 1;
193
                if (kl) {
194
                        int kn = ceil_quot (kl + 6, 232) + 1;
195
                        return 1420 / (18 +
196
                                       7 + ceil_quot (kl + 6 * kn, 34) +
197
                                       ceil_quot (dl + 6 * dn, 34));
198
                } else
199
                        return 1420 / (18 + 7 + ceil_quot (dl + 6 * dn, 34));
200
        }
201
        return rpt;
202
}
203
 
204
static inline void
205
check_XRC (ccw1_t         *de_ccw,
206
           DE_eckd_data_t *data,
207
           dasd_device_t  *device)
208
{
209
 
210
        dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
211
 
212
        /* switch on System Time Stamp - needed for XRC Support */
213
        if (private->rdc_data.facilities.XRC_supported) {
214
 
215
                data->ga_extended |= 0x08;   /* switch on 'Time Stamp Valid'   */
216
                data->ga_extended |= 0x02;   /* switch on 'Extended Parameter' */
217
 
218
                data->ep_sys_time = get_clock ();
219
 
220
                de_ccw->count = sizeof (DE_eckd_data_t);
221
                de_ccw->flags |= CCW_FLAG_SLI;
222
        }
223
 
224
        return;
225
 
226
} /* end check_XRC */
227
 
228
static inline int
229
define_extent (ccw1_t * de_ccw,
230
               DE_eckd_data_t * data,
231
               int trk, int totrk,
232
               int cmd, dasd_device_t * device, ccw_req_t* cqr)
233
{
234
        int rc=0;
235
        ch_t geo, beg, end;
236
        dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
237
 
238
        geo.cyl = private->rdc_data.no_cyl;
239
        geo.head = private->rdc_data.trk_per_cyl;
240
        beg.cyl = trk / geo.head;
241
        beg.head = trk % geo.head;
242
        end.cyl = totrk / geo.head;
243
        end.head = totrk % geo.head;
244
 
245
        memset (de_ccw, 0, sizeof (ccw1_t));
246
 
247
        de_ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT;
248
        de_ccw->count = 16;
249
 
250
        if ((rc=dasd_set_normalized_cda (de_ccw, __pa (data), cqr, device)))
251
                return rc;
252
 
253
        memset (data, 0, sizeof (DE_eckd_data_t));
254
        switch (cmd) {
255
        case DASD_ECKD_CCW_READ_HOME_ADDRESS:
256
        case DASD_ECKD_CCW_READ_RECORD_ZERO:
257
        case DASD_ECKD_CCW_READ:
258
        case DASD_ECKD_CCW_READ_MT:
259
        case DASD_ECKD_CCW_READ_CKD:    /* Fallthrough */
260
        case DASD_ECKD_CCW_READ_CKD_MT:
261
        case DASD_ECKD_CCW_READ_KD:
262
        case DASD_ECKD_CCW_READ_KD_MT:
263
        case DASD_ECKD_CCW_READ_COUNT:
264
                data->mask.perm = 0x1;
265
                data->attributes.operation = private->attrib.operation;
266
                break;
267
        case DASD_ECKD_CCW_WRITE:
268
        case DASD_ECKD_CCW_WRITE_MT:
269
        case DASD_ECKD_CCW_WRITE_KD:
270
        case DASD_ECKD_CCW_WRITE_KD_MT:
271
                data->mask.perm = 0x02;
272
                data->attributes.operation = private->attrib.operation;
273
 
274
                check_XRC (de_ccw,
275
                           data,
276
                           device);
277
                break;
278
        case DASD_ECKD_CCW_WRITE_CKD:
279
        case DASD_ECKD_CCW_WRITE_CKD_MT:
280
                data->attributes.operation = DASD_BYPASS_CACHE;
281
 
282
                check_XRC (de_ccw,
283
                           data,
284
                           device);
285
                break;
286
        case DASD_ECKD_CCW_ERASE:
287
        case DASD_ECKD_CCW_WRITE_HOME_ADDRESS:
288
        case DASD_ECKD_CCW_WRITE_RECORD_ZERO:
289
                data->mask.perm = 0x3;
290
                data->mask.auth = 0x1;
291
                data->attributes.operation = DASD_BYPASS_CACHE;
292
 
293
                check_XRC (de_ccw,
294
                           data,
295
                           device);
296
                break;
297
        default:
298
 
299
                MESSAGE (KERN_ERR,
300
                         "unknown opcode 0x%x",
301
                         cmd);
302
 
303
                break;
304
        }
305
 
306
        data->attributes.mode = 0x3; /* ECKD */
307
 
308
        if (private->rdc_data.cu_type == 0x2105
309
            && !(private->uses_cdl && trk < 2) ) {
310
 
311
                data->ga_extended |= 0x40;
312
        }
313
 
314
        /* check for sequential prestage - enhance cylinder range */
315
        if (data->attributes.operation == DASD_SEQ_PRESTAGE ||
316
            data->attributes.operation == DASD_SEQ_ACCESS     ) {
317
 
318
                if (end.cyl + private->attrib.nr_cyl < geo.cyl) {
319
 
320
                        end.cyl +=  private->attrib.nr_cyl;
321
 
322
                        DBF_DEV_EVENT (DBF_NOTICE, device,
323
                                       "Enhanced DE Cylinder from  %x to %x",
324
                                       (totrk / geo.head),
325
                                       end.cyl);
326
 
327
 
328
                } else {
329
                        end.cyl = (geo.cyl -1);
330
 
331
                        DBF_DEV_EVENT (DBF_NOTICE, device,
332
                                       "Enhanced DE Cylinder from  %x to "
333
                                       "End of device %x",
334
                                       (totrk / geo.head),
335
                                       end.cyl);
336
 
337
                }
338
        }
339
 
340
        data->beg_ext.cyl  = beg.cyl;
341
        data->beg_ext.head = beg.head;
342
        data->end_ext.cyl  = end.cyl;
343
        data->end_ext.head = end.head;
344
 
345
        return rc;
346
}
347
 
348
static inline int
349
locate_record (ccw1_t * lo_ccw,
350
               LO_eckd_data_t * data,
351
               int trk,
352
               int rec_on_trk,
353
               int no_rec,
354
               int cmd,
355
               dasd_device_t * device,
356
               int reclen,
357
               ccw_req_t* cqr)
358
{
359
        int rc=0;
360
        dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
361
        ch_t geo = { private->rdc_data.no_cyl,
362
                private->rdc_data.trk_per_cyl
363
        };
364
        ch_t seek = { trk / (geo.head), trk % (geo.head) };
365
        int sector = 0;
366
 
367
        DBF_EVENT (DBF_INFO,
368
                   "Locate: trk %d, rec %d, no_rec %d, cmd %d, reclen %d",
369
                   trk,
370
                   rec_on_trk,
371
                   no_rec,
372
                   cmd,
373
                   reclen);
374
 
375
        memset (lo_ccw, 0, sizeof (ccw1_t));
376
        lo_ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD;
377
        lo_ccw->count = 16;
378
        if ((rc=dasd_set_normalized_cda (lo_ccw, __pa (data), cqr, device)))
379
                return rc;
380
 
381
        memset (data, 0, sizeof (LO_eckd_data_t));
382
        if (rec_on_trk) {
383
                switch (private->rdc_data.dev_type) {
384
                case 0x3390:{
385
                        int dn, d;
386
                        dn = ceil_quot (reclen + 6, 232);
387
                        d = 9 + ceil_quot (reclen + 6 * (dn + 1), 34);
388
                        sector = (49 + (rec_on_trk - 1) * (10 + d)) / 8;
389
                        break;
390
                }
391
                case 0x3380:{
392
                        int d;
393
                        d = 7 + ceil_quot (reclen + 12, 32);
394
                        sector = (39 + (rec_on_trk - 1) * (8 + d)) / 7;
395
                        break;
396
                }
397
                case 0x9345:
398
                default:
399
                        sector = 0;
400
                }
401
        }
402
        data->sector = sector;
403
        data->count = no_rec;
404
        switch (cmd) {
405
        case DASD_ECKD_CCW_WRITE_HOME_ADDRESS:
406
                data->operation.orientation = 0x3;
407
                data->operation.operation = 0x03;
408
                break;
409
        case DASD_ECKD_CCW_READ_HOME_ADDRESS:
410
                data->operation.orientation = 0x3;
411
                data->operation.operation = 0x16;
412
                break;
413
        case DASD_ECKD_CCW_WRITE_RECORD_ZERO:
414
                data->operation.orientation = 0x1;
415
                data->operation.operation = 0x03;
416
                data->count++;
417
                break;
418
        case DASD_ECKD_CCW_READ_RECORD_ZERO:
419
                data->operation.orientation = 0x3;
420
                data->operation.operation = 0x16;
421
                data->count++;
422
                break;
423
        case DASD_ECKD_CCW_WRITE:
424
        case DASD_ECKD_CCW_WRITE_MT:
425
        case DASD_ECKD_CCW_WRITE_KD:
426
        case DASD_ECKD_CCW_WRITE_KD_MT:
427
                data->auxiliary.last_bytes_used = 0x1;
428
                data->length = reclen;
429
                data->operation.operation = 0x01;
430
                break;
431
        case DASD_ECKD_CCW_WRITE_CKD:
432
        case DASD_ECKD_CCW_WRITE_CKD_MT:
433
                data->auxiliary.last_bytes_used = 0x1;
434
                data->length = reclen;
435
                data->operation.operation = 0x03;
436
                break;
437
        case DASD_ECKD_CCW_READ:
438
        case DASD_ECKD_CCW_READ_MT:
439
        case DASD_ECKD_CCW_READ_KD:
440
        case DASD_ECKD_CCW_READ_KD_MT:
441
                data->auxiliary.last_bytes_used = 0x1;
442
                data->length = reclen;
443
                data->operation.operation = 0x06;
444
                break;
445
        case DASD_ECKD_CCW_READ_CKD:
446
        case DASD_ECKD_CCW_READ_CKD_MT:
447
                data->auxiliary.last_bytes_used = 0x1;
448
                data->length = reclen;
449
                data->operation.operation = 0x16;
450
                break;
451
        case DASD_ECKD_CCW_READ_COUNT:
452
                data->operation.operation = 0x06;
453
                break;
454
        case DASD_ECKD_CCW_ERASE:
455
                data->length = reclen;
456
                data->auxiliary.last_bytes_used = 0x1;
457
                data->operation.operation = 0x0b;
458
                break;
459
        default:
460
 
461
                MESSAGE (KERN_ERR,
462
                         "unknown opcode 0x%x",
463
                         cmd);
464
        }
465
        memcpy (&(data->seek_addr), &seek, sizeof (ch_t));
466
        memcpy (&(data->search_arg), &seek, sizeof (ch_t));
467
        data->search_arg.record = rec_on_trk;
468
        return rc;
469
}
470
 
471
static int
472
dasd_eckd_id_check (s390_dev_info_t * info)
473
{
474
        if (info->sid_data.cu_type == 0x3990 ||
475
            info->sid_data.cu_type == 0x2105)
476
                    if (info->sid_data.dev_type == 0x3390) return 0;
477
        if (info->sid_data.cu_type == 0x3990 ||
478
            info->sid_data.cu_type == 0x2105)
479
                    if (info->sid_data.dev_type == 0x3380) return 0;
480
        if (info->sid_data.cu_type == 0x9343)
481
                if (info->sid_data.dev_type == 0x9345)
482
                        return 0;
483
        return -ENODEV;
484
}
485
 
486
static int
487
dasd_eckd_check_characteristics (struct dasd_device_t *device)
488
{
489
        int   rc = 0;
490
        void *conf_data;
491
        void *rdc_data;
492
        int   conf_len;
493
        dasd_eckd_private_t *private;
494
 
495
        if (device == NULL) {
496
 
497
                MESSAGE (KERN_WARNING, "%s",
498
                         "Null device pointer passed to characteristics "
499
                         "checker");
500
 
501
                return -ENODEV;
502
        }
503
        device->private = kmalloc (sizeof (dasd_eckd_private_t),
504
                                   GFP_KERNEL);
505
 
506
        if (device->private == NULL) {
507
 
508
                MESSAGE (KERN_WARNING, "%s",
509
                        "memory allocation failed for private data");
510
 
511
                rc = -ENOMEM;
512
                goto fail;
513
        }
514
 
515
        private  = (dasd_eckd_private_t *) device->private;
516
        rdc_data = (void *) &(private->rdc_data);
517
 
518
        /* Read Device Characteristics */
519
        rc = read_dev_chars (device->devinfo.irq,
520
                             &rdc_data,
521
                             64);
522
        if (rc) {
523
 
524
                MESSAGE (KERN_WARNING,
525
                        "Read device characteristics returned error %d",
526
                         rc);
527
 
528
                goto fail;
529
        }
530
 
531
        DEV_MESSAGE (KERN_INFO, device,
532
                     "%04X/%02X(CU:%04X/%02X) Cyl:%d Head:%d Sec:%d",
533
                     private->rdc_data.dev_type,
534
                     private->rdc_data.dev_model,
535
                     private->rdc_data.cu_type,
536
                     private->rdc_data.cu_model.model,
537
                     private->rdc_data.no_cyl,
538
                     private->rdc_data.trk_per_cyl,
539
                     private->rdc_data.sec_per_trk);
540
 
541
        /* set default cache operations */
542
        private->attrib.operation = DASD_NORMAL_CACHE;
543
        private->attrib.nr_cyl    = 0;
544
 
545
        /* Read Configuration Data */
546
        rc = read_conf_data (device->devinfo.irq,
547
                             &conf_data,
548
                             &conf_len,
549
                             LPM_ANYPATH);
550
 
551
        if (rc == -EOPNOTSUPP) {
552
                rc = 0; /* this one is ok */
553
        }
554
        if (rc) {
555
 
556
                MESSAGE (KERN_WARNING,
557
                         "Read configuration data returned error %d",
558
                         rc);
559
 
560
                goto fail;
561
        }
562
        if (conf_data == NULL) {
563
 
564
                MESSAGE (KERN_WARNING, "%s",
565
                         "No configuration data retrieved");
566
 
567
                goto out; /* no errror */
568
        }
569
        if (conf_len != sizeof (dasd_eckd_confdata_t)) {
570
 
571
                MESSAGE (KERN_WARNING,
572
                         "sizes of configuration data mismatch"
573
                         "%d (read) vs %ld (expected)",
574
                         conf_len,
575
                         sizeof (dasd_eckd_confdata_t));
576
 
577
                goto out; /* no errror */
578
        }
579
        memcpy (&private->conf_data, conf_data,
580
                sizeof (dasd_eckd_confdata_t));
581
 
582
        DEV_MESSAGE (KERN_INFO, device,
583
                "%04X/%02X(CU:%04X/%02X): Configuration data read",
584
                private->rdc_data.dev_type,
585
                private->rdc_data.dev_model,
586
                private->rdc_data.cu_type,
587
                private->rdc_data.cu_model.model);
588
        goto out;
589
 
590
 fail:
591
        if (device->private) {
592
                kfree (device->private);
593
                device->private = NULL;
594
        }
595
 
596
 out:
597
        return rc;
598
}
599
 
600
static inline int
601
dasd_eckd_cdl_reclen (dasd_device_t * device, int recid)
602
{
603
        dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
604
        int byt_per_blk = device->sizes.bp_block;
605
        int blk_per_trk = recs_per_track (&(private->rdc_data), 0, byt_per_blk);
606
        if (recid < 3)
607
                return sizes_trk0[recid];
608
        if (recid < blk_per_trk)
609
                return byt_per_blk;
610
        if (recid < 2 * blk_per_trk)
611
                return LABEL_SIZE;
612
        return byt_per_blk;
613
}
614
 
615
static ccw_req_t *
616
dasd_eckd_init_analysis (struct dasd_device_t *device)
617
{
618
        ccw_req_t *cqr = NULL;
619
        ccw1_t *ccw;
620
        DE_eckd_data_t *DE_data;
621
        LO_eckd_data_t *LO_data;
622
        dasd_eckd_private_t *private = (dasd_eckd_private_t *)device->private;
623
        eckd_count_t *count_data = private->count_area;
624
 
625
        cqr = dasd_alloc_request (dasd_eckd_discipline.name, 8 + 1,
626
                                 sizeof (DE_eckd_data_t) +
627
                                 2 * sizeof (LO_eckd_data_t),
628
                                 device);
629
        if (cqr == NULL) {
630
 
631
                MESSAGE (KERN_WARNING, "%s",
632
                        "No memory to allocate initialization request");
633
                goto out;
634
        }
635
        DE_data = cqr->data;
636
        LO_data = cqr->data + sizeof (DE_eckd_data_t);
637
        ccw = cqr->cpaddr;
638
        if (define_extent (ccw, DE_data, 0, 2, DASD_ECKD_CCW_READ_COUNT, device, cqr)) {
639
                goto clear_cqr;
640
        }
641
        ccw->flags |= CCW_FLAG_CC;
642
        ccw++;
643
        if (locate_record (ccw, LO_data++, 0, 0, 4, DASD_ECKD_CCW_READ_COUNT,
644
                           device, 0, cqr)) {
645
                goto clear_cqr;
646
        }
647
        ccw->flags |= CCW_FLAG_CC;
648
        ccw++;
649
        ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
650
        ccw->count = 8;
651
        if (dasd_set_normalized_cda (ccw, __pa (count_data++), cqr, device)) {
652
                goto clear_cqr;
653
        }
654
        ccw->flags |= CCW_FLAG_CC;
655
        ccw++;
656
        ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
657
        ccw->count = 8;
658
        if (dasd_set_normalized_cda (ccw, __pa (count_data++), cqr, device)) {
659
                goto clear_cqr;
660
        }
661
        ccw->flags |= CCW_FLAG_CC;
662
        ccw++;
663
        ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
664
        ccw->count = 8;
665
        if (dasd_set_normalized_cda (ccw, __pa (count_data++), cqr, device)) {
666
                goto clear_cqr;
667
        }
668
        ccw->flags |= CCW_FLAG_CC;
669
        ccw++;
670
        ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
671
        ccw->count = 8;
672
        if (dasd_set_normalized_cda (ccw, __pa (count_data++), cqr, device)) {
673
                goto clear_cqr;
674
        }
675
        ccw->flags |= CCW_FLAG_CC;
676
        ccw++;
677
        if (locate_record (ccw, LO_data++, 2, 0, 1, DASD_ECKD_CCW_READ_COUNT,
678
                           device, 0, cqr)) {
679
                goto clear_cqr;
680
        }
681
        ccw->flags |= CCW_FLAG_CC;
682
        ccw++;
683
        ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
684
        ccw->count = 8;
685
        if (dasd_set_normalized_cda (ccw, __pa (count_data), cqr, device)) {
686
                goto clear_cqr;
687
        }
688
        cqr->device = device;
689
        cqr->retries = 0;
690
        cqr->buildclk = get_clock ();
691
        cqr->status = CQR_STATUS_FILLED;
692
        dasd_chanq_enq (&device->queue, cqr);
693
        goto out;
694
 
695
 clear_cqr:
696
        dasd_free_request (cqr,device);
697
 
698
        MESSAGE (KERN_WARNING, "%s",
699
                "No memory to allocate initialization request");
700
 
701
        cqr=NULL;
702
 out:
703
        return cqr;
704
}
705
 
706
static int
707
dasd_eckd_do_analysis (struct dasd_device_t *device)
708
{
709
        int sb, rpt;
710
        dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
711
        eckd_count_t *count_area = NULL;
712
        char *cdl_msg;
713
        int status;
714
        int i;
715
 
716
        private->uses_cdl = 1;
717
        status = device->init_cqr->status;
718
        dasd_chanq_deq (&device->queue, device->init_cqr);
719
        dasd_free_request (device->init_cqr, device);
720
        /* Free the cqr and cleanup device->sizes */
721
        if ( status != CQR_STATUS_DONE ) {
722
 
723
                DEV_MESSAGE (KERN_WARNING, device, "%s",
724
                             "volume analysis returned unformatted disk");
725
 
726
                return -EMEDIUMTYPE;
727
        }
728
        /* Check Track 0 for Compatible Disk Layout */
729
        for (i = 0; i < 3; i++) {
730
                if ((i < 3) &&
731
                    ((private->count_area[i].kl != 4) ||
732
                     (private->count_area[i].dl !=
733
                      dasd_eckd_cdl_reclen (device, i) - 4))) {
734
                        private->uses_cdl = 0;
735
                        break;
736
                }
737
        }
738
        if (i == 3) {
739
                count_area = &private->count_area[4];
740
        }
741
        if (private->uses_cdl == 0) {
742
                for (i = 0; i < 5; i++) {
743
                        if ((private->count_area[i].kl != 0) ||
744
                            (private->count_area[i].dl !=
745
                             private->count_area[0].dl)) {
746
                                break;
747
                        }
748
                }
749
                if (i == 5) {
750
                        count_area = &private->count_area[0];
751
                }
752
        } else {
753
                if (private->count_area[3].record == 1) {
754
 
755
                        DEV_MESSAGE (KERN_WARNING, device, "%s",
756
                                     "Trk 0: no records after VTOC!");
757
                }
758
        }
759
        if (count_area != NULL &&       /* we found notthing violating our disk layout */
760
            count_area->kl == 0) {
761
                /* find out blocksize */
762
                switch (count_area->dl) {
763
                case 512:
764
                case 1024:
765
                case 2048:
766
                case 4096:
767
                        device->sizes.bp_block = count_area->dl;
768
                        break;
769
                }
770
        }
771
        if (device->sizes.bp_block == 0) {
772
 
773
                DEV_MESSAGE (KERN_WARNING, device, "%s",
774
                             "Volume has incompatible disk layout");
775
 
776
                return -EMEDIUMTYPE;
777
        }
778
        device->sizes.s2b_shift = 0;     /* bits to shift 512 to get a block */
779
        device->sizes.pt_block = 2;
780
        for (sb = 512; sb < device->sizes.bp_block; sb = sb << 1)
781
                device->sizes.s2b_shift++;
782
 
783
        rpt = recs_per_track (&private->rdc_data, 0, device->sizes.bp_block);
784
        device->sizes.blocks = (private->rdc_data.no_cyl *
785
                                private->rdc_data.trk_per_cyl *
786
                                recs_per_track (&private->rdc_data, 0,
787
                                                device->sizes.bp_block));
788
        cdl_msg =
789
            private->
790
            uses_cdl ? "compatible disk layout" : "linux disk layout";
791
 
792
        DEV_MESSAGE (KERN_INFO, device,
793
                     "(%dkB blks): %dkB at %dkB/trk %s",
794
                     (device->sizes.bp_block >> 10),
795
                     ((private->rdc_data.no_cyl *
796
                       private->rdc_data.trk_per_cyl *
797
                       recs_per_track (&private->rdc_data, 0,
798
                                       device->sizes.bp_block) *
799
                       (device->sizes.bp_block >> 9)) >> 1),
800
                     ((recs_per_track (&private->rdc_data, 0,
801
                                       device->sizes.bp_block) *
802
                       device->sizes.bp_block) >> 10),
803
                     cdl_msg);
804
 
805
        return 0;
806
}
807
 
808
static int
809
dasd_eckd_fill_geometry (struct dasd_device_t *device, struct hd_geometry *geo)
810
{
811
        int rc = 0;
812
        dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
813
        switch (device->sizes.bp_block) {
814
        case 512:
815
        case 1024:
816
        case 2048:
817
        case 4096:
818
            geo->sectors = recs_per_track (&(private->rdc_data),
819
                                           0, device->sizes.bp_block);
820
            break;
821
        default:
822
            break;
823
        }
824
        geo->cylinders = private->rdc_data.no_cyl;
825
        geo->heads = private->rdc_data.trk_per_cyl;
826
        return rc;
827
}
828
 
829
static ccw_req_t *
830
dasd_eckd_format_device (dasd_device_t * device, format_data_t * fdata)
831
{
832
        int i;
833
        ccw_req_t *fcp = NULL;
834
        DE_eckd_data_t *DE_data = NULL;
835
        LO_eckd_data_t *LO_data = NULL;
836
        eckd_count_t *ct_data = NULL;
837
        eckd_count_t *r0_data = NULL;
838
        eckd_home_t *ha_data = NULL;
839
        ccw1_t *last_ccw = NULL;
840
        void *last_data = NULL;
841
        dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
842
 
843
        int rpt = recs_per_track (&(private->rdc_data), 0, fdata->blksize);
844
        int cyl = fdata->start_unit / private->rdc_data.trk_per_cyl;
845
        int head = fdata->start_unit % private->rdc_data.trk_per_cyl;
846
        int wrccws = rpt;
847
        int datasize = sizeof (DE_eckd_data_t) + sizeof (LO_eckd_data_t);
848
 
849
        if (fdata->start_unit >=
850
            (private->rdc_data.no_cyl * private->rdc_data.trk_per_cyl)){
851
 
852
                DEV_MESSAGE (KERN_INFO, device,
853
                             "Track no %d too big!",
854
                             fdata->start_unit);
855
 
856
                return NULL;
857
        }
858
        if ( fdata->start_unit > fdata->stop_unit) {
859
 
860
                DEV_MESSAGE (KERN_INFO, device,
861
                             "Track %d reached! ending.",
862
                             fdata->start_unit);
863
 
864
                return NULL;
865
        }
866
        switch (fdata->blksize) {
867
        case 512:
868
        case 1024:
869
        case 2048:
870
        case 4096:
871
                break;
872
        default:
873
 
874
                MESSAGE (KERN_WARNING,
875
                         "Invalid blocksize %d...terminating!",
876
                         fdata->blksize);
877
 
878
                return NULL;
879
        }
880
        switch (fdata->intensity) {
881
        case 0x00:
882
        case 0x01:
883
        case 0x03:
884
        case 0x04:              /* make track invalid */
885
        case 0x08:
886
        case 0x09:
887
        case 0x0b:
888
        case 0x0c:
889
                break;
890
        default:
891
 
892
                MESSAGE (KERN_WARNING,
893
                         "Invalid flags 0x%x...terminating!",
894
                         fdata->intensity);
895
 
896
                return NULL;
897
        }
898
 
899
        /* print status line */
900
        if ((private->rdc_data.no_cyl < 20) ?
901
            (fdata->start_unit % private->rdc_data.no_cyl == 0) :
902
            (fdata->start_unit % private->rdc_data.no_cyl == 0 &&
903
             (fdata->start_unit / private->rdc_data.no_cyl) %
904
             (private->rdc_data.no_cyl / 20))) {
905
 
906
                DBF_DEV_EVENT (DBF_NOTICE, device,
907
                               "Format Cylinder: %d Flags: %d",
908
                               fdata->start_unit / private->rdc_data.trk_per_cyl,
909
                               fdata->intensity);
910
 
911
        }
912
        if ((fdata->intensity & ~0x8) & 0x04) {
913
                wrccws = 1;
914
                rpt = 1;
915
        } else {
916
                if (fdata->intensity & 0x1) {
917
                        wrccws++;
918
                        datasize += sizeof (eckd_count_t);
919
                }
920
                if (fdata->intensity & 0x2) {
921
                        wrccws++;
922
                        datasize += sizeof (eckd_home_t);
923
                }
924
        }
925
        fcp = dasd_alloc_request (dasd_eckd_discipline.name,
926
                                 wrccws + 2 + 1,
927
                                 datasize + rpt * sizeof (eckd_count_t),
928
                                 device );
929
        if (fcp != NULL) {
930
                fcp->device = device;
931
                fcp->retries = 2;       /* set retry counter to enable ERP */
932
                last_data = fcp->data;
933
                DE_data = (DE_eckd_data_t *) last_data;
934
                last_data = (void *) (DE_data + 1);
935
                LO_data = (LO_eckd_data_t *) last_data;
936
                last_data = (void *) (LO_data + 1);
937
                if (fdata->intensity & 0x2) {
938
                        ha_data = (eckd_home_t *) last_data;
939
                        last_data = (void *) (ha_data + 1);
940
                }
941
                if (fdata->intensity & 0x1) {
942
                        r0_data = (eckd_count_t *) last_data;
943
                        last_data = (void *) (r0_data + 1);
944
                }
945
                ct_data = (eckd_count_t *) last_data;
946
 
947
                last_ccw = fcp->cpaddr;
948
 
949
                switch (fdata->intensity & ~0x08) {
950
                case 0x03:
951
                        if (define_extent (last_ccw, DE_data, fdata->start_unit, fdata->start_unit,
952
                                           DASD_ECKD_CCW_WRITE_HOME_ADDRESS,
953
                                           device, fcp)) {
954
                                goto clear_fcp;
955
                        }
956
                        last_ccw->flags |= CCW_FLAG_CC;
957
                        last_ccw++;
958
                        if (locate_record (last_ccw, LO_data, fdata->start_unit, 0, wrccws,
959
                                           DASD_ECKD_CCW_WRITE_HOME_ADDRESS, device,
960
                                           device->sizes.bp_block, fcp)) {
961
                                goto clear_fcp;
962
                        }
963
                        last_ccw->flags |= CCW_FLAG_CC;
964
                        last_ccw++;
965
                        break;
966
                case 0x01:
967
                        if (define_extent (last_ccw, DE_data, fdata->start_unit, fdata->start_unit,
968
                                           DASD_ECKD_CCW_WRITE_RECORD_ZERO, device, fcp)) {
969
                                goto clear_fcp;
970
                        }
971
                        last_ccw->flags |= CCW_FLAG_CC;
972
                        last_ccw++;
973
                        if (locate_record (last_ccw, LO_data, fdata->start_unit, 0, wrccws,
974
                                           DASD_ECKD_CCW_WRITE_RECORD_ZERO, device,
975
                                           device->sizes.bp_block, fcp)) {
976
                                goto clear_fcp;
977
                        }
978
                        last_ccw->flags |= CCW_FLAG_CC;
979
                        last_ccw++;
980
                        memset (r0_data, 0, sizeof (eckd_count_t));
981
                        break;
982
                case 0x04:
983
                        fdata->blksize = 8;
984
                case 0x00:
985
                        if (define_extent (last_ccw, DE_data, fdata->start_unit, fdata->start_unit,
986
                                           DASD_ECKD_CCW_WRITE_CKD, device, fcp)) {
987
                                dasd_free_request (fcp, device);
988
                                return NULL;
989
                        }
990
                        last_ccw->flags |= CCW_FLAG_CC;
991
                        last_ccw++;
992
                        if (locate_record (last_ccw, LO_data, fdata->start_unit, 0, wrccws,
993
                                           DASD_ECKD_CCW_WRITE_CKD, device, fdata->blksize, fcp)) {
994
                                goto clear_fcp;
995
                        }
996
                        last_ccw->flags |= CCW_FLAG_CC;
997
                        last_ccw++;
998
                        break;
999
                default:
1000
 
1001
                        MESSAGE (KERN_WARNING,
1002
                                 "Unknown format flags...%d",
1003
                                 fdata->intensity);
1004
 
1005
                        return NULL;
1006
                }
1007
                if (fdata->intensity & 0x02) {
1008
 
1009
                        MESSAGE (KERN_WARNING,
1010
                                 "Unsupported format flag...%d",
1011
                                 fdata->intensity);
1012
 
1013
                        return NULL;
1014
                }
1015
                if (fdata->intensity & 0x01) {  /* write record zero */
1016
                        r0_data->cyl = cyl;
1017
                        r0_data->head = head;
1018
                        r0_data->record = 0;
1019
                        r0_data->kl = 0;
1020
                        r0_data->dl = 8;
1021
                        last_ccw->cmd_code = DASD_ECKD_CCW_WRITE_RECORD_ZERO;
1022
                        last_ccw->count = 8;
1023
                        last_ccw->flags |= CCW_FLAG_CC | CCW_FLAG_SLI;
1024
                        if (dasd_set_normalized_cda (last_ccw, __pa (r0_data), fcp, device)) {
1025
                                goto clear_fcp;
1026
                        }
1027
                        last_ccw++;
1028
                }
1029
                if ((fdata->intensity & ~0x08) & 0x04) {        /* erase track */
1030
                        memset (ct_data, 0, sizeof (eckd_count_t));
1031
                        ct_data->cyl = cyl;
1032
                        ct_data->head = head;
1033
                        ct_data->record = 1;
1034
                        ct_data->kl = 0;
1035
                        ct_data->dl = 0;
1036
                        last_ccw->cmd_code = DASD_ECKD_CCW_WRITE_CKD;
1037
                        last_ccw->count = 8;
1038
                        last_ccw->flags |= CCW_FLAG_CC | CCW_FLAG_SLI;
1039
                        if (dasd_set_normalized_cda (last_ccw, __pa (ct_data), fcp, device)) {
1040
                                goto clear_fcp;
1041
                        }
1042
                        last_ccw++;
1043
                } else {        /* write remaining records */
1044
                        for (i = 0; i < rpt; i++) {
1045
                                memset (ct_data + i, 0, sizeof (eckd_count_t));
1046
                                (ct_data + i)->cyl = cyl;
1047
                                (ct_data + i)->head = head;
1048
                                (ct_data + i)->record = i + 1;
1049
                                (ct_data + i)->kl = 0;
1050
                                if (fdata->intensity & 0x08) {
1051
                                        // special handling when formatting CDL
1052
                                        switch (fdata->start_unit) {
1053
                                        case 0:
1054
                                                if (i < 3) {
1055
                                                        (ct_data + i)->kl = 4;
1056
 
1057
                                                            (ct_data + i)->dl =
1058
                                                            sizes_trk0[i] - 4;
1059
                                                } else
1060
                                                        (ct_data + i)->dl = fdata->blksize;
1061
                                                break;
1062
                                        case 1:
1063
                                                (ct_data + i)->kl = 44;
1064
                                                (ct_data + i)->dl = LABEL_SIZE - 44;
1065
                                                break;
1066
                                        default:
1067
                                                (ct_data + i)->dl = fdata->blksize;
1068
                                                break;
1069
                                        }
1070
                                } else
1071
                                        (ct_data + i)->dl = fdata->blksize;
1072
                                last_ccw->cmd_code = DASD_ECKD_CCW_WRITE_CKD;
1073
                                last_ccw->flags |= CCW_FLAG_CC | CCW_FLAG_SLI;
1074
                                last_ccw->count = 8;
1075
                                if (dasd_set_normalized_cda (last_ccw,
1076
                                                             __pa (ct_data + i), fcp, device)) {
1077
                                goto clear_fcp;
1078
                                }
1079
                                last_ccw++;
1080
                        }
1081
                }
1082
                (last_ccw - 1)->flags &= ~(CCW_FLAG_CC | CCW_FLAG_DC);
1083
                fcp->device = device;
1084
                fcp->buildclk = get_clock ();
1085
                fcp->status = CQR_STATUS_FILLED;
1086
        }
1087
        goto out;
1088
 clear_fcp:
1089
        dasd_free_request (fcp, device);
1090
        fcp=NULL;
1091
 out:
1092
        return fcp;
1093
}
1094
 
1095
static dasd_era_t
1096
dasd_eckd_examine_error (ccw_req_t * cqr, devstat_t * stat)
1097
{
1098
        dasd_device_t *device = (dasd_device_t *) cqr->device;
1099
 
1100
        if (stat->cstat == 0x00 &&
1101
            stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
1102
                    return dasd_era_none;
1103
 
1104
        switch (device->devinfo.sid_data.cu_type) {
1105
        case 0x3990:
1106
        case 0x2105:
1107
                return dasd_3990_erp_examine (cqr, stat);
1108
        case 0x9343:
1109
                return dasd_9343_erp_examine (cqr, stat);
1110
        default:
1111
 
1112
                MESSAGE (KERN_WARNING, "%s",
1113
                         "default (unknown CU type) - RECOVERABLE return");
1114
 
1115
                return dasd_era_recover;
1116
        }
1117
}
1118
 
1119
static dasd_erp_action_fn_t
1120
dasd_eckd_erp_action (ccw_req_t * cqr)
1121
{
1122
        dasd_device_t *device = (dasd_device_t *) cqr->device;
1123
 
1124
        switch (device->devinfo.sid_data.cu_type) {
1125
        case 0x3990:
1126
        case 0x2105:
1127
                return dasd_3990_erp_action;
1128
        case 0x9343:
1129
                /* Return dasd_9343_erp_action; */
1130
        default:
1131
                return dasd_default_erp_action;
1132
        }
1133
}
1134
 
1135
static dasd_erp_postaction_fn_t
1136
dasd_eckd_erp_postaction (ccw_req_t * cqr)
1137
{
1138
        return dasd_default_erp_postaction;
1139
}
1140
 
1141
 
1142
inline unsigned char
1143
dasd_eckd_cdl_cmd (dasd_device_t * device, int recid, int cmd)
1144
{
1145
        dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
1146
        int byt_per_blk = device->sizes.bp_block;
1147
        int blk_per_trk = recs_per_track (&(private->rdc_data), 0, byt_per_blk);
1148
        switch (cmd) {
1149
        case READ:
1150
                if (recid < 3)
1151
                        return DASD_ECKD_CCW_READ_KD_MT;
1152
                if (recid < blk_per_trk)
1153
                        return DASD_ECKD_CCW_READ_MT;
1154
                if (recid < 2 * blk_per_trk)
1155
                        return DASD_ECKD_CCW_READ_KD_MT;
1156
                return DASD_ECKD_CCW_READ_MT;
1157
                break;
1158
        case WRITE:
1159
                if (recid < 3)
1160
                        return DASD_ECKD_CCW_WRITE_KD_MT;
1161
                if (recid < blk_per_trk)
1162
                        return DASD_ECKD_CCW_WRITE_MT;
1163
                if (recid < 2 * blk_per_trk)
1164
                        return DASD_ECKD_CCW_WRITE_KD_MT;
1165
                return DASD_ECKD_CCW_WRITE_MT;
1166
                break;
1167
        default:
1168
                BUG ();
1169
        }
1170
        return 0;                // never executed
1171
}
1172
 
1173
 
1174
static ccw_req_t *
1175
dasd_eckd_build_cp_from_req (dasd_device_t * device, struct request *req)
1176
{
1177
        ccw_req_t *rw_cp = NULL;
1178
        int rw_cmd;
1179
        int bhct;
1180
        long size;
1181
        ccw1_t *ccw;
1182
        DE_eckd_data_t *DE_data;
1183
        LO_eckd_data_t *LO_data;
1184
        struct buffer_head *bh;
1185
        dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
1186
        int byt_per_blk = device->sizes.bp_block;
1187
        int shift = device->sizes.s2b_shift;
1188
        int blk_per_trk = recs_per_track (&(private->rdc_data), 0, byt_per_blk);
1189
        unsigned long reloc_sector = req->sector +
1190
                device->major_info->gendisk.part[MINOR(req->rq_dev)].start_sect;
1191
        int btrk = (reloc_sector >> shift) / blk_per_trk;
1192
        int etrk = ((reloc_sector + req->nr_sectors - 1) >> shift) / blk_per_trk;
1193
        int recid = reloc_sector >> shift;
1194
        int locate4k_set = 0;
1195
        int nlocs = 0;
1196
        int errcode;
1197
 
1198
        if (req->cmd == READ) {
1199
                rw_cmd = DASD_ECKD_CCW_READ_MT;
1200
        } else if (req->cmd == WRITE) {
1201
                rw_cmd = DASD_ECKD_CCW_WRITE_MT;
1202
        } else {
1203
 
1204
                MESSAGE (KERN_ERR,
1205
                         "Unknown command %d",
1206
                         req->cmd);
1207
 
1208
                return ERR_PTR(-EINVAL);
1209
        }
1210
        /* Build the request */
1211
        /* count bhs to prevent errors, when bh smaller than block */
1212
        bhct = 0;
1213
        for (bh = req->bh; bh; bh = bh->b_reqnext) {
1214
                if (bh->b_size < byt_per_blk) {
1215
                        MESSAGE(KERN_ERR, "ignoring bogus sized request: %d<%d",
1216
                                          bh->b_size, byt_per_blk);
1217
                        return ERR_PTR(-EINVAL);
1218
                }
1219
                bhct+= bh->b_size >> (device->sizes.s2b_shift+9);
1220
        }
1221
        if (btrk < 2 && private->uses_cdl) {
1222
                if (etrk < 2)
1223
                        nlocs = bhct;
1224
                else
1225
                        nlocs = 2 * blk_per_trk - recid;
1226
        }
1227
        rw_cp = dasd_alloc_request (dasd_eckd_discipline.name,
1228
                                    2 + nlocs + bhct + 1,
1229
                                    sizeof (DE_eckd_data_t) + (1 +
1230
                                                               nlocs) *
1231
                                    sizeof (LO_eckd_data_t),
1232
                                    device);
1233
        if (!rw_cp) {
1234
                return ERR_PTR(-ENOMEM);
1235
        }
1236
        DE_data = rw_cp->data;
1237
        LO_data = rw_cp->data + sizeof (DE_eckd_data_t);
1238
        ccw = rw_cp->cpaddr;
1239
        if ((errcode = define_extent (ccw, DE_data, btrk, etrk,
1240
                                      rw_cmd, device, rw_cp))) {
1241
                goto clear_rw_cp;
1242
        }
1243
        ccw->flags |= CCW_FLAG_CC;
1244
        for (bh = req->bh; bh != NULL;) {
1245
                for (size = 0; size < bh->b_size; size += byt_per_blk) {
1246
                        if (!locate4k_set) {
1247
                                // we need to chain a locate record before our rw-ccw
1248
                                ccw++;
1249
                                if ((recid / blk_per_trk) < 2
1250
                                    && private->uses_cdl) {
1251
                                        /* Do a locate record for our special blocks */
1252
                                        int cmd = dasd_eckd_cdl_cmd (device,recid, req->cmd);
1253
                                        if ((errcode = locate_record (ccw,
1254
                                                       LO_data++,
1255
                                                       recid / blk_per_trk,
1256
                                                       recid % blk_per_trk + 1,
1257
                                                       1, cmd, device,
1258
                                                       dasd_eckd_cdl_reclen(device, recid), rw_cp))) {
1259
                                                goto clear_rw_cp;
1260
                                        }
1261
                                } else {
1262
                                        // Do a locate record for standard blocks */
1263
                                        if ((errcode = locate_record (ccw,
1264
                                                       LO_data++,
1265
                                                       recid /blk_per_trk,
1266
                                                       recid %blk_per_trk + 1,
1267
                                                       (((reloc_sector +
1268
                                                          req->nr_sectors) >>
1269
                                                         shift) - recid),
1270
                                                       rw_cmd, device,
1271
                                                       device->sizes.bp_block, rw_cp))) {
1272
                                                goto clear_rw_cp;
1273
                                        }
1274
                                        locate4k_set = 1;
1275
                                }
1276
                                ccw->flags |= CCW_FLAG_CC;
1277
                        }
1278
                        ccw++;
1279
                        ccw->flags |= CCW_FLAG_CC;
1280
                        ccw->cmd_code = locate4k_set ? rw_cmd :
1281
                                dasd_eckd_cdl_cmd (device, recid, req->cmd);
1282
                        ccw->count = byt_per_blk;
1283
                        if (!locate4k_set) {
1284
                                ccw->count = dasd_eckd_cdl_reclen (device,recid);
1285
                                if (ccw->count < byt_per_blk) {
1286
                                    memset (bh->b_data + size + ccw->count,
1287
                                            0xE5, byt_per_blk - ccw->count);
1288
                                }
1289
                        }
1290
                        if ((errcode = dasd_set_normalized_cda (ccw, __pa (bh->b_data+size),
1291
                                                                rw_cp, device))) {
1292
                                goto clear_rw_cp;
1293
                        }
1294
                        recid++;
1295
                }
1296
                bh = bh->b_reqnext;
1297
        }
1298
        ccw->flags    &= ~(CCW_FLAG_DC | CCW_FLAG_CC);
1299
        rw_cp->device  = device;
1300
        rw_cp->expires = 5 * TOD_MIN;   /* 5 minutes */
1301
        rw_cp->req     = req;
1302
        rw_cp->lpm     = LPM_ANYPATH;
1303
        rw_cp->retries = 256;
1304
 
1305
        rw_cp->buildclk = get_clock ();
1306
 
1307
        check_then_set (&rw_cp->status,
1308
                        CQR_STATUS_EMPTY,
1309
                        CQR_STATUS_FILLED);
1310
 
1311
        goto out;
1312
 clear_rw_cp:
1313
        dasd_free_request (rw_cp,
1314
                           device);
1315
        rw_cp=ERR_PTR(errcode);
1316
 out:
1317
        return rw_cp;
1318
}
1319
 
1320
#if 0
1321
int
1322
dasd_eckd_cleanup_request (ccw_req_t * cqr)
1323
{
1324
        int ret = 0;
1325
        struct request *req = cqr->req;
1326
        dasd_device_t *device = cqr->device;
1327
        int byt_per_blk = device->sizes.bp_block;
1328
 
1329
        for (bh = req->bh; bh != NULL;) {
1330
                if (bh->b_size > byt_per_blk) {
1331
                        for (size = 0; size < bh->b_size; size += byt_per_blk) {
1332
                                ccw++;
1333
                                ccw->flags |= CCW_FLAG_CC;
1334
                                ccw->cmd_code = rw_cmd;
1335
                                ccw->count = byt_per_blk;
1336
                                set_normalized_cda (ccw,
1337
                                                    __pa (bh->b_data + size));
1338
                        }
1339
                        bh = bh->b_reqnext;
1340
                } else {        /* group N bhs to fit into byt_per_blk */
1341
                        for (size = 0; bh != NULL && size < byt_per_blk;) {
1342
                                ccw++;
1343
                                ccw->flags |= CCW_FLAG_DC;
1344
                                ccw->cmd_code = rw_cmd;
1345
                                ccw->count = bh->b_size;
1346
                                set_normalized_cda (ccw, __pa (bh->b_data));
1347
                                size += bh->b_size;
1348
                                bh = bh->b_reqnext;
1349
                        }
1350
                }
1351
        }
1352
        return ret;
1353
}
1354
#endif
1355
 
1356
/*
1357
 * DASD_ECKD_RESERVE
1358
 *
1359
 * DESCRIPTION
1360
 *    Buils a channel programm to reserve a device.
1361
 *    Options are set to 'synchronous wait for interrupt' and
1362
 *    'timeout the request'. This leads to an terminate IO if
1363
 *    the interrupt is outstanding for a certain time.
1364
 */
1365
ccw_req_t *
1366
dasd_eckd_reserve (struct dasd_device_t * device)
1367
{
1368
        ccw_req_t *cqr;
1369
 
1370
        cqr = dasd_alloc_request (dasd_eckd_discipline.name,
1371
                                  1 + 1, 32, device);
1372
        if (cqr == NULL) {
1373
 
1374
                MESSAGE (KERN_WARNING, "%s",
1375
                         "No memory to allocate initialization request");
1376
 
1377
                return NULL;
1378
        }
1379
        cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RESERVE;
1380
        cqr->cpaddr->flags |= CCW_FLAG_SLI;
1381
        cqr->cpaddr->count = 32;
1382
 
1383
        if (dasd_set_normalized_cda (cqr->cpaddr, __pa (cqr->data),
1384
                                     cqr, device)) {
1385
                dasd_free_request (cqr, device);
1386
                return NULL;
1387
        }
1388
 
1389
        cqr->device  = device;
1390
        cqr->retries = 0;
1391
        cqr->expires = 10 * TOD_SEC;
1392
        cqr->buildclk = get_clock ();
1393
        cqr->status  = CQR_STATUS_FILLED;
1394
        return cqr;
1395
}
1396
 
1397
/*
1398
 * DASD_ECKD_RELEASE
1399
 *
1400
 * DESCRIPTION
1401
 *    Buils a channel programm to releases a prior reserved
1402
 *    (see dasd_eckd_reserve) device.
1403
 */
1404
ccw_req_t *
1405
dasd_eckd_release (struct dasd_device_t * device)
1406
{
1407
        ccw_req_t *cqr;
1408
 
1409
        cqr = dasd_alloc_request (dasd_eckd_discipline.name,
1410
                                  1 + 1, 32, device);
1411
        if (cqr == NULL) {
1412
 
1413
                MESSAGE (KERN_WARNING, "%s",
1414
                         "No memory to allocate initialization request");
1415
 
1416
                return NULL;
1417
        }
1418
        cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RELEASE;
1419
        cqr->cpaddr->flags |= CCW_FLAG_SLI;
1420
        cqr->cpaddr->count = 32;
1421
 
1422
        if (dasd_set_normalized_cda (cqr->cpaddr, __pa (cqr->data),
1423
                                     cqr, device)) {
1424
                dasd_free_request (cqr, device);
1425
                return NULL;
1426
        }
1427
 
1428
        cqr->device  = device;
1429
        cqr->retries = 0;
1430
        cqr->expires = 10 * TOD_SEC;
1431
        cqr->buildclk = get_clock ();
1432
        cqr->status  = CQR_STATUS_FILLED;
1433
        return cqr;
1434
 
1435
}
1436
 
1437
/*
1438
 * DASD_ECKD_STEAL_LOCK
1439
 *
1440
 * DESCRIPTION
1441
 *    Buils a channel programm to break a device's reservation.
1442
 *    (unconditional reserve)
1443
 */
1444
ccw_req_t *
1445
dasd_eckd_steal_lock (struct dasd_device_t * device)
1446
{
1447
        ccw_req_t *cqr;
1448
 
1449
        cqr = dasd_alloc_request (dasd_eckd_discipline.name,
1450
                                  1 + 1, 32, device);
1451
        if (cqr == NULL) {
1452
 
1453
                MESSAGE (KERN_WARNING, "%s",
1454
                        "No memory to allocate initialization request");
1455
 
1456
                return NULL;
1457
        }
1458
        cqr->cpaddr->cmd_code = DASD_ECKD_CCW_SLCK;
1459
        cqr->cpaddr->flags |= CCW_FLAG_SLI;
1460
        cqr->cpaddr->count = 32;
1461
 
1462
        if (dasd_set_normalized_cda (cqr->cpaddr, __pa (cqr->data),
1463
                                     cqr, device)) {
1464
                dasd_free_request (cqr, device);
1465
                return NULL;
1466
        }
1467
 
1468
        cqr->device  = device;
1469
        cqr->retries = 0;
1470
        cqr->expires = 10 * TOD_SEC;
1471
        cqr->buildclk = get_clock ();
1472
        cqr->status  = CQR_STATUS_FILLED;
1473
        return cqr;
1474
}
1475
 
1476
static inline ccw1_t *
1477
dasd_eckd_find_cmd (ccw_req_t * cqr, int cmd)
1478
{
1479
        ccw1_t *cp;
1480
 
1481
        cp = cqr->cpaddr;
1482
        do {
1483
                if (cp->cmd_code == cmd)
1484
                        return cp;
1485
                if (cp->cmd_code == CCW_CMD_TIC) {
1486
                        cp = (ccw1_t *) (long) cp->cda;
1487
                        continue;
1488
                }
1489
                if (cp->flags & (CCW_FLAG_DC | CCW_FLAG_CC)) {
1490
                        cp++;
1491
                        continue;
1492
                }
1493
                break;
1494
        } while (1);
1495
        return NULL;
1496
}
1497
 
1498
static ccw_req_t *
1499
dasd_eckd_merge_cp (dasd_device_t * device)
1500
{
1501
        return NULL;
1502
}
1503
 
1504
static int
1505
dasd_eckd_fill_info (dasd_device_t * device, dasd_information2_t * info)
1506
{
1507
        int rc = 0;
1508
        info->label_block = 2;
1509
        if (((dasd_eckd_private_t *) device->private)->uses_cdl) {
1510
                info->FBA_layout = 0;
1511
                info->format = DASD_FORMAT_CDL;
1512
        } else {
1513
                info->FBA_layout = 1;
1514
                info->format = DASD_FORMAT_LDL;
1515
        }
1516
        info->characteristics_size = sizeof (dasd_eckd_characteristics_t);
1517
        memcpy (info->characteristics,
1518
                &((dasd_eckd_private_t *) device->private)->rdc_data,
1519
                sizeof (dasd_eckd_characteristics_t));
1520
        info->confdata_size = sizeof (dasd_eckd_confdata_t);
1521
        memcpy (info->configuration_data,
1522
                &((dasd_eckd_private_t *) device->private)->conf_data,
1523
                sizeof (dasd_eckd_confdata_t));
1524
        return rc;
1525
}
1526
 
1527
/*
1528
 * DASD_ECKD_READ_STATS
1529
 *
1530
 * DESCRIPTION
1531
 *   build the channel program to read the performance statistics
1532
 *   of the attached subsystem
1533
 */
1534
ccw_req_t *
1535
dasd_eckd_read_stats (struct dasd_device_t * device)
1536
{
1537
 
1538
        int                    rc;
1539
        ccw1_t                 *ccw;
1540
        ccw_req_t              *cqr;
1541
        dasd_psf_prssd_data_t  *prssdp;
1542
        dasd_rssd_perf_stats_t *statsp;
1543
 
1544
        cqr = dasd_alloc_request (dasd_eckd_discipline.name,
1545
                                  1 /* PSF */ + 1 /* RSSD */,
1546
                                  (sizeof (dasd_psf_prssd_data_t) +
1547
                                   sizeof (dasd_rssd_perf_stats_t) ),
1548
                                  device);
1549
 
1550
        if (cqr == NULL) {
1551
 
1552
                MESSAGE (KERN_WARNING, "%s",
1553
                         "No memory to allocate initialization request");
1554
 
1555
                return NULL;
1556
        }
1557
 
1558
        cqr->device  = device;
1559
        cqr->retries = 0;
1560
        cqr->expires = 10 * TOD_SEC;
1561
 
1562
        /* Prepare for Read Subsystem Data */
1563
        prssdp = (dasd_psf_prssd_data_t *) cqr->data;
1564
 
1565
        memset (prssdp, 0, sizeof (dasd_psf_prssd_data_t));
1566
 
1567
        prssdp->order     = PSF_ORDER_PRSSD;
1568
        prssdp->suborder  = 0x01; /* Perfomance Statistics */
1569
        prssdp->varies[1] = 0x01; /* Perf Statistics for the Subsystem */
1570
 
1571
        ccw = cqr->cpaddr;
1572
 
1573
        ccw->cmd_code = DASD_ECKD_CCW_PSF;
1574
        ccw->count    = sizeof (dasd_psf_prssd_data_t);
1575
        ccw->flags   |= CCW_FLAG_CC;
1576
 
1577
        if ((rc = dasd_set_normalized_cda (ccw,__pa (prssdp), cqr, device))) {
1578
 
1579
                dasd_free_request (cqr,
1580
                                   device);
1581
                return NULL;
1582
        }
1583
 
1584
        ccw++;
1585
 
1586
        /* Read Subsystem Data - Performance Statistics */
1587
        statsp = (dasd_rssd_perf_stats_t *) (prssdp + 1);
1588
        memset (statsp, 0, sizeof (dasd_rssd_perf_stats_t));
1589
 
1590
        ccw->cmd_code = DASD_ECKD_CCW_RSSD;
1591
        ccw->count    = sizeof (dasd_rssd_perf_stats_t);
1592
 
1593
        if ((rc = dasd_set_normalized_cda (ccw,__pa (statsp), cqr, device))) {
1594
 
1595
                dasd_free_request (cqr,
1596
                                   device);
1597
                return NULL;
1598
        }
1599
        cqr->buildclk = get_clock ();
1600
        cqr->status   = CQR_STATUS_FILLED;
1601
 
1602
        return cqr;
1603
} /* end  dasd_eckd_rstat */
1604
 
1605
/*
1606
 * DASD_ECKD_RET_STATS
1607
 *
1608
 * DESCRIPTION
1609
 *   returns pointer to Performance Statistics Data.
1610
 */
1611
dasd_rssd_perf_stats_t *
1612
dasd_eckd_ret_stats (ccw_req_t *cqr)
1613
{
1614
 
1615
        dasd_psf_prssd_data_t  *prssdp;
1616
        dasd_rssd_perf_stats_t *statsp;
1617
 
1618
        if (cqr == NULL) {
1619
 
1620
                return NULL;
1621
        }
1622
 
1623
        /* Prepare for Read Subsystem Data */
1624
        prssdp = (dasd_psf_prssd_data_t *)  cqr->data;
1625
        statsp = (dasd_rssd_perf_stats_t *) (prssdp + 1);
1626
 
1627
        return statsp;
1628
 
1629
} /* end  dasd_eckd_rstat */
1630
 
1631
 
1632
/*
1633
 * DASD_ECKD_GET_ATTRIB
1634
 *
1635
 * DESCRIPTION
1636
 *   returnes the cache attributes used in Define Extend (DE).
1637
 */
1638
int
1639
dasd_eckd_get_attrib (dasd_device_t *device,
1640
                      attrib_data_t *attrib)
1641
{
1642
        dasd_eckd_private_t *private;
1643
 
1644
        private = (dasd_eckd_private_t *) device->private;
1645
        *attrib = private->attrib;
1646
 
1647
        return 0;
1648
 
1649
} /* end dasd_eckd_get_attrib */
1650
 
1651
/*
1652
 * DASD_ECKD_SET_ATTRIB
1653
 *
1654
 * DESCRIPTION
1655
 *   stores the attributes for cache operation to be used in Define Extend (DE).
1656
 */
1657
int
1658
dasd_eckd_set_attrib (dasd_device_t *device,
1659
                      attrib_data_t *attrib)
1660
{
1661
        dasd_eckd_private_t *private;
1662
 
1663
        private = (dasd_eckd_private_t *) device->private;
1664
        private->attrib = *attrib;
1665
 
1666
        DBF_DEV_EVENT (DBF_ERR, device,
1667
                     "cache operation mode set to "
1668
                     "%x (%i cylinder prestage)",
1669
                     private->attrib.operation,
1670
                     private->attrib.nr_cyl);
1671
 
1672
        return 0;
1673
 
1674
} /* end dasd_eckd_set_attrib */
1675
 
1676
static void
1677
dasd_eckd_dump_sense (struct dasd_device_t *device,
1678
                      ccw_req_t            *req)
1679
{
1680
 
1681
        char *page = (char *) get_free_page (GFP_ATOMIC);
1682
        devstat_t *stat = &device->dev_status;
1683
        char *sense = stat->ii.sense.data;
1684
        int len, sl, sct;
1685
 
1686
        if (page == NULL) {
1687
 
1688
                MESSAGE (KERN_ERR, "%s",
1689
                        "No memory to dump sense data");
1690
 
1691
                return;
1692
        }
1693
 
1694
        len = sprintf (page, KERN_ERR PRINTK_HEADER
1695
                       "device %04X on irq %d: I/O status report:\n",
1696
                       device->devinfo.devno, device->devinfo.irq);
1697
        len += sprintf (page + len, KERN_ERR PRINTK_HEADER
1698
                        "in req: %p CS: 0x%02X DS: 0x%02X\n",
1699
                        req, stat->cstat, stat->dstat);
1700
        len += sprintf (page + len, KERN_ERR PRINTK_HEADER
1701
                        "Failing CCW: %p\n", (void *) (long) stat->cpa);
1702
        {
1703
 
1704
                ccw1_t *act = req->cpaddr;
1705
                int i = req->cplength;
1706
 
1707
                do {
1708
 
1709
                        DBF_EVENT (DBF_INFO,
1710
                                   "CCW %p: %08X %08X",
1711
                                   act,
1712
                                   ((int *) act)[0],
1713
                                   ((int *) act)[1]);
1714
 
1715
                        DBF_EVENT (DBF_INFO,
1716
                                   "DAT: %08X %08X %08X %08X",
1717
                                   ((int *) (addr_t) act->cda)[0],
1718
                                   ((int *) (addr_t) act->cda)[1],
1719
                                   ((int *) (addr_t) act->cda)[2],
1720
                                   ((int *) (addr_t) act->cda)[3]);
1721
 
1722
                        act++;
1723
 
1724
                } while (--i);
1725
        }
1726
        if (stat->flag & DEVSTAT_FLAG_SENSE_AVAIL) {
1727
                for (sl = 0; sl < 4; sl++) {
1728
                        len += sprintf (page + len, KERN_ERR PRINTK_HEADER
1729
                                        "Sense(hex) %2d-%2d:",
1730
                                        (8 * sl), ((8 * sl) + 7));
1731
 
1732
                        for (sct = 0; sct < 8; sct++) {
1733
                                len += sprintf (page + len, " %02x",
1734
                                                sense[8 * sl + sct]);
1735
                        }
1736
                        len += sprintf (page + len, "\n");
1737
                }
1738
 
1739
                if (sense[27] & DASD_SENSE_BIT_0) {
1740
                        /* 24 Byte Sense Data */
1741
                        len += sprintf (page + len, KERN_ERR PRINTK_HEADER
1742
                                        "24 Byte: %x MSG %x, %s MSGb to SYSOP\n",
1743
                                        sense[7] >> 4, sense[7] & 0x0f,
1744
                                        sense[1] & 0x10 ? "" : "no");
1745
                } else {
1746
                        /* 32 Byte Sense Data */
1747
                        len += sprintf (page + len, KERN_ERR PRINTK_HEADER
1748
                                        "32 Byte: Format: %x "
1749
                                        "Exception class %x\n",
1750
                                        sense[6] & 0x0f, sense[22] >> 4);
1751
                }
1752
        }
1753
 
1754
        MESSAGE_LOG (KERN_ERR,
1755
                     "Sense data:\n%s",
1756
                     page);
1757
 
1758
        free_page ((unsigned long) page);
1759
}
1760
 
1761
 
1762
dasd_discipline_t dasd_eckd_discipline = {
1763
        owner: THIS_MODULE,
1764
        name:"ECKD",
1765
        ebcname:"ECKD",
1766
        max_blocks:240,
1767
        id_check:dasd_eckd_id_check,
1768
        check_characteristics:dasd_eckd_check_characteristics,
1769
        init_analysis:dasd_eckd_init_analysis,
1770
        do_analysis:dasd_eckd_do_analysis,
1771
        fill_geometry:dasd_eckd_fill_geometry,
1772
        start_IO:dasd_start_IO,
1773
        term_IO:dasd_term_IO,
1774
        format_device:dasd_eckd_format_device,
1775
        examine_error:dasd_eckd_examine_error,
1776
        erp_action:dasd_eckd_erp_action,
1777
        erp_postaction:dasd_eckd_erp_postaction,
1778
        build_cp_from_req:dasd_eckd_build_cp_from_req,
1779
        dump_sense:dasd_eckd_dump_sense,
1780
        int_handler:dasd_int_handler,
1781
        reserve:dasd_eckd_reserve,
1782
        release:dasd_eckd_release,
1783
        steal_lock:dasd_eckd_steal_lock,
1784
        merge_cp:dasd_eckd_merge_cp,
1785
        fill_info:dasd_eckd_fill_info,
1786
        read_stats:dasd_eckd_read_stats,
1787
        ret_stats:dasd_eckd_ret_stats,
1788
        get_attrib:dasd_eckd_get_attrib,
1789
        set_attrib:dasd_eckd_set_attrib,
1790
        list:LIST_HEAD_INIT(dasd_eckd_discipline.list),
1791
};
1792
 
1793
int
1794
dasd_eckd_init (void)
1795
{
1796
        int rc = 0;
1797
 
1798
        MESSAGE (KERN_INFO,
1799
                "%s discipline initializing",
1800
                 dasd_eckd_discipline.name);
1801
 
1802
        ASCEBC (dasd_eckd_discipline.ebcname, 4);
1803
        dasd_discipline_add (&dasd_eckd_discipline);
1804
#ifdef CONFIG_DASD_DYNAMIC
1805
        {
1806
                int i;
1807
                for (i = 0;
1808
                     i < sizeof (dasd_eckd_known_devices) / sizeof (devreg_t);
1809
                     i++) {
1810
 
1811
                        MESSAGE (KERN_INFO,
1812
                                 "We are interested in: CU %04X/%02x",
1813
                                 dasd_eckd_known_devices[i].ci.hc.ctype,
1814
                                 dasd_eckd_known_devices[i].ci.hc.cmode);
1815
 
1816
                        s390_device_register (&dasd_eckd_known_devices[i]);
1817
                }
1818
        }
1819
#endif                          /* CONFIG_DASD_DYNAMIC */
1820
        return rc;
1821
}
1822
 
1823
void
1824
dasd_eckd_cleanup (void)
1825
{
1826
 
1827
        MESSAGE (KERN_INFO,
1828
                "%s discipline cleaning up",
1829
                 dasd_eckd_discipline.name);
1830
 
1831
#ifdef CONFIG_DASD_DYNAMIC
1832
        {
1833
                int i;
1834
                for (i = 0;
1835
                     i < sizeof (dasd_eckd_known_devices) / sizeof (devreg_t);
1836
                     i++) {
1837
 
1838
                        MESSAGE (KERN_INFO,
1839
                                 "We were interested in: CU %04X/%02x",
1840
                                 dasd_eckd_known_devices[i].ci.hc.ctype,
1841
                                 dasd_eckd_known_devices[i].ci.hc.cmode);
1842
 
1843
                        s390_device_unregister (&dasd_eckd_known_devices[i]);
1844
                }
1845
        }
1846
#endif                          /* CONFIG_DASD_DYNAMIC */
1847
        dasd_discipline_del (&dasd_eckd_discipline);
1848
}
1849
 
1850
#ifdef MODULE
1851
int
1852
init_module (void)
1853
{
1854
        int rc = 0;
1855
        rc = dasd_eckd_init ();
1856
        return rc;
1857
}
1858
 
1859
void
1860
cleanup_module (void)
1861
{
1862
        dasd_eckd_cleanup ();
1863
        return;
1864
}
1865
#endif
1866
 
1867
/*
1868
 * Overrides for Emacs so that we follow Linus's tabbing style.
1869
 * Emacs will notice this stuff at the end of the file and automatically
1870
 * adjust the settings for this buffer only.  This must remain at the end
1871
 * of the file.
1872
 * ---------------------------------------------------------------------------
1873
 * Local variables:
1874
 * c-indent-level: 4
1875
 * c-brace-imaginary-offset: 0
1876
 * c-brace-offset: -4
1877
 * c-argdecl-indent: 4
1878
 * c-label-offset: -4
1879
 * c-continued-statement-offset: 4
1880
 * c-continued-brace-offset: 0
1881
 * indent-tabs-mode: nil
1882
 * tab-width: 8
1883
 * End:
1884
 */

powered by: WebSVN 2.1.0

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