Return to BSD News archive
Newsgroups: comp.unix.bsd Path: sserve!manuel!munnari.oz.au!network.ucsd.edu!swrinde!cs.utexas.edu!sun-barr!ames!agate!tfs.com!tfs.com!julian From: julian@tfs.com (Julian Elischer) Subject: New scsi system beta3 (part 5 of 10) Message-ID: <1992Oct3.040155.13763@tfs.com> Organization: TRW Financial Systems Date: Sat, 3 Oct 1992 04:01:55 GMT Lines: 1315 # This is a shell archive. Save it in a file, remove anything before # this line, and then unpack it by entering "sh file". Note, it may # create directories; files and directories will be owned by you and # have default permissions. # # This archive contains: # # sys/chio.h # scsi/scsi_changer.h # scsi/ch.c # echo x - sys/chio.h sed 's/^X//' >sys/chio.h << 'END-of-sys/chio.h' X/* X * Copyright (c) 1982, 1986 The Regents of the University of California. X * All rights reserved. X * X * Redistribution and use in source and binary forms, with or without X * modification, are permitted provided that the following conditions X * are met: X * 1. Redistributions of source code must retain the above copyright X * notice, this list of conditions and the following disclaimer. X * 2. Redistributions in binary form must reproduce the above copyright X * notice, this list of conditions and the following disclaimer in the X * documentation and/or other materials provided with the distribution. X * 3. All advertising materials mentioning features or use of this software X * must display the following acknowledgement: X * This product includes software developed by the University of X * California, Berkeley and its contributors. X * 4. Neither the name of the University nor the names of its contributors X * may be used to endorse or promote products derived from this software X * without specific prior written permission. X * X * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE X * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF X * SUCH DAMAGE. X * X * @(#)chio.h 7.6 (Berkeley) 2/5/91 X */ X X/* This is a "convertet" mtio.h from 386BSD X Stefan Grefen grefen@goofy.zdv.uni-mainz.de X */ X X/* X * Structures and definitions for changer io control commands X */ X#ifndef _CHIO_H_ X#define _CHIO_H_ X X#define CH_INVERT 0x10000 X#define CH_ADDR_MASK 0xffff Xstruct chop { X short ch_op; /* operations defined below */ X short result; /* The result */ X union { X struct { X int chm; /* Transport element */ X int from; X int to; X } move; X struct { X int chm; /* Transport element */ X int to; X } position; X struct { X short chmo; /* Offset of first CHM */ X short chms; /* No. of CHM */ X short slots; /* No. of Storage Elements */ X short sloto; /* Offset of first SE */ X short imexs; /* No. of Import/Export Slots */ X short imexo; /* Offset of first IM/EX */ X short drives; /* No. of CTS */ X short driveo; /* Offset of first CTS */ X short rot; /* CHM can rotate */ X } getparam; X struct { X int type; X#define CH_CHM 1 X#define CH_STOR 2 X#define CH_IMEX 3 X#define CH_CTS 4 X int from; X struct { X u_char elema_1; X u_char elema_0; X u_char full:1; X u_char rsvd:1; X u_char except:1; X u_char :5; X u_char rsvd2; X union { X struct { X u_char add_sense_code; X u_char add_sense_code_qualifier; X } specs; X short add_sense; X/* WARINING LSB only */ X#define CH_CHOLDER 0x0290 /* Cartridge holder is missing */ X#define CH_STATUSQ 0x0390 /* Status is questionable */ X#define CH_CTS_CLOSED 0x0490 /* CTS door is closed */ X X } ch_add_sense; X u_char rsvd3[3]; X u_char :6; X u_char invert:1; X u_char svalid:1; X u_char source_1; X u_char source_0; X u_char rsvd4[4]; X } elem_data; X } get_elem_stat; X } u; X}; X X/* operations */ X#define CHMOVE 1 X#define CHPOSITION 2 X#define CHGETPARAM 3 X#define CHGETELEM 4 X X X/* Changer IO control command */ X#define CHIOOP _IOWR('c', 1, struct chop) /* do a mag tape op */ X#endif END-of-sys/chio.h echo x - scsi/scsi_changer.h sed 's/^X//' >scsi/scsi_changer.h << 'END-of-scsi/scsi_changer.h' X/* X * HISTORY X * $Log: scsi_tape.h,v $ X * X */ X X/* X * SCSI changer interface description X */ X X/* X * Written by Stefan Grefen (grefen@goofy.zdv.uni-mainz.de soon grefen@convex.com) X * based on the SCSI System by written Julian Elischer (julian@tfs.com) X * for TRW Financial Systems. X * X * TRW Financial Systems, in accordance with their agreement with Carnegie X * Mellon University, makes this software available to CMU to distribute X * or use in any manner that they see fit as long as this message is kept with X * the software. For this reason TFS also grants any other persons or X * organisations permission to use or modify this software. X * X * TFS supplies this software to be publicly redistributed X * on the understanding that TFS is not responsible for the correct X * functioning of this software in any circumstances. X * X */ X X/* X * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 X */ X X/* X * SCSI command format X */ Xstruct scsi_read_element_status X{ X u_char op_code; X u_char element_type_code:4; X u_char voltag:1; X u_char lun:3; X u_char starting_element_addr[2]; X u_char number_of_elements[2]; X u_char resv1; X u_char allocation_length[3]; X u_char resv2; X u_char link:1; X u_char flag:1; X u_char :6; X}; X#define RE_ALL_ELEMENTS 0 X#define RE_MEDIUM_TRANSPORT_ELEMENT 1 X#define RE_STORAGE_ELEMENT 2 X#define RE_IMPORT_EXPORT 3 X#define RE_DATA_TRANSFER_ELEMENT 4 X Xstruct scsi_move_medium X{ X u_char op_code; X u_char :5; X u_char lun:3; X u_char transport_element_address[2]; X u_char source_address[2]; X u_char destination_address[2]; X u_char rsvd[2]; X u_char invert:1; X u_char :7; X u_char link:1; X u_char flag:1; X u_char :6; X}; X Xstruct scsi_position_to_element X{ X u_char op_code; X u_char :5; X u_char lun:3; X u_char transport_element_address[2]; X u_char source_address[2]; X u_char rsvd[2]; X u_char invert:1; X u_char :7; X u_char link:1; X u_char flag:1; X u_char :6; X}; X X/* X * Opcodes X */ X#define POSITION_TO_ELEMENT 0x2b X#define MOVE_MEDIUM 0xa5 X#define READ_ELEMENT_STATUS 0xb8 X Xstruct scsi_element_status_data X{ X u_char first_element_reported[2]; X u_char number_of_elements_reported[2]; X u_char rsvd; X u_char byte_count_of_report[3]; X}; X Xstruct element_status_page X{ X u_char element_type_code; X u_char :5; X u_char avoltag:1; X u_char pvoltag:1; X u_char element_descriptor_length[2]; X u_char rsvd; X u_char byte_count_of_descriptor_data[3]; X}; X END-of-scsi/scsi_changer.h echo x - scsi/ch.c sed 's/^X//' >scsi/ch.c << 'END-of-scsi/ch.c' X/* X * Mach Operating System X * Copyright (c) 1990 Carnegie-Mellon University X * Copyright (c) 1989 Carnegie-Mellon University X * All rights reserved. The CMU software License Agreement specifies X * the terms and conditions for use and redistribution. X */ X/* X * HISTORY X * X * X */ X X#include <sys/types.h> X#include <ch.h> X X#include <sys/param.h> X#include <sys/systm.h> X X#include <sys/errno.h> X#include <sys/ioctl.h> X#include <sys/buf.h> X#include <sys/proc.h> X#include <sys/user.h> X#include <sys/chio.h> X X#if defined(OSF) X#define SECSIZE 512 X#endif /* defined(OSF) */ X X#include <scsi/scsi_all.h> X#include <scsi/scsi_changer.h> X#include <scsi/scsiconf.h> X X Xstruct scsi_xfer ch_scsi_xfer[NCH]; Xint ch_xfer_block_wait[NCH]; X X X#define PAGESIZ 4096 X#define STQSIZE 4 X#define CH_RETRIES 4 X X X#define MODE(z) ( (minor(z) & 0x0F) ) X#define UNIT(z) ( (minor(z) >> 4) ) X X#ifndef MACH X#define ESUCCESS 0 X#endif MACH X Xint ch_info_valid[NCH]; /* the info about the device is valid */ Xint ch_initialized[NCH] ; Xint ch_debug = 1; X Xint chattach(); Xint ch_done(); Xstruct ch_data X{ X int flags; X struct scsi_switch *sc_sw; /* address of scsi low level switch */ X int ctlr; /* so they know which one we want */ X int targ; /* our scsi target ID */ X int lu; /* out scsi lu */ X short chmo; /* Offset of first CHM */ X short chms; /* No. of CHM */ X short slots; /* No. of Storage Elements */ X short sloto; /* Offset of first SE */ X short imexs; /* No. of Import/Export Slots */ X short imexo; /* Offset of first IM/EX */ X short drives; /* No. of CTS */ X short driveo; /* Offset of first CTS */ X short rot; /* CHM can rotate */ X u_long op_matrix; /* possible opertaions */ X u_short lsterr; /* details of lasterror */ X u_char stor; /* posible Storage locations */ X}ch_data[NCH]; X X#define CH_OPEN 0x01 X#define CH_KNOWN 0x02 X Xstatic int next_ch_unit = 0; X/***********************************************************************\ X* The routine called by the low level scsi routine when it discovers * X* A device suitable for this driver * X\***********************************************************************/ X Xint chattach(ctlr,targ,lu,scsi_switch) Xstruct scsi_switch *scsi_switch; X{ X int unit,i,stat; X unsigned char *tbl; X X if(scsi_debug & PRINTROUTINES) printf("chattach: "); X /*******************************************************\ X * Check we have the resources for another drive * X \*******************************************************/ X unit = next_ch_unit++; X if( unit >= NCH) X { X printf("Too many scsi changers..(%d > %d) reconfigure kernel",(unit + 1),NCH); X return(0); X } X /*******************************************************\ X * Store information needed to contact our base driver * X \*******************************************************/ X ch_data[unit].sc_sw = scsi_switch; X ch_data[unit].ctlr = ctlr; X ch_data[unit].targ = targ; X ch_data[unit].lu = lu; X X /*******************************************************\ X * Use the subdriver to request information regarding * X * the drive. We cannot use interrupts yet, so the * X * request must specify this. * X \*******************************************************/ X if((ch_mode_sense(unit, SCSI_NOSLEEP | SCSI_NOMASK /*| SCSI_SILENT*/))) X { X printf(" ch%d: scsi changer, %d slot(s) %d drive(s) %d arm(s) %d i/e-slot(s) \n", X unit, ch_data[unit].slots, ch_data[unit].drives, ch_data[unit].chms, ch_data[unit].imexs); X stat=CH_KNOWN; X } X else X { X printf(" ch%d: scsi changer :- offline\n", unit); X stat=CH_OPEN; X } X ch_initialized[unit] = stat; X X return; X X} X X X X/*******************************************************\ X* open the device. * X\*******************************************************/ Xchopen(dev) X{ X int errcode = 0; X int unit,mode; X X unit = UNIT(dev); X mode = MODE(dev); X X /*******************************************************\ X * Check the unit is legal * X \*******************************************************/ X if ( unit >= NCH ) X { X printf("ch %d > %d\n",unit,NCH); X errcode = ENXIO; X return(errcode); X } X /*******************************************************\ X * Only allow one at a time * X \*******************************************************/ X if(ch_data[unit].flags & CH_OPEN) X { X printf("CH%d already open\n",unit); X errcode = ENXIO; X goto bad; X } X X if(ch_debug||(scsi_debug & (PRINTROUTINES | TRACEOPENS))) X printf("chopen: dev=0x%x (unit %d (of %d))\n" X , dev, unit, NCH); X /*******************************************************\ X * Make sure the device has been initialised * X \*******************************************************/ X X if (!ch_initialized[unit]) X return(ENXIO); X if (ch_initialized[unit]!=CH_KNOWN) { X if((ch_mode_sense(unit, SCSI_NOSLEEP | SCSI_NOMASK /*| SCSI_SILENT*/))) X { X ch_initialized[unit]=CH_KNOWN; X } X else X { X printf(" ch%d: scsi changer :- offline\n", unit); X return(ENXIO); X } X } X /*******************************************************\ X * Check that it is still responding and ok. * X \*******************************************************/ X X if(ch_debug || (scsi_debug & TRACEOPENS)) X printf("device is "); X if (!(ch_req_sense(unit, 0))) X { X errcode = ENXIO; X if(ch_debug || (scsi_debug & TRACEOPENS)) X printf("not responding\n"); X goto bad; X } X if(ch_debug || (scsi_debug & TRACEOPENS)) X printf("ok\n"); X X if(!(ch_test_ready(unit,0))) X { X printf("ch%d not ready\n",unit); X return(EIO); X } X X ch_info_valid[unit] = TRUE; X X /*******************************************************\ X * Load the physical device parameters * X \*******************************************************/ X X ch_data[unit].flags = CH_OPEN; X return(errcode); Xbad: X return(errcode); X} X X/*******************************************************\ X* close the device.. only called if we are the LAST * X* occurence of an open device * X\*******************************************************/ Xchclose(dev) X{ X unsigned char unit,mode; X X unit = UNIT(dev); X mode = MODE(dev); X X if(scsi_debug & TRACEOPENS) X printf("Closing device"); X ch_data[unit].flags = 0; X return(0); X} X X X/*******************************************************\ X* Actually translate the requested transfer into * X* one the physical driver can understand * X* The transfer is described by a buf and will include * X* only one physical transfer. * X\*******************************************************/ X Xint chstrategy(bp) Xstruct buf *bp; X{ X struct buf *dp; X unsigned char unit; X unsigned int opri; X X bp->b_error = EIO; X X bp->b_flags |= B_ERROR; X X /*******************************************************\ X * Correctly set the buf to indicate a completed xfer * X \*******************************************************/ X iodone(bp); X return; X} X X X/***************************************************************\ X* chstart * X* This routine is also called after other non-queued requests * X* have been made of the scsi driver, to ensure that the queue * X* continues to be drained. * X\***************************************************************/ X/* chstart() is called at splbio */ Xchstart(unit) X{ X int drivecount; X register struct buf *bp = 0; X register struct buf *dp; X struct scsi_xfer *xs; X int blkno, nblk; X X X if(scsi_debug & PRINTROUTINES) printf("chstart%d ",unit); X /*******************************************************\ X * See if there is a buf to do and we are not already * X * doing one * X \*******************************************************/ X xs=&ch_scsi_xfer[unit]; X if(xs->flags & INUSE) X { X return; /* unit already underway */ X } X if(ch_xfer_block_wait[unit]) /* a special awaits, let it proceed first */ X { X wakeup(&ch_xfer_block_wait[unit]); X return; X } X X return; X X} X X X/*******************************************************\ X* This routine is called by the scsi interrupt when * X* the transfer is complete. X\*******************************************************/ Xint ch_done(unit,xs) Xint unit; Xstruct scsi_xfer *xs; X{ X struct buf *bp; X int retval; X X if(ch_debug||(scsi_debug & PRINTROUTINES)) printf("ch_done%d ",unit); X if (! (xs->flags & INUSE)) X panic("scsi_xfer not in use!"); X wakeup(xs); X} X/*******************************************************\ X* Perform special action on behalf of the user * X* Knows about the internals of this device * X\*******************************************************/ Xchioctl(dev, cmd, arg, mode) Xdev_t dev; Xint cmd; Xcaddr_t arg; X{ X /* struct ch_cmd_buf *args;*/ X union scsi_cmd *scsi_cmd; X register i,j; X unsigned int opri; X int errcode = 0; X unsigned char unit; X int number,flags,ret; X X /*******************************************************\ X * Find the device that the user is talking about * X \*******************************************************/ X flags = 0; /* give error messages, act on errors etc. */ X unit = UNIT(dev); X X switch(cmd) X { X case CHIOOP: { X struct chop *ch=(struct chop *) arg; X if (ch_debug) X printf("[chtape_chop: %x]\n", ch->ch_op); X X switch ((short)(ch->ch_op)) { X case CHGETPARAM: X ch->u.getparam.chmo= ch_data[unit].chmo; X ch->u.getparam.chms= ch_data[unit].chms; X ch->u.getparam.sloto= ch_data[unit].sloto; X ch->u.getparam.slots= ch_data[unit].slots; X ch->u.getparam.imexo= ch_data[unit].imexo; X ch->u.getparam.imexs= ch_data[unit].imexs; X ch->u.getparam.driveo= ch_data[unit].driveo; X ch->u.getparam.drives= ch_data[unit].drives; X ch->u.getparam.rot= ch_data[unit].rot; X ch->result=0; X return 0; X break; X case CHPOSITION: X return ch_position(unit,&ch->result,ch->u.position.chm, X ch->u.position.to, X flags); X case CHMOVE: X return ch_move(unit,&ch->result, ch->u.position.chm, X ch->u.move.from, ch->u.move.to, X flags); X case CHGETELEM: X return ch_getelem(unit,&ch->result, ch->u.get_elem_stat.type, X ch->u.get_elem_stat.from, &ch->u.get_elem_stat.elem_data, X flags); X default: X return EINVAL; X } X X } X#ifdef NOT_NOW X /*******************************************************\ X * This is a direct command for the scsi driver, pass * X * it on.. * X \*******************************************************/ X case A_CMD: X args = (struct ch_cmd_buf *) arg; X ch_cmd(args->byte[0], args->byte[1], args->byte, args->byte[3], args->byte[4], args->byte[5], args->byte[6], args->byte[7]); X break; X /*******************************************************\ X * This is a low level scsi command ... just do it * X \*******************************************************/ X case A_SCSI: X /* will not work yet... fix it later.... X errcode = ch_scsi_cmd(UNIT(dev), X arg, X /* len */ 10, X ccb_data, X sizeof(ccb_data), X 100000, X 0); X break; X#endif NOT_NOW X default: X return EINVAL; X } X X return(ret?ESUCCESS:EIO); X} X Xch_getelem(unit,stat,type,from,data,flags) Xint unit,from,flags; Xshort *stat; Xchar *data; X{ X struct scsi_read_element_status scsi_cmd; X char elbuf[32]; X int ret; X X bzero(&scsi_cmd, sizeof(scsi_cmd)); X scsi_cmd.op_code = READ_ELEMENT_STATUS; X scsi_cmd.element_type_code=type; X scsi_cmd.starting_element_addr[0]=(from>>8)&0xff; X scsi_cmd.starting_element_addr[1]=from&0xff; X scsi_cmd.number_of_elements[1]=1; X scsi_cmd.allocation_length[2]=32; X X if ((ret=ch_scsi_cmd(unit, X &scsi_cmd, X sizeof(scsi_cmd), X elbuf, X 32, X 100000, X flags) !=ESUCCESS)) { X *stat=ch_data[unit].lsterr; X bcopy(elbuf+16,data,16); X return ret; X } X bcopy(elbuf+16,data,16); /*Just a hack sh */ X return ret; X} X Xch_move(unit,stat,chm,from,to,flags) Xint unit,chm,from,to,flags; Xshort *stat; X{ X struct scsi_move_medium scsi_cmd; X int ret; X X bzero(&scsi_cmd, sizeof(scsi_cmd)); X scsi_cmd.op_code = MOVE_MEDIUM; X scsi_cmd.transport_element_address[0]=(chm>>8)&0xff; X scsi_cmd.transport_element_address[1]=chm&0xff; X scsi_cmd.source_address[0]=(from>>8)&0xff; X scsi_cmd.source_address[1]=from&0xff; X scsi_cmd.destination_address[0]=(to>>8)&0xff; X scsi_cmd.destination_address[1]=to&0xff; X scsi_cmd.invert=(chm&CH_INVERT)?1:0; X if ((ret=ch_scsi_cmd(unit, X &scsi_cmd, X sizeof(scsi_cmd), X NULL, X 0, X 100000, X flags) !=ESUCCESS)) { X *stat=ch_data[unit].lsterr; X return ret; X } X return ret; X} X Xch_position(unit,stat,chm,to,flags) Xint unit,chm,to,flags; Xshort *stat; X{ X struct scsi_position_to_element scsi_cmd; X int ret; X X bzero(&scsi_cmd, sizeof(scsi_cmd)); X scsi_cmd.op_code = POSITION_TO_ELEMENT; X scsi_cmd.transport_element_address[0]=(chm>>8)&0xff; X scsi_cmd.transport_element_address[1]=chm&0xff; X scsi_cmd.source_address[0]=(to>>8)&0xff; X scsi_cmd.source_address[1]=to&0xff; X scsi_cmd.invert=(chm&CH_INVERT)?1:0; X if ((ret=ch_scsi_cmd(unit, X &scsi_cmd, X sizeof(scsi_cmd), X NULL, X 0, X 100000, X flags) !=ESUCCESS)) { X *stat=ch_data[unit].lsterr; X return ret; X } X return ret; X} X X/*******************************************************\ X* Check with the device that it is ok, (via scsi driver)* X\*******************************************************/ Xch_req_sense(unit, flags) Xint flags; X{ X struct scsi_sense_data sense; X struct scsi_sense scsi_cmd; X X bzero(&scsi_cmd, sizeof(scsi_cmd)); X scsi_cmd.op_code = REQUEST_SENSE; X scsi_cmd.length = sizeof(sense); X X if (ch_scsi_cmd(unit, X &scsi_cmd, X sizeof(struct scsi_sense), X &sense, X sizeof(sense), X 100000, X flags | SCSI_DATA_IN) != 0) X { X return(FALSE); X } X else X return(TRUE); X} X X/*******************************************************\ X* Get scsi driver to send a "are you ready" command * X\*******************************************************/ Xch_test_ready(unit,flags) Xint unit,flags; X{ X struct scsi_test_unit_ready scsi_cmd; X X bzero(&scsi_cmd, sizeof(scsi_cmd)); X scsi_cmd.op_code = TEST_UNIT_READY; X X if (ch_scsi_cmd(unit, X &scsi_cmd, X sizeof(struct scsi_test_unit_ready), X 0, X 0, X 100000, X flags) != 0) { X return(FALSE); X } else X return(TRUE); X} X X X#ifdef __STDC__ X#define b2tol(a) (((unsigned)(a##_1) << 8) + (unsigned)a##_0 ) X#else X#define b2tol(a) (((unsigned)(a/**/_1) << 8) + (unsigned)a/**/_0 ) X#endif X X/*******************************************************\ X* Get the scsi driver to send a full inquiry to the * X* device and use the results to fill out the global * X* parameter structure. * X\*******************************************************/ Xch_mode_sense(unit, flags) Xint unit,flags; X{ X struct scsi_mode_sense scsi_cmd; X u_char scsi_sense[128]; /* Can't use scsi_mode_sense_data because of */ X /* missing block descriptor */ X u_char *b; X int i,l; X X /*******************************************************\ X * First check if we have it all loaded * X \*******************************************************/ X if (ch_info_valid[unit]==CH_KNOWN) return(TRUE); X /*******************************************************\ X * First do a mode sense * X \*******************************************************/ X ch_info_valid[unit] &= ~CH_KNOWN; X for(l=1;l>=0;l--) { X bzero(&scsi_cmd, sizeof(scsi_cmd)); X scsi_cmd.op_code = MODE_SENSE; X scsi_cmd.dbd = l; X scsi_cmd.page_code = 0x3f; /* All Pages */ X scsi_cmd.length = sizeof(scsi_sense); X /*******************************************************\ X * do the command, but we don't need the results * X * just print them for our interest's sake * X \*******************************************************/ X if (ch_scsi_cmd(unit, X &scsi_cmd, X sizeof(struct scsi_mode_sense), X &scsi_sense, X sizeof(scsi_sense), X 5000, X flags | SCSI_DATA_IN) == 0) { X ch_info_valid[unit] = CH_KNOWN; X break; X } X } X if (ch_info_valid[unit]!=CH_KNOWN) { X if(!(flags & SCSI_SILENT)) X printf("could not mode sense for unit %d\n", unit); X return(FALSE); X } X l=scsi_sense[0]-3; X b=&scsi_sense[4]; X /*****************************\ X * To avoid alignment problems * X \*****************************/ X/*FIX THIS FOR MSB */ X#define p2copy(valp) (valp[1]+ (valp[0]<<8));valp+=2 X#define p4copy(valp) (valp[3]+ (valp[2]<<8) + (valp[1]<<16) + (valp[0]<<24));valp+=4 X#if 0 X printf("\nmode_sense %d\n",l); X for(i=0;i<l+4;i++) { X printf("%x%c",scsi_sense[i],i%8==7?'\n':':'); X } X printf("\n"); X#endif X for(i=0;i<l;) { X int pc=(*b++)&0x3f; X int pl=*b++; X u_char *bb=b; X switch(pc) { X case 0x1d: X ch_data[unit].chmo =p2copy(bb); X ch_data[unit].chms =p2copy(bb); X ch_data[unit].sloto =p2copy(bb); X ch_data[unit].slots =p2copy(bb); X ch_data[unit].imexo =p2copy(bb); X ch_data[unit].imexs =p2copy(bb); X ch_data[unit].driveo =p2copy(bb); X ch_data[unit].drives =p2copy(bb); X break; X case 0x1e: X ch_data[unit].rot = (*b)&1; X break; X case 0x1f: X ch_data[unit].stor = *b&0xf; X bb+=2; X ch_data[unit].stor =p4copy(bb); X break; X default: X break; X } X b+=pl; X i+=pl+2; X } X if (ch_debug) X { X printf("unit %d: cht(%d-%d)slot(%d-%d)imex(%d-%d)cts(%d-%d) %s rotate\n", X unit, X ch_data[unit].chmo, X ch_data[unit].chms, X ch_data[unit].sloto, X ch_data[unit].slots, X ch_data[unit].imexo, X ch_data[unit].imexs, X ch_data[unit].driveo, X ch_data[unit].drives, X ch_data[unit].rot?"can":"can't"); X } X return(TRUE); X} X X/*******************************************************\ X* ask the scsi driver to perform a command for us. * X* Call it through the switch table, and tell it which * X* sub-unit we want, and what target and lu we wish to * X* talk to. Also tell it where to find the command * X* how long int is. * X* Also tell it where to read/write the data, and how * X* long the data is supposed to be * X\*******************************************************/ Xint ch_scsi_cmd(unit,scsi_cmd,cmdlen,data_addr,datalen,timeout,flags) X Xint unit,flags; Xstruct scsi_generic *scsi_cmd; Xint cmdlen; Xint timeout; Xu_char *data_addr; Xint datalen; X{ X struct scsi_xfer *xs; X int retval; X int s; X X if(ch_debug||(scsi_debug & PRINTROUTINES)) printf("\nch_scsi_cmd%d %x", X unit,scsi_cmd->opcode); X if(ch_data[unit].sc_sw) /* If we have a scsi driver */ X { X X xs = &(ch_scsi_xfer[unit]); X if(!(flags & SCSI_NOMASK)) X s = splbio(); X ch_xfer_block_wait[unit]++; /* there is someone waiting */ X while (xs->flags & INUSE) X { X sleep(&ch_xfer_block_wait[unit],PRIBIO+1); X } X ch_xfer_block_wait[unit]--; X xs->flags = INUSE; X if(!(flags & SCSI_NOMASK)) X splx(s); X X /*******************************************************\ X * Fill out the scsi_xfer structure * X \*******************************************************/ X xs->flags |= flags; X xs->adapter = ch_data[unit].ctlr; X xs->targ = ch_data[unit].targ; X xs->lu = ch_data[unit].lu; X xs->retries = CH_RETRIES; X xs->timeout = timeout; X xs->cmd = scsi_cmd; X xs->cmdlen = cmdlen; X xs->data = data_addr; X xs->datalen = datalen; X xs->resid = datalen; X xs->when_done = (flags & SCSI_NOMASK) X ?(int (*)())0 X :ch_done; X xs->done_arg = unit; X xs->done_arg2 = (int)xs; Xretry: xs->error = XS_NOERROR; X xs->bp = 0; X ch_data[unit].lsterr=0; X retval = (*(ch_data[unit].sc_sw->scsi_cmd))(xs); X switch(retval) X { X case SUCCESSFULLY_QUEUED: X while(!(xs->flags & ITSDONE)) X sleep(xs,PRIBIO+1); X X case HAD_ERROR: X case COMPLETE: X switch(xs->error) X { X case XS_NOERROR: X retval = ESUCCESS; X break; X case XS_SENSE: X retval = (ch_interpret_sense(unit,xs)); X break; X case XS_DRIVER_STUFFUP: X retval = EIO; X break; X case XS_TIMEOUT: X if(xs->retries-- ) X { X xs->flags &= ~ITSDONE; X goto retry; X } X retval = EIO; X break; X case XS_BUSY: X if(xs->retries-- ) X { X xs->flags &= ~ITSDONE; X goto retry; X } X retval = EIO; X break; X default: X retval = EIO; X printf("st%d: unknown error category from scsi driver\n" X ,unit); X break; X } X break; X case TRY_AGAIN_LATER: X if(xs->retries-- ) X { X xs->flags &= ~ITSDONE; X goto retry; X } X retval = EIO; X break; X default: X retval = EIO; X } X xs->flags = 0; /* it's free! */ X chstart(unit); X } X else X { X printf("chd: not set up\n",unit); X return(EINVAL); X } X return(retval); X} X/***************************************************************\ X* Look at the returned sense and act on the error and detirmine * X* The unix error number to pass back... (0 = report no error) * X\***************************************************************/ X Xint ch_interpret_sense(unit,xs) Xint unit; Xstruct scsi_xfer *xs; X{ X struct scsi_sense_data *sense; X int key; X int silent = xs->flags & SCSI_SILENT; X X /***************************************************************\ X * If errors are ok, report a success * X \***************************************************************/ X if(xs->flags & SCSI_ERR_OK) return(ESUCCESS); X X /***************************************************************\ X * Get the sense fields and work out what CLASS * X \***************************************************************/ X sense = &(xs->sense); X switch(sense->error_class) X { X /***************************************************************\ X * If it's class 7, use the extended stuff and interpret the key * X \***************************************************************/ X case 7: X { X key=sense->ext.extended.sense_key; X if(sense->ext.extended.ili) X if(!silent) X { X printf("length error "); X } X if(sense->valid) X xs->resid = ntohl(*((long *)sense->ext.extended.info)); X if(xs->bp) X { X xs->bp->b_flags |= B_ERROR; X return(ESUCCESS); X } X if(sense->ext.extended.eom) X if(!silent) printf("end of medium "); X if(sense->ext.extended.filemark) X if(!silent) printf("filemark "); X if(ch_debug) X { X printf("code%x class%x valid%x\n" X ,sense->error_code X ,sense->error_class X ,sense->valid); X printf("seg%x key%x ili%x eom%x fmark%x\n" X ,sense->ext.extended.segment X ,sense->ext.extended.sense_key X ,sense->ext.extended.ili X ,sense->ext.extended.eom X ,sense->ext.extended.filemark); X printf("info: %x %x %x %x followed by %d extra bytes\n" X ,sense->ext.extended.info[0] X ,sense->ext.extended.info[1] X ,sense->ext.extended.info[2] X ,sense->ext.extended.info[3] X ,sense->ext.extended.extra_len); X printf("extra: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x\n" X ,sense->ext.extended.extra_bytes[0] X ,sense->ext.extended.extra_bytes[1] X ,sense->ext.extended.extra_bytes[2] X ,sense->ext.extended.extra_bytes[3] X ,sense->ext.extended.extra_bytes[4] X ,sense->ext.extended.extra_bytes[5] X ,sense->ext.extended.extra_bytes[6] X ,sense->ext.extended.extra_bytes[7] X ,sense->ext.extended.extra_bytes[8] X ,sense->ext.extended.extra_bytes[9] X ,sense->ext.extended.extra_bytes[10] X ,sense->ext.extended.extra_bytes[11] X ,sense->ext.extended.extra_bytes[12] X ,sense->ext.extended.extra_bytes[13] X ,sense->ext.extended.extra_bytes[14] X ,sense->ext.extended.extra_bytes[15]); X X } X switch(key) X { X case 0x0: X return(ESUCCESS); X case 0x1: X if(!silent) X { X printf("st%d: soft error(corrected) ", unit); X if(sense->valid) X { X printf("block no. %d (decimal)\n", X (sense->ext.extended.info[0] <<24)| X (sense->ext.extended.info[1] <<16)| X (sense->ext.extended.info[2] <<8)| X (sense->ext.extended.info[3] )); X } X else X { X printf("\n"); X } X } X return(ESUCCESS); X case 0x2: X if(!silent) printf("st%d: not ready\n ", unit); X ch_data[unit].lsterr=(sense->ext.extended.info[12]<<8)| X sense->ext.extended.info[13] ; X return(ENODEV); X case 0x3: X if(!silent) X { X printf("st%d: medium error ", unit); X if(sense->valid) X { X printf("block no. %d (decimal)\n", X (sense->ext.extended.info[0] <<24)| X (sense->ext.extended.info[1] <<16)| X (sense->ext.extended.info[2] <<8)| X (sense->ext.extended.info[3] )); X } X else X { X printf("\n"); X } X } X return(EIO); X case 0x4: X if(!silent) printf("st%d: non-media hardware failure\n ", X unit); X ch_data[unit].lsterr=(sense->ext.extended.info[12]<<8)| X sense->ext.extended.info[13] ; X return(EIO); X case 0x5: X if(!silent) printf("st%d: illegal request\n ", unit); X ch_data[unit].lsterr=(sense->ext.extended.info[12]<<8)| X sense->ext.extended.info[13] ; X return(EINVAL); X case 0x6: X if(!silent) printf("st%d: Unit attention.\n ", unit); X ch_data[unit].lsterr=(sense->ext.extended.info[12]<<8)| X sense->ext.extended.info[13] ; X ch_info_valid[unit] = FALSE; X if (ch_data[unit].flags & CH_OPEN) /* TEMP!!!! */ X return(EIO); X else X return(ESUCCESS); X case 0x7: X if(!silent) X { X printf("st%d: attempted protection violation " X , unit); X if(sense->valid) X { X printf("block no. %d (decimal)\n", X (sense->ext.extended.info[0] <<24)| X (sense->ext.extended.info[1] <<16)| X (sense->ext.extended.info[2] <<8)| X (sense->ext.extended.info[3] )); X } X else X { X printf("\n"); X } X } X return(EACCES); X case 0x8: X if(!silent) X { X printf("st%d: block wrong state (worm)\n " X , unit); X if(sense->valid) X { X printf("block no. %d (decimal)\n", X (sense->ext.extended.info[0] <<24)| X (sense->ext.extended.info[1] <<16)| X (sense->ext.extended.info[2] <<8)| X (sense->ext.extended.info[3] )); X } X else X { X printf("\n"); X } X } X return(EIO); X case 0x9: X if(!silent) printf("st%d: vendor unique\n", X unit); X return(EIO); X case 0xa: X if(!silent) printf("st%d: copy aborted\n ", X unit); X return(EIO); X case 0xb: X if(!silent) printf("st%d: command aborted\n ", X unit); X ch_data[unit].lsterr=(sense->ext.extended.info[12]<<8)| X sense->ext.extended.info[13] ; X return(EIO); X case 0xc: X if(!silent) X { X printf("st%d: search returned\n ", unit); X if(sense->valid) X { X printf("block no. %d (decimal)\n", X (sense->ext.extended.info[0] <<24)| X (sense->ext.extended.info[1] <<16)| X (sense->ext.extended.info[2] <<8)| X (sense->ext.extended.info[3] )); X } X else X { X printf("\n"); X } X } X return(ESUCCESS); X case 0xd: X if(!silent) printf("st%d: volume overflow\n ", X unit); X return(ENOSPC); X case 0xe: X if(!silent) X { X printf("st%d: verify miscompare\n ", unit); X if(sense->valid) X { X printf("block no. %d (decimal)\n", X (sense->ext.extended.info[0] <<24)| X (sense->ext.extended.info[1] <<16)| X (sense->ext.extended.info[2] <<8)| X (sense->ext.extended.info[3] )); X } X else X { X printf("\n"); X } X } X return(EIO); X case 0xf: X if(!silent) printf("st%d: unknown error key\n ", X unit); X return(EIO); X } X break; X } X /***************************************************************\ X * If it's NOT class 7, just report it. * X \***************************************************************/ X case 0: X case 1: X case 2: X case 3: X case 4: X case 5: X case 6: X { X if(!silent) printf("st%d: error class %d code %d\n", X unit, X sense->error_class, X sense->error_code); X if(sense->valid) X if(!silent) printf("block no. %d (decimal)\n", X (sense->ext.unextended.blockhi <<16), X + (sense->ext.unextended.blockmed <<8), X + (sense->ext.unextended.blocklow )); X } X return(EIO); X } X} X X X END-of-scsi/ch.c exit