X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;ds=sidebyside;f=drivers%2Fs390%2Fblock%2Fdasd_eckd.c;h=df8902364762d87b1b9d5dc6579e4e09e294afca;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=56f471c23a51b199f9862280341edb06b9ffdc32;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 56f471c23..df8902364 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -7,7 +7,7 @@ * Bugreports.to..: * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * - * $Revision: 1.61 $ + * $Revision: 1.68 $ */ #include @@ -37,9 +37,12 @@ #define ECKD_C0(i) (i->home_bytes) #define ECKD_F(i) (i->formula) -#define ECKD_F1(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f1):(i->factors.f_0x02.f1)) -#define ECKD_F2(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f2):(i->factors.f_0x02.f2)) -#define ECKD_F3(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f3):(i->factors.f_0x02.f3)) +#define ECKD_F1(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f1):\ + (i->factors.f_0x02.f1)) +#define ECKD_F2(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f2):\ + (i->factors.f_0x02.f2)) +#define ECKD_F3(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f3):\ + (i->factors.f_0x02.f3)) #define ECKD_F4(i) (ECKD_F(i)==0x02?(i->factors.f_0x02.f4):0) #define ECKD_F5(i) (ECKD_F(i)==0x02?(i->factors.f_0x02.f5):0) #define ECKD_F6(i) (i->factor6) @@ -151,7 +154,6 @@ bytes_per_record(struct dasd_eckd_characteristics *rdc, int kl, int dl) bpr = fl1 + fl2; break; default: - MESSAGE(KERN_ERR, "unknown formula%d", rdc->formula); bpr = 0; break; } @@ -209,8 +211,8 @@ check_XRC (struct ccw1 *de_ccw, /* switch on System Time Stamp - needed for XRC Support */ if (private->rdc_data.facilities.XRC_supported) { - data->ga_extended |= 0x08; /* switch on 'Time Stamp Valid' */ - data->ga_extended |= 0x02; /* switch on 'Extended Parameter' */ + data->ga_extended |= 0x08; /* switch on 'Time Stamp Valid' */ + data->ga_extended |= 0x02; /* switch on 'Extended Parameter' */ data->ep_sys_time = get_clock (); @@ -272,7 +274,7 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk, check_XRC (ccw, data, device); break; default: - MESSAGE(KERN_ERR, "unknown opcode 0x%x", cmd); + DEV_MESSAGE(KERN_ERR, device, "unknown opcode 0x%x", cmd); break; } @@ -318,7 +320,7 @@ locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, int trk, private = (struct dasd_eckd_private *) device->private; - DBF_EVENT(DBF_INFO, + DBF_DEV_EVENT(DBF_INFO, device, "Locate: trk %d, rec %d, no_rec %d, cmd %d, reclen %d", trk, rec_on_trk, no_rec, cmd, reclen); @@ -400,7 +402,7 @@ locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, int trk, data->operation.operation = 0x0b; break; default: - MESSAGE(KERN_ERR, "unknown opcode 0x%x", cmd); + DEV_MESSAGE(KERN_ERR, device, "unknown opcode 0x%x", cmd); } data->seek_addr.cyl = data->search_arg.cyl = trk / private->rdc_data.trk_per_cyl; @@ -458,8 +460,9 @@ dasd_eckd_check_characteristics(struct dasd_device *device) private = kmalloc(sizeof(struct dasd_eckd_private), GFP_KERNEL | GFP_DMA); if (private == NULL) { - MESSAGE(KERN_WARNING, "%s", - "memory allocation failed for private data"); + DEV_MESSAGE(KERN_WARNING, device, "%s", + "memory allocation failed for private " + "data"); return -ENOMEM; } device->private = (void *) private; @@ -474,8 +477,9 @@ dasd_eckd_check_characteristics(struct dasd_device *device) rdc_data = (void *) &(private->rdc_data); rc = read_dev_chars(device->cdev, &rdc_data, 64); if (rc) { - MESSAGE(KERN_WARNING, - "Read device characteristics returned error %d", rc); + DEV_MESSAGE(KERN_WARNING, device, + "Read device characteristics returned error %d", + rc); return rc; } @@ -492,19 +496,20 @@ dasd_eckd_check_characteristics(struct dasd_device *device) /* Read Configuration Data */ rc = read_conf_data(device->cdev, &conf_data, &conf_len); if (rc && rc != -EOPNOTSUPP) { /* -EOPNOTSUPP is ok */ - MESSAGE(KERN_WARNING, - "Read configuration data returned error %d", rc); + DEV_MESSAGE(KERN_WARNING, device, + "Read configuration data returned error %d", rc); return rc; } if (conf_data == NULL) { - MESSAGE(KERN_WARNING, "%s", "No configuration data retrieved"); + DEV_MESSAGE(KERN_WARNING, device, "%s", + "No configuration data retrieved"); return 0; /* no errror */ } if (conf_len != sizeof (struct dasd_eckd_confdata)) { - MESSAGE(KERN_WARNING, - "sizes of configuration data mismatch" - "%d (read) vs %ld (expected)", - conf_len, sizeof (struct dasd_eckd_confdata)); + DEV_MESSAGE(KERN_WARNING, device, + "sizes of configuration data mismatch" + "%d (read) vs %ld (expected)", + conf_len, sizeof (struct dasd_eckd_confdata)); kfree(conf_data); /* allocated by read_conf_data() */ return 0; /* no errror */ @@ -746,8 +751,9 @@ dasd_eckd_format_device(struct dasd_device * device, return ERR_PTR(-EINVAL); } if (dasd_check_blocksize(fdata->blksize) != 0) { - MESSAGE(KERN_WARNING, "Invalid blocksize %d...terminating!", - fdata->blksize); + DEV_MESSAGE(KERN_WARNING, device, + "Invalid blocksize %d...terminating!", + fdata->blksize); return ERR_PTR(-EINVAL); } @@ -783,7 +789,8 @@ dasd_eckd_format_device(struct dasd_device * device, sizeof(struct eckd_count); break; default: - MESSAGE(KERN_WARNING, "Invalid flags 0x%x.", fdata->intensity); + DEV_MESSAGE(KERN_WARNING, device, "Invalid flags 0x%x.", + fdata->intensity); return ERR_PTR(-EINVAL); } /* Allocate the format ccw request. */ @@ -918,8 +925,8 @@ dasd_eckd_examine_error(struct dasd_ccw_req * cqr, struct irb * irb) return dasd_9343_erp_examine(cqr, irb); case 0x3880: default: - MESSAGE(KERN_WARNING, "%s", - "default (unknown CU type) - RECOVERABLE return"); + DEV_MESSAGE(KERN_WARNING, device, "%s", + "default (unknown CU type) - RECOVERABLE return"); return dasd_era_recover; } } @@ -937,7 +944,6 @@ dasd_eckd_erp_action(struct dasd_ccw_req * cqr) case 0x1750: return dasd_3990_erp_action; case 0x9343: - /* Return dasd_9343_erp_action; */ case 0x3880: default: return dasd_default_erp_action; @@ -995,7 +1001,8 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req) return ERR_PTR(-EINVAL); count += bv->bv_len >> (device->s2b_shift + 9); #if defined(CONFIG_ARCH_S390X) - if (idal_is_needed (page_address(bv->bv_page), bv->bv_len)) + if (idal_is_needed (page_address(bv->bv_page), + bv->bv_len)) cidaw += bv->bv_len >> (device->s2b_shift + 9); #endif } @@ -1035,6 +1042,14 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req) } rq_for_each_bio(bio, req) bio_for_each_segment(bv, bio, i) { dst = page_address(bv->bv_page) + bv->bv_offset; + if (dasd_page_cache) { + char *copy = kmem_cache_alloc(dasd_page_cache, + SLAB_DMA | __GFP_NOWARN); + if (copy && rq_data_dir(req) == WRITE) + memcpy(copy + bv->bv_offset, dst, bv->bv_len); + if (copy) + dst = copy + bv->bv_offset; + } for (off = 0; off < bv->bv_len; off += blksize) { sector_t trkid = recid; unsigned int recoffs = sector_div(trkid, blk_per_trk); @@ -1088,6 +1103,58 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req) return cqr; } +static int +dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req) +{ + struct dasd_eckd_private *private; + struct ccw1 *ccw; + struct bio *bio; + struct bio_vec *bv; + char *dst, *cda; + unsigned int blksize, blk_per_trk, off; + sector_t recid; + int i, status; + + if (!dasd_page_cache) + goto out; + private = (struct dasd_eckd_private *) cqr->device->private; + blksize = cqr->device->bp_block; + blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize); + recid = req->sector >> cqr->device->s2b_shift; + ccw = cqr->cpaddr; + /* Skip over define extent & locate record. */ + ccw++; + if (private->uses_cdl == 0 || recid > 2*blk_per_trk) + ccw++; + rq_for_each_bio(bio, req) bio_for_each_segment(bv, bio, i) { + dst = page_address(bv->bv_page) + bv->bv_offset; + for (off = 0; off < bv->bv_len; off += blksize) { + /* Skip locate record. */ + if (private->uses_cdl && recid <= 2*blk_per_trk) + ccw++; + if (dst) { + if (ccw->flags & CCW_FLAG_IDA) + cda = *((char **)((addr_t) ccw->cda)); + else + cda = (char *)((addr_t) ccw->cda); + if (dst != cda) { + if (rq_data_dir(req) == READ) + memcpy(dst, cda, bv->bv_len); + kmem_cache_free(dasd_page_cache, + (void *)((addr_t)cda & PAGE_MASK)); + } + dst = NULL; + } + ccw++; + recid++; + } + } +out: + status = cqr->status == DASD_CQR_DONE; + dasd_sfree_request(cqr, cqr->device); + return status; +} + static int dasd_eckd_fill_info(struct dasd_device * device, struct dasd_information2_t * info) @@ -1132,10 +1199,10 @@ dasd_eckd_release(struct block_device *bdev, int no, long args) cqr = dasd_smalloc_request(dasd_eckd_discipline.name, 1, 32, device); - if (cqr == NULL) { - MESSAGE(KERN_WARNING, "%s", - "No memory to allocate initialization request"); - return -ENOMEM; + if (IS_ERR(cqr)) { + DEV_MESSAGE(KERN_WARNING, device, "%s", + "Could not allocate initialization request"); + return PTR_ERR(cqr); } cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RELEASE; cqr->cpaddr->flags |= CCW_FLAG_SLI; @@ -1176,10 +1243,10 @@ dasd_eckd_reserve(struct block_device *bdev, int no, long args) cqr = dasd_smalloc_request(dasd_eckd_discipline.name, 1, 32, device); - if (cqr == NULL) { - MESSAGE(KERN_WARNING, "%s", - "No memory to allocate initialization request"); - return -ENOMEM; + if (IS_ERR(cqr)) { + DEV_MESSAGE(KERN_WARNING, device, "%s", + "Could not allocate initialization request"); + return PTR_ERR(cqr); } cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RESERVE; cqr->cpaddr->flags |= CCW_FLAG_SLI; @@ -1219,10 +1286,10 @@ dasd_eckd_steal_lock(struct block_device *bdev, int no, long args) cqr = dasd_smalloc_request(dasd_eckd_discipline.name, 1, 32, device); - if (cqr == NULL) { - MESSAGE(KERN_WARNING, "%s", - "No memory to allocate initialization request"); - return -ENOMEM; + if (IS_ERR(cqr)) { + DEV_MESSAGE(KERN_WARNING, device, "%s", + "Could not allocate initialization request"); + return PTR_ERR(cqr); } cqr->cpaddr->cmd_code = DASD_ECKD_CCW_SLCK; cqr->cpaddr->flags |= CCW_FLAG_SLI; @@ -1263,10 +1330,10 @@ dasd_eckd_performance(struct block_device *bdev, int no, long args) (sizeof (struct dasd_psf_prssd_data) + sizeof (struct dasd_rssd_perf_stats_t)), device); - if (cqr == NULL) { - MESSAGE(KERN_WARNING, "%s", - "No memory to allocate initialization request"); - return -ENOMEM; + if (IS_ERR(cqr)) { + DEV_MESSAGE(KERN_WARNING, device, "%s", + "Could not allocate initialization request"); + return PTR_ERR(cqr); } cqr->device = device; cqr->retries = 0; @@ -1362,58 +1429,47 @@ dasd_eckd_set_attrib(struct block_device *bdev, int no, long args) sizeof (struct attrib_data_t))) { return -EFAULT; } - private = (struct dasd_eckd_private *) device->private; - private->attrib = attrib; - DBF_DEV_EVENT(DBF_ERR, device, - "cache operation mode set to " - "%x (%i cylinder prestage)", - private->attrib.operation, private->attrib.nr_cyl); - + DEV_MESSAGE(KERN_INFO, device, + "cache operation mode set to %x (%i cylinder prestage)", + private->attrib.operation, private->attrib.nr_cyl); return 0; } +/* + * Print sense data and related channel program. + * Parts are printed because printk buffer is only 1024 bytes. + */ static void dasd_eckd_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req, struct irb *irb) { - char *page; - struct ccw1 *act; - int len, sl, sct; + struct ccw1 *act, *end, *last; + int len, sl, sct, count; page = (char *) get_zeroed_page(GFP_ATOMIC); if (page == NULL) { - MESSAGE(KERN_ERR, "%s", "No memory to dump sense data"); + DEV_MESSAGE(KERN_ERR, device, " %s", + "No memory to dump sense data"); return; } len = sprintf(page, KERN_ERR PRINTK_HEADER - "device %s: I/O status report:\n", + " I/O status report for device %s:\n", device->cdev->dev.bus_id); len += sprintf(page + len, KERN_ERR PRINTK_HEADER - "in req: %p CS: 0x%02X DS: 0x%02X\n", req, + " in req: %p CS: 0x%02X DS: 0x%02X\n", req, irb->scsw.cstat, irb->scsw.dstat); len += sprintf(page + len, KERN_ERR PRINTK_HEADER - "Failing CCW: %p\n", + " device %s: Failing CCW: %p\n", + device->cdev->dev.bus_id, (void *) (addr_t) irb->scsw.cpa); - act = req->cpaddr; - do { - DBF_EVENT(DBF_INFO, - "CCW %p: %08X %08X", - act, ((int *) act)[0], ((int *) act)[1]); - DBF_EVENT(DBF_INFO, - "DAT: %08X %08X %08X %08X", - ((int *) (addr_t) act->cda)[0], - ((int *) (addr_t) act->cda)[1], - ((int *) (addr_t) act->cda)[2], - ((int *) (addr_t) act->cda)[3]); - } while (act++->flags & (CCW_FLAG_CC | CCW_FLAG_DC)); if (irb->esw.esw0.erw.cons) { for (sl = 0; sl < 4; sl++) { len += sprintf(page + len, KERN_ERR PRINTK_HEADER - "Sense(hex) %2d-%2d:", + " Sense(hex) %2d-%2d:", (8 * sl), ((8 * sl) + 7)); for (sct = 0; sct < 8; sct++) { @@ -1426,23 +1482,86 @@ dasd_eckd_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req, if (irb->ecw[27] & DASD_SENSE_BIT_0) { /* 24 Byte Sense Data */ len += sprintf(page + len, KERN_ERR PRINTK_HEADER - "24 Byte: %x MSG %x, %s MSGb to SYSOP\n", + " 24 Byte: %x MSG %x, " + "%s MSGb to SYSOP\n", irb->ecw[7] >> 4, irb->ecw[7] & 0x0f, irb->ecw[1] & 0x10 ? "" : "no"); } else { /* 32 Byte Sense Data */ len += sprintf(page + len, KERN_ERR PRINTK_HEADER - "32 Byte: Format: %x " + " 32 Byte: Format: %x " "Exception class %x\n", irb->ecw[6] & 0x0f, irb->ecw[22] >> 4); } } else { len += sprintf(page + len, KERN_ERR PRINTK_HEADER - "SORRY - NO VALID SENSE AVAILABLE\n"); + " SORRY - NO VALID SENSE AVAILABLE\n"); } + MESSAGE_LOG(KERN_ERR, "%s", + page + sizeof(KERN_ERR PRINTK_HEADER)); - MESSAGE(KERN_ERR, "Sense data:\n%s", page); + /* dump the Channel Program */ + /* print first CCWs (maximum 8) */ + act = req->cpaddr; + for (last = act; last->flags & (CCW_FLAG_CC | CCW_FLAG_DC); last++); + end = min(act + 8, last); + len = sprintf(page, KERN_ERR PRINTK_HEADER + " Related CP in req: %p\n", req); + while (act <= end) { + len += sprintf(page + len, KERN_ERR PRINTK_HEADER + " CCW %p: %08X %08X DAT:", + act, ((int *) act)[0], ((int *) act)[1]); + for (count = 0; count < 32 && count < act->count; + count += sizeof(int)) + len += sprintf(page + len, " %08X", + ((int *) (addr_t) act->cda) + [(count>>2)]); + len += sprintf(page + len, "\n"); + act++; + } + MESSAGE_LOG(KERN_ERR, "%s", + page + sizeof(KERN_ERR PRINTK_HEADER)); + + /* print failing CCW area */ + len = 0; + if (act < ((struct ccw1 *)(addr_t) irb->scsw.cpa) - 2) { + act = ((struct ccw1 *)(addr_t) irb->scsw.cpa) - 2; + len += sprintf(page + len, KERN_ERR PRINTK_HEADER "......\n"); + } + end = min((struct ccw1 *)(addr_t) irb->scsw.cpa + 2, last); + while (act <= end) { + len += sprintf(page + len, KERN_ERR PRINTK_HEADER + " CCW %p: %08X %08X DAT:", + act, ((int *) act)[0], ((int *) act)[1]); + for (count = 0; count < 32 && count < act->count; + count += sizeof(int)) + len += sprintf(page + len, " %08X", + ((int *) (addr_t) act->cda) + [(count>>2)]); + len += sprintf(page + len, "\n"); + act++; + } + /* print last CCWs */ + if (act < last - 2) { + act = last - 2; + len += sprintf(page + len, KERN_ERR PRINTK_HEADER "......\n"); + } + while (act <= last) { + len += sprintf(page + len, KERN_ERR PRINTK_HEADER + " CCW %p: %08X %08X DAT:", + act, ((int *) act)[0], ((int *) act)[1]); + for (count = 0; count < 32 && count < act->count; + count += sizeof(int)) + len += sprintf(page + len, " %08X", + ((int *) (addr_t) act->cda) + [(count>>2)]); + len += sprintf(page + len, "\n"); + act++; + } + if (len > 0) + MESSAGE_LOG(KERN_ERR, "%s", + page + sizeof(KERN_ERR PRINTK_HEADER)); free_page((unsigned long) page); } @@ -1474,6 +1593,7 @@ static struct dasd_discipline dasd_eckd_discipline = { .erp_action = dasd_eckd_erp_action, .erp_postaction = dasd_eckd_erp_postaction, .build_cp = dasd_eckd_build_cp, + .free_cp = dasd_eckd_free_cp, .dump_sense = dasd_eckd_dump_sense, .fill_info = dasd_eckd_fill_info, };