/* * Copyright (c) 1998,1999,2000 * Traakan, Inc., Los Altos, CA * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Project: NDMJOB * Ident: $Id: $ * * Description: * */ #include "smc_priv.h" #include "scsiconst.h" int smc_scsi_xa (struct smc_ctrl_block *smc) { int try = 0; int rc; int sense_key; unsigned char * sense_data = smc->scsi_req.sense_data; for (try = 0; try < 2; try++) { rc = (*smc->issue_scsi_req)(smc); if (rc || smc->scsi_req.completion_status != SMCSR_CS_GOOD) { strcpy (smc->errmsg, "SCSI request failed"); if (rc == 0) rc = -1; continue; /* retry */ } switch (SCSI_STATUS_BYTE_CODE(smc->scsi_req.status_byte)) { case SCSI_STATUS_GOOD: return 0; case SCSI_STATUS_CHECK_CONDITION: /* sense data processed below */ break; default: strcpy (smc->errmsg, "SCSI unexpected status"); return -1; } sense_key = sense_data[2] & SCSI_SENSE_SENSE_KEY_MASK; if (sense_key == SCSI_SENSE_KEY_UNIT_ATTENTION) { int valid; int asc, ascq, asq, cmd; long info; valid = sense_data[0] & SCSI_SENSE_VALID_BIT; info = SMC_GET4(&sense_data[3]); asc = sense_data[12]; ascq = sense_data[13]; asq = _ASQ(asc,ascq); cmd = smc->scsi_req.cmd[0]; sprintf (smc->errmsg, "SCSI attn s0=%x asq=%x,%x cmd=%x info=%lx", sense_data[0], asc, ascq, cmd, info); rc = 1; } else { strcpy (smc->errmsg, "SCSI check condition"); rc = 1; break; /* don't retry, investigate */ } } if (!rc) rc = -1; return rc; } #define SINQ_MEDIA_CHANGER 0x08 int smc_inquire (struct smc_ctrl_block *smc) { struct smc_scsi_req * sr = &smc->scsi_req; unsigned char data[128]; int rc; int i; bzero (sr, sizeof *sr); bzero (data, sizeof data); sr->n_cmd = 6; sr->cmd[0] = SCSI_CMD_INQUIRY; sr->cmd[4] = sizeof data; /* allocation length */ sr->data = data; sr->n_data_avail = sizeof data; sr->data_dir = SMCSR_DD_IN; rc = smc_scsi_xa (smc); if (rc != 0) return rc; if (data[0] != SINQ_MEDIA_CHANGER) { strcpy (smc->errmsg, "Not a media changer"); return -1; } for (i = 28-1; i >= 0; i--) { int c = data[8+i]; if (c != ' ') break; } for (; i >= 0; i--) { int c = data[8+i]; if (! (' ' <= c && c < 0x7F)) c = '*'; smc->ident[i] = c; } return 0; } int smc_test_unit_ready (struct smc_ctrl_block *smc) { struct smc_scsi_req * sr = &smc->scsi_req; int rc; bzero (sr, sizeof *sr); sr->n_cmd = 6; sr->cmd[0] = SCSI_CMD_TEST_UNIT_READY; rc = smc_scsi_xa (smc); return rc; } int smc_get_elem_aa (struct smc_ctrl_block *smc) { struct smc_scsi_req * sr = &smc->scsi_req; unsigned char data[256]; int rc; bzero (sr, sizeof *sr); bzero (data, sizeof data); bzero (&smc->elem_aa, sizeof smc->elem_aa); smc->valid_elem_aa = 0; sr->n_cmd = 6; sr->cmd[0] = SCSI_CMD_MODE_SENSE_6; sr->cmd[1] = 0x08; /* DBD */ sr->cmd[2] = 0x1D; /* current elem addrs */ sr->cmd[3] = 0; /* reserved */ sr->cmd[4] = 255; /* allocation length */ sr->cmd[5] = 0; /* reserved */ sr->data = data; sr->n_data_avail = 255; sr->data_dir = SMCSR_DD_IN; rc = smc_scsi_xa (smc); if (rc != 0) return rc; if (data[0] < 18) { strcpy (smc->errmsg, "short sense data"); return -1; } rc = smc_parse_element_address_assignment ((void*)&data[4], &smc->elem_aa); if (rc) { strcpy (smc->errmsg, "elem_addr_assignment format error"); return -1; } smc->valid_elem_aa = 1; return 0; } /* * 17.2.2 INITIALIZE ELEMENT STATUS command * * The INITIALIZE ELEMENT STATUS command (see table 329) will cause the * medium changer to check all elements for medium and any other status * relevant to that element. The intent of this command is to enable the * initiator to get a quick response from a following READ ELEMENT STATUS * command. It may be useful to issue this command after a power failure, * or if medium has been changed by an operator, or if configurations have * been changed. * * Table 329 - INITIALIZE ELEMENT STATUS command * +====-=======-========-========-========-========-========-========-======+ * | Bit| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | * |Byte| | | | | | | | | * |====+====================================================================| * | 0 | Operation code (07h) | * |----+--------------------------------------------------------------------| * | 1 |Logical unit number | Reserved | * |----+--------------------------------------------------------------------| * | 2 | Reserved | * |----+--------------------------------------------------------------------| * | 3 | Reserved | * |----+--------------------------------------------------------------------| * | 4 | Reserved | * |----+--------------------------------------------------------------------| * | 5 | Control | * +=========================================================================+ */ int smc_init_elem_status (struct smc_ctrl_block *smc) { struct smc_scsi_req * sr = &smc->scsi_req; int rc; bzero (sr, sizeof *sr); sr->n_cmd = 6; sr->cmd[0] = SCSI_CMD_INITIALIZE_ELEMENT_STATUS; sr->data_dir = SMCSR_DD_NONE; rc = smc_scsi_xa (smc); if (rc != 0) return rc; return 0; } /* * 17.2.5 READ ELEMENT STATUS command * * The READ ELEMENT STATUS command (see table 332) requests that the * target report the status of its internal elements to the initiator. * * Table 332 - READ ELEMENT STATUS command * +====-=======-========-========-========-========-========-========-=======+ * | Bit| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | * |Byte| | | | | | | | | * |====+=====================================================================| * | 0 | Operation code (B8h) | * |----+---------------------------------------------------------------------| * | 1 |Logical unit number | VolTag | Element type code | * |----+---------------------------------------------------------------------| * | 2 |(MSB) | * |----+-- Starting element address --| * | 3 | (LSB)| * |----+---------------------------------------------------------------------| * | 4 |(MSB) | * |----+-- Number of elements --| * | 5 | (LSB)| * |----+---------------------------------------------------------------------| * | 6 | Reserved | * |----+---------------------------------------------------------------------| * | 7 |(MSB) | * |----+-- --| * | 8 | Allocation length | * |----+-- --| * | 9 | (LSB)| * |----+---------------------------------------------------------------------| * |10 | Reserved | * |----+---------------------------------------------------------------------| * |11 | Control | * +==========================================================================+ * * * A volume tag (VolTag) bit of one indicates that the target shall report * volume tag information if this feature is supported. A value of zero * indicates that volume tag information shall not be reported. If the * volume tag feature is not supported this field shall be treated as * reserved. * * The element type code field specifies the particular element type(s) * selected for reporting by this command. A value of zero specifies that * status for all element types shall be reported. The element type codes * are defined in table 333. * * Table 333 - Element type code * +=============-===================================================+ * | Code | Description | * |-------------+---------------------------------------------------| * | 0h | All element types reported, (valid in CDB only) | * | 1h | Medium transport element | * | 2h | Storage element | * | 3h | Import export element | * | 4h | Data transfer element | * | 5h - Fh | Reserved | * +=================================================================+ * * * The starting element address specifies the minimum element address to * report. Only elements with an element type code permitted by the * element type code specification, and an element address greater than or * equal to the starting element address shall be reported. Element * descriptor blocks are not generated for undefined element addresses. * * The number of elements specifies the maximum number of element * descriptors to be created by the target for this command. The value * specified by this field is not the range of element addresses to be * considered for reporting but rather the number of defined elements to * report. If the allocation length is not sufficient to transfer all the * element descriptors, the target shall transfer all those descriptors * that can be completely transferred and this shall not be considered an * error. */ int smc_read_elem_status (struct smc_ctrl_block *smc) { struct smc_scsi_req * sr = &smc->scsi_req; unsigned char data[8192]; int rc; retry: bzero (sr, sizeof *sr); bzero (data, sizeof data); bzero (&smc->elem_desc, sizeof smc->elem_desc); smc->n_elem_desc = 0; smc->valid_elem_desc = 0; sr->n_cmd = 12; sr->cmd[0] = SCSI_CMD_READ_ELEMENT_STATUS; if (!smc->dont_ask_for_voltags) { sr->cmd[1] = 0x10; /* VolTag, all types */ } else { sr->cmd[1] = 0x00; /* !VolTag, all types */ } sr->cmd[2] = 0; /* starting elem MSB */ sr->cmd[3] = 0; /* starting elem LSB */ sr->cmd[4] = 0; /* number of elem MSB */ sr->cmd[5] = SMC_MAX_ELEMENT; /* number of elem LSB */ sr->cmd[6] = 0; /* reserved */ SMC_PUT3 (&sr->cmd[7], sizeof data); sr->cmd[10] = 0; /* reserved */ sr->data = data; sr->n_data_avail = sizeof data; sr->data_dir = SMCSR_DD_IN; rc = smc_scsi_xa (smc); if (rc != 0) { if (smc->dont_ask_for_voltags) return rc; smc->dont_ask_for_voltags = 1; goto retry; } rc = smc_parse_element_status_data ((void*)data, sr->n_data_done, smc->elem_desc, SMC_MAX_ELEMENT); if (rc < 0) { strcpy (smc->errmsg, "elem_status format error"); return -1; } smc->n_elem_desc = rc; smc->valid_elem_aa = 1; return 0; } int smc_move (struct smc_ctrl_block *smc, unsigned from_addr, unsigned to_addr, int invert, unsigned chs_addr) { struct smc_scsi_req * sr = &smc->scsi_req; int rc; bzero (sr, sizeof *sr); sr->n_cmd = 12; sr->cmd[0] = SCSI_CMD_MOVE_MEDIUM; SMC_PUT2(&sr->cmd[2], chs_addr); SMC_PUT2(&sr->cmd[4], from_addr); SMC_PUT2(&sr->cmd[6], to_addr); /* TODO: invert */ sr->data_dir = SMCSR_DD_NONE; rc = smc_scsi_xa (smc); if (rc != 0) return rc; return 0; } int smc_position (struct smc_ctrl_block *smc, unsigned to_addr, int invert) { return -1; } int smc_handy_move_to_drive (struct smc_ctrl_block *smc, unsigned from_se_ix) { return -1; } int smc_handy_move_from_drive (struct smc_ctrl_block *smc, unsigned to_se_ix) { return -1; }