diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/s390/block/dasd_3990_erp.c |
Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/s390/block/dasd_3990_erp.c')
-rw-r--r-- | drivers/s390/block/dasd_3990_erp.c | 2742 |
1 files changed, 2742 insertions, 0 deletions
diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c new file mode 100644 index 000000000000..c143ecb53d9d --- /dev/null +++ b/drivers/s390/block/dasd_3990_erp.c @@ -0,0 +1,2742 @@ +/* + * File...........: linux/drivers/s390/block/dasd_3990_erp.c + * Author(s)......: Horst Hummel <Horst.Hummel@de.ibm.com> + * Holger Smolinski <Holger.Smolinski@de.ibm.com> + * Bugreports.to..: <Linux390@de.ibm.com> + * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000, 2001 + * + * $Revision: 1.36 $ + */ + +#include <linux/timer.h> +#include <linux/slab.h> +#include <asm/idals.h> +#include <asm/todclk.h> + +#define PRINTK_HEADER "dasd_erp(3990): " + +#include "dasd_int.h" +#include "dasd_eckd.h" + + +struct DCTL_data { + unsigned char subcommand; /* e.g Inhibit Write, Enable Write,... */ + unsigned char modifier; /* Subcommand modifier */ + unsigned short res; /* reserved */ +} __attribute__ ((packed)); + +/* + ***************************************************************************** + * SECTION ERP EXAMINATION + ***************************************************************************** + */ + +/* + * DASD_3990_ERP_EXAMINE_24 + * + * DESCRIPTION + * Checks only for fatal (unrecoverable) error. + * A detailed examination of the sense data is done later outside + * the interrupt handler. + * + * Each bit configuration leading to an action code 2 (Exit with + * programming error or unusual condition indication) + * are handled as fatal errorīs. + * + * All other configurations are handled as recoverable errors. + * + * RETURN VALUES + * dasd_era_fatal for all fatal (unrecoverable errors) + * dasd_era_recover for all others. + */ +static dasd_era_t +dasd_3990_erp_examine_24(struct dasd_ccw_req * cqr, char *sense) +{ + + struct dasd_device *device = cqr->device; + + /* check for 'Command Reject' */ + if ((sense[0] & SNS0_CMD_REJECT) && + (!(sense[2] & SNS2_ENV_DATA_PRESENT))) { + + DEV_MESSAGE(KERN_ERR, device, "%s", + "EXAMINE 24: Command Reject detected - " + "fatal error"); + + return dasd_era_fatal; + } + + /* check for 'Invalid Track Format' */ + if ((sense[1] & SNS1_INV_TRACK_FORMAT) && + (!(sense[2] & SNS2_ENV_DATA_PRESENT))) { + + DEV_MESSAGE(KERN_ERR, device, "%s", + "EXAMINE 24: Invalid Track Format detected " + "- fatal error"); + + return dasd_era_fatal; + } + + /* check for 'No Record Found' */ + if (sense[1] & SNS1_NO_REC_FOUND) { + + /* FIXME: fatal error ?!? */ + DEV_MESSAGE(KERN_ERR, device, + "EXAMINE 24: No Record Found detected %s", + device->state <= DASD_STATE_BASIC ? + " " : "- fatal error"); + + return dasd_era_fatal; + } + + /* return recoverable for all others */ + return dasd_era_recover; +} /* END dasd_3990_erp_examine_24 */ + +/* + * DASD_3990_ERP_EXAMINE_32 + * + * DESCRIPTION + * Checks only for fatal/no/recoverable error. + * A detailed examination of the sense data is done later outside + * the interrupt handler. + * + * RETURN VALUES + * dasd_era_none no error + * dasd_era_fatal for all fatal (unrecoverable errors) + * dasd_era_recover for recoverable others. + */ +static dasd_era_t +dasd_3990_erp_examine_32(struct dasd_ccw_req * cqr, char *sense) +{ + + struct dasd_device *device = cqr->device; + + switch (sense[25]) { + case 0x00: + return dasd_era_none; + + case 0x01: + DEV_MESSAGE(KERN_ERR, device, "%s", "EXAMINE 32: fatal error"); + + return dasd_era_fatal; + + default: + + return dasd_era_recover; + } + +} /* end dasd_3990_erp_examine_32 */ + +/* + * DASD_3990_ERP_EXAMINE + * + * DESCRIPTION + * Checks only for fatal/no/recover error. + * A detailed examination of the sense data is done later outside + * the interrupt handler. + * + * The logic is based on the 'IBM 3990 Storage Control Reference' manual + * 'Chapter 7. Error Recovery Procedures'. + * + * RETURN VALUES + * dasd_era_none no error + * dasd_era_fatal for all fatal (unrecoverable errors) + * dasd_era_recover for all others. + */ +dasd_era_t +dasd_3990_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb) +{ + + char *sense = irb->ecw; + dasd_era_t era = dasd_era_recover; + struct dasd_device *device = cqr->device; + + /* check for successful execution first */ + if (irb->scsw.cstat == 0x00 && + irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) + return dasd_era_none; + + /* distinguish between 24 and 32 byte sense data */ + if (sense[27] & DASD_SENSE_BIT_0) { + + era = dasd_3990_erp_examine_24(cqr, sense); + + } else { + + era = dasd_3990_erp_examine_32(cqr, sense); + + } + + /* log the erp chain if fatal error occurred */ + if ((era == dasd_era_fatal) && (device->state >= DASD_STATE_READY)) { + dasd_log_sense(cqr, irb); + dasd_log_ccw(cqr, 0, irb->scsw.cpa); + } + + return era; + +} /* END dasd_3990_erp_examine */ + +/* + ***************************************************************************** + * SECTION ERP HANDLING + ***************************************************************************** + */ +/* + ***************************************************************************** + * 24 and 32 byte sense ERP functions + ***************************************************************************** + */ + +/* + * DASD_3990_ERP_CLEANUP + * + * DESCRIPTION + * Removes the already build but not necessary ERP request and sets + * the status of the original cqr / erp to the given (final) status + * + * PARAMETER + * erp request to be blocked + * final_status either DASD_CQR_DONE or DASD_CQR_FAILED + * + * RETURN VALUES + * cqr original cqr + */ +static struct dasd_ccw_req * +dasd_3990_erp_cleanup(struct dasd_ccw_req * erp, char final_status) +{ + struct dasd_ccw_req *cqr = erp->refers; + + dasd_free_erp_request(erp, erp->device); + cqr->status = final_status; + return cqr; + +} /* end dasd_3990_erp_cleanup */ + +/* + * DASD_3990_ERP_BLOCK_QUEUE + * + * DESCRIPTION + * Block the given device request queue to prevent from further + * processing until the started timer has expired or an related + * interrupt was received. + */ +static void +dasd_3990_erp_block_queue(struct dasd_ccw_req * erp, int expires) +{ + + struct dasd_device *device = erp->device; + + DEV_MESSAGE(KERN_INFO, device, + "blocking request queue for %is", expires/HZ); + + device->stopped |= DASD_STOPPED_PENDING; + erp->status = DASD_CQR_QUEUED; + + dasd_set_timer(device, expires); +} + +/* + * DASD_3990_ERP_INT_REQ + * + * DESCRIPTION + * Handles 'Intervention Required' error. + * This means either device offline or not installed. + * + * PARAMETER + * erp current erp + * RETURN VALUES + * erp modified erp + */ +static struct dasd_ccw_req * +dasd_3990_erp_int_req(struct dasd_ccw_req * erp) +{ + + struct dasd_device *device = erp->device; + + /* first time set initial retry counter and erp_function */ + /* and retry once without blocking queue */ + /* (this enables easier enqueing of the cqr) */ + if (erp->function != dasd_3990_erp_int_req) { + + erp->retries = 256; + erp->function = dasd_3990_erp_int_req; + + } else { + + /* issue a message and wait for 'device ready' interrupt */ + DEV_MESSAGE(KERN_ERR, device, "%s", + "is offline or not installed - " + "INTERVENTION REQUIRED!!"); + + dasd_3990_erp_block_queue(erp, 60*HZ); + } + + return erp; + +} /* end dasd_3990_erp_int_req */ + +/* + * DASD_3990_ERP_ALTERNATE_PATH + * + * DESCRIPTION + * Repeat the operation on a different channel path. + * If all alternate paths have been tried, the request is posted with a + * permanent error. + * + * PARAMETER + * erp pointer to the current ERP + * + * RETURN VALUES + * erp modified pointer to the ERP + */ +static void +dasd_3990_erp_alternate_path(struct dasd_ccw_req * erp) +{ + struct dasd_device *device = erp->device; + __u8 opm; + + /* try alternate valid path */ + opm = ccw_device_get_path_mask(device->cdev); + //FIXME: start with get_opm ? + if (erp->lpm == 0) + erp->lpm = LPM_ANYPATH & ~(erp->irb.esw.esw0.sublog.lpum); + else + erp->lpm &= ~(erp->irb.esw.esw0.sublog.lpum); + + if ((erp->lpm & opm) != 0x00) { + + DEV_MESSAGE(KERN_DEBUG, device, + "try alternate lpm=%x (lpum=%x / opm=%x)", + erp->lpm, erp->irb.esw.esw0.sublog.lpum, opm); + + /* reset status to queued to handle the request again... */ + if (erp->status > DASD_CQR_QUEUED) + erp->status = DASD_CQR_QUEUED; + erp->retries = 1; + } else { + DEV_MESSAGE(KERN_ERR, device, + "No alternate channel path left (lpum=%x / " + "opm=%x) -> permanent error", + erp->irb.esw.esw0.sublog.lpum, opm); + + /* post request with permanent error */ + if (erp->status > DASD_CQR_QUEUED) + erp->status = DASD_CQR_FAILED; + } +} /* end dasd_3990_erp_alternate_path */ + +/* + * DASD_3990_ERP_DCTL + * + * DESCRIPTION + * Setup cqr to do the Diagnostic Control (DCTL) command with an + * Inhibit Write subcommand (0x20) and the given modifier. + * + * PARAMETER + * erp pointer to the current (failed) ERP + * modifier subcommand modifier + * + * RETURN VALUES + * dctl_cqr pointer to NEW dctl_cqr + * + */ +static struct dasd_ccw_req * +dasd_3990_erp_DCTL(struct dasd_ccw_req * erp, char modifier) +{ + + struct dasd_device *device = erp->device; + struct DCTL_data *DCTL_data; + struct ccw1 *ccw; + struct dasd_ccw_req *dctl_cqr; + + dctl_cqr = dasd_alloc_erp_request((char *) &erp->magic, 1, + sizeof (struct DCTL_data), + erp->device); + if (IS_ERR(dctl_cqr)) { + DEV_MESSAGE(KERN_ERR, device, "%s", + "Unable to allocate DCTL-CQR"); + erp->status = DASD_CQR_FAILED; + return erp; + } + + DCTL_data = dctl_cqr->data; + + DCTL_data->subcommand = 0x02; /* Inhibit Write */ + DCTL_data->modifier = modifier; + + ccw = dctl_cqr->cpaddr; + memset(ccw, 0, sizeof (struct ccw1)); + ccw->cmd_code = CCW_CMD_DCTL; + ccw->count = 4; + ccw->cda = (__u32)(addr_t) DCTL_data; + dctl_cqr->function = dasd_3990_erp_DCTL; + dctl_cqr->refers = erp; + dctl_cqr->device = erp->device; + dctl_cqr->magic = erp->magic; + dctl_cqr->expires = 5 * 60 * HZ; + dctl_cqr->retries = 2; + + dctl_cqr->buildclk = get_clock(); + + dctl_cqr->status = DASD_CQR_FILLED; + + return dctl_cqr; + +} /* end dasd_3990_erp_DCTL */ + +/* + * DASD_3990_ERP_ACTION_1 + * + * DESCRIPTION + * Setup ERP to do the ERP action 1 (see Reference manual). + * Repeat the operation on a different channel path. + * If all alternate paths have been tried, the request is posted with a + * permanent error. + * Note: duplex handling is not implemented (yet). + * + * PARAMETER + * erp pointer to the current ERP + * + * RETURN VALUES + * erp pointer to the ERP + * + */ +static struct dasd_ccw_req * +dasd_3990_erp_action_1(struct dasd_ccw_req * erp) +{ + + erp->function = dasd_3990_erp_action_1; + + dasd_3990_erp_alternate_path(erp); + + return erp; + +} /* end dasd_3990_erp_action_1 */ + +/* + * DASD_3990_ERP_ACTION_4 + * + * DESCRIPTION + * Setup ERP to do the ERP action 4 (see Reference manual). + * Set the current request to PENDING to block the CQR queue for that device + * until the state change interrupt appears. + * Use a timer (20 seconds) to retry the cqr if the interrupt is still + * missing. + * + * PARAMETER + * sense sense data of the actual error + * erp pointer to the current ERP + * + * RETURN VALUES + * erp pointer to the ERP + * + */ +static struct dasd_ccw_req * +dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense) +{ + + struct dasd_device *device = erp->device; + + /* first time set initial retry counter and erp_function */ + /* and retry once without waiting for state change pending */ + /* interrupt (this enables easier enqueing of the cqr) */ + if (erp->function != dasd_3990_erp_action_4) { + + DEV_MESSAGE(KERN_INFO, device, "%s", + "dasd_3990_erp_action_4: first time retry"); + + erp->retries = 256; + erp->function = dasd_3990_erp_action_4; + + } else { + + if (sense[25] == 0x1D) { /* state change pending */ + + DEV_MESSAGE(KERN_INFO, device, + "waiting for state change pending " + "interrupt, %d retries left", + erp->retries); + + dasd_3990_erp_block_queue(erp, 30*HZ); + + } else if (sense[25] == 0x1E) { /* busy */ + DEV_MESSAGE(KERN_INFO, device, + "busy - redriving request later, " + "%d retries left", + erp->retries); + dasd_3990_erp_block_queue(erp, HZ); + } else { + + /* no state change pending - retry */ + DEV_MESSAGE (KERN_INFO, device, + "redriving request immediately, " + "%d retries left", + erp->retries); + erp->status = DASD_CQR_QUEUED; + } + } + + return erp; + +} /* end dasd_3990_erp_action_4 */ + +/* + ***************************************************************************** + * 24 byte sense ERP functions (only) + ***************************************************************************** + */ + +/* + * DASD_3990_ERP_ACTION_5 + * + * DESCRIPTION + * Setup ERP to do the ERP action 5 (see Reference manual). + * NOTE: Further handling is done in xxx_further_erp after the retries. + * + * PARAMETER + * erp pointer to the current ERP + * + * RETURN VALUES + * erp pointer to the ERP + * + */ +static struct dasd_ccw_req * +dasd_3990_erp_action_5(struct dasd_ccw_req * erp) +{ + + /* first of all retry */ + erp->retries = 10; + erp->function = dasd_3990_erp_action_5; + + return erp; + +} /* end dasd_3990_erp_action_5 */ + +/* + * DASD_3990_HANDLE_ENV_DATA + * + * DESCRIPTION + * Handles 24 byte 'Environmental data present'. + * Does a analysis of the sense data (message Format) + * and prints the error messages. + * + * PARAMETER + * sense current sense data + * + * RETURN VALUES + * void + */ +static void +dasd_3990_handle_env_data(struct dasd_ccw_req * erp, char *sense) +{ + + struct dasd_device *device = erp->device; + char msg_format = (sense[7] & 0xF0); + char msg_no = (sense[7] & 0x0F); + + switch (msg_format) { + case 0x00: /* Format 0 - Program or System Checks */ + + if (sense[1] & 0x10) { /* check message to operator bit */ + + switch (msg_no) { + case 0x00: /* No Message */ + break; + case 0x01: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 0 - Invalid Command"); + break; + case 0x02: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 0 - Invalid Command " + "Sequence"); + break; + case 0x03: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 0 - CCW Count less than " + "required"); + break; + case 0x04: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 0 - Invalid Parameter"); + break; + case 0x05: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 0 - Diagnostic of Sepecial" + " Command Violates File Mask"); + break; + case 0x07: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 0 - Channel Returned with " + "Incorrect retry CCW"); + break; + case 0x08: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 0 - Reset Notification"); + break; + case 0x09: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 0 - Storage Path Restart"); + break; + case 0x0A: + DEV_MESSAGE(KERN_WARNING, device, + "FORMAT 0 - Channel requested " + "... %02x", sense[8]); + break; + case 0x0B: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 0 - Invalid Defective/" + "Alternate Track Pointer"); + break; + case 0x0C: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 0 - DPS Installation " + "Check"); + break; + case 0x0E: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 0 - Command Invalid on " + "Secondary Address"); + break; + case 0x0F: + DEV_MESSAGE(KERN_WARNING, device, + "FORMAT 0 - Status Not As " + "Required: reason %02x", sense[8]); + break; + default: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 0 - Reseved"); + } + } else { + switch (msg_no) { + case 0x00: /* No Message */ + break; + case 0x01: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 0 - Device Error Source"); + break; + case 0x02: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 0 - Reserved"); + break; + case 0x03: + DEV_MESSAGE(KERN_WARNING, device, + "FORMAT 0 - Device Fenced - " + "device = %02x", sense[4]); + break; + case 0x04: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 0 - Data Pinned for " + "Device"); + break; + default: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 0 - Reserved"); + } + } + break; + + case 0x10: /* Format 1 - Device Equipment Checks */ + switch (msg_no) { + case 0x00: /* No Message */ + break; + case 0x01: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 1 - Device Status 1 not as " + "expected"); + break; + case 0x03: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 1 - Index missing"); + break; + case 0x04: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 1 - Interruption cannot be reset"); + break; + case 0x05: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 1 - Device did not respond to " + "selection"); + break; + case 0x06: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 1 - Device check-2 error or Set " + "Sector is not complete"); + break; + case 0x07: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 1 - Head address does not " + "compare"); + break; + case 0x08: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 1 - Device status 1 not valid"); + break; + case 0x09: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 1 - Device not ready"); + break; + case 0x0A: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 1 - Track physical address did " + "not compare"); + break; + case 0x0B: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 1 - Missing device address bit"); + break; + case 0x0C: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 1 - Drive motor switch is off"); + break; + case 0x0D: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 1 - Seek incomplete"); + break; + case 0x0E: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 1 - Cylinder address did not " + "compare"); + break; + case 0x0F: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 1 - Offset active cannot be " + "reset"); + break; + default: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 1 - Reserved"); + } + break; + + case 0x20: /* Format 2 - 3990 Equipment Checks */ + switch (msg_no) { + case 0x08: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 2 - 3990 check-2 error"); + break; + case 0x0E: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 2 - Support facility errors"); + break; + case 0x0F: + DEV_MESSAGE(KERN_WARNING, device, + "FORMAT 2 - Microcode detected error %02x", + sense[8]); + break; + default: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 2 - Reserved"); + } + break; + + case 0x30: /* Format 3 - 3990 Control Checks */ + switch (msg_no) { + case 0x0F: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 3 - Allegiance terminated"); + break; + default: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 3 - Reserved"); + } + break; + + case 0x40: /* Format 4 - Data Checks */ + switch (msg_no) { + case 0x00: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 4 - Home address area error"); + break; + case 0x01: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 4 - Count area error"); + break; + case 0x02: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 4 - Key area error"); + break; + case 0x03: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 4 - Data area error"); + break; + case 0x04: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 4 - No sync byte in home address " + "area"); + break; + case 0x05: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 4 - No sync byte in count address " + "area"); + break; + case 0x06: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 4 - No sync byte in key area"); + break; + case 0x07: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 4 - No sync byte in data area"); + break; + case 0x08: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 4 - Home address area error; " + "offset active"); + break; + case 0x09: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 4 - Count area error; offset " + "active"); + break; + case 0x0A: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 4 - Key area error; offset " + "active"); + break; + case 0x0B: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 4 - Data area error; " + "offset active"); + break; + case 0x0C: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 4 - No sync byte in home " + "address area; offset active"); + break; + case 0x0D: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 4 - No syn byte in count " + "address area; offset active"); + break; + case 0x0E: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 4 - No sync byte in key area; " + "offset active"); + break; + case 0x0F: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 4 - No syn byte in data area; " + "offset active"); + break; + default: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 4 - Reserved"); + } + break; + + case 0x50: /* Format 5 - Data Check with displacement information */ + switch (msg_no) { + case 0x00: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 5 - Data Check in the " + "home address area"); + break; + case 0x01: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 5 - Data Check in the count area"); + break; + case 0x02: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 5 - Data Check in the key area"); + break; + case 0x03: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 5 - Data Check in the data area"); + break; + case 0x08: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 5 - Data Check in the " + "home address area; offset active"); + break; + case 0x09: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 5 - Data Check in the count area; " + "offset active"); + break; + case 0x0A: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 5 - Data Check in the key area; " + "offset active"); + break; + case 0x0B: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 5 - Data Check in the data area; " + "offset active"); + break; + default: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 5 - Reserved"); + } + break; + + case 0x60: /* Format 6 - Usage Statistics/Overrun Errors */ + switch (msg_no) { + case 0x00: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 6 - Overrun on channel A"); + break; + case 0x01: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 6 - Overrun on channel B"); + break; + case 0x02: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 6 - Overrun on channel C"); + break; + case 0x03: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 6 - Overrun on channel D"); + break; + case 0x04: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 6 - Overrun on channel E"); + break; + case 0x05: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 6 - Overrun on channel F"); + break; + case 0x06: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 6 - Overrun on channel G"); + break; + case 0x07: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 6 - Overrun on channel H"); + break; + default: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 6 - Reserved"); + } + break; + + case 0x70: /* Format 7 - Device Connection Control Checks */ + switch (msg_no) { + case 0x00: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 7 - RCC initiated by a connection " + "check alert"); + break; + case 0x01: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 7 - RCC 1 sequence not " + "successful"); + break; + case 0x02: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 7 - RCC 1 and RCC 2 sequences not " + "successful"); + break; + case 0x03: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 7 - Invalid tag-in during " + "selection sequence"); + break; + case 0x04: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 7 - extra RCC required"); + break; + case 0x05: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 7 - Invalid DCC selection " + "response or timeout"); + break; + case 0x06: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 7 - Missing end operation; device " + "transfer complete"); + break; + case 0x07: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 7 - Missing end operation; device " + "transfer incomplete"); + break; + case 0x08: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 7 - Invalid tag-in for an " + "immediate command sequence"); + break; + case 0x09: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 7 - Invalid tag-in for an " + "extended command sequence"); + break; + case 0x0A: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 7 - 3990 microcode time out when " + "stopping selection"); + break; + case 0x0B: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 7 - No response to selection " + "after a poll interruption"); + break; + case 0x0C: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 7 - Permanent path error (DASD " + "controller not available)"); + break; + case 0x0D: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 7 - DASD controller not available" + " on disconnected command chain"); + break; + default: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 7 - Reserved"); + } + break; + + case 0x80: /* Format 8 - Additional Device Equipment Checks */ + switch (msg_no) { + case 0x00: /* No Message */ + case 0x01: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 8 - Error correction code " + "hardware fault"); + break; + case 0x03: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 8 - Unexpected end operation " + "response code"); + break; + case 0x04: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 8 - End operation with transfer " + "count not zero"); + break; + case 0x05: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 8 - End operation with transfer " + "count zero"); + break; + case 0x06: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 8 - DPS checks after a system " + "reset or selective reset"); + break; + case 0x07: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 8 - DPS cannot be filled"); + break; + case 0x08: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 8 - Short busy time-out during " + "device selection"); + break; + case 0x09: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 8 - DASD controller failed to " + "set or reset the long busy latch"); + break; + case 0x0A: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 8 - No interruption from device " + "during a command chain"); + break; + default: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 8 - Reserved"); + } + break; + + case 0x90: /* Format 9 - Device Read, Write, and Seek Checks */ + switch (msg_no) { + case 0x00: + break; /* No Message */ + case 0x06: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 9 - Device check-2 error"); + break; + case 0x07: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 9 - Head address did not compare"); + break; + case 0x0A: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 9 - Track physical address did " + "not compare while oriented"); + break; + case 0x0E: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 9 - Cylinder address did not " + "compare"); + break; + default: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT 9 - Reserved"); + } + break; + + case 0xF0: /* Format F - Cache Storage Checks */ + switch (msg_no) { + case 0x00: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT F - Operation Terminated"); + break; + case 0x01: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT F - Subsystem Processing Error"); + break; + case 0x02: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT F - Cache or nonvolatile storage " + "equipment failure"); + break; + case 0x04: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT F - Caching terminated"); + break; + case 0x06: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT F - Cache fast write access not " + "authorized"); + break; + case 0x07: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT F - Track format incorrect"); + break; + case 0x09: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT F - Caching reinitiated"); + break; + case 0x0A: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT F - Nonvolatile storage " + "terminated"); + break; + case 0x0B: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT F - Volume is suspended duplex"); + break; + case 0x0C: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT F - Subsystem status connot be " + "determined"); + break; + case 0x0D: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT F - Caching status reset to " + "default"); + break; + case 0x0E: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT F - DASD Fast Write inhibited"); + break; + default: + DEV_MESSAGE(KERN_WARNING, device, "%s", + "FORMAT D - Reserved"); + } + break; + + default: /* unknown message format - should not happen */ + DEV_MESSAGE (KERN_WARNING, device, + "unknown message format %02x", + msg_format); + break; + } /* end switch message format */ + +} /* end dasd_3990_handle_env_data */ + +/* + * DASD_3990_ERP_COM_REJ + * + * DESCRIPTION + * Handles 24 byte 'Command Reject' error. + * + * PARAMETER + * erp current erp_head + * sense current sense data + * + * RETURN VALUES + * erp 'new' erp_head - pointer to new ERP + */ +static struct dasd_ccw_req * +dasd_3990_erp_com_rej(struct dasd_ccw_req * erp, char *sense) +{ + + struct dasd_device *device = erp->device; + + erp->function = dasd_3990_erp_com_rej; + + /* env data present (ACTION 10 - retry should work) */ + if (sense[2] & SNS2_ENV_DATA_PRESENT) { + + DEV_MESSAGE(KERN_DEBUG, device, "%s", + "Command Reject - environmental data present"); + + dasd_3990_handle_env_data(erp, sense); + + erp->retries = 5; + + } else { + /* fatal error - set status to FAILED */ + DEV_ME |