📄 rf_camlayer.c
字号:
/* * Copyright (c) 1995 Carnegie-Mellon University. * All rights reserved. * * Author: Mark Holland * * Permission to use, copy, modify and distribute this software and * its documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. *//******************************************************************************** * camlayer.c -- code for interfacing to the OSF/1 CAM layer * * the generic call structure is to allocate a RF_DiskOp_t data structure describing * what you want to do by calling one of the "alloc" routines, then actually * do the op by calling the corresponding "do" routine, and the free the RF_DiskOp_t * by calling FreeDiskOp. *******************************************************************************//* $Locker: $ * $Log: rf_camlayer.c,v $ * Revision 1.33 1996/08/16 17:51:22 jimz * begin AIX additions * * Revision 1.32 1996/07/19 16:10:34 jimz * deal better with disk labels + partitions * * Revision 1.31 1996/07/18 22:57:14 jimz * port simulator to AIX * * Revision 1.30 1996/07/15 17:22:18 jimz * nit-pick code cleanup * resolve stdlib problems on DEC OSF * * Revision 1.29 1996/06/10 11:55:47 jimz * Straightened out some per-array/not-per-array distinctions, fixed * a couple bugs related to confusion. Added shutdown lists. Removed * layout shutdown function (now subsumed by shutdown lists). * * Revision 1.28 1996/06/09 02:36:46 jimz * lots of little crufty cleanup- fixup whitespace * issues, comment #ifdefs, improve typing in some * places (esp size-related) * * Revision 1.27 1996/06/07 21:33:04 jimz * begin using consistent types for sector numbers, * stripe numbers, row+col numbers, recon unit numbers * * Revision 1.26 1996/06/05 18:06:02 jimz * Major code cleanup. The Great Renaming is now done. * Better modularity. Better typing. Fixed a bunch of * synchronization bugs. Made a lot of global stuff * per-desc or per-array. Removed dead code. * * Revision 1.25 1996/06/03 23:28:26 jimz * more bugfixes * check in tree to sync for IPDS runs with current bugfixes * there still may be a problem with threads in the script test * getting I/Os stuck- not trivially reproducible (runs ~50 times * in a row without getting stuck) * * Revision 1.24 1996/05/30 23:22:16 jimz * bugfixes of serialization, timing problems * more cleanup * * Revision 1.23 1996/05/30 11:29:41 jimz * Numerous bug fixes. Stripe lock release code disagreed with the taking code * about when stripes should be locked (I made it consistent: no parity, no lock) * There was a lot of extra serialization of I/Os which I've removed- a lot of * it was to calculate values for the cache code, which is no longer with us. * More types, function, macro cleanup. Added code to properly quiesce the array * on shutdown. Made a lot of stuff array-specific which was (bogusly) general * before. Fixed memory allocation, freeing bugs. * * Revision 1.22 1996/05/27 18:56:37 jimz * more code cleanup * better typing * compiles in all 3 environments * * Revision 1.21 1996/05/24 22:17:04 jimz * continue code + namespace cleanup * typed a bunch of flags * * Revision 1.20 1996/05/23 21:46:35 jimz * checkpoint in code cleanup (release prep) * lots of types, function names have been fixed * * Revision 1.19 1996/05/23 00:33:23 jimz * code cleanup: move all debug decls to rf_options.c, all extern * debug decls to rf_options.h, all debug vars preceded by rf_ * * Revision 1.18 1996/05/18 19:51:34 jimz * major code cleanup- fix syntax, make some types consistent, * add prototypes, clean out dead code, et cetera * * Revision 1.17 1996/05/06 18:44:23 jimz * add ShutdownCamLayer() * * Revision 1.16 1995/12/12 18:10:06 jimz * MIN -> RF_MIN, MAX -> RF_MAX, ASSERT -> RF_ASSERT * fix 80-column brain damage in comments * * Revision 1.15 1995/12/01 15:16:19 root * added copyright info * */#ifdef __osf__#ifndef KERNEL#include <errno.h>#include <fcntl.h>#include <stdlib.h>#include <stdio.h>#include <string.h>#include <strings.h>#include <ctype.h>#include <unistd.h>#include <sys/ioctl.h>#else /* !KERNEL */#include <labels.h>#endif /* !KERNEL */#include "rf_types.h"#include "rf_sys.h"#include "rf_ccmn.h"#include "rf_raid.h"#include "rf_general.h"#include "rf_camlayer.h"#include "rf_shutdown.h"#include "rf_options.h"/* A "handle" data structure via which we can do I/O through the cam layer * The ua_ccb is not used in the kernel. Will it mess up anything to leave it here anyway? * We could hack around it by #ifdef'ing it out when in the kernel, but it doesn't seem worth it. */typedef struct _cam_io_handle { UAGT_CAM_CCB ua_ccb; CCB_SCSIIO ccb; unsigned char snsBuf[RF_CAM_SENSEDATALEN];} CamIOHandle;static int camfd = (-1); /* file descriptor for /dev/cam */#ifndef KERNELstatic void rf_release_sim_queue(CCB_SCSIIO *ccb);static void rf_print_ccb_status(CCB_HEADER *cp);#endif /* !KERNEL */#ifndef KERNEL/*ARGSUSED*/static void rf_ShutdownCamLayer(ignored) void *ignored;{ int rc; rc = close(camfd); camfd = (-1);}#endif /* !KERNEL *//*ARGSUSED*/int rf_ConfigureCamLayer(listp) RF_ShutdownList_t **listp;{#ifndef KERNEL int rc; /* open the cam file */ if ((camfd = open("/dev/cam", O_RDWR, 0)) < 0) { RF_ERRORMSG("Unable to open /dev/cam\n"); perror("CAM open"); return(errno); } rc = rf_ShutdownCreate(listp, rf_ShutdownCamLayer, NULL); if (rc) { RF_ERRORMSG3("Unable to add to shutdown list file %s line %d rc=%d\n", __FILE__, __LINE__, rc); close(camfd); return(rc); }#endif /* !KERNEL */ return(0);}/******************************************************************************** * * creates/destroys a "handle" via which we can do I/O through the cam layer * the return value is cast to void * so that the caller need not know * anything at all about cam data structures. * *******************************************************************************/void *rf_CreateCamIOHandle(){ CamIOHandle *p; RF_Malloc(p, sizeof(CamIOHandle), (CamIOHandle *)); return((void *)p);}void rf_DestroyCamIOHandle(h) void *h;{ RF_Free((CamIOHandle *)h,sizeof(CamIOHandle)); /* unspeakably gratuitous castage here */}/******************************************************************************** * extracts the bus & target IDs from the device file name. * assumes that the file name conforms to the DEC OSF/1 spec *******************************************************************************/int rf_extract_ids(name, bus_id, targ_id, lun) char *name; int *bus_id; int *targ_id; int *lun;{ char *p; unsigned devnum; for (p=name; (*p) && (*p<'0' || *p>'9'); p++); if (!*p) { printf("Invalid device name for disk device \"%s\".\n",name); return(ENODEV); } if (p > name && (*(p-1) >= 'a' && *(p-1) <= 'g')) *lun = *(p-1) - 'a' + 1; else *lun = 0; devnum = atoi(p); *targ_id = devnum&0x7; *bus_id = devnum>>3; return(0);}/******************************************************************************** * these are utility routines used by the code below. *******************************************************************************/#ifndef KERNEL/* allocate the data structures */#define RF_ALLOCATE_CCB_AND_SENSE(_uaccb_, _ccb_, _sns_) { \ RF_Calloc(_ccb_, 1, sizeof(CCB_SCSIIO), (CCB_SCSIIO *)); \ RF_Calloc(_uaccb_, 1, sizeof(UAGT_CAM_CCB), (UAGT_CAM_CCB *)); \ RF_Calloc(_sns_, 1, sizeof(ALL_REQ_SNS_DATA), (ALL_REQ_SNS_DATA *)); \} /* set up some default parameters */static void rf_set_default_ccb_params( UAGT_CAM_CCB *ua_ccb, CCB_SCSIIO *ccb, ALL_REQ_SNS_DATA *sns, unsigned direction, u_char *dataptr, unsigned datalen, unsigned cdblen){ ccb->cam_ch.my_addr = (struct ccb_header *) ccb; ccb->cam_ch.cam_ccb_len = sizeof(CCB_SCSIIO); ccb->cam_ch.cam_func_code = XPT_SCSI_IO; ccb->cam_sense_ptr = (u_char *) sns; ccb->cam_sense_len = (u_char)sizeof(*sns); ccb->cam_ch.cam_flags = direction; ccb->cam_data_ptr = (u_char *) dataptr; ccb->cam_dxfer_len = datalen; ccb->cam_cdb_len = cdblen; ccb->cam_timeout = CAM_TIME_DEFAULT; ua_ccb->uagt_ccb = (CCB_HEADER *) ccb; ua_ccb->uagt_ccblen = sizeof(CCB_SCSIIO); ua_ccb->uagt_snsbuf = (u_char *) sns; ua_ccb->uagt_snslen = sizeof(*sns); ua_ccb->uagt_cdb = (CDB_UN *) NULL; ua_ccb->uagt_cdblen = 0; ua_ccb->uagt_buffer = dataptr; ua_ccb->uagt_buflen = datalen;}#endif /* !KERNEL *//******************************************************************************** * the next few routines allocate data structures necessary for telling * the CAM layer what operation we want to do and how to control it. * this is used only at user level. *******************************************************************************//* create a RF_DiskOp_t for doing a READ CAPACITY */int rf_SCSI_AllocReadCapacity(ua_ccb_out) RF_DiskOp_t **ua_ccb_out;{ CCB_SCSIIO *ccb; /* I/O command control block */ UAGT_CAM_CCB *ua_ccb; /* user agent ccb for communication to CAM layer */ ALL_REQ_SNS_DATA *sns; /* sense data buffer */ DIR_READ_CAP_DATA *dat; /* read capacity data buffer */ DIR_READ_CAP_CDB10 *rdcap; /* SCSI command descriptor block (cdb) for READ CAPACITY */#ifndef KERNEL RF_ALLOCATE_CCB_AND_SENSE(ua_ccb, ccb, sns); RF_Calloc(dat, 1, sizeof(DIR_READ_CAP_DATA), (DIR_READ_CAP_DATA *)); rf_set_default_ccb_params(ua_ccb, ccb, sns, CAM_DIR_IN, (u_char *)dat, sizeof(DIR_READ_CAP_DATA), sizeof(DIR_READ_CAP_CDB10)); rdcap = (DIR_READ_CAP_CDB10 *) &(ccb->cam_cdb_io.cam_cdb_bytes[0]); (void) bzero( (char *) rdcap, sizeof(DIR_READ_CAP_CDB10) ); rdcap->opcode = DIR_READCAP_OP; *ua_ccb_out = (RF_DiskOp_t *) ua_ccb;#endif /* !KERNEL */ return(0);}/* create a RF_DiskOp_t for doing a TEST UNIT READY */int rf_SCSI_AllocTUR(ua_ccb_out) RF_DiskOp_t **ua_ccb_out;{ CCB_SCSIIO *ccb; /* I/O command control block */ UAGT_CAM_CCB *ua_ccb; /* user agent ccb for communication to CAM layer */ ALL_REQ_SNS_DATA *sns; /* sense data buffer */ ALL_TUR_CDB *tur; /* scsi cdb for TEST UNIT READY */#ifndef KERNEL RF_ALLOCATE_CCB_AND_SENSE(ua_ccb, ccb, sns); rf_set_default_ccb_params(ua_ccb, ccb, sns, CAM_DIR_NONE, NULL, 0, sizeof(ALL_TUR_CDB)); tur = (ALL_TUR_CDB *) &(ccb->cam_cdb_io.cam_cdb_bytes[0]); (void) bzero( (char *) tur, sizeof(ALL_TUR_CDB) ); tur->opcode = ALL_TUR_OP; *ua_ccb_out = (RF_DiskOp_t *) ua_ccb;#endif /* !KERNEL */ return(0);}/******************************************************************************** * free a previously allocated RF_DiskOp_t. Common to all alloc routines. *******************************************************************************/int rf_SCSI_FreeDiskOp(op, free_the_buf) RF_DiskOp_t *op; int free_the_buf;{#ifndef KERNEL UAGT_CAM_CCB *ua_ccb = (UAGT_CAM_CCB *) op; if (free_the_buf) { RF_Free(ua_ccb->uagt_buffer, ua_ccb->uagt_buflen); } RF_Free(ua_ccb->uagt_snsbuf, sizeof(ALL_REQ_SNS_DATA)); RF_Free(ua_ccb->uagt_ccb, sizeof(CCB_SCSIIO)); RF_Free(ua_ccb, sizeof(UAGT_CAM_CCB));#endif /* !KERNEL */ return(0);}/*************************************************************************** * rf_get_big_endian * little-big endian conversion routine ***************************************************************************/static int rf_get_big_endian(buf, length) unsigned char *buf; int length;{ register long temp = 0; int i; for(i=0; i<length; i++) temp = (temp << 8) | *buf++; return(temp);}/******************************************************************************** * the next few routines actually do an operation, after it has been set up by * one of the allocation routines above ********************************************************************************/#ifdef KERNEL/* this gets invoked when a scsi command such as ccmn_tur completes. * copied from p. D-40 of device driver manual. */static void rf_done(ccb) CCB_SCSIIO *ccb;{ PDRV_DEVICE *pd; int s; pd = (PDRV_DEVICE *) ((PDRV_WS *) ccb->cam_pdrv_ptr)->pws_pdrv; if (!pd) RF_PANIC(); PDRV_IPLSMP_LOCK(pd, LK_RETRY, s); if (!ccb->cam_req_map) { /* not really necessary (yet) b/c we only use this for TUR and READ CAP */ wakeup(ccb); } PDRV_IPLSMP_UNLOCK(pd, s);}#endif /* KERNEL *//******************************************************************************** * generic routine to perform an op, called from "do" routines below ********************************************************************************/static int rf_do_scsi_op(dev, ua_ccb, str, max_retries) dev_t dev; UAGT_CAM_CCB *ua_ccb; /* user agent ccb for comm to cam layer */ char *str; /* identify what op we're doing for err report */ int max_retries; /* max number of allowable retries */{ CCB_SCSIIO *ccb = (CCB_SCSIIO *) ua_ccb->uagt_ccb; int status = 0;#ifdef KERNEL PDRV_DEVICE *pdrv_ptr; pdrv_ptr = GET_PDRV_PTR(dev);#endif /* KERNEL */ for (; max_retries>=0; max_retries--) {#ifndef KERNEL if (ioctl(camfd, UAGT_CAM_IO, (caddr_t) ua_ccb) < 0) { fprintf(stderr,"%s: ",str); perror("Error on CAM UAGT ioctl:"); return(-1); /* no retry in this case */ } if (ccb->cam_ch.cam_status != CAM_REQ_CMP) { RF_ERRORMSG1("SCSI CAM error on %s\n",str); rf_print_ccb_status( &(ccb->cam_ch) ); if (ccb->cam_ch.cam_status & CAM_SIM_QFRZN) rf_release_sim_queue(ccb); continue; } else break;#else /* KERNEL */ status = ccmn_send_ccb_wait(pdrv_ptr, ccb, 0, WAIT_PRIORITY); if (!status) break;#endif /* KERNEL */ } return(status);}/* do a TEST UNIT READY. bus,targ,lun is actually redundant since we have dev.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -