/* * Medium sense for 34xx tapes. There is no 'real' medium sense call. * So we just do a normal sense.
*/ staticvoid __tape_34xx_medium_sense(struct tape_request *request)
{ struct tape_device *device = request->device; unsignedchar *sense;
if (request->rc == 0) {
sense = request->cpdata;
/* * This isn't quite correct. But since INTERVENTION_REQUIRED * means that the drive is 'neither ready nor on-line' it is * only slightly inaccurate to say there is no tape loaded if * the drive isn't online...
*/ if (sense[0] & SENSE_INTERVENTION_REQUIRED)
tape_med_state_set(device, MS_UNLOADED); else
tape_med_state_set(device, MS_LOADED);
if (sense[1] & SENSE_WRITE_PROTECT)
device->tape_generic_status |= GMT_WR_PROT(~0); else
device->tape_generic_status &= ~GMT_WR_PROT(~0);
} else
DBF_EVENT(4, "tape_34xx: medium sense failed with rc=%d\n",
request->rc);
tape_free_request(request);
}
staticint tape_34xx_medium_sense(struct tape_device *device)
{ struct tape_request *request; int rc;
/* * These functions are currently used only to schedule a medium_sense for * later execution. This is because we get an interrupt whenever a medium * is inserted but cannot call tape_do_io* from an interrupt context. * Maybe that's useful for other actions we want to start from the * interrupt handler. * Note: the work handler is called by the system work queue. The tape * commands started by the handler need to be asynchrounous, otherwise * a deadlock can occur e.g. in case of a deferred cc=1 (see __tape_do_irq).
*/ staticvoid
tape_34xx_work_handler(struct work_struct *work)
{ struct tape_34xx_work *p =
container_of(work, struct tape_34xx_work, work); struct tape_device *device = p->device;
if ((p = kzalloc(sizeof(*p), GFP_ATOMIC)) == NULL) return -ENOMEM;
INIT_WORK(&p->work, tape_34xx_work_handler);
p->device = tape_get_device(device);
p->op = op;
schedule_work(&p->work); return 0;
}
/* * Done Handler is called when dev stat = DEVICE-END (successful operation)
*/ staticinlineint
tape_34xx_done(struct tape_request *request)
{
DBF_EVENT(6, "%s done\n", tape_op_verbose[request->op]);
switch (request->op) { case TO_DSE: case TO_RUN: case TO_WRI: case TO_WTM: case TO_ASSIGN: case TO_UNASSIGN:
tape_34xx_delete_sbid_from(request->device, 0); break; default:
;
} return TAPE_IO_SUCCESS;
}
staticinlineint
tape_34xx_erp_failed(struct tape_request *request, int rc)
{
DBF_EVENT(3, "Error recovery failed for %s (RC=%d)\n",
tape_op_verbose[request->op], rc); return rc;
}
/* * This function is called, when no request is outstanding and we get an * interrupt
*/ staticint
tape_34xx_unsolicited_irq(struct tape_device *device, struct irb *irb)
{ if (irb->scsw.cmd.dstat == 0x85) { /* READY */ /* A medium was inserted in the drive. */
DBF_EVENT(6, "xuud med\n");
tape_34xx_delete_sbid_from(device, 0);
tape_34xx_schedule_work(device, TO_MSEN);
} else {
DBF_EVENT(3, "unsol.irq! dev end: %08x\n", device->cdev_id);
tape_dump_sense_dbf(device, NULL, irb);
} return TAPE_IO_SUCCESS;
}
/* * Read Opposite Error Recovery Function: * Used, when Read Forward does not work
*/ staticint
tape_34xx_erp_read_opposite(struct tape_device *device, struct tape_request *request)
{ if (request->op == TO_RFO) { /* * We did read forward, but the data could not be read * *correctly*. We transform the request to a read backward * and try again.
*/
tape_std_read_backward(device, request); return tape_34xx_erp_retry(request);
}
/* * We tried to read forward and backward, but hat no * success -> failed.
*/ return tape_34xx_erp_failed(request, -EIO);
}
/* * Handle data overrun between cu and drive. The channel speed might * be too slow.
*/ staticint
tape_34xx_erp_overrun(struct tape_device *device, struct tape_request *request, struct irb *irb)
{ if (irb->ecw[3] == 0x40) {
dev_warn (&device->cdev->dev, "A data overrun occurred between" " the control unit and tape unit\n"); return tape_34xx_erp_failed(request, -EIO);
} return tape_34xx_erp_bug(device, request, irb, -1);
}
/* * Handle record sequence error.
*/ staticint
tape_34xx_erp_sequence(struct tape_device *device, struct tape_request *request, struct irb *irb)
{ if (irb->ecw[3] == 0x41) { /* * cu detected incorrect block-id sequence on tape.
*/
dev_warn (&device->cdev->dev, "The block ID sequence on the " "tape is incorrect\n"); return tape_34xx_erp_failed(request, -EIO);
} /* * Record sequence error bit is set, but erpa does not * show record sequence error.
*/ return tape_34xx_erp_bug(device, request, irb, -2);
}
/* * This function analyses the tape's sense-data in case of a unit-check. * If possible, it tries to recover from the error. Else the user is * informed about the problem.
*/ staticint
tape_34xx_unit_check(struct tape_device *device, struct tape_request *request, struct irb *irb)
{ int inhibit_cu_recovery;
__u8* sense;
/* * Special cases for various tape-states when reaching * end of recorded area * * FIXME: Maybe a special case of the special case: * sense[0] == SENSE_EQUIPMENT_CHECK && * sense[1] == SENSE_DRIVE_ONLINE && * sense[3] == 0x47 (Volume Fenced) * * This was caused by continued FSF or FSR after an * 'End Of Data'.
*/ if ((
sense[0] == SENSE_DATA_CHECK ||
sense[0] == SENSE_EQUIPMENT_CHECK ||
sense[0] == (SENSE_EQUIPMENT_CHECK | SENSE_DEFERRED_UNIT_CHECK)
) && (
sense[1] == SENSE_DRIVE_ONLINE ||
sense[1] == (SENSE_BEGINNING_OF_TAPE | SENSE_WRITE_MODE)
)) { switch (request->op) { /* * sense[0] == SENSE_DATA_CHECK && * sense[1] == SENSE_DRIVE_ONLINE * sense[3] == 0x36 (End Of Data) * * Further seeks might return a 'Volume Fenced'.
*/ case TO_FSF: case TO_FSB: /* Trying to seek beyond end of recorded area */ return tape_34xx_erp_failed(request, -ENOSPC); case TO_BSB: return tape_34xx_erp_retry(request);
/* * sense[0] == SENSE_DATA_CHECK && * sense[1] == SENSE_DRIVE_ONLINE && * sense[3] == 0x36 (End Of Data)
*/ case TO_LBL: /* Block could not be located. */
tape_34xx_delete_sbid_from(device, 0); return tape_34xx_erp_failed(request, -EIO);
case TO_RFO: /* Read beyond end of recorded area -> 0 bytes read */ return tape_34xx_erp_failed(request, 0);
/* * sense[0] == SENSE_EQUIPMENT_CHECK && * sense[1] == SENSE_DRIVE_ONLINE && * sense[3] == 0x38 (Physical End Of Volume)
*/ case TO_WRI: /* Writing at physical end of volume */ return tape_34xx_erp_failed(request, -ENOSPC); default: return tape_34xx_erp_failed(request, 0);
}
}
/* Sensing special bits */ if (sense[0] & SENSE_BUS_OUT_CHECK) return tape_34xx_erp_retry(request);
if (sense[0] & SENSE_DATA_CHECK) { /* * hardware failure, damaged tape or improper * operating conditions
*/ switch (sense[3]) { case 0x23: /* a read data check occurred */ if ((sense[2] & SENSE_TAPE_SYNC_MODE) ||
inhibit_cu_recovery) // data check is not permanent, may be // recovered. We always use async-mode with // cu-recovery, so this should *never* happen. return tape_34xx_erp_bug(device, request,
irb, -4);
/* data check is permanent, CU recovery has failed */
dev_warn (&device->cdev->dev, "A read error occurred " "that cannot be recovered\n"); return tape_34xx_erp_failed(request, -EIO); case 0x25: // a write data check occurred if ((sense[2] & SENSE_TAPE_SYNC_MODE) ||
inhibit_cu_recovery) // data check is not permanent, may be // recovered. We always use async-mode with // cu-recovery, so this should *never* happen. return tape_34xx_erp_bug(device, request,
irb, -5);
// data check is permanent, cu-recovery has failed
dev_warn (&device->cdev->dev, "A write error on the " "tape cannot be recovered\n"); return tape_34xx_erp_failed(request, -EIO); case 0x26: /* Data Check (read opposite) occurred. */ return tape_34xx_erp_read_opposite(device, request); case 0x28: /* ID-Mark at tape start couldn't be written */
dev_warn (&device->cdev->dev, "Writing the ID-mark " "failed\n"); return tape_34xx_erp_failed(request, -EIO); case 0x31: /* Tape void. Tried to read beyond end of device. */
dev_warn (&device->cdev->dev, "Reading the tape beyond" " the end of the recorded area failed\n"); return tape_34xx_erp_failed(request, -ENOSPC); case 0x41: /* Record sequence error. */
dev_warn (&device->cdev->dev, "The tape contains an " "incorrect block ID sequence\n"); return tape_34xx_erp_failed(request, -EIO); default: /* all data checks for 3480 should result in one of * the above erpa-codes. For 3490, other data-check
* conditions do exist. */ if (device->cdev->id.driver_info == tape_3480) return tape_34xx_erp_bug(device, request,
irb, -6);
}
}
if (sense[0] & SENSE_OVERRUN) return tape_34xx_erp_overrun(device, request, irb);
if (sense[1] & SENSE_RECORD_SEQUENCE_ERR) return tape_34xx_erp_sequence(device, request, irb);
/* Sensing erpa codes */ switch (sense[3]) { case 0x00: /* Unit check with erpa code 0. Report and ignore. */ return TAPE_IO_SUCCESS; case 0x21: /* * Data streaming not operational. CU will switch to * interlock mode. Reissue the command.
*/ return tape_34xx_erp_retry(request); case 0x22: /* * Path equipment check. Might be drive adapter error, buffer * error on the lower interface, internal path not usable, * or error during cartridge load.
*/
dev_warn (&device->cdev->dev, "A path equipment check occurred" " for the tape device\n"); return tape_34xx_erp_failed(request, -EIO); case 0x24: /* * Load display check. Load display was command was issued, * but the drive is displaying a drive check message. Can * be threated as "device end".
*/ return tape_34xx_erp_succeeded(request); case 0x27: /* * Command reject. May indicate illegal channel program or * buffer over/underrun. Since all channel programs are * issued by this driver and ought be correct, we assume a * over/underrun situation and retry the channel program.
*/ return tape_34xx_erp_retry(request); case 0x29: /* * Function incompatible. Either the tape is idrc compressed * but the hardware isn't capable to do idrc, or a perform * subsystem func is issued and the CU is not on-line.
*/ return tape_34xx_erp_failed(request, -EIO); case 0x2a: /* * Unsolicited environmental data. An internal counter * overflows, we can ignore this and reissue the cmd.
*/ return tape_34xx_erp_retry(request); case 0x2b: /* * Environmental data present. Indicates either unload * completed ok or read buffered log command completed ok.
*/ if (request->op == TO_RUN) { /* Rewind unload completed ok. */
tape_med_state_set(device, MS_UNLOADED); return tape_34xx_erp_succeeded(request);
} /* tape_34xx doesn't use read buffered log commands. */ return tape_34xx_erp_bug(device, request, irb, sense[3]); case 0x2c: /* * Permanent equipment check. CU has tried recovery, but * did not succeed.
*/ return tape_34xx_erp_failed(request, -EIO); case 0x2d: /* Data security erase failure. */ if (request->op == TO_DSE) return tape_34xx_erp_failed(request, -EIO); /* Data security erase failure, but no such command issued. */ return tape_34xx_erp_bug(device, request, irb, sense[3]); case 0x2e: /* * Not capable. This indicates either that the drive fails * reading the format id mark or that format specified * is not supported by the drive.
*/
dev_warn (&device->cdev->dev, "The tape unit cannot process " "the tape format\n"); return tape_34xx_erp_failed(request, -EMEDIUMTYPE); case 0x30: /* The medium is write protected. */
dev_warn (&device->cdev->dev, "The tape medium is write-" "protected\n"); return tape_34xx_erp_failed(request, -EACCES); case 0x32: // Tension loss. We cannot recover this, it's an I/O error.
dev_warn (&device->cdev->dev, "The tape does not have the " "required tape tension\n"); return tape_34xx_erp_failed(request, -EIO); case 0x33: /* * Load Failure. The cartridge was not inserted correctly or * the tape is not threaded correctly.
*/
dev_warn (&device->cdev->dev, "The tape unit failed to load" " the cartridge\n");
tape_34xx_delete_sbid_from(device, 0); return tape_34xx_erp_failed(request, -EIO); case 0x34: /* * Unload failure. The drive cannot maintain tape tension * and control tape movement during an unload operation.
*/
dev_warn (&device->cdev->dev, "Automatic unloading of the tape" " cartridge failed\n"); if (request->op == TO_RUN) return tape_34xx_erp_failed(request, -EIO); return tape_34xx_erp_bug(device, request, irb, sense[3]); case 0x35: /* * Drive equipment check. One of the following: * - cu cannot recover from a drive detected error * - a check code message is shown on drive display * - the cartridge loader does not respond correctly * - a failure occurs during an index, load, or unload cycle
*/
dev_warn (&device->cdev->dev, "An equipment check has occurred" " on the tape unit\n"); return tape_34xx_erp_failed(request, -EIO); case 0x36: if (device->cdev->id.driver_info == tape_3490) /* End of data. */ return tape_34xx_erp_failed(request, -EIO); /* This erpa is reserved for 3480 */ return tape_34xx_erp_bug(device, request, irb, sense[3]); case 0x37: /* * Tape length error. The tape is shorter than reported in * the beginning-of-tape data.
*/
dev_warn (&device->cdev->dev, "The tape information states an" " incorrect length\n"); return tape_34xx_erp_failed(request, -EIO); case 0x38: /* * Physical end of tape. A read/write operation reached * the physical end of tape.
*/ if (request->op==TO_WRI ||
request->op==TO_DSE ||
request->op==TO_WTM) return tape_34xx_erp_failed(request, -ENOSPC); return tape_34xx_erp_failed(request, -EIO); case 0x39: /* Backward at Beginning of tape. */ return tape_34xx_erp_failed(request, -EIO); case 0x3a: /* Drive switched to not ready. */
dev_warn (&device->cdev->dev, "The tape unit is not ready\n"); return tape_34xx_erp_failed(request, -EIO); case 0x3b: /* Manual rewind or unload. This causes an I/O error. */
dev_warn (&device->cdev->dev, "The tape medium has been " "rewound or unloaded manually\n");
tape_34xx_delete_sbid_from(device, 0); return tape_34xx_erp_failed(request, -EIO); case 0x42: /* * Degraded mode. A condition that can cause degraded * performance is detected.
*/
dev_warn (&device->cdev->dev, "The tape subsystem is running " "in degraded mode\n"); return tape_34xx_erp_retry(request); case 0x43: /* Drive not ready. */
tape_34xx_delete_sbid_from(device, 0);
tape_med_state_set(device, MS_UNLOADED); /* Some commands commands are successful even in this case */ if (sense[1] & SENSE_DRIVE_ONLINE) { switch(request->op) { case TO_ASSIGN: case TO_UNASSIGN: case TO_DIS: case TO_NOP: return tape_34xx_done(request); break; default: break;
}
} return tape_34xx_erp_failed(request, -ENOMEDIUM); case 0x44: /* Locate Block unsuccessful. */ if (request->op != TO_BLOCK && request->op != TO_LBL) /* No locate block was issued. */ return tape_34xx_erp_bug(device, request,
irb, sense[3]); return tape_34xx_erp_failed(request, -EIO); case 0x45: /* The drive is assigned to a different channel path. */
dev_warn (&device->cdev->dev, "The tape unit is already " "assigned\n"); return tape_34xx_erp_failed(request, -EIO); case 0x46: /* * Drive not on-line. Drive may be switched offline, * the power supply may be switched off or * the drive address may not be set correctly.
*/
dev_warn (&device->cdev->dev, "The tape unit is not online\n"); return tape_34xx_erp_failed(request, -EIO); case 0x47: /* Volume fenced. CU reports volume integrity is lost. */
dev_warn (&device->cdev->dev, "The control unit has fenced " "access to the tape volume\n");
tape_34xx_delete_sbid_from(device, 0); return tape_34xx_erp_failed(request, -EIO); case 0x48: /* Log sense data and retry request. */ return tape_34xx_erp_retry(request); case 0x49: /* Bus out check. A parity check error on the bus was found. */
dev_warn (&device->cdev->dev, "A parity error occurred on the " "tape bus\n"); return tape_34xx_erp_failed(request, -EIO); case 0x4a: /* Control unit erp failed. */
dev_warn (&device->cdev->dev, "I/O error recovery failed on " "the tape control unit\n"); return tape_34xx_erp_failed(request, -EIO); case 0x4b: /* * CU and drive incompatible. The drive requests micro-program * patches, which are not available on the CU.
*/
dev_warn (&device->cdev->dev, "The tape unit requires a " "firmware update\n"); return tape_34xx_erp_failed(request, -EIO); case 0x4c: /* * Recovered Check-One failure. Cu develops a hardware error, * but is able to recover.
*/ return tape_34xx_erp_retry(request); case 0x4d: if (device->cdev->id.driver_info == tape_3490) /* * Resetting event received. Since the driver does * not support resetting event recovery (which has to * be handled by the I/O Layer), retry our command.
*/ return tape_34xx_erp_retry(request); /* This erpa is reserved for 3480. */ return tape_34xx_erp_bug(device, request, irb, sense[3]); case 0x4e: if (device->cdev->id.driver_info == tape_3490) { /* * Maximum block size exceeded. This indicates, that * the block to be written is larger than allowed for * buffered mode.
*/
dev_warn (&device->cdev->dev, "The maximum block size" " for buffered mode is exceeded\n"); return tape_34xx_erp_failed(request, -ENOBUFS);
} /* This erpa is reserved for 3480. */ return tape_34xx_erp_bug(device, request, irb, sense[3]); case 0x50: /* * Read buffered log (Overflow). CU is running in extended * buffered log mode, and a counter overflows. This should * never happen, since we're never running in extended * buffered log mode.
*/ return tape_34xx_erp_retry(request); case 0x51: /* * Read buffered log (EOV). EOF processing occurs while the * CU is in extended buffered log mode. This should never * happen, since we're never running in extended buffered * log mode.
*/ return tape_34xx_erp_retry(request); case 0x52: /* End of Volume complete. Rewind unload completed ok. */ if (request->op == TO_RUN) {
tape_med_state_set(device, MS_UNLOADED);
tape_34xx_delete_sbid_from(device, 0); return tape_34xx_erp_succeeded(request);
} return tape_34xx_erp_bug(device, request, irb, sense[3]); case 0x53: /* Global command intercept. */ return tape_34xx_erp_retry(request); case 0x54: /* Channel interface recovery (temporary). */ return tape_34xx_erp_retry(request); case 0x55: /* Channel interface recovery (permanent). */
dev_warn (&device->cdev->dev, "A channel interface error cannot be" " recovered\n"); return tape_34xx_erp_failed(request, -EIO); case 0x56: /* Channel protocol error. */
dev_warn (&device->cdev->dev, "A channel protocol error " "occurred\n"); return tape_34xx_erp_failed(request, -EIO); case 0x57: /* * 3480: Attention intercept. * 3490: Global status intercept.
*/ return tape_34xx_erp_retry(request); case 0x5a: /* * Tape length incompatible. The tape inserted is too long, * which could cause damage to the tape or the drive.
*/
dev_warn (&device->cdev->dev, "The tape unit does not support " "the tape length\n"); return tape_34xx_erp_failed(request, -EIO); case 0x5b: /* Format 3480 XF incompatible */ if (sense[1] & SENSE_BEGINNING_OF_TAPE) /* The tape will get overwritten. */ return tape_34xx_erp_retry(request);
dev_warn (&device->cdev->dev, "The tape unit does not support" " format 3480 XF\n"); return tape_34xx_erp_failed(request, -EIO); case 0x5c: /* Format 3480-2 XF incompatible */
dev_warn (&device->cdev->dev, "The tape unit does not support tape " "format 3480-2 XF\n"); return tape_34xx_erp_failed(request, -EIO); case 0x5d: /* Tape length violation. */
dev_warn (&device->cdev->dev, "The tape unit does not support" " the current tape length\n"); return tape_34xx_erp_failed(request, -EMEDIUMTYPE); case 0x5e: /* Compaction algorithm incompatible. */
dev_warn (&device->cdev->dev, "The tape unit does not support" " the compaction algorithm\n"); return tape_34xx_erp_failed(request, -EMEDIUMTYPE);
/* The following erpas should have been covered earlier. */ case 0x23: /* Read data check. */ case 0x25: /* Write data check. */ case 0x26: /* Data check (read opposite). */ case 0x28: /* Write id mark check. */ case 0x31: /* Tape void. */ case 0x40: /* Overrun error. */ case 0x41: /* Record sequence error. */ /* All other erpas are reserved for future use. */ default: return tape_34xx_erp_bug(device, request, irb, sense[3]);
}
}
if ((irb->scsw.cmd.dstat & DEV_STAT_UNIT_EXCEP) &&
(irb->scsw.cmd.dstat & DEV_STAT_DEV_END) &&
(request->op == TO_WRI)) { /* Write at end of volume */ return tape_34xx_erp_failed(request, -ENOSPC);
}
if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) return tape_34xx_unit_check(device, request, irb);
if (irb->scsw.cmd.dstat & DEV_STAT_DEV_END) { /* * A unit exception occurs on skipping over a tapemark block.
*/ if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_EXCEP) { if (request->op == TO_BSB || request->op == TO_FSB)
request->rescnt++; else
DBF_EVENT(5, "Unit Exception!\n");
} return tape_34xx_done(request);
}
/* * Build up the search block ID list. The block ID consists of a logical * block number and a hardware specific part. The hardware specific part * helps the tape drive to speed up searching for a specific block.
*/ staticvoid
tape_34xx_add_sbid(struct tape_device *device, struct tape_34xx_block_id bid)
{ struct list_head * sbid_list; struct tape_34xx_sbid * sbid; struct list_head * l;
/* * immediately return if there is no list at all or the block to add * is located in segment 1 of wrap 0 because this position is used * if no hardware position data is supplied.
*/
sbid_list = (struct list_head *) device->discdata; if (!sbid_list || (bid.segment < 2 && bid.wrap == 0)) return;
/* * Search the position where to insert the new entry. Hardware * acceleration uses only the segment and wrap number. So we * need only one entry for a specific wrap/segment combination. * If there is a block with a lower number but the same hard- * ware position data we just update the block number in the * existing entry.
*/
list_for_each(l, sbid_list) {
sbid = list_entry(l, struct tape_34xx_sbid, list);
/* Sort in according to logical block number. */ if (bid.block < sbid->bid.block) {
tape_34xx_append_new_sbid(bid, l->prev); break;
}
} /* List empty or new block bigger than last entry. */ if (l == sbid_list)
tape_34xx_append_new_sbid(bid, l->prev);
/* * Delete all entries from the search block ID list that belong to tape blocks * equal or higher than the given number.
*/ staticvoid
tape_34xx_delete_sbid_from(struct tape_device *device, int from)
{ struct list_head * sbid_list; struct tape_34xx_sbid * sbid; struct list_head * l; struct list_head * n;
sbid_list = (struct list_head *) device->discdata; if (!sbid_list) return;
MODULE_DEVICE_TABLE(ccw, tape_34xx_ids);
MODULE_AUTHOR("(C) 2001-2002 IBM Deutschland Entwicklung GmbH");
MODULE_DESCRIPTION("Linux on zSeries channel attached 3480 tape device driver");
MODULE_LICENSE("GPL");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.