X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=ndmp-src%2Fsmc_api.c;fp=ndmp-src%2Fsmc_api.c;h=d2f9b267a24bc137cec113df9b1bee38474aa4e8;hb=fd48f3e498442f0cbff5f3606c7c403d0566150e;hp=0000000000000000000000000000000000000000;hpb=96f35b20267e8b1a1c846d476f27fcd330e0b018;p=debian%2Famanda diff --git a/ndmp-src/smc_api.c b/ndmp-src/smc_api.c new file mode 100644 index 0000000..d2f9b26 --- /dev/null +++ b/ndmp-src/smc_api.c @@ -0,0 +1,437 @@ +/* + * 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; +}