1 /*
2  * Copyright (c) 1998,1999,2000
3  *      Traakan, Inc., Los Altos, CA
4  *      All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice unmodified, this list of conditions, and the following
11  *    disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 /*
30  * Project:  NDMJOB
31  * Ident:    $Id: $
32  *
33  * Description:
34  *
35  */
36 
37 
38 #include "smc_priv.h"
39 #include "scsiconst.h"
40 
41 
smc_scsi_xa(struct smc_ctrl_block * smc)42 int smc_scsi_xa(struct smc_ctrl_block* smc)
43 {
44   int try
45     = 0;
46   int rc;
47   int sense_key;
48   unsigned char* sense_data = smc->scsi_req.sense_data;
49 
50   for (try = 0; try < 2; try ++) {
51     rc = (*smc->issue_scsi_req)(smc);
52     if (rc || smc->scsi_req.completion_status != SMCSR_CS_GOOD) {
53       strcpy(smc->errmsg, "SCSI request failed");
54       if (rc == 0) rc = -1;
55       continue; /* retry */
56     }
57 
58     switch (SCSI_STATUS_BYTE_CODE(smc->scsi_req.status_byte)) {
59       case SCSI_STATUS_GOOD:
60         return 0;
61 
62       case SCSI_STATUS_CHECK_CONDITION:
63         /* sense data processed below */
64         break;
65 
66       default:
67         strcpy(smc->errmsg, "SCSI unexpected status");
68         return -1;
69     }
70 
71     sense_key = sense_data[2] & SCSI_SENSE_SENSE_KEY_MASK;
72 
73     if (sense_key == SCSI_SENSE_KEY_UNIT_ATTENTION) {
74       int valid;
75       int asc, ascq, asq, cmd;
76       long info;
77 
78       valid = sense_data[0] & SCSI_SENSE_VALID_BIT;
79       info = SMC_GET4(&sense_data[3]);
80       asc = sense_data[12];
81       ascq = sense_data[13];
82       asq = _ASQ(asc, ascq);
83       cmd = smc->scsi_req.cmd[0];
84 
85       sprintf(smc->errmsg, "SCSI attn s0=%x asq=%x,%x cmd=%x info=%lx",
86               sense_data[0], asc, ascq, cmd, info);
87 
88       rc = 1;
89     } else {
90       strcpy(smc->errmsg, "SCSI check condition");
91       rc = 1;
92       break; /* don't retry, investigate */
93     }
94   }
95 
96   if (!rc) rc = -1;
97   return rc;
98 }
99 
100 
101 #define SINQ_MEDIA_CHANGER 0x08
102 
smc_inquire(struct smc_ctrl_block * smc)103 int smc_inquire(struct smc_ctrl_block* smc)
104 {
105   struct smc_scsi_req* sr = &smc->scsi_req;
106   unsigned char data[128];
107   int rc;
108   int i;
109 
110   bzero(sr, sizeof *sr);
111   bzero(data, sizeof data);
112 
113   sr->n_cmd = 6;
114   sr->cmd[0] = SCSI_CMD_INQUIRY;
115   sr->cmd[4] = sizeof data; /* allocation length */
116 
117   sr->data = data;
118   sr->n_data_avail = sizeof data;
119   sr->data_dir = SMCSR_DD_IN;
120 
121   rc = smc_scsi_xa(smc);
122   if (rc != 0) return rc;
123 
124   if (data[0] != SINQ_MEDIA_CHANGER) {
125     strcpy(smc->errmsg, "Not a media changer");
126     return -1;
127   }
128 
129   for (i = 28 - 1; i >= 0; i--) {
130     int c = data[8 + i];
131 
132     if (c != ' ') break;
133   }
134 
135   for (; i >= 0; i--) {
136     int c = data[8 + i];
137 
138     if (!(' ' <= c && c < 0x7F)) c = '*';
139     smc->ident[i] = c;
140   }
141 
142   return 0;
143 }
144 
smc_test_unit_ready(struct smc_ctrl_block * smc)145 int smc_test_unit_ready(struct smc_ctrl_block* smc)
146 {
147   struct smc_scsi_req* sr = &smc->scsi_req;
148   int rc;
149 
150   bzero(sr, sizeof *sr);
151 
152   sr->n_cmd = 6;
153   sr->cmd[0] = SCSI_CMD_TEST_UNIT_READY;
154 
155   rc = smc_scsi_xa(smc);
156 
157   return rc;
158 }
159 
smc_get_elem_aa(struct smc_ctrl_block * smc)160 int smc_get_elem_aa(struct smc_ctrl_block* smc)
161 {
162   struct smc_scsi_req* sr = &smc->scsi_req;
163   unsigned char data[256];
164   int rc;
165 
166   bzero(sr, sizeof *sr);
167   bzero(data, sizeof data);
168   bzero(&smc->elem_aa, sizeof smc->elem_aa);
169   smc->valid_elem_aa = 0;
170 
171   sr->n_cmd = 6;
172   sr->cmd[0] = SCSI_CMD_MODE_SENSE_6;
173   sr->cmd[1] = 0x08; /* DBD */
174   sr->cmd[2] = 0x1D; /* current elem addrs */
175   sr->cmd[3] = 0;    /* reserved */
176   sr->cmd[4] = 255;  /* allocation length */
177   sr->cmd[5] = 0;    /* reserved */
178 
179   sr->data = data;
180   sr->n_data_avail = 255;
181   sr->data_dir = SMCSR_DD_IN;
182 
183   rc = smc_scsi_xa(smc);
184   if (rc != 0) return rc;
185 
186   if (data[0] < 18) {
187     strcpy(smc->errmsg, "short sense data");
188     return -1;
189   }
190 
191 
192   rc = smc_parse_element_address_assignment((void*)&data[4], &smc->elem_aa);
193   if (rc) {
194     strcpy(smc->errmsg, "elem_addr_assignment format error");
195     return -1;
196   }
197 
198   smc->valid_elem_aa = 1;
199 
200   return 0;
201 }
202 
203 /*
204  * 17.2.2 INITIALIZE ELEMENT STATUS command
205  *
206  * The INITIALIZE ELEMENT STATUS command (see table 329) will cause the
207  * medium changer to check all elements for medium and any other status
208  * relevant to that element. The intent of this command is to enable the
209  * initiator to get a quick response from a following READ ELEMENT STATUS
210  * command. It may be useful to issue this command after a power failure,
211  * or if medium has been changed by an operator, or if configurations have
212  * been changed.
213  *
214  *                 Table 329 - INITIALIZE ELEMENT STATUS command
215  * +====-=======-========-========-========-========-========-========-======+
216  * | Bit|  7    |   6    |   5    |   4    |   3    |   2    |   1    |   0  |
217  * |Byte|       |        |        |        |        |        |        |      |
218  * |====+====================================================================|
219  * | 0  |                          Operation code (07h)                      |
220  * |----+--------------------------------------------------------------------|
221  * | 1  |Logical unit number      |                Reserved                  |
222  * |----+--------------------------------------------------------------------|
223  * | 2  |                          Reserved                                  |
224  * |----+--------------------------------------------------------------------|
225  * | 3  |                          Reserved                                  |
226  * |----+--------------------------------------------------------------------|
227  * | 4  |                          Reserved                                  |
228  * |----+--------------------------------------------------------------------|
229  * | 5  |                          Control                                   |
230  * +=========================================================================+
231  */
232 
233 
smc_init_elem_status(struct smc_ctrl_block * smc)234 int smc_init_elem_status(struct smc_ctrl_block* smc)
235 {
236   struct smc_scsi_req* sr = &smc->scsi_req;
237   int rc;
238 
239   bzero(sr, sizeof *sr);
240 
241   sr->n_cmd = 6;
242   sr->cmd[0] = SCSI_CMD_INITIALIZE_ELEMENT_STATUS;
243 
244   sr->data_dir = SMCSR_DD_NONE;
245 
246   rc = smc_scsi_xa(smc);
247   if (rc != 0) return rc;
248 
249   return 0;
250 }
251 
252 
253 /*
254  * 17.2.5 READ ELEMENT STATUS command
255  *
256  * The READ ELEMENT STATUS command (see table 332) requests that the
257  * target report the status of its internal elements to the initiator.
258  *
259  *                    Table 332 - READ ELEMENT STATUS command
260  * +====-=======-========-========-========-========-========-========-=======+
261  * | Bit|  7    |   6    |   5    |   4    |   3    |   2    |   1    |   0   |
262  * |Byte|       |        |        |        |        |        |        |       |
263  * |====+=====================================================================|
264  * | 0  |                          Operation code (B8h)                       |
265  * |----+---------------------------------------------------------------------|
266  * | 1  |Logical unit number      | VolTag |        Element type code         |
267  * |----+---------------------------------------------------------------------|
268  * | 2  |(MSB)                                                                |
269  * |----+--                        Starting element address                 --|
270  * | 3  |                                                                (LSB)|
271  * |----+---------------------------------------------------------------------|
272  * | 4  |(MSB)                                                                |
273  * |----+--                        Number of elements                       --|
274  * | 5  |                                                                (LSB)|
275  * |----+---------------------------------------------------------------------|
276  * | 6  |                          Reserved                                   |
277  * |----+---------------------------------------------------------------------|
278  * | 7  |(MSB)                                                                |
279  * |----+--                                                                 --|
280  * | 8  |                          Allocation length                          |
281  * |----+--                                                                 --|
282  * | 9  |                                                                (LSB)|
283  * |----+---------------------------------------------------------------------|
284  * |10  |                          Reserved                                   |
285  * |----+---------------------------------------------------------------------|
286  * |11  |                          Control                                    |
287  * +==========================================================================+
288  *
289  *
290  * A volume tag (VolTag) bit of one indicates that the target shall report
291  * volume tag information if this feature is supported. A value of zero
292  * indicates that volume tag information shall not be reported. If the
293  * volume tag feature is not supported this field shall be treated as
294  * reserved.
295  *
296  * The element type code field specifies the particular element type(s)
297  * selected for reporting by this command.  A value of zero specifies that
298  * status for all element types shall be reported.  The element type codes
299  * are defined in table 333.
300  *
301  *                         Table 333 - Element type code
302  *      +=============-===================================================+
303  *      |    Code     |  Description                                      |
304  *      |-------------+---------------------------------------------------|
305  *      |      0h     |  All element types reported, (valid in CDB only)  |
306  *      |      1h     |  Medium transport element                         |
307  *      |      2h     |  Storage element                                  |
308  *      |      3h     |  Import export element                            |
309  *      |      4h     |  Data transfer element                            |
310  *      |   5h - Fh   |  Reserved                                         |
311  *      +=================================================================+
312  *
313  *
314  * The starting element address specifies the minimum element address to
315  * report. Only elements with an element type code permitted by the
316  * element type code specification, and an element address greater than or
317  * equal to the starting element address shall be reported. Element
318  * descriptor blocks are not generated for undefined element addresses.
319  *
320  * The number of elements specifies the maximum number of element
321  * descriptors to be created by the target for this command. The value
322  * specified by this field is not the range of element addresses to be
323  * considered for reporting but rather the number of defined elements to
324  * report. If the allocation length is not sufficient to transfer all the
325  * element descriptors, the target shall transfer all those descriptors
326  * that can be completely transferred and this shall not be considered an
327  * error.
328  */
329 
smc_read_elem_status(struct smc_ctrl_block * smc)330 int smc_read_elem_status(struct smc_ctrl_block* smc)
331 {
332   struct smc_scsi_req* sr = &smc->scsi_req;
333   unsigned char data[SMC_PAGE_LEN];
334   int rc;
335 
336 retry:
337   bzero(sr, sizeof *sr);
338   bzero(data, sizeof data);
339   smc_cleanup_element_status_data(smc);
340   smc->n_elem_desc = 0;
341   smc->valid_elem_desc = 0;
342 
343   sr->n_cmd = 12;
344   sr->cmd[0] = SCSI_CMD_READ_ELEMENT_STATUS;
345   if (!smc->dont_ask_for_voltags) {
346     sr->cmd[1] = 0x10; /* VolTag, all types */
347   } else {
348     sr->cmd[1] = 0x00; /* !VolTag, all types */
349   }
350   sr->cmd[2] = 0;                             /* starting elem MSB */
351   sr->cmd[3] = 0;                             /* starting elem LSB */
352   sr->cmd[4] = (SMC_MAX_ELEMENT >> 8) & 0xff; /* number of elem MSB */
353   sr->cmd[5] = (SMC_MAX_ELEMENT)&0xff;        /* number of elem LSB */
354   sr->cmd[6] = 0;                             /* reserved */
355   SMC_PUT3(&sr->cmd[7], sizeof data);
356   sr->cmd[10] = 0; /* reserved */
357 
358   sr->data = data;
359   sr->n_data_avail = sizeof data;
360   sr->data_dir = SMCSR_DD_IN;
361 
362   rc = smc_scsi_xa(smc);
363   if (rc != 0) {
364     if (smc->dont_ask_for_voltags) return rc;
365     smc->dont_ask_for_voltags = 1;
366     goto retry;
367   }
368 
369   rc = smc_parse_element_status_data((void*)data, sr->n_data_done, smc,
370                                      SMC_MAX_ELEMENT);
371   if (rc < 0) {
372     strcpy(smc->errmsg, "elem_status format error");
373     return -1;
374   }
375 
376   smc->n_elem_desc = rc;
377 
378   smc->valid_elem_aa = 1;
379 
380   return 0;
381 }
382 
383 
smc_move(struct smc_ctrl_block * smc,unsigned from_addr,unsigned to_addr,int invert,unsigned chs_addr)384 int smc_move(struct smc_ctrl_block* smc,
385              unsigned from_addr,
386              unsigned to_addr,
387              int invert,
388              unsigned chs_addr)
389 {
390   struct smc_scsi_req* sr = &smc->scsi_req;
391   int rc;
392 
393   bzero(sr, sizeof *sr);
394 
395   sr->n_cmd = 12;
396   sr->cmd[0] = SCSI_CMD_MOVE_MEDIUM;
397   SMC_PUT2(&sr->cmd[2], chs_addr);
398   SMC_PUT2(&sr->cmd[4], from_addr);
399   SMC_PUT2(&sr->cmd[6], to_addr);
400   /* TODO: invert */
401 
402   sr->data_dir = SMCSR_DD_NONE;
403 
404   rc = smc_scsi_xa(smc);
405   if (rc != 0) return rc;
406 
407   return 0;
408 }
409 
smc_position(struct smc_ctrl_block * smc,unsigned to_addr,int invert)410 int smc_position(struct smc_ctrl_block* smc, unsigned to_addr, int invert)
411 {
412   return -1;
413 }
414 
415 
smc_handy_move_to_drive(struct smc_ctrl_block * smc,unsigned from_se_ix)416 int smc_handy_move_to_drive(struct smc_ctrl_block* smc, unsigned from_se_ix)
417 {
418   return -1;
419 }
420 
smc_handy_move_from_drive(struct smc_ctrl_block * smc,unsigned to_se_ix)421 int smc_handy_move_from_drive(struct smc_ctrl_block* smc, unsigned to_se_ix)
422 {
423   return -1;
424 }
425