📄 dasd_3990_erp.c
字号:
dasd_3990_erp_compound_path(erp, sense); } if ((erp->function == dasd_3990_erp_compound_path) && (erp->status == DASD_CQR_ERROR)) { erp = dasd_3990_erp_compound_code(erp, sense); } if ((erp->function == dasd_3990_erp_compound_code) && (erp->status == DASD_CQR_ERROR)) { dasd_3990_erp_compound_config(erp, sense); } /* if no compound action ERP specified, the request failed */ if (erp->status == DASD_CQR_ERROR) { erp->status = DASD_CQR_FAILED; } return erp;} /* end dasd_3990_erp_compound *//* * DASD_3990_ERP_INSPECT_32 * * DESCRIPTION * Does a detailed inspection of the 32 byte sense data * and sets up a related error recovery action. * * PARAMETER * sense sense data of the actual error * erp pointer to the currently created default ERP * * RETURN VALUES * erp_filled pointer to the ERP * */static struct dasd_ccw_req *dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense){ struct dasd_device *device = erp->device; erp->function = dasd_3990_erp_inspect_32; if (sense[25] & DASD_SENSE_BIT_0) { /* compound program action codes (byte25 bit 0 == '1') */ dasd_3990_erp_compound_retry(erp, sense); } else { /* single program action codes (byte25 bit 0 == '0') */ switch (sense[25]) { case 0x00: /* success - use default ERP for retries */ DEV_MESSAGE(KERN_DEBUG, device, "%s", "ERP called for successful request" " - just retry"); break; case 0x01: /* fatal error */ DEV_MESSAGE(KERN_ERR, device, "%s", "Fatal error should have been " "handled within the interrupt handler"); erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED); break; case 0x02: /* intervention required */ case 0x03: /* intervention required during dual copy */ erp = dasd_3990_erp_int_req(erp); break; case 0x0F: /* length mismatch during update write command */ DEV_MESSAGE(KERN_ERR, device, "%s", "update write command error - should not " "happen;\n" "Please send this message together with " "the above sense data to linux390@de." "ibm.com"); erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED); break; case 0x10: /* logging required for other channel program */ erp = dasd_3990_erp_action_10_32(erp, sense); break; case 0x15: /* next track outside defined extend */ DEV_MESSAGE(KERN_ERR, device, "%s", "next track outside defined extend - " "should not happen;\n" "Please send this message together with " "the above sense data to linux390@de." "ibm.com"); erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED); break; case 0x1B: /* unexpected condition during write */ erp = dasd_3990_erp_action_1B_32(erp, sense); break; case 0x1C: /* invalid data */ DEV_MESSAGE(KERN_EMERG, device, "%s", "Data recovered during retry with PCI " "fetch mode active"); /* not possible to handle this situation in Linux */ panic ("Invalid data - No way to inform application " "about the possibly incorrect data"); break; case 0x1D: /* state-change pending */ DEV_MESSAGE(KERN_DEBUG, device, "%s", "A State change pending condition exists " "for the subsystem or device"); erp = dasd_3990_erp_action_4(erp, sense); break; case 0x1E: /* busy */ DEV_MESSAGE(KERN_DEBUG, device, "%s", "Busy condition exists " "for the subsystem or device"); erp = dasd_3990_erp_action_4(erp, sense); break; default: /* all others errors - default erp */ break; } } return erp;} /* end dasd_3990_erp_inspect_32 *//* ***************************************************************************** * main ERP control fuctions (24 and 32 byte sense) ***************************************************************************** *//* * DASD_3990_ERP_INSPECT * * DESCRIPTION * Does a detailed inspection for sense data by calling either * the 24-byte or the 32-byte inspection routine. * * PARAMETER * erp pointer to the currently created default ERP * RETURN VALUES * erp_new contens was possibly modified */static struct dasd_ccw_req *dasd_3990_erp_inspect(struct dasd_ccw_req * erp){ struct dasd_ccw_req *erp_new = NULL; /* sense data are located in the refers record of the */ /* already set up new ERP ! */ char *sense = erp->refers->irb.ecw; /* distinguish between 24 and 32 byte sense data */ if (sense[27] & DASD_SENSE_BIT_0) { /* inspect the 24 byte sense data */ erp_new = dasd_3990_erp_inspect_24(erp, sense); } else { /* inspect the 32 byte sense data */ erp_new = dasd_3990_erp_inspect_32(erp, sense); } /* end distinguish between 24 and 32 byte sense data */ return erp_new;}/* * DASD_3990_ERP_ADD_ERP * * DESCRIPTION * This funtion adds an additional request block (ERP) to the head of * the given cqr (or erp). * This erp is initialized as an default erp (retry TIC) * * PARAMETER * cqr head of the current ERP-chain (or single cqr if * first error) * RETURN VALUES * erp pointer to new ERP-chain head */static struct dasd_ccw_req *dasd_3990_erp_add_erp(struct dasd_ccw_req * cqr){ struct dasd_device *device = cqr->device; struct ccw1 *ccw; /* allocate additional request block */ struct dasd_ccw_req *erp; erp = dasd_alloc_erp_request((char *) &cqr->magic, 2, 0, cqr->device); if (IS_ERR(erp)) { if (cqr->retries <= 0) { DEV_MESSAGE(KERN_ERR, device, "%s", "Unable to allocate ERP request"); cqr->status = DASD_CQR_FAILED; cqr->stopclk = get_clock (); } else { DEV_MESSAGE (KERN_ERR, device, "Unable to allocate ERP request " "(%i retries left)", cqr->retries); dasd_set_timer(device, (HZ << 3)); } return cqr; } /* initialize request with default TIC to current ERP/CQR */ ccw = erp->cpaddr; ccw->cmd_code = CCW_CMD_NOOP; ccw->flags = CCW_FLAG_CC; ccw++; ccw->cmd_code = CCW_CMD_TIC; ccw->cda = (long)(cqr->cpaddr); erp->function = dasd_3990_erp_add_erp; erp->refers = cqr; erp->device = cqr->device; erp->magic = cqr->magic; erp->expires = 0; erp->retries = 256; erp->buildclk = get_clock(); erp->status = DASD_CQR_FILLED; return erp;}/* * DASD_3990_ERP_ADDITIONAL_ERP * * DESCRIPTION * An additional ERP is needed to handle the current error. * Add ERP to the head of the ERP-chain containing the ERP processing * determined based on the sense data. * * PARAMETER * cqr head of the current ERP-chain (or single cqr if * first error) * * RETURN VALUES * erp pointer to new ERP-chain head */static struct dasd_ccw_req *dasd_3990_erp_additional_erp(struct dasd_ccw_req * cqr){ struct dasd_ccw_req *erp = NULL; /* add erp and initialize with default TIC */ erp = dasd_3990_erp_add_erp(cqr); /* inspect sense, determine specific ERP if possible */ if (erp != cqr) { erp = dasd_3990_erp_inspect(erp); } return erp;} /* end dasd_3990_erp_additional_erp *//* * DASD_3990_ERP_ERROR_MATCH * * DESCRIPTION * Check if the device status of the given cqr is the same. * This means that the failed CCW and the relevant sense data * must match. * I don't distinguish between 24 and 32 byte sense because in case of * 24 byte sense byte 25 and 27 is set as well. * * PARAMETER * cqr1 first cqr, which will be compared with the * cqr2 second cqr. * * RETURN VALUES * match 'boolean' for match found * returns 1 if match found, otherwise 0. */static intdasd_3990_erp_error_match(struct dasd_ccw_req *cqr1, struct dasd_ccw_req *cqr2){ /* check failed CCW */ if (cqr1->irb.scsw.cpa != cqr2->irb.scsw.cpa) { // return 0; /* CCW doesn't match */ } /* check sense data; byte 0-2,25,27 */ if (!((memcmp (cqr1->irb.ecw, cqr2->irb.ecw, 3) == 0) && (cqr1->irb.ecw[27] == cqr2->irb.ecw[27]) && (cqr1->irb.ecw[25] == cqr2->irb.ecw[25]))) { return 0; /* sense doesn't match */ } return 1; /* match */} /* end dasd_3990_erp_error_match *//* * DASD_3990_ERP_IN_ERP * * DESCRIPTION * check if the current error already happened before. * quick exit if current cqr is not an ERP (cqr->refers=NULL) * * PARAMETER * cqr failed cqr (either original cqr or already an erp) * * RETURN VALUES * erp erp-pointer to the already defined error * recovery procedure OR * NULL if a 'new' error occurred. */static struct dasd_ccw_req *dasd_3990_erp_in_erp(struct dasd_ccw_req *cqr){ struct dasd_ccw_req *erp_head = cqr, /* save erp chain head */ *erp_match = NULL; /* save erp chain head */ int match = 0; /* 'boolean' for matching error found */ if (cqr->refers == NULL) { /* return if not in erp */ return NULL; } /* check the erp/cqr chain for current error */ do { match = dasd_3990_erp_error_match(erp_head, cqr->refers); erp_match = cqr; /* save possible matching erp */ cqr = cqr->refers; /* check next erp/cqr in queue */ } while ((cqr->refers != NULL) && (!match)); if (!match) { return NULL; /* no match was found */ } return erp_match; /* return address of matching erp */} /* END dasd_3990_erp_in_erp *//* * DASD_3990_ERP_FURTHER_ERP (24 & 32 byte sense) * * DESCRIPTION * No retry is left for the current ERP. Check what has to be done * with the ERP. * - do further defined ERP action or * - wait for interrupt or * - exit with permanent error * * PARAMETER * erp ERP which is in progress with no retry left * * RETURN VALUES * erp modified/additional ERP */static struct dasd_ccw_req *dasd_3990_erp_further_erp(struct dasd_ccw_req *erp){ struct dasd_device *device = erp->device; char *sense = erp->irb.ecw; /* check for 24 byte sense ERP */ if ((erp->function == dasd_3990_erp_bus_out) || (erp->function == dasd_3990_erp_action_1) || (erp->function == dasd_3990_erp_action_4)) { erp = dasd_3990_erp_action_1(erp); } else if (erp->function == dasd_3990_erp_action_5) { /* retries have not been successful */ /* prepare erp for retry on different channel path */ erp = dasd_3990_erp_action_1(erp); if (!(sense[2] & DASD_SENSE_BIT_0)) { /* issue a Diagnostic Control command with an * Inhibit Write subcommand */ switch (sense[25]) { case 0x17: case 0x57:{ /* controller */ erp = dasd_3990_erp_DCTL(erp, 0x20); break; } case 0x18: case 0x58:{ /* channel path */ erp = dasd_3990_erp_DCTL(erp, 0x40); break; } case 0x19: case 0x59:{ /* storage director */ erp = dasd_3990_erp_DCTL(erp, 0x80); break; } default: DEV_MESSAGE(KERN_DEBUG, device, "invalid subcommand modifier 0x%x " "for Diagnostic Control Command", sense[25]); } } /* check for 32 byte sense ERP */ } else if ((erp->function == dasd_3990_erp_compound_retry) || (erp->function == dasd_3990_erp_compound_path) || (erp->function == dasd_3990_erp_compound_code) || (erp->function == dasd_3990_erp_compound_config)) { erp = dasd_3990_erp_compound(erp, sense); } else { /* No retry left and no additional special handling */ /*necessary */ DEV_MESSAGE(KERN_ERR, device, "no retries left for erp %p - " "set status to FAILED", erp); erp->status = DASD_CQR_FAILED; } return erp;} /* end dasd_3990_erp_further_erp *//* * DASD_3990_ERP_HANDLE_MATCH_ERP * * DESCRIPTION * An error occurred again and an ERP has been detected which is already * used to handle this error (e.g. retries). * All prior ERP's are asumed to be successful and therefore removed * from queue. * If retry counter of matching erp is already 0, it is checked if further * action is needed (besides retry) or if the ERP has failed. * * PARAMETER * erp_head first ERP in ERP-chain * erp ERP that handles the actual error. * (matching erp) * * RETURN VALUES * erp modified/additional ERP */static struct dasd_ccw_req *dasd_3990_erp_handle_match_erp(struct dasd_ccw_req *erp_head, struct dasd_ccw_req *erp){ struct dasd_device *device = erp_head->device; struct dasd_ccw_req *erp_done = erp_head; /* finished req */ struct dasd_ccw_req *erp_free = NULL; /* req to be freed */ /* loop over successful ERPs and remove them from chanq */ while (erp_done != erp) { if (erp_done == NULL) /* end of chain reached */ panic(PRINTK_HEADER "Programming error in ERP! The " "original request was lost\n"); /* remove the request from the device queue */ list_del(&erp_done->list); erp_free = erp_done; erp_done = erp_done->refers; /* free the finished erp request */ dasd_free_erp_request(erp_free, erp_free->device); } /* end while */ if (erp->retries > 0) { char *sense = erp->refers->irb.ecw; /* check for special retries */ if (erp->function == dasd_3990_erp_action_4) { erp = dasd_3990_erp_action_4(erp, sense); } else if (erp->function == dasd_3990_erp_action_1B_32) { erp = dasd_3990_update_1B(erp, sense); } else if (erp->function == dasd_3990_erp_int_req) { erp = dasd_3990_erp_int_req(erp); } else { /* simple retry */ DEV_MESSAGE(KERN_DEBUG, device, "%i retries left for erp %p", erp->retries, erp); /* handle
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -