* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
*
- * $Revision: 1.54 $
*/
#include <linux/config.h>
#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)
struct dasd_eckd_private {
struct dasd_eckd_characteristics rdc_data;
struct dasd_eckd_confdata conf_data;
+ struct dasd_eckd_path path_data;
struct eckd_count count_area[5];
int init_cqr_status;
int uses_cdl;
{ CCW_DEVICE_DEVTYPE (0x3990, 0, 0x3380, 0), driver_info: 0x4},
{ CCW_DEVICE_DEVTYPE (0x2105, 0, 0x3380, 0), driver_info: 0x5},
{ CCW_DEVICE_DEVTYPE (0x9343, 0, 0x9345, 0), driver_info: 0x6},
+ { CCW_DEVICE_DEVTYPE (0x2107, 0, 0x3390, 0), driver_info: 0x7},
+ { CCW_DEVICE_DEVTYPE (0x2107, 0, 0x3380, 0), driver_info: 0x8},
+ { CCW_DEVICE_DEVTYPE (0x1750, 0, 0x3390, 0), driver_info: 0x9},
+ { CCW_DEVICE_DEVTYPE (0x1750, 0, 0x3380, 0), driver_info: 0xa},
{ /* end of list */ },
};
bpr = fl1 + fl2;
break;
default:
- MESSAGE(KERN_ERR, "unknown formula%d", rdc->formula);
bpr = 0;
break;
}
/* 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 ();
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;
}
data->attributes.mode = 0x3; /* ECKD */
- if (private->rdc_data.cu_type == 0x2105
+ if ((private->rdc_data.cu_type == 0x2105 ||
+ private->rdc_data.cu_type == 0x2107 ||
+ private->rdc_data.cu_type == 0x1750)
&& !(private->uses_cdl && trk < 2))
- data->ga_extended |= 0x40;
+ data->ga_extended |= 0x40; /* Regular Data Format Mode */
geo.cyl = private->rdc_data.no_cyl;
geo.head = private->rdc_data.trk_per_cyl;
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);
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;
return LABEL_SIZE;
}
+static int
+dasd_eckd_read_conf(struct dasd_device *device)
+{
+ void *conf_data;
+ int conf_len, conf_data_saved;
+ int rc;
+ __u8 lpm;
+ struct dasd_eckd_private *private;
+ struct dasd_eckd_path *path_data;
+
+ private = (struct dasd_eckd_private *) device->private;
+ path_data = (struct dasd_eckd_path *) &private->path_data;
+ path_data->opm = ccw_device_get_path_mask(device->cdev);
+ lpm = 0x80;
+ conf_data_saved = 0;
+
+ /* get configuration data per operational path */
+ for (lpm = 0x80; lpm; lpm>>= 1) {
+ if (lpm & path_data->opm){
+ rc = read_conf_data_lpm(device->cdev, &conf_data,
+ &conf_len, lpm);
+ if (rc && rc != -EOPNOTSUPP) { /* -EOPNOTSUPP is ok */
+ MESSAGE(KERN_WARNING,
+ "Read configuration data returned "
+ "error %d", rc);
+ return rc;
+ }
+ if (conf_data == NULL) {
+ MESSAGE(KERN_WARNING, "%s", "No configuration "
+ "data retrieved");
+ continue; /* 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));
+ kfree(conf_data);
+ continue; /* no errror */
+ }
+ /* save first valid configuration data */
+ if (!conf_data_saved){
+ memcpy(&private->conf_data, conf_data,
+ sizeof (struct dasd_eckd_confdata));
+ conf_data_saved++;
+ }
+ switch (((char *)conf_data)[242] & 0x07){
+ case 0x02:
+ path_data->npm |= lpm;
+ break;
+ case 0x03:
+ path_data->ppm |= lpm;
+ break;
+ }
+ kfree(conf_data);
+ }
+ }
+ return 0;
+}
+
+
static int
dasd_eckd_check_characteristics(struct dasd_device *device)
{
struct dasd_eckd_private *private;
void *rdc_data;
- void *conf_data;
- int conf_len;
int rc;
private = (struct dasd_eckd_private *) device->private;
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;
}
+ memset(private, 0, sizeof(struct dasd_eckd_private));
device->private = (void *) private;
}
/* Invalidate status of initial analysis. */
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;
}
private->rdc_data.sec_per_trk);
/* 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);
- return rc;
- }
- if (conf_data == NULL) {
- MESSAGE(KERN_WARNING, "%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));
- return 0; /* no errror */
- }
- memcpy(&private->conf_data, conf_data,
- sizeof (struct dasd_eckd_confdata));
+ rc = dasd_eckd_read_conf (device);
+ return rc;
- return 0;
}
static struct dasd_ccw_req *
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);
}
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. */
switch (cdev->id.cu_type) {
case 0x3990:
case 0x2105:
+ case 0x2107:
+ case 0x1750:
return dasd_3990_erp_examine(cqr, irb);
case 0x9343:
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;
}
}
switch (cdev->id.cu_type) {
case 0x3990:
case 0x2105:
+ case 0x2107:
+ case 0x1750:
return dasd_3990_erp_action;
case 0x9343:
- /* Return dasd_9343_erp_action; */
case 0x3880:
default:
return dasd_default_erp_action;
/* Eckd can only do full blocks. */
return ERR_PTR(-EINVAL);
count += bv->bv_len >> (device->s2b_shift + 9);
-#if defined(CONFIG_ARCH_S390X)
- cidaw += idal_nr_words(page_address(bv->bv_page) +
- bv->bv_offset, bv->bv_len);
+#if defined(CONFIG_64BIT)
+ if (idal_is_needed (page_address(bv->bv_page),
+ bv->bv_len))
+ cidaw += bv->bv_len >> (device->s2b_shift + 9);
#endif
}
}
}
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);
if (dasd_eckd_cdl_special(blk_per_trk, recid)){
rcmd |= 0x8;
count = dasd_eckd_cdl_reclen(recid);
- if (count < blksize)
+ if (count < blksize &&
+ rq_data_dir(req) == READ)
memset(dst + count, 0xe5,
blksize - count);
}
recid++;
}
}
+ if (req->flags & REQ_FAILFAST)
+ set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
cqr->device = device;
cqr->expires = 5 * 60 * HZ; /* 5 minutes */
- cqr->lpm = LPM_ANYPATH;
- cqr->retries = 2;
+ cqr->lpm = private->path_data.ppm;
+ cqr->retries = 256;
cqr->buildclk = get_clock();
cqr->status = DASD_CQR_FILLED;
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)
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;
cqr->cpaddr->cda = (__u32)(addr_t) cqr->data;
cqr->device = device;
clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
+ set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
cqr->retries = 0;
cqr->expires = 2 * HZ;
cqr->buildclk = get_clock();
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;
cqr->cpaddr->cda = (__u32)(addr_t) cqr->data;
cqr->device = device;
clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
+ set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
cqr->retries = 0;
cqr->expires = 2 * HZ;
cqr->buildclk = get_clock();
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;
cqr->cpaddr->cda = (__u32)(addr_t) cqr->data;
cqr->device = device;
clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
+ set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
cqr->retries = 0;
cqr->expires = 2 * HZ;
cqr->buildclk = get_clock();
(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;
/* Prepare for Read Subsystem Data */
prssdp = (struct dasd_psf_prssd_data *) cqr->data;
stats = (struct dasd_rssd_perf_stats_t *) (prssdp + 1);
- rc = copy_to_user((long *) args, (long *) stats,
+ rc = copy_to_user((long __user *) args, (long *) stats,
sizeof(struct dasd_rssd_perf_stats_t));
}
dasd_sfree_request(cqr, cqr->device);
private = (struct dasd_eckd_private *) device->private;
attrib = private->attrib;
-
- rc = copy_to_user((long *) args, (long *) &attrib,
+
+ rc = copy_to_user((long __user *) args, (long *) &attrib,
sizeof (struct attrib_data_t));
-
+
return rc;
}
if (device == NULL)
return -ENODEV;
- if (copy_from_user(&attrib, (void *) args,
+ if (copy_from_user(&attrib, (void __user *) 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++) {
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);
}
.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,
};