linux-old/drivers/s390/block/dasd_eckd.c
<<
>>
Prefs
   1/* 
   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))
  62MODULE_LICENSE("GPL");
  63#endif
  64#endif
  65
  66dasd_discipline_t dasd_eckd_discipline;
  67
  68typedef 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
  77static
  78devreg_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
 103int sizes_trk0[] = { 28, 148, 84 };
 104#define LABEL_SIZE 140
 105
 106static inline unsigned int
 107round_up_multiple (unsigned int no, unsigned int mult)
 108{
 109        int rem = no % mult;
 110        return (rem ? no - rem + mult : no);
 111}
 112
 113static inline unsigned int
 114ceil_quot (unsigned int d1, unsigned int d2)
 115{
 116        return (d1 + (d2 - 1)) / d2;
 117}
 118
 119static inline int
 120bytes_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
 162static inline unsigned int
 163bytes_per_track (dasd_eckd_characteristics_t * rdc)
 164{
 165        return *(unsigned int *) (rdc->byte_per_track) >> 8;
 166}
 167
 168static inline unsigned int
 169recs_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
 204static inline void
 205check_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
 228static inline int
 229define_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
 348static inline int
 349locate_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
 471static int
 472dasd_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
 486static int
 487dasd_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
 600static inline int
 601dasd_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
 615static ccw_req_t *
 616dasd_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
 706static int
 707dasd_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
 808static int
 809dasd_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
 829static ccw_req_t *
 830dasd_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
1095static dasd_era_t
1096dasd_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
1119static dasd_erp_action_fn_t
1120dasd_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
1135static dasd_erp_postaction_fn_t
1136dasd_eckd_erp_postaction (ccw_req_t * cqr)
1137{
1138        return dasd_default_erp_postaction;
1139}
1140
1141
1142inline unsigned char
1143dasd_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
1174static ccw_req_t *
1175dasd_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
1321int
1322dasd_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 */
1365ccw_req_t *
1366dasd_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 */
1404ccw_req_t *
1405dasd_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 */
1444ccw_req_t *
1445dasd_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
1476static inline ccw1_t *
1477dasd_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
1498static ccw_req_t *
1499dasd_eckd_merge_cp (dasd_device_t * device)
1500{
1501        return NULL;
1502}
1503
1504static int
1505dasd_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 */
1534ccw_req_t *
1535dasd_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 */
1611dasd_rssd_perf_stats_t *
1612dasd_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 */
1638int
1639dasd_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 */
1657int
1658dasd_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
1676static void
1677dasd_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
1762dasd_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
1793int
1794dasd_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
1823void
1824dasd_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
1851int
1852init_module (void)
1853{
1854        int rc = 0;
1855        rc = dasd_eckd_init ();
1856        return rc;
1857}
1858
1859void
1860cleanup_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 */
1885
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.