1 /* $FreeBSD$ */ 2 /* $NetBSD: scsi_changer.h,v 1.11 1998/02/13 08:28:32 enami Exp $ */ 3 4 /*- 5 * Copyright (c) 1996 Jason R. Thorpe <thorpej@and.com> 6 * All rights reserved. 7 * 8 * Partially based on an autochanger driver written by Stefan Grefen 9 * and on an autochanger driver written by the Systems Programming Group 10 * at the University of Utah Computer Science Department. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgements: 22 * This product includes software developed by Jason R. Thorpe 23 * for And Communications, http://www.and.com/ 24 * 4. The name of the author may not be used to endorse or promote products 25 * derived from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 28 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 29 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 30 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 31 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 32 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 33 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 34 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 35 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37 * SUCH DAMAGE. 38 */ 39 40 /* 41 * SCSI changer interface description 42 */ 43 44 /*- 45 * Partially derived from software written by Stefan Grefen 46 * (grefen@goofy.zdv.uni-mainz.de soon grefen@convex.com) 47 * based on the SCSI System by written Julian Elischer (julian@tfs.com) 48 * for TRW Financial Systems. 49 * 50 * TRW Financial Systems, in accordance with their agreement with Carnegie 51 * Mellon University, makes this software available to CMU to distribute 52 * or use in any manner that they see fit as long as this message is kept with 53 * the software. For this reason TFS also grants any other persons or 54 * organisations permission to use or modify this software. 55 * 56 * TFS supplies this software to be publicly redistributed 57 * on the understanding that TFS is not responsible for the correct 58 * functioning of this software in any circumstances. 59 * 60 * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 61 */ 62 63 #ifndef _SCSI_SCSI_CH_H 64 #define _SCSI_SCSI_CH_H 1 65 66 #include <sys/cdefs.h> 67 68 /* 69 * SCSI command format 70 */ 71 72 /* 73 * Exchange the medium in the source element with the medium 74 * located at the destination element. 75 */ 76 struct scsi_exchange_medium { 77 u_int8_t opcode; 78 #define EXCHANGE_MEDIUM 0xa6 79 u_int8_t byte2; 80 u_int8_t tea[2]; /* transport element address */ 81 u_int8_t src[2]; /* source address */ 82 u_int8_t fdst[2]; /* first destination address */ 83 u_int8_t sdst[2]; /* second destination address */ 84 u_int8_t invert; 85 #define EXCHANGE_MEDIUM_INV1 0x01 86 #define EXCHANGE_MEDIUM_INV2 0x02 87 u_int8_t control; 88 }; 89 90 /* 91 * Cause the medium changer to check all elements for medium and any 92 * other status relevant to the element. 93 */ 94 struct scsi_initialize_element_status { 95 u_int8_t opcode; 96 #define INITIALIZE_ELEMENT_STATUS 0x07 97 u_int8_t byte2; 98 u_int8_t reserved[3]; 99 u_int8_t control; 100 }; 101 102 /* 103 * Request the changer to move a unit of media from the source element 104 * to the destination element. 105 */ 106 struct scsi_move_medium { 107 u_int8_t opcode; 108 u_int8_t byte2; 109 u_int8_t tea[2]; /* transport element address */ 110 u_int8_t src[2]; /* source element address */ 111 u_int8_t dst[2]; /* destination element address */ 112 u_int8_t reserved[2]; 113 u_int8_t invert; 114 #define MOVE_MEDIUM_INVERT 0x01 115 u_int8_t control; 116 }; 117 118 /* 119 * Position the specified transport element (picker) in front of 120 * the destination element specified. 121 */ 122 struct scsi_position_to_element { 123 u_int8_t opcode; 124 u_int8_t byte2; 125 u_int8_t tea[2]; /* transport element address */ 126 u_int8_t dst[2]; /* destination element address */ 127 u_int8_t reserved[2]; 128 u_int8_t invert; 129 #define POSITION_TO_ELEMENT_INVERT 0x01 130 u_int8_t control; 131 }; 132 133 /* 134 * Request that the changer report the status of its internal elements. 135 */ 136 struct scsi_read_element_status { 137 u_int8_t opcode; 138 u_int8_t byte2; 139 #define READ_ELEMENT_STATUS_VOLTAG 0x10 /* report volume tag info */ 140 /* ...next 4 bits are an element type code... */ 141 u_int8_t sea[2]; /* starting element address */ 142 u_int8_t count[2]; /* number of elements */ 143 u_int8_t flags; 144 #define READ_ELEMENT_STATUS_DVCID 0x01 /* report device serial number */ 145 #define READ_ELEMENT_STATUS_CURDATA 0x02 /* allow motion during command */ 146 147 u_int8_t len[3]; /* length of data buffer */ 148 u_int8_t reserved1; 149 u_int8_t control; 150 }; 151 152 struct scsi_request_volume_element_address { 153 u_int8_t opcode; 154 u_int8_t byte2; 155 #define REQUEST_VOLUME_ELEMENT_ADDRESS_VOLTAG 0x10 156 /* ...next 4 bits are an element type code... */ 157 u_int8_t eaddr[2]; /* element address */ 158 u_int8_t count[2]; /* number of elements */ 159 u_int8_t reserved0; 160 u_int8_t len[3]; /* length of data buffer */ 161 u_int8_t reserved1; 162 u_int8_t control; 163 }; 164 165 /* XXX scsi_release */ 166 167 /* 168 * Changer-specific mode page numbers. 169 */ 170 #define CH_ELEMENT_ADDR_ASSIGN_PAGE 0x1D 171 #define CH_TRANS_GEOM_PARAMS_PAGE 0x1E 172 #define CH_DEVICE_CAP_PAGE 0x1F 173 174 /* 175 * Data returned by READ ELEMENT STATUS consists of an 8-byte header 176 * followed by one or more read_element_status_pages. 177 */ 178 struct read_element_status_header { 179 u_int8_t fear[2]; /* first element address reported */ 180 u_int8_t count[2]; /* number of elements available */ 181 u_int8_t reserved; 182 u_int8_t nbytes[3]; /* byte count of all pages */ 183 }; 184 185 struct read_element_status_page_header { 186 u_int8_t type; /* element type code; see type codes below */ 187 u_int8_t flags; 188 #define READ_ELEMENT_STATUS_AVOLTAG 0x40 189 #define READ_ELEMENT_STATUS_PVOLTAG 0x80 190 u_int8_t edl[2]; /* element descriptor length */ 191 u_int8_t reserved; 192 u_int8_t nbytes[3]; /* byte count of all descriptors */ 193 }; 194 195 /* 196 * Format of a volume tag 197 */ 198 199 struct volume_tag { 200 u_int8_t vif[32]; /* volume identification field */ 201 u_int8_t reserved[2]; 202 u_int8_t vsn[2]; /* volume sequence number */ 203 }; 204 205 struct read_element_status_device_id { 206 u_int8_t prot_code_set; 207 #define READ_ELEMENT_STATUS_CODE_SET(p) ((p) & 0x0F) 208 #define READ_ELEMENT_STATUS_PROTOCOL_ID(p) ((p) >> 4) 209 210 u_int8_t piv_assoc_designator_type; 211 #define READ_ELEMENT_STATUS_PIV_SET 0x80 212 #define READ_ELEMENT_STATUS_ASSOCIATION(p) ((p) >> 4) 213 #define READ_ELEMENT_STATUS_DESIGNATOR_TYPE(p) ((p) & 0x0F) 214 215 u_int8_t reserved2; 216 u_int8_t designator_length; 217 u_int8_t designator[256]; /* Allocate max length */ 218 }; 219 220 struct read_element_status_descriptor { 221 u_int8_t eaddr[2]; /* element address */ 222 u_int8_t flags1; 223 224 #define READ_ELEMENT_STATUS_FULL 0x01 225 #define READ_ELEMENT_STATUS_IMPEXP 0x02 226 #define READ_ELEMENT_STATUS_EXCEPT 0x04 227 #define READ_ELEMENT_STATUS_ACCESS 0x08 228 #define READ_ELEMENT_STATUS_EXENAB 0x10 229 #define READ_ELEMENT_STATUS_INENAB 0x20 230 231 #define READ_ELEMENT_STATUS_MT_MASK1 0x05 232 #define READ_ELEMENT_STATUS_ST_MASK1 0x0c 233 #define READ_ELEMENT_STATUS_IE_MASK1 0x3f 234 #define READ_ELEMENT_STATUS_DT_MASK1 0x0c 235 236 u_int8_t reserved0; 237 u_int8_t sense_code; 238 u_int8_t sense_qual; 239 240 union { 241 struct { 242 u_int8_t dt_scsi_flags; 243 244 #define READ_ELEMENT_STATUS_DT_LUNMASK 0x07 245 #define READ_ELEMENT_STATUS_DT_LUVALID 0x10 246 #define READ_ELEMENT_STATUS_DT_IDVALID 0x20 247 #define READ_ELEMENT_STATUS_DT_NOTBUS 0x80 248 249 u_int8_t dt_scsi_addr; 250 u_int8_t reserved1; 251 } scsi_2; 252 253 /* reserved and obsolete (as of SCSI-3) fields */ 254 u_int8_t reserved_or_obsolete[3]; 255 } dt_or_obsolete; 256 257 u_int8_t flags2; 258 #define READ_ELEMENT_STATUS_INVERT 0x40 259 #define READ_ELEMENT_STATUS_SVALID 0x80 260 #define READ_ELEMENT_STATUS_ED 0x80 261 #define READ_ELEMENT_STATUS_MEDIA_TYPE_MASK 0x07 262 263 u_int8_t ssea[2]; /* source storage element address */ 264 265 union { 266 struct volume_tag pvoltag; 267 struct volume_tag voltag[2]; 268 struct read_element_status_device_id devid; 269 struct { 270 struct volume_tag pvoltag; 271 struct read_element_status_device_id devid; 272 } pvol_and_devid; 273 struct { 274 struct volume_tag voltag[2]; 275 struct read_element_status_device_id devid; 276 } vol_tags_and_devid; 277 } voltag_devid; 278 }; 279 280 /* XXX add data returned by REQUEST VOLUME ELEMENT ADDRESS */ 281 282 /* Element type codes */ 283 #define ELEMENT_TYPE_MASK 0x0f /* Note: these aren't bits */ 284 #define ELEMENT_TYPE_ALL 0x00 285 #define ELEMENT_TYPE_MT 0x01 286 #define ELEMENT_TYPE_ST 0x02 287 #define ELEMENT_TYPE_IE 0x03 288 #define ELEMENT_TYPE_DT 0x04 289 290 /* 291 * XXX The following definitions should be common to all SCSI device types. 292 */ 293 #define PGCODE_MASK 0x3f /* valid page number bits in pg_code */ 294 #define PGCODE_PS 0x80 /* indicates page is savable */ 295 296 /* 297 * Send volume tag information to the changer 298 */ 299 300 struct scsi_send_volume_tag { 301 u_int8_t opcode; 302 #define SEND_VOLUME_TAG 0xb6 303 u_int8_t byte2; 304 u_int8_t ea[2]; /* element address */ 305 u_int8_t reserved2; 306 u_int8_t sac; /* send action code */ 307 308 #define SEND_VOLUME_TAG_ASSERT_PRIMARY 0x08 309 #define SEND_VOLUME_TAG_ASSERT_ALTERNATE 0x09 310 #define SEND_VOLUME_TAG_REPLACE_PRIMARY 0x0a 311 #define SEND_VOLUME_TAG_REPLACE_ALTERNATE 0x0b 312 #define SEND_VOLUME_TAG_UNDEFINED_PRIMARY 0x0c 313 #define SEND_VOLUME_TAG_UNDEFINED_ALTERNATE 0x0d 314 315 u_int8_t reserved4[2]; 316 u_int8_t pll[2]; /* parameter list length */ 317 u_int8_t reserved5; 318 u_int8_t control; 319 }; 320 321 /* 322 * Parameter format for SEND VOLUME TAG 323 */ 324 325 struct scsi_send_volume_tag_parameters { 326 u_int8_t vitf[32]; /* volume tag identification template */ 327 u_int8_t reserved1[2]; 328 u_int8_t minvsn[2]; /* minimum volume sequence number */ 329 u_int8_t reserved2[2]; 330 u_int8_t maxvsn[2]; /* maximum volume sequence number */ 331 }; 332 333 /* 334 * Device capabilities page. 335 * 336 * This page defines characteristics of the element types in the 337 * medium changer device. 338 * 339 * Note in the definitions below, the following abbreviations are 340 * used: 341 * MT Medium transport element (picker) 342 * ST Storage transport element (slot) 343 * IE Import/export element (portal) 344 * DT Data transfer element (tape/disk drive) 345 */ 346 struct page_device_capabilities { 347 u_int8_t pg_code; /* page code (0x1f) */ 348 u_int8_t pg_length; /* page length (0x12) */ 349 350 /* 351 * The STOR_xx bits indicate that an element of a given 352 * type may provide independent storage for a unit of 353 * media. The top four bits of this value are reserved. 354 */ 355 u_int8_t stor; 356 #define STOR_MT 0x01 357 #define STOR_ST 0x02 358 #define STOR_IE 0x04 359 #define STOR_DT 0x08 360 361 u_int8_t reserved0; 362 363 /* 364 * The MOVE_TO_yy bits indicate the changer supports 365 * moving a unit of medium from an element of a given type to an 366 * element of type yy. This is used to determine if a given 367 * MOVE MEDIUM command is legal. The top four bits of each 368 * of these values are reserved. 369 */ 370 u_int8_t move_from[CHET_MAX + 1]; 371 #define MOVE_TO_MT 0x01 372 #define MOVE_TO_ST 0x02 373 #define MOVE_TO_IE 0x04 374 #define MOVE_TO_DT 0x08 375 376 u_int8_t reserved1[4]; 377 378 /* 379 * Similar to above, but for EXCHANGE MEDIUM. 380 */ 381 u_int8_t exchange_with[CHET_MAX + 1]; 382 #define EXCHANGE_WITH_MT 0x01 383 #define EXCHANGE_WITH_ST 0x02 384 #define EXCHANGE_WITH_IE 0x04 385 #define EXCHANGE_WITH_DT 0x08 386 }; 387 388 /* 389 * Medium changer elemement address assignment page. 390 * 391 * Some of these fields can be a little confusing, so an explanation 392 * is in order. 393 * 394 * Each component within a medium changer apparatus is called an 395 * "element". 396 * 397 * The "medium transport element address" is the address of the first 398 * picker (robotic arm). "Number of medium transport elements" tells 399 * us how many pickers exist in the changer. 400 * 401 * The "first storage element address" is the address of the first 402 * slot in the tape or disk magazine. "Number of storage elements" tells 403 * us how many slots exist in the changer. 404 * 405 * The "first import/export element address" is the address of the first 406 * medium portal accessible both by the medium changer and an outside 407 * human operator. This is where the changer might deposit tapes destined 408 * for some vault. The "number of import/export elements" tells us 409 * not many of these portals exist in the changer. NOTE: this number may 410 * be 0. 411 * 412 * The "first data transfer element address" is the address of the first 413 * tape or disk drive in the changer. "Number of data transfer elements" 414 * tells us how many drives exist in the changer. 415 */ 416 struct page_element_address_assignment { 417 u_int8_t pg_code; /* page code (0x1d) */ 418 u_int8_t pg_length; /* page length (0x12) */ 419 420 /* Medium transport element address */ 421 u_int8_t mtea[2]; 422 423 /* Number of medium transport elements */ 424 u_int8_t nmte[2]; 425 426 /* First storage element address */ 427 u_int8_t fsea[2]; 428 429 /* Number of storage elements */ 430 u_int8_t nse[2]; 431 432 /* First import/export element address */ 433 u_int8_t fieea[2]; 434 435 /* Number of import/export elements */ 436 u_int8_t niee[2]; 437 438 /* First data transfer element address */ 439 u_int8_t fdtea[2]; 440 441 /* Number of data trafer elements */ 442 u_int8_t ndte[2]; 443 444 u_int8_t reserved[2]; 445 }; 446 447 /* 448 * Transport geometry parameters page. 449 * 450 * Defines whether each medium transport element is a member of a set of 451 * elements that share a common robotics subsystem and whether the element 452 * is capable of media rotation. One transport geometry descriptor is 453 * transferred for each medium transport element, beginning with the first 454 * medium transport element (other than the default transport element address 455 * of 0). 456 */ 457 struct page_transport_geometry_parameters { 458 u_int8_t pg_code; /* page code (0x1e) */ 459 u_int8_t pg_length; /* page length; variable */ 460 461 /* Transport geometry descriptor(s) are here. */ 462 463 u_int8_t misc; 464 #define CAN_ROTATE 0x01 465 466 /* Member number in transport element set. */ 467 u_int8_t member; 468 }; 469 470 __BEGIN_DECLS 471 void scsi_move_medium(struct ccb_scsiio *csio, u_int32_t retries, 472 void (*cbfcnp)(struct cam_periph *, union ccb *), 473 u_int8_t tag_action, u_int32_t tea, u_int32_t src, 474 u_int32_t dst, int invert, u_int8_t sense_len, 475 u_int32_t timeout); 476 477 void scsi_exchange_medium(struct ccb_scsiio *csio, u_int32_t retries, 478 void (*cbfcnp)(struct cam_periph *, union ccb *), 479 u_int8_t tag_action, u_int32_t tea, u_int32_t src, 480 u_int32_t dst1, u_int32_t dst2, int invert1, 481 int invert2, u_int8_t sense_len, u_int32_t timeout); 482 483 void scsi_position_to_element(struct ccb_scsiio *csio, u_int32_t retries, 484 void (*cbfcnp)(struct cam_periph *, union ccb *), 485 u_int8_t tag_action, u_int32_t tea, u_int32_t dst, 486 int invert, u_int8_t sense_len, 487 u_int32_t timeout); 488 489 void scsi_read_element_status(struct ccb_scsiio *csio, u_int32_t retries, 490 void (*cbfcnp)(struct cam_periph *, union ccb *), 491 u_int8_t tag_action, int voltag, u_int32_t sea, 492 int curdata, int dvcid, 493 u_int32_t count, u_int8_t *data_ptr, 494 u_int32_t dxfer_len, u_int8_t sense_len, 495 u_int32_t timeout); 496 497 void scsi_initialize_element_status(struct ccb_scsiio *csio, u_int32_t retries, 498 void (*cbfcnp)(struct cam_periph *, union ccb *), 499 u_int8_t tag_action, u_int8_t sense_len, 500 u_int32_t timeout); 501 void scsi_send_volume_tag(struct ccb_scsiio *csio, u_int32_t retries, 502 void (*cbfcnp)(struct cam_periph *, union ccb *), 503 u_int8_t tag_action, 504 u_int16_t element_address, 505 u_int8_t send_action_code, 506 struct scsi_send_volume_tag_parameters *parameters, 507 u_int8_t sense_len, u_int32_t timeout); 508 __END_DECLS 509 510 #endif /* _SCSI_SCSI_CH_H */ 511