/************************************************************************* * Description * hba_vms.c - Implements a sample OpenVMS HBA API compliant vendor library * defining the entry points for the DLL application * * License: * The contents of this file are subject to the SNIA Public License * Version 1.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * * www.snia.org/smi/developers/cim * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. * * The Original Code is SNIA HBA API Sample Vendor Specific Library * * The Initial Developer of the Original Code is: * Benjamin F. Kuo, Troika Networks, Inc. (benk@troikanetworks.com) * * Contributor(s): * Tuan Lam, QLogic Corp. (t_lam@qlc.com) * Dan Willie, Emulex Corp. (Dan.Willie@emulex.com) * Dixon Hutchinson, Legato Systems, Inc. (dhutchin@legato.com) * ************************************************************************* * Revision History: * * X-3 OH0104 Oliver Hellwig 5-Jan-2006 * 1) vms_get_lun_list: fix buggy code to properly retry * lun list request if the lun list was too small. * 2) vms_send_scsi_qio: was not returning the scsi status * if there was an IOSB error code. For VMS, an IOSB * error just means that the SCSI command completed * with an error. * 3) vms_lookup_mapping: when parsing the lun list, don't * assume that lun 0 is at the beginning because the HSG80 * puts it at the end. * 4) vms_lookup_mapping: plug up a memory leak where the * lun_list wasn't being freed. * 5) Update the URL in the header for the SNIA license. * 6) vms_lookup_mapping: don't overrun the output buffer; * and return HBA_STATUS_ERROR_MORE_DATA if more data * is available than able to be returned. * * X-2 OH0103 Oliver Hellwig 11-Nov-2005 * a) In vms_get_udid, don't reverse the byte order for the * SCSI lun. * b) In vms_lookup_mapping, prevent an infinite loop by * looking for the SS$_NOLINKS and SS$_BADPARAM error returns. * c) Add additional debugging code and make minor formatting * changes. * * 23-Jun-2005 Oliver Hellwig Fix various bugs * 30-Oct-2003 J. Malmberg Port to OpenVMS. ************************************************************************* */ #include #include #include #include #include "hbaapi.h" #include "vendorhbaapi.h" #ifdef __DECC #pragma message disable longlongtype #pragma message disable dollarid #pragma message disable valuepres #pragma message disable pragma #endif #include /* printf and puts for debug only */ #ifndef __NEW_STARLET #define __NEW_STARLET 1 #endif #include #include #include #include #include #include #include #include #include #include #include #ifndef RDCAP_CMD$K_RDCAP_OPCODE #define RDCAP_CMD$K_RDCAP_OPCODE 0x25 #endif #ifndef RDCAP_CMD$K_LENGTH #define RDCAP_CMD$K_LENGTH 10 #endif #include /* #include */ /* world-wide id definitions */ #include #include #pragma message save #pragma message disable pragma #pragma message disable noparmlist #pragma message disable extendtype /* #include Use manual definitions */ #pragma message restore #define HBA_M_CHANNEL_OPEN 1 #define HBA_M_NOFG_DEV 2 #ifndef FC$C_QIO_SNIA_REQUEST #define FC$C_QIO_SNIA_REQUEST 14 #endif #ifndef FC$C_QIO_SUB_SNIA_ADP_ATTR #define FC$C_QIO_SUB_SNIA_ADP_ATTR 0 #endif #ifndef FC$C_QIO_SUB_SNIA_PORT_ATTR #define FC$C_QIO_SUB_SNIA_PORT_ATTR 1 #endif #ifndef FC$C_QIO_SUB_SNIA_PORTSTAT #define FC$C_QIO_SUB_SNIA_PORTSTAT 2 #endif #ifndef FC$C_QIO_SUB_SNIA_DISCPORTATTR #define FC$C_QIO_SUB_SNIA_DISCPORTATTR 3 #endif #ifndef FC$C_QIO_SUB_SNIA_RNIDMGMT #define FC$C_QIO_SUB_SNIA_RNIDMGMT 4 #endif #ifndef FC$C_QIO_SUB_SNIA_DISCWWPNATTR #define FC$C_QIO_SUB_SNIA_DISCWWPNATTR 5 #endif #define DEFAULT_SCSI_RETRIES 3 #ifdef __DECC #pragma member_alignment save #pragma nomember_alignment quadword #endif typedef struct _snia_rq_header { int64 command_code; /* FC$C_QIO_SNIA_REQUEST */ int64 qw_count; /* count of Quadwords following this cell */ int64 sub_command; /* Specific SNIA command */ uint64 data; /* Comand specific data (optional) */ } SNIA_RQ_HEADER; #define VMS_DEVNAME_SIZE 64 /* Standard 3 longword itemlist */ /*------------------------------*/ #pragma nomember_alignment longword typedef struct itm_list_3 { unsigned short buflen; unsigned short itemcode; void * buffer; unsigned short * ret_len; } ITEM_LIST_3; #ifdef __DECC #pragma member_alignment restore #endif int SYS$ASCTIM (unsigned short * timelen, struct dsc$descriptor_s * time_name, const void * timadr, unsigned long cvtflg); int SYS$DEVICE_SCAN (struct dsc$descriptor_s * ret_devnam, unsigned short * retlen, const struct dsc$descriptor_s * search_devnam, const ITEM_LIST_3 * item_list, void * context); int SYS$ASSIGN (const struct dsc$descriptor_s * devnam, unsigned short * chan, unsigned long acmode, const struct dsc$descriptor_s * mbxnam, unsigned long flags); int SYS$DASSGN(unsigned short chan); int SYS$GETDVIW (unsigned long efn, unsigned short chan, const struct dsc$descriptor_s * devname, const ITEM_LIST_3 * item_list, void * iosb, void (* astadr)(unsigned long), unsigned long astarg, void * reserved); int SYS$QIOW (unsigned long efn, unsigned short chan, unsigned long func, void * iosb, void (* astadr)(unsigned long), ...); int SYS$SETIMR (unsigned long efn, int64 delay, void (* astadr)(unsigned long), void * astarg); int SYS$SYNCH (unsigned long efn, void * iosb); int SYS$TRNLNM (const unsigned long *trnattr, /* attr - attributes */ const struct dsc$descriptor_s * tabdesc, /* tabnam - table name */ const struct dsc$descriptor_s * logdesc, /* lognam - logical name */ const unsigned char * acmode, /* acmode - access mode */ const ITEM_LIST_3 * trnlst); /* itmlst - item list */ /* IOC$ routines */ extern int ioc$get_udid(const DEVID * devid_data, int * udid); extern int ioc$get_rpt_dev_udid (const unsigned long * dev_data, int data_len, int *udid); extern int ioc$get_page80_wwid (const INQUIRY_DATA * inq_data, const PAGE80 * pg80_data, SN_WWID * wwid); extern int ioc$get_page83_wwid (const PAGE83 * pg83_data, WWID * wwid); int ioc_std$ascwwid_to_binwwid (const char *strptr, int inlen, WWID * wwid_ptr, int *retlen); int ioc_std$binwwid_to_ascwwid (const WWID *wwid_ptr, char * wwid_string, int inlen, int *retlen); /* Begin implementation */ /* * Two functions are exported. They both are used to register entry points. * Remember, this is a Rev2 Vendor specific library, but we might be * called by either a Rev2 or a Rev1. The Rev1 callers will call * HBA_RegisterLibrary. The Rev2 callers SHOULD call HBA_RegisterLibaryV2. * The size of the structure referenced in the Rev2 call is larger then in * the Rev1 call and the Rev1 sturcture is duplicated at the beginning of the * Rev2 structure */ /* These two exported functions need to be the last ones in the module, or * the prototypes for the entrypoints need to be declared ahead of them. */ #define vms_check_null_arg(arg) if (arg == NULL) \ return HBA_STATUS_ERROR_ARG typedef struct vms_fcp_port_info { struct vms_fcp_port_info *port_flink; struct vms_fcp_port_info *port_blink; struct vms_adapter_info *adp_blink; HBA_UINT32 port_index; HBA_WWN nodewwn; HBA_WWN portwwn; unsigned short flags; unsigned short chan; unsigned short pad; char hba_device_name[80]; /* 63 significant, rest alignment pad */ char fcp_device_name[80]; /* 63 significant, rest alignment pad */ } VMS_FCP_PORT_INFO; typedef struct vms_adapter_info { struct vms_adapter_info *adp_flink; struct vms_fcp_port_info *port_flink; struct vms_fcp_port_info *port_blink; unsigned long devtype; HBA_UINT32 adp_count; HBA_UINT32 port_count; HBA_WWN nodewwn; char hba_device_name[80]; /* 63 significant, rest alignment pad */ } VMS_ADAPTER_INFO; static VMS_ADAPTER_INFO * vms_adapter_list = NULL; typedef struct event_list_st { struct event_list_st * flink; struct event_list_st * blink; } EVENT_LIST; static EVENT_LIST event_list_head; typedef struct vms_open_adapter_info { unsigned long flags; unsigned short chan; unsigned short pad; VMS_ADAPTER_INFO * vms_hba_attr; PHBA_ADAPTERATTRIBUTES hba_attr; } VMS_OPEN_ADAPTER_INFO; static VMS_OPEN_ADAPTER_INFO vms_open_adapter_data[0xFFFF] = {0}; static int vms_open_adapter_count = 0; const static HBA_WWN NULL_WWN = {0,0,0,0,0,0,0,0}; /* * Routine search_logname_table_for_wwid * * Functional Description: This routine looks up a wwid to see if a tape * or a jukebox device has been configured for it. * * Stolen from IOGEN-FIBRE-CONFIG.C * * * Formal Parameters: * wwid_ptr Pointer to input WWID to be translated. * devnam_equiv_string Pointer to output string which will hold * the equivalence string. * len Size of equivalence string. * * Outputs: * SS$_NORMAL The logical name was found. * SS$_NOLOGNAM The logical name was not found. * Other status values returned by SYS$TRNLNM. * devnam_equiv_string will return the equivalence string (with a null * terminator) in case of SS$_NORMAL, will return null * string otherwise. */ static int search_logname_table_for_wwid (const WWID *wwid_ptr, char *devnam_equiv_string, int len) { /* Declare an item list */ ITEM_LIST_3 items[4]; unsigned short eqvbuf1_len=0; unsigned int index=0; unsigned int lnmlen=0; unsigned short len_of_lnmlen=0; unsigned int i, status; const unsigned long trnattr = LNM$M_INTERLOCKED; const unsigned char acmode = PSL$C_EXEC; unsigned int wwid_datlen; struct dsc$descriptor_s logdesc; $DESCRIPTOR(tabdesc,"LNM$DEV_WWID_TABLE"); wwid_datlen = (int) (wwid_ptr->wwid$r_header.wwidhdr$v_wwid_length); logdesc.dsc$w_length = wwid_datlen + sizeof(WWIDHDR); logdesc.dsc$b_dtype = DSC$K_DTYPE_T; logdesc.dsc$b_class = DSC$K_CLASS_S; logdesc.dsc$a_pointer = (char *) wwid_ptr; memset(devnam_equiv_string, 0, len); /* Assign values to the item list */ index = 0; /* Get index 0 equiv string. */ items[0].buflen = sizeof(int); items[0].itemcode = LNM$_INDEX; items[0].buffer = &index; items[0].ret_len = 0; /* Ret len of INDEX not defined */ /* Get length, not really needed? */ items[1].buflen = sizeof(int); items[1].itemcode = LNM$_LENGTH; items[1].buffer = &lnmlen; items[1].ret_len = &len_of_lnmlen; /* Set up equivalence buffer. Only valid if returned length (below) > 0 */ /* Note: The returned string in not null-terminated. */ items[2].buflen = len; items[2].itemcode = LNM$_STRING; items[2].buffer = devnam_equiv_string; items[2].ret_len = &eqvbuf1_len; items[3].buflen = 0; items[3].itemcode = 0; /* Now see if the current WWID is a defined logical name. */ status = SYS$TRNLNM (&trnattr, /* attr - attributes */ &tabdesc, /* tabnam - table name */ &logdesc, /* lognam - logical name (WWID) */ &acmode, /* acmode - access mode */ items); /* itmlst - item list */ /* If name was not translated, be sure to return null equiv string. */ if (status != SS$_NORMAL) devnam_equiv_string[0] = 0; else { /* If name was translated, make sure there's enough room for the null terminator. */ if ( strlen(devnam_equiv_string) >= len) return SS$_BADPARAM; } return status; } /* Routine vms_get_fcp_chan (adapter_ptr, fcp_ptr, chan) * * Functional Description: * * This function returns the current channel attached to an FCP port * that is on a Fibre HBA for accessing the PG device. If the PG * device does not currently have a channel, one will be assigned. * If the Adapter is not Emulex, then Qlogic is assumed and the fcp * channel is the same as the adapter channel because PGQ also * does FCP. * * Formal Parameters: * * adapter_ptr Pointer to structure with Fibre Adapter info. * fcp_ptr Pointer to strucure with FCP port info. * chan Pointer to return the channel information. * * Return Values: * VMS status for assigning the channel. * */ static int vms_get_fcp_chan (unsigned short hba_chan, const struct vms_adapter_info * adapter_ptr, VMS_FCP_PORT_INFO * fcp_ptr, unsigned short * port_chan) { int status; status = SS$_NORMAL; if (adapter_ptr->devtype == DT$_LP7000_FC) { if ((fcp_ptr->flags & HBA_M_CHANNEL_OPEN) == 0) { struct dsc$descriptor_s devnam_dsc; devnam_dsc.dsc$a_pointer = fcp_ptr->fcp_device_name; devnam_dsc.dsc$w_length = strlen(fcp_ptr->fcp_device_name); devnam_dsc.dsc$b_dtype = DSC$K_DTYPE_T; devnam_dsc.dsc$b_class = DSC$K_CLASS_S; status = SYS$ASSIGN (&devnam_dsc, &fcp_ptr->chan, 0, 0, 0); if (!$VMS_STATUS_SUCCESS(status)) { #if 0 printf("vms_get_fcp_chan(): sys$assign error status = 0x%x\n", status); printf("vms_get_fcp_chan(): assign channel to device \"%s\"\n", fcp_ptr->fcp_device_name); #endif return status; #if 0 } else { printf("%s chan = %d\n", fcp_ptr->fcp_device_name, (int)fcp_ptr->chan); #endif } fcp_ptr->flags |= HBA_M_CHANNEL_OPEN; *port_chan = fcp_ptr->chan; } else { *port_chan = fcp_ptr->chan; } } else { /* * PGQ also handles FCP */ *port_chan = hba_chan; } return status; } /* * Routine get_vms_adapter_attributes(handle) * * Functional Description: * * This function returns the VMS specific HBA attributes which were * looked up when the adapter was opened. * * Formal Parameters: * * handle Handle number for the adapter. * * Return Values: * * Pointer to cached VMS specific addapter attributes. * */ static VMS_ADAPTER_INFO * get_vms_adapter_attributes(HBA_HANDLE handle) { VMS_ADAPTER_INFO * ret_ptr; ret_ptr = NULL; /* Sanity check */ /*--------------*/ if ((handle != 0) && (handle <= 0xFFFF)) { int i; i = handle - 1; if ((vms_open_adapter_data[i].flags & HBA_M_CHANNEL_OPEN) != 0) ret_ptr = vms_open_adapter_data[i].vms_hba_attr; } return ret_ptr; } /* * Routine vms_getdiscportattributes(chan, dport, wwpn, target, * fcp_ptr, portattributes) * * Functional Description: * * This function returns the HBA port attributes. * * Formal Parameters: * * chan Open channel for the adapter. * dport fc-la for the discovered port if known. * wwpn world wide port name for discovered port. * target address of fc-la returned for the port. * fcp_ptr pointer to information about the port. * portattributes pointer to structure to fill in with the * attributes of the port. * * Return Values: * HBA_STATUS_OK The port attributes were returned. * other error codes from called routines. * * */ static HBA_STATUS vms_getdiscportattributes( unsigned short chan, HBA_UINT32 dport, HBA_WWN * wwpn, int * target, VMS_FCP_PORT_INFO * fcp_ptr, HBA_PORTATTRIBUTES *portattributes ) { HBA_STATUS ret_stat; unsigned short iosb[4]; SNIA_RQ_HEADER snia_rq; int status; vms_check_null_arg(fcp_ptr); vms_check_null_arg(portattributes); snia_rq.command_code = FC$C_QIO_SNIA_REQUEST; snia_rq.qw_count = 2; if (wwpn == NULL) { snia_rq.sub_command = FC$C_QIO_SUB_SNIA_DISCPORTATTR; snia_rq.data = dport; } else { snia_rq.sub_command = FC$C_QIO_SUB_SNIA_DISCWWPNATTR; memcpy(&snia_rq.data, wwpn, sizeof (HBA_WWN)); } status = SYS$QIOW (EFN$C_ENF, chan, /* Channel */ IO$_ACCESS, /* I/O Function Code */ iosb, /* I/O Status Block */ 0, /* AST Address - none */ 0, /* AST Parameter - none */ &snia_rq, /* Request Block */ sizeof(SNIA_RQ_HEADER), /* Request Block size */ portattributes, /* Returned attributes */ sizeof(HBA_PORTATTRIBUTES), /* atribute size */ 0, /* Not used */ 0); /* Not used */ if (!$VMS_STATUS_SUCCESS(status) || !$VMS_STATUS_SUCCESS(iosb[0])) { if (iosb[0] == SS$_INVARG) { if (wwpn == NULL) ret_stat = HBA_STATUS_ERROR_ILLEGAL_INDEX; else ret_stat = HBA_STATUS_ERROR_ILLEGAL_WWN; } else { /* This function is not implemented by the driver */ ret_stat = HBA_STATUS_ERROR_NOT_SUPPORTED; } } else { ret_stat = HBA_STATUS_OK; if (target != NULL) *target = iosb[3] * 256 + iosb[2]; } return ret_stat; } /* * Routine vms_get_target_from_wwid (handle, hbaPortwwn, discoveredPortwwn, * target, ret_attributes, port_chan) * * Functional Description: * * This routine looks up the FC-LA target for a discovered port WWN, * and also returns the channel number for the portwwn. * * Formal Parameters: * * handle handle for the HBA. * hbaPortwwn local port on the HBA. * discoveredPortwwn remote port fc-la is needed for. * target address of location to return the target in. * port_chan address of location to return the port channel in. * * Return Values: * * HBA_STATUS_OK Successful completion. * HBA_STATUS_ERROR_* The best HBA_STATUS_ERROR message to describe * the failure. */ static HBA_STATUS vms_get_target_from_wwid (HBA_HANDLE handle, HBA_WWN hbaPortwwn, HBA_WWN discoveredPortwwn, int * target, HBA_PORTATTRIBUTES * ret_attributes, unsigned short * port_chan) { HBA_STATUS ret_stat; VMS_ADAPTER_INFO * vms_hba_attr; ret_stat = HBA_STATUS_ERROR_INVALID_HANDLE; /* Sanity check */ /*--------------*/ vms_hba_attr = get_vms_adapter_attributes(handle); if (vms_hba_attr != NULL) { VMS_FCP_PORT_INFO * fcp_ptr; HBA_PORTATTRIBUTES *port_attributes; uint64 *port_wwnptr; port_wwnptr = (uint64 *)&hbaPortwwn; if (ret_attributes == NULL) { port_attributes = malloc(sizeof(HBA_PORTATTRIBUTES)); if (port_attributes == NULL) return HBA_STATUS_ERROR; } else port_attributes = ret_attributes; ret_stat = HBA_STATUS_ERROR_ILLEGAL_WWN; fcp_ptr = vms_hba_attr->port_flink; /* Look for the port index */ /*-------------------------*/ while (fcp_ptr != (VMS_FCP_PORT_INFO *)&vms_hba_attr->port_flink) { int wcheck; /* Do we know the local port or do we have to look every one? */ /*------------------------------------------------------------*/ wcheck = 1; if (*port_wwnptr == 0) { /* Need to look for discovered port on all */ /*-----------------------------------------*/ wcheck = 0; } else { uint64 *test_wwnptr; /* Only need to look if this is the correct port */ /*-----------------------------------------------*/ test_wwnptr = (uint64 *)&fcp_ptr->portwwn; if (*test_wwnptr == *port_wwnptr) wcheck = 0; } /* need to check this local port */ /*-------------------------------*/ if (wcheck == 0) { int i; unsigned short hba_chan; i = handle - 1; hba_chan = vms_open_adapter_data[i].chan; #if 0 { uint64 wwn; memcpy(&wwn, &discoveredPortwwn, 8); printf("calling vms_getdiscportattributes for wwn %llx\n", wwn); } #endif ret_stat = vms_getdiscportattributes (hba_chan, 0, &discoveredPortwwn, target, fcp_ptr, port_attributes); if (ret_stat == HBA_STATUS_OK) { int status; status = vms_get_fcp_chan (hba_chan, vms_hba_attr, fcp_ptr, port_chan); if (!$VMS_STATUS_SUCCESS(status)) { ret_stat = HBA_STATUS_ERROR; #if 0 printf("vms_get_target_from_wwid(): vms_get_fcp_chan() status = 0x%x\n", status); #endif } /* We found a match, so we are done */ /*----------------------------------*/ break; } else { /* if we know the port WWN then error out */ /*----------------------------------------*/ if (port_wwnptr != NULL) { ret_stat = HBA_STATUS_ERROR_NOT_A_TARGET; #if 0 printf("vms_get_target_from_wwid(): HBA_STATUS_ERROR_NOT_A_TARGET, ret_stat = %d\n",ret_stat); #endif break; } } } /* End of wcheck == 0 */ fcp_ptr = fcp_ptr->port_flink; } /* End of loop to search local ports */ if (ret_attributes == NULL) free(port_attributes); } /* end of adapter check passing */ return ret_stat; } /* * Routine vms_report_hba_scsi_status(status, scsi_status) * * Functional Description: * * This routine converts common SCSI status values to the expected * HBA status values. * * Formal Parameters: * * status VMS status value. * scsi_status SCSI Status value. * * Return Values: * * HBA_STATUS_OK Good status * HBA_STATUS_ERROR Untranslatable error * HBA_STATUS */ static HBA_STATUS vms_cvt_hba_scsi_status(int status, HBA_UINT8 scsi_status) { HBA_STATUS ret_stat; ret_stat = HBA_STATUS_ERROR; if (!$VMS_STATUS_SUCCESS(status)) { if (scsi_status == SCSI$C_CHECK_CONDITION) ret_stat = HBA_STATUS_SCSI_CHECK_CONDITION; if (scsi_status == SCSI$C_BUSY) ret_stat = HBA_STATUS_ERROR_TARGET_BUSY; } else { if (scsi_status == SCSI$C_GOOD) ret_stat = HBA_STATUS_OK; } return ret_stat; } /* * Routine vms_send_scsi_qio (chan, cdb, retries, xfer_count, scsistatus, * bufsize, databuf, sensesize, sensebuf) * * Functional Description: * * This routine is based on the send_qio() routine from iogen-fibre-config * All scsi commands will be sent through this routine. * * * Formal Parameters: * * chan channel to the FCP port device * path_cdb Pointer to structure containing a path * and a SCSI Command Descriptor Block * retries Number of retries to attempt. * xfer_count Actual bytes transferred. * scsi_status Pointer to return the SCSI status * bufsize Size of buffer to hold return data * databuf Pointer to buffer to hold return data * sensesize Size of the sense buffer * sensebuf Sensebuffer * * Return Values: * * SS$_NORMAL Successful completion. * SS$_NOSUCHDEV FC-LA is invalid, device not connected, device is * neither SCC nor direct-attach disk, or no data was * received. * SS$_INVLOGIN Process is not logged in. * SS$_NOMOREDEV FC-LA is beyond the range of nodes on the fibre. * SS$_ABORT Serious error, (e.g. QIO system service failed, * port driver ss$_insfmem error) * ... or any status value that can be returned by the port driver. */ static int vms_send_scsi_qio (unsigned short chan, const PATH_CDB *cdb, unsigned int retries, unsigned int *xfer_count, /* Number of bytes returned */ unsigned char *scsi_status, int bufsize, void * databuf, int sensesize, void * sensebuf) { IOSB qio_iosb; /* Misc. I/O status blocks */ int port_status; /* Status returned in IOSB */ int qio_status; int tries; memset (&qio_iosb, 0, IOSB$K_LENGTH); memset (databuf, 0, bufsize); if (sensebuf != NULL) memset(sensebuf, 0, sensesize); tries = 0; do { *scsi_status = 0xff; qio_status = SYS$QIOW (EFN$C_ENF, chan, IO$_READLBLK | IO$M_EXISTS, &qio_iosb, 0, 0, databuf, bufsize, cdb, sizeof(PATH_CDB), sensebuf, sensesize); #if 0 printf("hba_vms IO$_READLBLK: status = 0x%x, iosb stat = 0x%x\n", qio_status, qio_iosb.iosb$w_status); #endif /* Both QIO submit and I/O should be success */ /*-------------------------------------------*/ if ($VMS_STATUS_SUCCESS(qio_status)) { qio_status = qio_iosb.iosb$w_status; *scsi_status = qio_iosb.iosb$w_dev_depend_high & 0xFF; #if 0 } else { printf("hba_vms IO$_READLBLK qio status = 0x%x\n", qio_status); #endif } if ($VMS_STATUS_SUCCESS(qio_status)) { if (*scsi_status == SCSI$C_GOOD) break; if ((*scsi_status == SCSI$C_QUEUE_FULL) || (*scsi_status == SCSI$C_BUSY)) { sleep(1); continue; } } else { #if 0 if (qio_status != SS$_MEDOFL && qio_iosb.iosb$w_status) { printf("hba_vms IO$_READLBLK failed: iosb status = 0x%x\n", qio_status); } #endif /* See if this can be retried */ /*----------------------------*/ if (qio_status == SS$_MEDOFL) sleep(1); else break; } tries++; } while (tries < retries); /* Exit on system service error */ if (!$VMS_STATUS_SUCCESS(qio_status)) return qio_status; port_status = qio_iosb.iosb$w_status; *xfer_count = qio_iosb.iosb$w_bcnt; /* If no data was received, then treat it as if no device was found. */ /*-------------------------------------------------------------------*/ if ((*xfer_count == 0) && (bufsize != 0)) return SS$_NOSUCHDEV; return qio_status; } /* * Routine static int vms_scsi_inquiry (chan, target, lun, cdb_byte1, * cdb_byte2, retries, xfer_count, * scsi_status, bufsize, databuf, * sensesize, sensebuf) * * Functional Description: * * This routine sets up a CDB for a SCSI Inquiry and calls the * vms_send_scsi_qio routine to get the information. * * Formal Parameters: * * chan channel to the FCP port device * target FC_LA target * lun lun for device * retries Number of retries allowed * scsistatus Pointer to return the SCSI status * xfer_count Amount of data returned in bytes * bufsize Size of buffer to hold return data * databuf Pointer to buffer to hold return data * sensesize Size of the sense buffer * sensebuf Sensebuffer * * Return Values: * * SS$_NORMAL Successful completion. * ... or any status value that can be returned by the port driver. */ static int vms_scsi_inquiry (unsigned short chan, int target, int64 lun, int cdb_byte1, int cdb_byte2, unsigned int retries, unsigned int * xfer_count, HBA_UINT8 *scsi_status, int bufsize, void * databuf, int sensesize, void * sensebuf) { int status; PATH_CDB path_cdb; int buf_size; /* Inquiry can only return 255 bytes */ buf_size = bufsize; if (buf_size > 255) buf_size = 255; /* Set up the CDB */ /*----------------*/ path_cdb.snia_path$is_target = target; path_cdb.snia_path$q_lun = lun; path_cdb.snia_path$l_length = INQ_CMD$K_LENGTH; path_cdb.snia_path$b_cdb[0] = INQ_CMD$K_INQ_OPCODE; path_cdb.snia_path$b_cdb[1] = cdb_byte1; path_cdb.snia_path$b_cdb[2] = cdb_byte2; path_cdb.snia_path$b_cdb[3] = 0; path_cdb.snia_path$b_cdb[4] = buf_size; path_cdb.snia_path$b_cdb[5] = 0; /* Send the command */ /*------------------*/ status = vms_send_scsi_qio (chan, &path_cdb, retries, xfer_count, /* Number of bytes returned */ scsi_status, bufsize, databuf, sensesize, sensebuf); return status; } /* * Routine static int vms_scsi_read_capacity (chan, target, lun, cdb_byte1, * cdb_byte2, retries, xfer_count, * scsi_status, bufsize, databuf, * sensesize, sensebuf) * * Functional Description: * * This routine sets up a CDB for a SCSI Read Capacity and calls the * vms_send_scsi_qio routine to get the information. * * Formal Parameters: * * chan channel to the FCP port device * target FC_LA target * lun lun for device * retries Number of retries allowed * scsistatus Pointer to return the SCSI status * xfer_count Amount of data returned in bytes * bufsize Size of buffer to hold return data * databuf Pointer to buffer to hold return data * sensesize Size of the sense buffer * sensebuf Sensebuffer * * Return Values: * * SS$_NORMAL Successful completion. * ... or any status value that can be returned by the port driver. */ static int vms_scsi_read_capacity (unsigned short chan, int target, int64 lun, unsigned int retries, unsigned int * xfer_count, HBA_UINT8 *scsi_status, int bufsize, void * databuf, int sensesize, void * sensebuf) { int status; PATH_CDB path_cdb; /* Set up the CDB */ /*----------------*/ memset(&path_cdb, 0, sizeof(PATH_CDB)); path_cdb.snia_path$is_target = target; path_cdb.snia_path$q_lun = lun; path_cdb.snia_path$l_length = RDCAP_CMD$K_LENGTH; path_cdb.snia_path$b_cdb[0] = RDCAP_CMD$K_RDCAP_OPCODE; /* Send the command */ /*------------------*/ status = vms_send_scsi_qio (chan, &path_cdb, retries, xfer_count, /* Number of bytes returned */ scsi_status, bufsize, databuf, sensesize, sensebuf); #if 0 if (!$VMS_STATUS_SUCCESS(status)) { printf("read capacity vms error status = 0x%x\n", status); } if (*scsi_status && *scsi_status != 0xffu) { printf(" Read Capacity SCSI error status = %d, target = %d, lun = %d" ,(int)*scsi_status ,target ,(int)lun ); if (sensesize) { int i; int max = sensesize > 19 ? 19 : sensesize; unsigned char *sbp = sensebuf; printf(", sense buffer: "); for (i=0; i> 24) & 0xff; path_cdb.snia_path$b_cdb[7] = (bufsize >> 16) & 0xff; path_cdb.snia_path$b_cdb[8] = (bufsize >> 8) & 0xff; path_cdb.snia_path$b_cdb[9] = bufsize & 0xff; /* Send the command */ /*------------------*/ status = vms_send_scsi_qio (chan, &path_cdb, retries, xfer_count, /* Number of bytes returned */ scsi_status, bufsize, databuf, sensesize, sensebuf); if ($VMS_STATUS_SUCCESS(status) && (*scsi_status == SCSI$C_GOOD)) { unsigned char *src; unsigned char *dst; RPTLUN_DATA *lun_data; int max_size; int i; lun_data = (RPTLUN_DATA *)databuf; max_size = bufsize; if (max_size > *xfer_count) max_size = *xfer_count; /* Get the list length from the return data. */ /* Fix the endian of the length */ /*-------------------------------------------*/ src = (unsigned char *)&lun_data->rptlun_data$l_list_length; dst = (unsigned char *)list_length + 3; for (i = 0; i <= 3; i++) *dst-- = *src++; #if 0 } else { /* place holder for debugging output */ #endif } return status; } /* * Routine static int vms_get_udid (chan, target, lun, hsg_flag, * udid, bufsize, databuf, * sensesize, sensebuf) * * Functional Description: * * This routine gets the unit id for a DISK or a Generic SCSI device. * * Formal Parameters: * * chan channel to the FCP port device * target FC_LA target * lun lun for device * hsg_flag Device is hsg, use old method only * udid Unit Identifier. * bufsize Size of buffer to hold return data * databuf Pointer to buffer to hold return data * sensesize Size of the sense buffer * sensebuf Sensebuffer * * Return Values: * * SS$_NORMAL Successful completion. * ... or any status value that can be returned by the port driver. */ static int vms_get_udid (unsigned short chan, int target, int64 lun, int hsg_flag, unsigned short * udid) { int status; PATH_CDB path_cdb; unsigned int xfer_count; HBA_UINT8 scsi_status; unsigned char sensebuf[20]; /* All the Sense data we care about */ int long_udid; status = SS$_IVIDENT; *udid = 0xFFFF; #ifdef MAINT_CMD$K_LENGTH if (hsg_flag == 0) { MAINT_CMD * maint_cdb; unsigned long maint_data[3]; /* Set up the CDB for new method */ /*-------------------------------*/ path_cdb.snia_path$is_target = target; path_cdb.snia_path$q_lun = lun; path_cdb.snia_path$l_length = MAINT_CMD$K_LENGTH; maint_cdb = (MAINT_CMD *)path_cdb.snia_path$b_cdb; memset(maint_cdb, 0, MAINT_CMD$K_LENGTH); maint_cdb->maint_cmd$b_opcode = MAINT_CMD$K_IN_OPCODE; maint_cdb->maint_cmd$v_service_action = MAINT_CMD$C_RPT_PERCMP_ID; maint_cdb->maint_cmd$b_alloc_length[3] = sizeof(maint_data); #if 0 { int i; unsigned char *cdb = (unsigned char *)path_cdb; printf("path cdb: "); for (i=0; i<12; i++) printf("%02X ", cdb[i]); printf("\n"); } #endif #if 0 { int i; unsigned char *cdb = (unsigned char *)maint_cdb; printf("maint cdb: "); for (i=0; i<12; i++) printf("%02X ", cdb[i]); printf("\n"); } #endif /* Send the command */ /*------------------*/ status = vms_send_scsi_qio (chan, &path_cdb, DEFAULT_SCSI_RETRIES, &xfer_count, /* Number of bytes returned */ &scsi_status, sizeof(maint_data), maint_data, sizeof(sensebuf), sensebuf); /* Validate and extract the udid */ /*-------------------------------*/ if ($VMS_STATUS_SUCCESS(status) && (xfer_count >= 5)) { int data_len; data_len = 8; if (xfer_count < data_len) data_len = xfer_count; /* Parse and validate the unit number */ /*------------------------------------*/ status = ioc$get_rpt_dev_udid(maint_data, data_len, &long_udid); *udid = long_udid & 0xffff; #if 0 { int i; unsigned char *dp = (unsigned char *)maint_data; printf(" %d bytes of maint_data: ", xfer_count); for (i=0; idevid_cmd$b_opcode = DEVID_CMD$K_RD_DEVID_OPCODE; /* >>>>>> NOTE: the bytes are not reversed <<<<<<<<<<<<<<< X-2a */ devid_cdb->devid_cmd$b_alloc_length[0] = (char)sizeof(DEVID); devid_cdb->devid_cmd$b_alloc_length[1] = sizeof(DEVID) >> 8; /* Send the command */ /*------------------*/ status = vms_send_scsi_qio (chan, &path_cdb, DEFAULT_SCSI_RETRIES, &xfer_count, /* Number of bytes returned */ &scsi_status, sizeof(devid_data), &devid_data, sizeof(sensebuf), sensebuf); #if 0 if (hsg_flag) { int i; printf("get_udid (HSG): status = 0x%x, data count = %d\n", status, xfer_count); if (scsi_status) { printf(" scsi status = %d, sensebuf: ", scsi_status); for (i=0; i= 5)) { /* Parse and validate the unit number */ /*------------------------------------*/ status = ioc$get_udid(&devid_data, &long_udid); *udid = long_udid & 0xffff; #if 0 if (hsg_flag) { printf("get_udid (HSG): ioc$get_udid status = 0x%x, udid = 0x%x\n", status, long_udid); } #endif #if 0 { int i; unsigned char *dp = (unsigned char *)&devid_data; printf(" %d bytes of devid_data: ", xfer_count); for (i=0; i 0) { if ((fcp_name[i] == 'G') && (fcp_name[i-1] == 'F')) { fcp_name[i-1] = 'P'; break; } i--; } /* Does it exist and is it what it should be? */ /*--------------------------------------------*/ status = SYS$GETDVIW (EFN$C_ENF, 0, &devnam_dsc, item_list, dvi_iosb, 0, 0, 0); if ($VMS_STATUS_SUCCESS(status)) { if ((devclass == DC$_BUS) && (devtype = DT$_FCP_SCSI)) { /* Found FCP Fibre Channel Adapter */ /*---------------------------------*/ strncpy(fcp_device_name, fcp_name, VMS_DEVNAME_SIZE); fcp_device_name[VMS_DEVNAME_SIZE-1] = 0; } } } /* * Routine vms_add_to_adapter_list (adapter_name, devtype) * * Functional Description: * * This procedure calculates the expected fcp device name based on * the adapter name. * * Formal Parameters: * * adapter_name Pointer to the adapter name. * devtype Device type from sys$getdvi. * * Return Values: * Number of adapters currently in the list. * */ static HBA_UINT32 vms_add_to_adapter_list (const char * adapter_name, unsigned long devtype) { VMS_ADAPTER_INFO * adapter_ptr; VMS_ADAPTER_INFO * last_adp_ptr; VMS_FCP_PORT_INFO * fcp_ptr; VMS_FCP_PORT_INFO * last_fcp_ptr; HBA_UINT32 retval; int found; ITEM_LIST_3 item_list[3]; char wwpn_str[33]; unsigned short wwpn_str_len; char wwnn_str[33]; unsigned short wwnn_str_len; struct dsc$descriptor_s devnam_dsc; HBA_WWN nodewwn; HBA_WWN portwwn; unsigned short port_count; unsigned short dvi_iosb[4]; int status; found = 0; retval = 0; adapter_ptr = vms_adapter_list; last_adp_ptr = vms_adapter_list; /* Now get the world wide node name */ /*----------------------------------*/ item_list[0].buflen = 32; item_list[0].itemcode = DVI$_FC_NODE_NAME; item_list[0].buffer = wwnn_str; item_list[0].ret_len = &wwnn_str_len; item_list[1].buflen = 32; item_list[1].itemcode = DVI$_FC_PORT_NAME; item_list[1].buffer = wwpn_str; item_list[1].ret_len = &wwpn_str_len; item_list[2].buflen = 0; item_list[2].itemcode = 0; devnam_dsc.dsc$a_pointer = (char *)adapter_name; devnam_dsc.dsc$w_length = strlen(adapter_name); devnam_dsc.dsc$b_dtype = DSC$K_DTYPE_T; devnam_dsc.dsc$b_class = DSC$K_CLASS_S; status = SYS$GETDVIW (EFN$C_ENF, 0, &devnam_dsc, item_list, dvi_iosb, 0, 0, 0); if ($VMS_STATUS_SUCCESS(status)) { int wwn_size = sizeof(HBA_WWN); wwnn_str[wwnn_str_len] = 0; status = ioc_std$ascwwid_to_binwwid (wwnn_str, wwnn_str_len, (WWID *)&nodewwn, &wwn_size); status = ioc_std$ascwwid_to_binwwid (wwpn_str, wwpn_str_len, (WWID *)&portwwn, &wwn_size); } /* Make sure that this is not a new adapter */ /*------------------------------------------*/ while (adapter_ptr != NULL) { int test_val; test_val = memcmp(&nodewwn, &adapter_ptr->nodewwn, sizeof(HBA_WWN)); if (test_val == 0) found = 1; last_adp_ptr = adapter_ptr; adapter_ptr = adapter_ptr->adp_flink; retval++; } /* If it was not found, add it to the list */ /*-----------------------------------------*/ if (found == 0) { VMS_ADAPTER_INFO *new_ptr; new_ptr = malloc(sizeof(VMS_ADAPTER_INFO)); if (new_ptr != NULL) { int status; /* Link it on the chain */ /*----------------------*/ if (last_adp_ptr == NULL) vms_adapter_list = new_ptr; else last_adp_ptr->adp_flink = new_ptr; /* Initialize the storage */ /*------------------------*/ new_ptr->devtype = devtype; new_ptr->adp_flink = NULL; memcpy(&new_ptr->nodewwn, &nodewwn, sizeof(HBA_WWN)); strncpy(new_ptr->hba_device_name, adapter_name, VMS_DEVNAME_SIZE); new_ptr->port_flink = (VMS_FCP_PORT_INFO *)&new_ptr->port_flink; new_ptr->port_blink = (VMS_FCP_PORT_INFO *)&new_ptr->port_flink; new_ptr->adp_count = retval; adapter_ptr = new_ptr; retval++; } } /* Add the port information */ /*--------------------------*/ port_count = 0; found = 0; if (adapter_ptr != NULL) { /* Is this port already known? */ /*-----------------------------*/ fcp_ptr = adapter_ptr->port_flink; while (fcp_ptr != (VMS_FCP_PORT_INFO *)&adapter_ptr->port_flink) { int test_val; test_val = memcmp(&portwwn, &fcp_ptr->nodewwn, sizeof(HBA_WWN)); if (test_val == 0) found = 1; fcp_ptr = fcp_ptr->port_flink; port_count++; } /* If it was not found, add it to the list */ /*-----------------------------------------*/ if (found == 0) { VMS_FCP_PORT_INFO * new_ptr; new_ptr = malloc(sizeof(VMS_FCP_PORT_INFO)); if (new_ptr != NULL) { int status; /* Link it on the chain */ /*----------------------*/ __PAL_INSQUEL_D((void **)adapter_ptr->port_flink, new_ptr); /* Initialize the storage */ /*------------------------*/ new_ptr->adp_blink = adapter_ptr; new_ptr->flags = 0; new_ptr->chan = 0; memcpy(&new_ptr->nodewwn, &nodewwn, sizeof(HBA_WWN)); memcpy(&new_ptr->portwwn, &portwwn, sizeof(HBA_WWN)); strncpy (new_ptr->hba_device_name, adapter_name, VMS_DEVNAME_SIZE); vms_get_fcp_device(new_ptr->fcp_device_name, adapter_name); new_ptr->port_index = port_count; adapter_ptr->port_count = port_count + 1; } } } return retval; } /* * Routine VMS_GetVersion(void) * * Functional Description: * * This procedure is returns the HBA Library compliance level. * It is a manditory function in the HBAAPI. * * Formal Parameters: None. * * Return Values: * HBA_LIBVERSION that this driver was built against. * */ static HBA_UINT32 VMS_GetVersion(void) { return HBA_LIBVERSION; } /* * Routine VMS_GetNumberOfAdapters(void) * * Functional Description: * * This procedure is returns the number of HBA adaptors found * on the system. * * Because of the way that the HBA library will use this value, * this procedure must create a list of HBA adapters so it will * work properly if some adapters were not found on previous * calls because of either a hot plug or not being discovered * by autogen. * * It is a manditory function in the HBAAPI. * * Formal Parameters: None. * * Return Values: * Number of adapters found. * */ static HBA_UINT32 VMS_GetNumberOfAdapters(void) { int status; HBA_UINT32 count; int scan_context; char ret_devnam[VMS_DEVNAME_SIZE]; unsigned short ret_devnam_len; struct dsc$descriptor_s ret_devnam_dsc; struct dsc$descriptor_s * tst_devnam_ptr; ITEM_LIST_3 item_list[3]; unsigned long devclass; unsigned long devtype; int dt_types[] = { DT$_LP7000_FC, /* Emulex Fibre Channel Adapters */ #ifdef DT$_ISP23XX_FC DT$_ISP23XX_FC, /* Qlogic Fibre Channel Adapters */ #endif #ifdef DT$_ISP24XX_FC DT$_ISP24XX_FC, /* Qlogic Fibre Channel Adapters */ #endif 0 }; int i; count = 0; tst_devnam_ptr = NULL; devclass = DC$_BUS; ret_devnam_dsc.dsc$a_pointer = ret_devnam; ret_devnam_dsc.dsc$w_length = sizeof(ret_devnam) - 1; ret_devnam_dsc.dsc$b_dtype = DSC$K_DTYPE_T; ret_devnam_dsc.dsc$b_class = DSC$K_CLASS_S; /* Also set up the filter to look for Fibre Channel Devices */ /*----------------------------------------------------------*/ item_list[0].buflen = sizeof devclass; item_list[0].itemcode = DVS$_DEVCLASS; item_list[0].buffer = &devclass; item_list[0].ret_len = NULL; item_list[1].buflen = sizeof devtype; item_list[1].itemcode = DVS$_DEVTYPE; item_list[1].buffer = &devtype; item_list[1].ret_len = NULL; item_list[2].buflen = 0; item_list[2].itemcode = 0; for (i=0; dt_types[i]; i++) { devtype = dt_types[i]; scan_context = 0; do { ret_devnam_dsc.dsc$w_length = sizeof(ret_devnam); status = SYS$DEVICE_SCAN (&ret_devnam_dsc, &ret_devnam_len, tst_devnam_ptr, item_list, &scan_context); if (status == SS$_NORMAL) { /* Fix up the device name */ /*------------------------*/ ret_devnam_dsc.dsc$w_length = ret_devnam_len; ret_devnam_dsc.dsc$a_pointer[ret_devnam_len] = 0; count = vms_add_to_adapter_list (ret_devnam_dsc.dsc$a_pointer, devtype); #if 0 printf("%s = %s\n", ret_devnam_dsc.dsc$a_pointer, devtype==DT$_LP7000_FC?"DT$_LP7000_FC":devtype==DT$_ISP23XX_FC? "DT$_ISP23XX_FC":"DT$_ISP24XX_FC"); #endif } } while (status == SS$_NORMAL); } return count; } /* * Routine VMS_GetAdapterName(adapterindex, adaptername) * * Functional Description: * * This procedure is returns the operating system name for the * adapter found by the VMS_GetNumberOfAdapters routine. * * It is a manditory function in the HBAAPI. * * Formal Parameters: * * adapterindex Offset to the number of adapters found on this host. * adaptername Address to return the name of the adapter. * * Return Values: * HBA_STATUS_OK An adapter exists at this index. * HBA_STATUS_ERROR_ILLEGAL_INDEX An adapter does not exist at this index. * other error codes from called routines. * */ static HBA_STATUS VMS_GetAdapterName(HBA_UINT32 adapterindex, char *adaptername) { HBA_STATUS ret_stat; int i; VMS_ADAPTER_INFO * adapter_ptr; /* Make sure that there is a pointer */ /*-----------------------------------*/ vms_check_null_arg(adaptername); /* Make sure that we have a list of adapters */ /*-------------------------------------------*/ if (vms_add_to_adapter_list == NULL) VMS_GetNumberOfAdapters(); ret_stat = HBA_STATUS_ERROR_ILLEGAL_INDEX; adapter_ptr = vms_adapter_list; i = 0; /* Walk down the list to find it */ /*-------------------------------*/ while (adapter_ptr != NULL) { if (adapterindex == adapter_ptr->adp_count) { VMS_FCP_PORT_INFO * fcp_ptr; strncpy (adaptername, adapter_ptr->hba_device_name, VMS_DEVNAME_SIZE-1); adaptername[VMS_DEVNAME_SIZE] = 0; ret_stat = HBA_STATUS_OK; break; } /* Sanity check */ /*--------------*/ if (i > adapter_ptr->adp_count) { ret_stat = HBA_STATUS_ERROR; break; } /* Next */ /*------*/ i++; adapter_ptr = adapter_ptr->adp_flink; } return ret_stat; } /* * Routine VMS_OpenAdapter (adaptername) * * Functional Description: * * This procedure looks up the adapter name, and opens a channel * to it. * * It is a manditory function in the HBAAPI. * * Formal Parameters: * * adaptername Address of the name of the adapter. * * Return Values: * Handle number for the adapter. 0 is used to indicate any failure. * */ /* Manditory */ static HBA_HANDLE VMS_OpenAdapter(char* adaptername ) { unsigned short ret_handle; /* See warning below */ VMS_ADAPTER_INFO * adapter_ptr; struct dsc$descriptor_s devnam_dsc; ITEM_LIST_3 item_list[2]; char devnam[VMS_DEVNAME_SIZE]; unsigned short devnam_len; PHBA_ADAPTERATTRIBUTES hba_attrs; PHBA_PORTATTRIBUTES port_attrs; char wwpn_str[33]; unsigned short wwpn_str_len; int i; unsigned short dvi_iosb[4]; int status; vms_check_null_arg(adaptername); ret_handle = 0; /* * WARNING WARNING, Danger Will Robinson, * The wrapper library will mask the return of this function to * the lower 16 bits. Think of this function as returning * UINT16 */ /* Look up fixed attributes now */ /*------------------------------*/ hba_attrs = malloc(sizeof(HBA_ADAPTERATTRIBUTES)); if (hba_attrs == NULL) return ret_handle; else memset(hba_attrs, 0, sizeof(HBA_ADAPTERATTRIBUTES)); /* Convert the name to match what would be stored */ /*------------------------------------------------*/ devnam_dsc.dsc$a_pointer = adaptername; devnam_dsc.dsc$w_length = strlen(adaptername); devnam_dsc.dsc$b_dtype = DSC$K_DTYPE_T; devnam_dsc.dsc$b_class = DSC$K_CLASS_S; item_list[0].buflen = VMS_DEVNAME_SIZE; item_list[0].itemcode = DVI$_FULLDEVNAM; item_list[0].buffer = devnam; item_list[0].ret_len = &devnam_len; item_list[1].buflen = 0; item_list[1].itemcode = 0; status = SYS$GETDVIW (EFN$C_ENF, 0, &devnam_dsc, item_list, dvi_iosb, 0, 0, 0); if ($VMS_STATUS_SUCCESS(status)) { /* Fix up the length of the descriptor */ /*-------------------------------------*/ devnam[devnam_len] = 0; devnam_dsc.dsc$a_pointer = devnam; devnam_dsc.dsc$w_length = devnam_len; } adapter_ptr = vms_adapter_list; /* Make sure that the Open Table is clear */ /*----------------------------------------*/ if (vms_open_adapter_count == 0) memset(vms_open_adapter_data, 0, sizeof (VMS_OPEN_ADAPTER_INFO)); /* Walk down the list to find the adapter - Can not trust caller */ /*---------------------------------------------------------------*/ i = 0; while (adapter_ptr != NULL) { int found; found = 0; if (strncmp (devnam, adapter_ptr->hba_device_name, VMS_DEVNAME_SIZE) == 0) { for (i = 0; i < vms_open_adapter_count; i++) if (vms_open_adapter_data[i].flags == 0) { found = 1; ret_handle = i + 1; } if ((found == 0) && (vms_open_adapter_count < 0xFFFF)) { found = 1; vms_open_adapter_count++; ret_handle = vms_open_adapter_count; } } if (found != 0) break; /* Next */ /*------*/ adapter_ptr = adapter_ptr->adp_flink; } if (ret_handle != 0) { int status; VMS_FCP_PORT_INFO * fcp_ptr; i = ret_handle - 1; status = SYS$ASSIGN (&devnam_dsc, &vms_open_adapter_data[i].chan, 0, 0, 0); /* Look up fixed attributes now */ /*------------------------------*/ if ($VMS_STATUS_SUCCESS(status)) { unsigned short iosb[4]; SNIA_RQ_HEADER snia_rq; #if 0 printf("open adapter: %s chan = %d\n", devnam, (int)vms_open_adapter_data[i].chan); #endif vms_open_adapter_data[i].flags = HBA_M_CHANNEL_OPEN; vms_open_adapter_data[i].hba_attr = hba_attrs; vms_open_adapter_data[i].vms_hba_attr = adapter_ptr; snia_rq.command_code = FC$C_QIO_SNIA_REQUEST; snia_rq.qw_count = 1; snia_rq.sub_command = FC$C_QIO_SUB_SNIA_ADP_ATTR; status = SYS$QIOW (EFN$C_ENF, vms_open_adapter_data[i].chan, /* Channel */ IO$_ACCESS, /* I/O Function Code */ iosb, /* I/O Status Block */ 0, /* AST Address - none */ 0, /* AST Parameter - none */ &snia_rq, /* Request Block */ sizeof(SNIA_RQ_HEADER), /* Request Block size */ hba_attrs, /* Returned attributes */ sizeof(HBA_ADAPTERATTRIBUTES), /* atribute size */ 0, /* Not used */ 0); /* Not used */ if (!$VMS_STATUS_SUCCESS(status) || !$VMS_STATUS_SUCCESS(iosb[0])) { strcpy(hba_attrs->Manufacturer, "Unknown"); /* Manditory */ strcpy(hba_attrs->SerialNumber, "Unknown"); /* Manditory */ /* should be dvi$_serialnum */ strcpy(hba_attrs->Model, "Unknown"); /* Manditory */ strcpy(hba_attrs->ModelDescription, ""); /* Optional NULL string */ /* NodeWWN is optional and can be 0 */ memcpy (&hba_attrs->NodeWWN, &adapter_ptr->nodewwn, sizeof(HBA_WWN)); /* Optional Null String */ strcpy(hba_attrs->NodeSymbolicName, "OpenVMS Fibre Driver"); /* Optional NULL string */ strcpy(hba_attrs->HardwareVersion, ""); /* Optional NULL string */ strcpy(hba_attrs->DriverVersion, ""); /* Optional NULL string */ strcpy(hba_attrs->OptionROMVersion, ""); /* Optional NULL string */ strcpy(hba_attrs->FirmwareVersion, ""); /* Optional set to 0 */ hba_attrs->VendorSpecificID = 0; /* Manditory - Driver may not know */ hba_attrs->NumberOfPorts = 1; /* Optional Null String */ strcpy(hba_attrs->DriverName, "SYS$LOADABLE_IMAGES:SYS$FG*DRIVER.EXE"); } else { /* Fix up the driver version */ if (hba_attrs->DriverVersion[0] == '\0') { int status; uint64 link_time; unsigned short timelen; struct dsc$descriptor_s time_desc; memcpy(&link_time, &hba_attrs->DriverVersion[3], 8); time_desc.dsc$w_length=sizeof(hba_attrs->DriverVersion); time_desc.dsc$b_dtype = DSC$K_DTYPE_T; time_desc.dsc$b_class = DSC$K_CLASS_S; time_desc.dsc$a_pointer = hba_attrs->DriverVersion; status = SYS$ASCTIM (&timelen, &time_desc, &link_time, 0); hba_attrs->DriverVersion[timelen] = '\0'; } } /* The adapter may not know how many ports it really has */ /*-------------------------------------------------------*/ hba_attrs->NumberOfPorts = adapter_ptr->port_count; } else { /* No channel */ /*------------*/ ret_handle = 0; free(hba_attrs); } } return ret_handle; } /* * Routine VMS_OpenAdapterByWWN(handle, wwn) * * Functional Description: * * This procedure looks up the adapter name from the wwn, and opens * a channel to it. * * It is an Optional function in the HBAAPI. * * Formal Parameters: * * adaptername Address to return the name of the adapter. * handle Handle number for the adapter. * 0 is used to indicate any failure. * * Return Values: * HBA_STATUS_OK An adapter exists with this name. * other error codes from called routines. * */ static HBA_STATUS VMS_OpenAdapterByWWN(HBA_HANDLE * handle, HBA_WWN wwn) { /* * WARNING WARNING, Danger Will Robinson, * The wrapper library will mask the handle of this function to * the lower 16 bits. Think of this HBA_HANDLE as UINT16 */ HBA_STATUS ret_stat; int i; unsigned short ret_handle; VMS_ADAPTER_INFO * adapter_ptr; vms_check_null_arg(handle); ret_handle = 0; ret_stat = HBA_STATUS_ERROR_ILLEGAL_WWN; adapter_ptr = vms_adapter_list; /* Walk down the list to find the adapter - Can not trust caller */ /*---------------------------------------------------------------*/ i = 0; while (adapter_ptr != NULL) { int test_wwnn; int test_wwpn; test_wwnn = memcmp(&wwn, &adapter_ptr->nodewwn, sizeof(HBA_WWN)); test_wwpn = 1; /* if the WWNodeName does not match, need to check the port WWN */ /*--------------------------------------------------------------*/ if (test_wwnn != 0) { VMS_FCP_PORT_INFO * fcp_ptr; /* Now look for ports that match */ fcp_ptr = adapter_ptr->port_flink; /* Look for the port index */ /*-------------------------*/ while (fcp_ptr != (VMS_FCP_PORT_INFO *)&adapter_ptr->port_flink) { test_wwpn = memcmp(&wwn, &fcp_ptr->portwwn, sizeof(HBA_WWN)); if (test_wwpn == 0) { break; } fcp_ptr = fcp_ptr->port_flink; } } /* If either matches, open the port */ /*----------------------------------*/ if ((test_wwnn == 0) || (test_wwpn == 0)) { ret_handle = VMS_OpenAdapter(adapter_ptr->hba_device_name); if (ret_handle != 0) ret_stat = HBA_STATUS_OK; break; } /* Next */ /*------*/ adapter_ptr = adapter_ptr->adp_flink; } *handle = ret_handle; return ret_stat; } /* * Routine VMS_CloseAdapter(handle) * * Functional Description: * * This closes a channel for the HBA, and cleans up any data structures * allocated to it. * * It is an Manditory function in the HBAAPI. * * Formal Parameters: * * handle Handle number for the adapter. * * Return Values: None. * */ static void VMS_CloseAdapter(HBA_HANDLE handle) { /* Sanity check and close */ /*------------------------*/ if ((handle != 0) && (handle <= 0xFFFF)) { int i; i = handle - 1; /* Is the channel open? */ /*----------------------*/ if ((vms_open_adapter_data[i].flags & HBA_M_CHANNEL_OPEN) != 0) { int status; VMS_FCP_PORT_INFO *fcp_ptr; VMS_ADAPTER_INFO * vms_hba_attr; /* Close the channel */ /*-------------------*/ vms_hba_attr = get_vms_adapter_attributes(handle); vms_open_adapter_data[i].flags = 0; status = SYS$DASSGN(vms_open_adapter_data[i].chan); #if 0 printf("Close FG Channel %d\n", vms_open_adapter_data[i].chan); #endif /* Close any port channels that may be open */ /*------------------------------------------*/ fcp_ptr = vms_hba_attr->port_flink; while (fcp_ptr != (VMS_FCP_PORT_INFO *)&vms_hba_attr->port_flink) { int status2; if ((fcp_ptr->flags & HBA_M_CHANNEL_OPEN) != 0) { fcp_ptr->flags = 0; status2 = SYS$DASSGN(fcp_ptr->chan); #if 0 printf("Close PG Channel %d\n", fcp_ptr->chan); #endif } fcp_ptr = fcp_ptr->port_flink; } if (vms_open_adapter_count > 0) { vms_open_adapter_count--; } else if (vms_open_adapter_count < 0) { vms_open_adapter_count = 0; } } } } /* * Routine get_adapter_attributes(handle) * * Functional Description: * * This function returns the HBA attributes which were looked up * when the adapter was opened. * * Internal function. * * Formal Parameters: * * handle Handle number for the adapter. * * Return Values: * * Pointer to cached addapter attributes. * */ static PHBA_ADAPTERATTRIBUTES get_adapter_attributes(HBA_HANDLE handle) { PHBA_ADAPTERATTRIBUTES ret_ptr; ret_ptr = NULL; /* Sanity check */ /*--------------*/ if ((handle != 0) && (handle <= 0xFFFF)) { int i; i = handle - 1; if ((vms_open_adapter_data[i].flags & HBA_M_CHANNEL_OPEN) != 0) ret_ptr = vms_open_adapter_data[i].hba_attr; } return ret_ptr; } /* * Routine VMS_GetAdapterAttributes(handle, hbaattributes) * * Functional Description: * * This function returns the HBA attributes which were looked up * when the adapter was opened. * * It is an Manditory function in the HBAAPI. * * Formal Parameters: * * handle Handle number for the adapter. * hbaattributes pointer to structure to fill in with the * attributes of the adapter. * * Return Values: * HBA_STATUS_OK The adapter attributes were returned. * other error codes from called routines. * * */ static HBA_STATUS VMS_GetAdapterAttributes( HBA_HANDLE handle, PHBA_ADAPTERATTRIBUTES hbaattributes ) { PHBA_ADAPTERATTRIBUTES adapter_attrs; HBA_STATUS ret_stat; ret_stat = HBA_STATUS_ERROR_INVALID_HANDLE; /* Sanity check */ /*--------------*/ adapter_attrs = get_adapter_attributes(handle); if (adapter_attrs != NULL) { memcpy(hbaattributes, adapter_attrs, sizeof(HBA_ADAPTERATTRIBUTES)); ret_stat = HBA_STATUS_OK; } return ret_stat; } /* * Routine vms_getportattributes(chan, fcp_ptr, target, portattributes) * * Functional Description: * * This function returns the HBA port attributes. * * Formal Parameters: * * handle Handle number for the adapter. * fcp_ptr pointer to information about the port. * target fc-la target for the port. * portattributes pointer to structure to fill in with the * attributes of the port. * * Return Values: * HBA_STATUS_OK The port attributes were returned. * other error codes from called routines. * * */ static HBA_STATUS vms_getportattributes( unsigned short chan, VMS_FCP_PORT_INFO * fcp_ptr, int * target, HBA_PORTATTRIBUTES *portattributes ) { HBA_STATUS ret_stat; unsigned short iosb[4]; SNIA_RQ_HEADER snia_rq; int status; vms_check_null_arg(fcp_ptr); vms_check_null_arg(portattributes); snia_rq.command_code = FC$C_QIO_SNIA_REQUEST; snia_rq.qw_count = 1; snia_rq.sub_command = FC$C_QIO_SUB_SNIA_PORT_ATTR; status = SYS$QIOW (EFN$C_ENF, chan, /* Channel */ IO$_ACCESS, /* I/O Function Code */ iosb, /* I/O Status Block */ 0, /* AST Address - none */ 0, /* AST Parameter - none */ &snia_rq, /* Request Block */ sizeof(SNIA_RQ_HEADER), /* Request Block size */ portattributes, /* Returned attributes */ sizeof(HBA_PORTATTRIBUTES), /* atribute size */ 0, /* Not used */ 0); /* Not used */ if (!$VMS_STATUS_SUCCESS(status) || !$VMS_STATUS_SUCCESS(iosb[0])) { if (iosb[0] == SS$_INVARG) ret_stat = HBA_STATUS_ERROR_ILLEGAL_INDEX; else { /* The underlying Fibre Driver does not support this call */ ret_stat = HBA_STATUS_ERROR_NOT_SUPPORTED; } } else { ret_stat = HBA_STATUS_OK; if (target != NULL) *target = iosb[3] * 256 + iosb[2]; } /* Optional - Null string */ if (fcp_ptr->fcp_device_name[0] != 0) strcpy(portattributes->OSDeviceName, fcp_ptr->fcp_device_name); else strcpy(portattributes->OSDeviceName, fcp_ptr->hba_device_name); return ret_stat; } /* * Routine VMS_GetAdapterPortAttributes(handle, portindex, portattributes) * * Functional Description: * * This function returns the port attributes. * * It is an Manditory function in the HBAAPI. * * Formal Parameters: * * handle Handle number for the adapter. * portindex indicates which port of the adapter * portattributes pointer to structure to fill in with the * attributes of the port. * * Return Values: * HBA_STATUS_OK The port attributes were returned. * other error codes from called routines. * * */ static HBA_STATUS VMS_GetAdapterPortAttributes( HBA_HANDLE handle, HBA_UINT32 portindex, HBA_PORTATTRIBUTES *portattributes ) { HBA_STATUS ret_stat; VMS_ADAPTER_INFO * vms_hba_attr; ret_stat = HBA_STATUS_ERROR_INVALID_HANDLE; /* Sanity check */ /*--------------*/ vms_hba_attr = get_vms_adapter_attributes(handle); if (vms_hba_attr != NULL) { ret_stat = HBA_STATUS_ERROR_ILLEGAL_INDEX; /* Is the port in range? */ /*-----------------------*/ if (portindex < vms_hba_attr->port_count) { VMS_FCP_PORT_INFO * fcp_ptr; fcp_ptr = vms_hba_attr->port_flink; /* Look for the port index */ /*-------------------------*/ while (fcp_ptr != (VMS_FCP_PORT_INFO *)&vms_hba_attr->port_flink) { if (fcp_ptr->port_index == portindex) { int i; unsigned short chan; /* Get the data */ /*--------------*/ i = handle - 1; chan = vms_open_adapter_data[i].chan; ret_stat = vms_getportattributes (chan, fcp_ptr, NULL, portattributes); break; } fcp_ptr = fcp_ptr->port_flink; } } } return ret_stat; } /* * Routine VMS_GetPortStatistics(handle, portindex, portstatistics) * * Functional Description: * * This function returns the HBA attributes which were looked up * when the adapter was opened. * * It is an Manditory function in the HBAAPI. * * Formal Parameters: * * handle Handle number for the adapter. * portindex port number on the adapter. * portstatistics pointer to structure to fill in with the * statistics for the port. * * Return Values: * HBA_STATUS_OK The adapter attributes were returned. * other error codes from called routines. * * */ static HBA_STATUS VMS_GetPortStatistics( HBA_HANDLE handle, HBA_UINT32 portindex, HBA_PORTSTATISTICS *portstatistics ) { HBA_STATUS ret_stat; VMS_ADAPTER_INFO * vms_hba_attr; vms_check_null_arg(portstatistics); ret_stat = HBA_STATUS_ERROR_INVALID_HANDLE; /* Sanity check */ /*--------------*/ vms_hba_attr = get_vms_adapter_attributes(handle); if (vms_hba_attr != NULL) { ret_stat = HBA_STATUS_ERROR_ILLEGAL_INDEX; if (portindex < vms_hba_attr->port_count) { VMS_FCP_PORT_INFO * fcp_ptr; fcp_ptr = vms_hba_attr->port_flink; /* Look for the port index */ /*-------------------------*/ while (fcp_ptr != (VMS_FCP_PORT_INFO *)&vms_hba_attr->port_flink) { if (fcp_ptr->port_index == portindex) { unsigned short iosb[4]; SNIA_RQ_HEADER snia_rq; int status; int i; unsigned short chan; /* Get the channel */ /*-----------------*/ i = handle - 1; chan = vms_open_adapter_data[i].chan; snia_rq.command_code = FC$C_QIO_SNIA_REQUEST; snia_rq.qw_count = 1; snia_rq.sub_command = FC$C_QIO_SUB_SNIA_PORTSTAT; status = SYS$QIOW (EFN$C_ENF, chan, /* Channel */ IO$_ACCESS, /* I/O Function Code */ iosb, /* I/O Status Block */ 0, /* AST Address - none */ 0, /* AST Parameter - none */ &snia_rq, /* Request Block */ sizeof(SNIA_RQ_HEADER), /* Request Block size */ portstatistics, /* Returned attributes */ sizeof(HBA_PORTSTATISTICS), /* atribute size */ 0, /* Not used */ 0); /* Not used */ if ($VMS_STATUS_SUCCESS(status) && $VMS_STATUS_SUCCESS(iosb[0])) ret_stat = HBA_STATUS_OK; else ret_stat = HBA_STATUS_ERROR_NOT_SUPPORTED; break; } fcp_ptr = fcp_ptr->port_flink; } } } return ret_stat; } /* * Routine VMS_GetDiscoveredPortAttrs(handle, portindex, * discoveredportindex, * portattributes) * * Functional Description: * * This function returns the discovered port attributes. * * It is an Manditory function in the HBAAPI. * * Formal Parameters: * * handle Handle number for the adapter. * portindex indicates which port of the adapter * portattributes pointer to structure to fill in with the * attributes of the port. * * Return Values: * HBA_STATUS_OK The port attributes were returned. * other error codes from called routines. * * */ static HBA_STATUS VMS_GetDiscoveredPortAttrs( HBA_HANDLE handle, HBA_UINT32 portindex, HBA_UINT32 discoveredportindex, HBA_PORTATTRIBUTES *portattributes ) { HBA_STATUS ret_stat; VMS_ADAPTER_INFO * vms_hba_attr; vms_check_null_arg(portattributes); ret_stat = HBA_STATUS_ERROR_INVALID_HANDLE; /* Sanity check */ /*--------------*/ vms_hba_attr = get_vms_adapter_attributes(handle); if (vms_hba_attr != NULL) { ret_stat = HBA_STATUS_ERROR_ILLEGAL_INDEX; /* Is the port in range? */ /*-----------------------*/ if (portindex < vms_hba_attr->port_count) { VMS_FCP_PORT_INFO * fcp_ptr; fcp_ptr = vms_hba_attr->port_flink; /* Look for the port index */ /*-------------------------*/ while (fcp_ptr != (VMS_FCP_PORT_INFO *)&vms_hba_attr->port_flink) { if (fcp_ptr->port_index == portindex) { int i; unsigned short chan; /* Get the data */ /*--------------*/ i = handle - 1; chan = vms_open_adapter_data[i].chan; ret_stat = vms_getdiscportattributes (chan, discoveredportindex, NULL, NULL, fcp_ptr, portattributes); break; } fcp_ptr = fcp_ptr->port_flink; } } } return ret_stat; } /* * Routine VMS_GetDiscoveredPortAttrs(handle, portWWN, * discoveredportindex, * portattributes) * * Functional Description: * * This function returns the discovered port attributes. * * It is an Optional function in the HBAAPI. * * Formal Parameters: * * handle Handle number for the adapter. * portWWN indicates which port of the adapter. * portattributes pointer to structure to fill in with the * attributes of the port. * * Return Values: * HBA_STATUS_OK The port attributes were returned. * other error codes from called routines. * * */ static HBA_STATUS VMS_GetPortAttributesByWWN( HBA_HANDLE handle, HBA_WWN PortWWN, HBA_PORTATTRIBUTES *portattributes ) { HBA_STATUS ret_stat; VMS_ADAPTER_INFO * vms_hba_attr; vms_check_null_arg(portattributes); ret_stat = HBA_STATUS_ERROR_INVALID_HANDLE; /* Sanity check */ /*--------------*/ vms_hba_attr = get_vms_adapter_attributes(handle); if (vms_hba_attr != NULL) { VMS_FCP_PORT_INFO * fcp_ptr; ret_stat = HBA_STATUS_ERROR_ILLEGAL_WWN; fcp_ptr = vms_hba_attr->port_flink; /* Look for the port wwn */ /*-----------------------*/ while (fcp_ptr != (VMS_FCP_PORT_INFO *)&vms_hba_attr->port_flink) { int test_val; test_val = memcmp(&fcp_ptr->portwwn, &PortWWN, sizeof(HBA_WWN)); if (test_val == 0) { int i; unsigned short chan; /* Get the data */ /*--------------*/ i = handle - 1; chan = vms_open_adapter_data[i].chan; ret_stat = vms_getportattributes (chan, fcp_ptr, NULL, portattributes); break; } fcp_ptr = fcp_ptr->port_flink; } /* Try as WWPN for discovered port */ /*---------------------------------*/ if (ret_stat == HBA_STATUS_ERROR_ILLEGAL_WWN) { int i; unsigned short chan; i = handle - 1; chan = vms_open_adapter_data[i].chan; ret_stat = vms_getdiscportattributes (chan, 0, &PortWWN, NULL, fcp_ptr, portattributes); } } return ret_stat; } /* * Routine VMS_RefreshInformation(handle) * * Functional Description: * * This function is currently a noop. * * It is an Manditory function in the HBAAPI. * * Formal Parameters: * * handle Handle number for the adapter. * * Return Values: None. * * */ static void VMS_RefreshInformation(HBA_HANDLE handle) { } /* * Routine vms_check_handle_open(handle) * * Functional Description: * * This function checks to see if a handle is open. * * Formal Parameters: * * handle Handle number for the adapter. * * Return Values: * HBA_STATUS_OK Handle is open. * HBA_STATUS_ERROR_INVALID_HANDLE Handle is not open. * */ static HBA_STATUS vms_check_handle_open(HBA_HANDLE handle) { HBA_STATUS ret_stat; ret_stat = HBA_STATUS_ERROR_INVALID_HANDLE; /* Sanity check handle */ /*---------------------*/ if (handle <= 0xFFFF) { int i; /* Is the channel open? */ /*----------------------*/ i = handle - 1; if ((vms_open_adapter_data[i].flags & HBA_M_CHANNEL_OPEN) != 0) { ret_stat = HBA_STATUS_OK; } } return ret_stat; } /* Routine vms_get_scsi_id(fcp_chan, target, lun, scsi_devtype, scsi_id, lu_id) * * Functional Description: * * This function looks up the information needed to fill in the * HBA_SCSIENTRY and HBA_LUID structures. * * HBA_SCSIENTRY * .OSDeviceName = Operating system device name [255] characters. * Will create from IOGEN algorithm. * .ScsiBusNumber = * .ScsiTargetNumber = FC-LA target used for the lookup. * .ScsiOSLun = UDID? * * HBA_LUID = PortWWN from page 83 (ASCII/BINARY?) * * * Formal Parameters: * * fcp_chan Channel to get SCSI information from the port. * target fc-la for remote port. * lun lun of the remote fc-la. * scsi_id Address of the HBA_SCSIENTRY structure to fill in. * lu_id Address of the HBA_LUID structure to fill in. * * Return Values: * VMS status value of the operation. * */ static int vms_get_scsi_id (unsigned short fcp_chan, int target, int64 lun, unsigned char *scsi_devtype, HBA_SCSIID *scsi_id, HBA_LUID *lu_id) { #pragma message save #pragma message disable multichar int status; unsigned char databuf[255]; /* SCSI data */ unsigned char sensebuf[20]; /* All the Sense data we care about */ HBA_UINT8 scsi_status; INQUIRY_DATA inq_data; /* Data returned from standard inquiry */ WWID wwid; int hsg_check = 0; int page83_support = 0; int page80_support = 0; int got_wwid = 0; unsigned short udid = 0xFFFF; unsigned int xfer_count; status = vms_scsi_inquiry (fcp_chan, target, lun, 0, 0, DEFAULT_SCSI_RETRIES, &xfer_count, &scsi_status, 255, &inq_data, sizeof(sensebuf), sensebuf); if (!$VMS_STATUS_SUCCESS(status)) { return status; } if ((scsi_status != SCSI$C_GOOD) || (xfer_count == 0)) return SS$_MEDOFL; *scsi_devtype = inq_data.scsi$inq$v_device_type; if (xfer_count >= 11) { #if 0 printf("Target %d product_id: %c%c%c; ", target ,inq_data.scsi$inq$b_product_id[0] ,inq_data.scsi$inq$b_product_id[1] ,inq_data.scsi$inq$b_product_id[2] ); #endif if (inq_data.scsi$inq$b_product_id[0] == 'H' && inq_data.scsi$inq$b_product_id[1] == 'S' && inq_data.scsi$inq$b_product_id[2] == 'G') hsg_check = 1; #if 0 if (hsg_check) printf("hsg_check\n"); #endif } /* Now get the UDID */ /*------------------*/ if ((*scsi_devtype != SCSI$C_TAPE) && (*scsi_devtype != SCSI$C_JUKEBOX)) { status = vms_get_udid (fcp_chan, target, lun, hsg_check, &udid); #if 0 if (!$VMS_STATUS_SUCCESS(status)) { printf("Could not get UDID for Target %d product_id: %c%c%c; ", target ,inq_data.scsi$inq$b_product_id[0] ,inq_data.scsi$inq$b_product_id[1] ,inq_data.scsi$inq$b_product_id[2] ); printf("vms_get_scsi_id(): vms_get_udid status = 0x%X\n", status); } #endif } /* Now get the supported pages if the device will admit to any */ /*-------------------------------------------------------------*/ status = vms_scsi_inquiry (fcp_chan, target, lun, INQ_CMD$M_ENABLE_VPD, 0, DEFAULT_SCSI_RETRIES, &xfer_count, &scsi_status, sizeof(databuf), databuf, sizeof(sensebuf), sensebuf); if ($VMS_STATUS_SUCCESS(status)) { if ((scsi_status == SCSI$C_GOOD) && (xfer_count != 0)) { PAGE00 * page00; int pagelen; int i; int count; page00 = (PAGE00 *)databuf; pagelen = page00->page00$b_page_len & 0xFF; if (pagelen < (xfer_count - 4)) pagelen = xfer_count - 4; count = 0; for (i = 0; i < pagelen; i++) { if (page00->page00$b_supported_page[i] == 0x80) { count++; page80_support = 1; } else { if (page00->page00$b_supported_page[i] == 0x83) { count++; page83_support = 1; } } if (count == 2) break; } } #if 0 } else { printf("vms_get_scsi_id(): page00 vms_scsi_inquiry status = 0x%X\n", status); #endif } if (page83_support) { /* Now try to get the WWID from page 83 */ /*--------------------------------------*/ status = vms_scsi_inquiry (fcp_chan, target, lun, INQ_CMD$M_ENABLE_VPD, 0x83, DEFAULT_SCSI_RETRIES, &xfer_count, &scsi_status, sizeof(databuf), databuf, sizeof(sensebuf), sensebuf); if ($VMS_STATUS_SUCCESS(status)) { status = ioc$get_page83_wwid ((PAGE83 *)databuf, &wwid); if ($VMS_STATUS_SUCCESS(status)) got_wwid = 1; #if 0 } else { printf("vms_get_scsi_id(): page83 vms_scsi_inquiry status = 0x%X\n", status); #endif } } /* No wwid from page 83? */ /*-----------------------*/ if (!got_wwid && page80_support) { status = vms_scsi_inquiry (fcp_chan, target, lun, INQ_CMD$M_ENABLE_VPD, 0x80, DEFAULT_SCSI_RETRIES, &xfer_count, &scsi_status, sizeof(databuf), databuf, sizeof(sensebuf), sensebuf); if ($VMS_STATUS_SUCCESS(status)) { status = ioc$get_page80_wwid (&inq_data, (PAGE80 *)databuf, (SN_WWID *)&wwid); if ($VMS_STATUS_SUCCESS(status)) got_wwid = 1; #if 0 } else { printf("vms_get_scsi_id(): page80 vms_scsi_inquiry status = 0x%X\n", status); #endif } } if ((*scsi_devtype == SCSI$C_SCC) || (*scsi_devtype == SCSI$C_DISK)) { if (udid != 0xFFFF) { /* DISK $1$DGAnnn: or Storage Controller $1$GGAnn: */ /*-------------------------------------------------*/ if (*scsi_devtype == SCSI$C_SCC) { sprintf(scsi_id->OSDeviceName, "$1$GGA%d:", udid); } else { sprintf(scsi_id->OSDeviceName, "$1$DGA%d:", udid); } } else { sprintf(scsi_id->OSDeviceName, "%c%c%c (NO UDID)" ,inq_data.scsi$inq$b_product_id[0] ,inq_data.scsi$inq$b_product_id[1] ,inq_data.scsi$inq$b_product_id[2] ); } } else { if ((*scsi_devtype == SCSI$C_TAPE) || (*scsi_devtype == SCSI$C_JUKEBOX)) { /* Tapes are $2$MGAnnn: , Jukeboxes $2$GGAnnn: */ if (got_wwid) { status = search_logname_table_for_wwid (&wwid, scsi_id->OSDeviceName, 255); } } } /* These do not mean anything to VMS right now */ scsi_id->ScsiBusNumber = 0; scsi_id->ScsiTargetNumber = 0; scsi_id->ScsiOSLun = 0; if ((lu_id != NULL) && got_wwid) { int ret_len; status = ioc_std$binwwid_to_ascwwid (&wwid, (char *)lu_id, 255, &ret_len); } return status; } #pragma message restore /* * Routine vms_get_lun_list (fcp_chan, target, lun, &lun_data, * &lun_alloc, &lun_count) * * Functional Description: * * This routine allocates memory and returns a list of luns for * a given device. It is up to the caller to free the memory * allocated. * * Formal Parameters: * * chan channel to the FCP port device * target FC_LA target * lun lun for device * lun_data Pointer to buffer to hold return data * lun_alloc Size of buffer allocated to hold return data * lun_count Count of luns returned. * * Return Values: * * SS$_NORMAL Successful completion. * ... or any status value that can be returned by the port driver. */ #define DFLT_BUFLEN RPTLUN_HDR$K_LENGTH + (8*32) /* 32 luns as first try */ static int vms_get_lun_list (unsigned short fcp_chan, int target, int64 lun, RPTLUN_DATA * *lun_data, unsigned long * lun_alloc, unsigned long * lun_count) { int status; RPTLUN_DATA *new_data; unsigned int xfer_count; HBA_UINT8 scsi_status; unsigned char sensebuf[20]; int retries; unsigned long list_length; *lun_alloc = DFLT_BUFLEN; *lun_count = 0; retries = 1; do { int insuff_alloc; /* Get some memory for the lun list */ /*----------------------------------*/ new_data = malloc(*lun_alloc); if (new_data == NULL) { status = SS$_INSFMEM; *lun_alloc = 0; break; } /* Get a list of the LUNS */ /*------------------------*/ status = vms_scsi_report_luns (fcp_chan, target, lun, DEFAULT_SCSI_RETRIES, &xfer_count, &scsi_status, &list_length, *lun_alloc, new_data, sizeof(sensebuf), sensebuf); if (!$VMS_STATUS_SUCCESS(status)) { free(new_data); new_data = NULL; *lun_alloc = 0; break; } /* Got the LUN data but the allocated buffer size was too */ /* small. Allocate a larger buffer & retry the command. */ /*--------------------------------------------------------*/ *lun_count = list_length / 8; insuff_alloc = (RPTLUN_HDR$K_LENGTH + list_length) > *lun_alloc; if (insuff_alloc) { free(new_data); new_data = NULL; /* Determine how much space is needed for lun data */ /*-------------------------------------------------*/ *lun_alloc = RPTLUN_HDR$K_LENGTH + list_length; } } while (retries-- > 0); /* Return pointer to dynamically allocated LUN data and length of */ /* that allocated memory. This will be deallocated by the calling */ /* routine once it has finished with the LUN data. */ /*-----------------------------------------------------------------*/ *lun_data = new_data; return status; } /* * Routine vms_lookup_mapping (handle, wwpn, pmappingV1, pmappingV2) * * Functional Description: * * This function returns the mapping of SCSI devices accessable to * the driver to the fcp id and device names for the * HBA_GetFcpTargetMapping and HBA_GetFcpTargetMappingV2 routines. * * * Formal Parameters: * * handle Handle for the adapter. * wwpn World Wide Port Name. * pmappingV1 A list of V1 mapping functions. * pmappingV2 A list of V1 mapping functions. * * Return Values: * HBA_STATUS_OK A list of mappings was returned. * other error codes from called routines. * */ static HBA_STATUS vms_lookup_mapping (HBA_HANDLE handle, HBA_WWN * wwpn, HBA_FCPTARGETMAPPING * pmappingV1, HBA_FCPTARGETMAPPINGV2 * pmappingV2) { HBA_STATUS ret_stat; VMS_ADAPTER_INFO * vms_hba_attr; unsigned short hba_chan; int status; HBA_STATUS hba_stat; ret_stat = HBA_STATUS_ERROR_INVALID_HANDLE; /* Sanity check */ /*--------------*/ vms_hba_attr = get_vms_adapter_attributes(handle); if (vms_hba_attr != NULL) { HBA_SCSIID *scsi_id; HBA_FCPID *fcp_id; HBA_LUID *lu_id; HBA_SCSIID dummy_scsi_id; HBA_FCPID dummy_fcp_id; int exceeded_max = 0; VMS_FCP_PORT_INFO * fcp_ptr; HBA_PORTATTRIBUTES *port_attributes; int entry_index; int entry_count; int index; int max_index; int i; ret_stat = HBA_STATUS_ERROR; entry_index = 0; entry_count = 0; if (pmappingV1 != NULL) { max_index = pmappingV1->NumberOfEntries; scsi_id = &pmappingV1->entry[entry_index].ScsiId; fcp_id = &pmappingV1->entry[entry_index].FcpId; lu_id = NULL; } else { max_index = pmappingV2->NumberOfEntries; scsi_id = &pmappingV2->entry[entry_index].ScsiId; fcp_id = &pmappingV2->entry[entry_index].FcpId; lu_id = &pmappingV2->entry[entry_index].LUID; } if (max_index == 0) { return HBA_STATUS_ERROR_ARG; } port_attributes = malloc(sizeof(HBA_PORTATTRIBUTES)); fcp_ptr = vms_hba_attr->port_flink; i = handle - 1; hba_chan = vms_open_adapter_data[i].chan; status = 0; while (fcp_ptr != (VMS_FCP_PORT_INFO *)&vms_hba_attr->port_flink) { unsigned short fcp_chan; int64 lun; int target; unsigned char scsi_devtype; /* Device type info from inquiry data */ uint64 *test_wwnptr; uint64 *port_wwnptr; /* Only need to look if this is the correct port */ /*-----------------------------------------------*/ test_wwnptr = (uint64 *)wwpn; port_wwnptr = (uint64 *)&fcp_ptr->portwwn; if (wwpn != NULL) { if (*test_wwnptr == *port_wwnptr) { fcp_ptr = fcp_ptr->port_flink; continue; } } /* Get the fcp channel */ /*---------------------*/ status = vms_get_fcp_chan (hba_chan, vms_hba_attr, fcp_ptr, &fcp_chan); if (!$VMS_STATUS_SUCCESS(status)) { printf("vms_lookup_mapping(): vms_get_fcp_chan status = 0x%x\n", status); break; } for (target = 1;; target++) { int inq_status; int i; int64 *lunptr = NULL; /* Check LUN 0, and get device type, etc */ /*---------------------------------------*/ status = vms_get_scsi_id (fcp_chan, target, 0, &scsi_devtype, scsi_id, lu_id); #if 0 printf("scsi id target = %d, handle = %d, status = 0x%x\n", target, handle, status); #endif /* if we did not find a device try the next target */ /*-------------------------------------------------*/ if (status == SS$_NOMOREDEV || status == SS$_NOLINKS || status == SS$_BADPARAM) { /* X-2b */ #if 0 printf("error break: scsi id target = %d, handle = %d, status = 0x%x\n", target, (int)handle, status); #endif break; } if (!$VMS_STATUS_SUCCESS(status)) { continue; } #if 0 if (!strlen(scsi_id->OSDeviceName)) { printf("Null Device Name from vms_get_scsi_id()\n"); printf("scsi id target = %d, handle = %d, status = 0x%x, devtype = %d\n", target, handle, status, scsi_devtype ); exit(0); } #endif #if 0 printf("scsi id target = %d, handle = %d, status = 0x%x, devtype = %d, name = \"%s\"\n", target, handle, status, scsi_devtype, scsi_id->OSDeviceName ); #endif /* First we need the FCP attributes for this target */ /*--------------------------------------------------*/ hba_stat = vms_getdiscportattributes (hba_chan, target-1, /* this function expects a base of zero */ NULL, NULL, fcp_ptr, port_attributes); if (hba_stat != HBA_STATUS_OK) { /* Should not happen! */ /*--------------------*/ status = SS$_MEDOFL; continue; } else { status = SS$_NORMAL; } if (ret_stat != HBA_STATUS_ERROR_MORE_DATA) { /* Fill in the HBA_FcpId part of the structure */ /*---------------------------------------------*/ fcp_id->FcId = port_attributes->PortFcId; fcp_id->FcpLun = 0; memcpy (&fcp_id->NodeWWN, &port_attributes->NodeWWN, sizeof(HBA_WWN)); memcpy (&fcp_id->PortWWN, &port_attributes->PortWWN, sizeof(HBA_WWN)); } /* * NOTE that the entry_count could exceed the actual data * returned to the user if the user buffer was too small. This * is required by the standard so that the user will know * how large to make the buffer on a subsequent call. */ entry_count++; /* Set up for next entry */ /*-----------------------*/ entry_index++; if (entry_index >= max_index) { ret_stat = HBA_STATUS_ERROR_MORE_DATA; } if (ret_stat != HBA_STATUS_ERROR_MORE_DATA) { if (pmappingV1 != NULL) { scsi_id = &pmappingV1->entry[entry_index].ScsiId; fcp_id = &pmappingV1->entry[entry_index].FcpId; } else { scsi_id = &pmappingV2->entry[entry_index].ScsiId; fcp_id = &pmappingV2->entry[entry_index].FcpId; lu_id = &pmappingV2->entry[entry_index].LUID; } } else if (!exceeded_max) { exceeded_max = 1; scsi_id = &dummy_scsi_id; fcp_id = &dummy_fcp_id; lu_id = NULL; } /* Get the lun list */ /*------------------*/ if (status == SS$_NORMAL) { unsigned long lun_count; int getlun_status; unsigned long lun_alloc; RPTLUN_DATA *lun_data = NULL; /* Look for addtional LUNS */ /*-------------------------*/ getlun_status = vms_get_lun_list (fcp_chan, target, 0, &lun_data, &lun_alloc, &lun_count); if (lun_data != NULL) { lunptr = (int64 *)&lun_data->rptlun_data$r_lun_list; } else { lun_count = 16; /* Assume 16 luns */ } #if 0 printf("Lun Count = %d, vms_get_lun_list status = 0x%x", lun_count, getlun_status); if (lun_data) printf(", got LUN data:"); printf("\n"); { int i; int64 *p = (int64 *)&lun_data->rptlun_data$r_lun_list; for (i=0; iFcId = port_attributes->PortFcId; fcp_id->FcpLun = test_lun; memcpy (&fcp_id->NodeWWN, &port_attributes->NodeWWN, sizeof(HBA_WWN)); memcpy (&fcp_id->PortWWN, &port_attributes->PortWWN, sizeof(HBA_WWN)); } entry_count++; /* Set up for next entry */ /*-----------------------*/ entry_index++; if (entry_index >= max_index) { ret_stat = HBA_STATUS_ERROR_MORE_DATA; } if (ret_stat != HBA_STATUS_ERROR_MORE_DATA) { if (pmappingV1 != NULL) { scsi_id = &pmappingV1->entry[entry_index].ScsiId; fcp_id = &pmappingV1->entry[entry_index].FcpId; } else { scsi_id = &pmappingV2->entry[entry_index].ScsiId; fcp_id = &pmappingV2->entry[entry_index].FcpId; lu_id = &pmappingV2->entry[entry_index].LUID; } } else if (!exceeded_max) { exceeded_max = 1; scsi_id = &dummy_scsi_id; fcp_id = &dummy_fcp_id; lu_id = NULL; } } /* for (i = 0; i < lun_count; i++) */ if (lun_data != NULL) { free(lun_data); lun_data = NULL; } } /* if (status == SS$_NORMAL) */ } /* for (target = 1;; target++) */ fcp_ptr = fcp_ptr->port_flink; /* For V1, check the next port */ /*-----------------------------*/ if (wwpn != NULL) { if (*test_wwnptr == *port_wwnptr) break; } } /* while (fcp_ptr != (VMS_FCP_PORT_INFO *)&vms_hba_attr->port_flink) */ free(port_attributes); /* Something was found */ /*---------------------*/ if (entry_index != 0 && ret_stat == HBA_STATUS_ERROR) ret_stat = HBA_STATUS_OK; /* * The standard wants us to return the total number of units available, * not just the number of units we put into the buffer. This lets the * user know how large to make the buffer on the next call. */ if (pmappingV1 != NULL) { pmappingV1->NumberOfEntries = entry_count; } else { pmappingV2->NumberOfEntries = entry_count; } } /* if (vms_hba_attr != NULL) */ return ret_stat; } /* * Routine VMS_GetFcpTargetMapping (handle, pmapping) * * Functional Description: * * This function returns the mapping of SCSI devices on the * accessable by the adapter to the operating system device names. * * It is an Optional function in the HBAAPI. * It is needed for the OpenVIEW Storage Area Manager product. * * Formal Parameters: * * handle Handle number for the adapter. * pmapping A list of mapping functions. * * Return Values: * HBA_STATUS_OK A list of mappings was returned. * other error codes from called routines. * */ static HBA_STATUS VMS_GetFcpTargetMapping (HBA_HANDLE handle, HBA_FCPTARGETMAPPING * pmapping) { HBA_STATUS ret_stat; VMS_ADAPTER_INFO * vms_hba_attr; unsigned short hba_chan; vms_check_null_arg(pmapping); if (pmapping->NumberOfEntries == 0) return HBA_STATUS_ERROR_ARG; ret_stat = vms_lookup_mapping(handle, NULL, pmapping, NULL); return ret_stat; } /* * Routine VMS_GetFcpTargetMappingV2 (handle, wwn, pmapping) * * Functional Description: * * This function returns the mapping of SCSI devices on the * accessable by the adapter to the operating system device names. * * It is an Optional function in the HBAAPI. * It may be needed for the OpenVIEW Storage Area Manager product. * * Formal Parameters: * * handle Handle number for the adapter. * wwn Local port to obtain the mappings from. * pmapping A list of mapping functions. * * Return Values: * HBA_STATUS_OK A list of mappings was returned. * other error codes from called routines. * */ static HBA_STATUS VMS_GetFcpTargetMappingV2 (HBA_HANDLE handle, HBA_WWN wwn, HBA_FCPTARGETMAPPINGV2 * pmapping) { HBA_STATUS ret_stat; VMS_ADAPTER_INFO * vms_hba_attr; vms_check_null_arg(pmapping); ret_stat = vms_lookup_mapping(handle, &wwn, NULL, pmapping); return ret_stat; } /* * Routine VMS_GetFcpPersistentBinding (handle, * pcapability) * * Functional Description: * * This function returns the Persistent Binding. * * It is an Optional function in the HBAAPI. * It is not currently implemeted. * * Formal Parameters: * * handle Handle number for the adapter. * pcapability A list of capabilities for binding. * * Return Values: * HBA_STATUS_ERROR_NOT_SUPPORTED Routine is not supported. * * HBA_STATUS_OK A list of mappings was returned. * other error codes from called routines. * */ static HBA_STATUS VMS_GetFcpPersistentBinding (HBA_HANDLE handle, HBA_FCPBINDING * pcapability) { HBA_STATUS ret_stat; VMS_ADAPTER_INFO * vms_hba_attr; vms_check_null_arg(pcapability); /* Sanity check */ /*--------------*/ vms_hba_attr = get_vms_adapter_attributes(handle); if (vms_hba_attr != NULL) { pcapability->NumberOfEntries = 0; ret_stat = HBA_STATUS_OK; /* Not yet implmented */ ret_stat = HBA_STATUS_ERROR_NOT_SUPPORTED; } return ret_stat; } /* * Routine VMS_ReportLuns(handle, portwwn, pRspBuffer, RspBufferSize, * pSenseBuffer, SenseBufferSize) * * Functional Description: * * This function reports the luns available behind the adapter. * * It is an Optional function in the HBAAPI. * It will be needed to implement the HBA_GetFcpTargetMapping funtions. * * Formal Parameters: * * handle Handle number for the adapter. * portwwn local port to report the LUNs for. * pRspBuffer pointer to buffer to return the LUN data. * RspBufferSize Size of the return buffer. * pSenseBuffer Pointer to sense buffer. * SenseBufferSize Size of the sense buffer. * * Return Values: * HBA_STATUS_ERROR_NOT_SUPPORTED Routine is not supported. * * HBA_STATUS_OK A list of LUNs were returned. * other error codes from called routines. * */ static HBA_STATUS VMS_ReportLUNs (HBA_HANDLE handle, HBA_WWN portwwn, void * pRspBuffer, HBA_UINT32 RspBufferSize, void * pSenseBuffer, HBA_UINT32 SenseBufferSize) { HBA_STATUS ret_stat; VMS_ADAPTER_INFO * vms_hba_attr; HBA_UINT8 scsi_status; int target; unsigned short port_chan; unsigned int xfer_count; ret_stat = HBA_STATUS_ERROR_INVALID_HANDLE; if (RspBufferSize != 0) vms_check_null_arg(pRspBuffer); if (SenseBufferSize != 0) vms_check_null_arg(pSenseBuffer); /* Get the target for the discovered port */ /*----------------------------------------*/ ret_stat = vms_get_target_from_wwid (handle, NULL_WWN, portwwn, &target, NULL, &port_chan); if (ret_stat == HBA_STATUS_OK) { int status; unsigned long list_length; status = vms_scsi_report_luns (port_chan, target, 0, 0, /* no retries */ &xfer_count, &scsi_status, &list_length, RspBufferSize, pRspBuffer, SenseBufferSize, pSenseBuffer); ret_stat = vms_cvt_hba_scsi_status(status, scsi_status); /* Check to see if the data was truncated */ /*----------------------------------------*/ if (ret_stat == HBA_STATUS_OK) { int max_size; max_size = RspBufferSize; if (max_size > xfer_count) max_size = xfer_count; if ((list_length + 8) > max_size) ret_stat = HBA_STATUS_ERROR_MORE_DATA; } #if 0 } else { printf("ERROR: failed call to vms_get_target_from_wwid, ret_stat = %d\n", ret_stat); #endif } return ret_stat; } /* * Routine VMS_ScsiReportLUNsV2 (handle, hbaPortwwn, discoveredPortwwn, * pRspBuffer, pRspBufferSize, pScsiStatus, * pSenseBuffer, pSenseBufferSize) * * Functional Description: * * This function reports the luns available behind the adapter. * * It is an Optional function in the HBAAPI. * It will be needed to implement the HBA_GetFcpTargetMapping funtions. * * Formal Parameters: * * handle Handle number for the adapter. * portwwn local port to report the LUNs for. * pRspBuffer pointer to buffer to return the LUN data. * pRspBufferSize pointer to size of the return buffer. * pScsiStatus pointer to return SCSI Status byte. * pSenseBuffer pointer to sense buffer. * SenseBufferSize pointer to size of the sense buffer. * * Return Values: * HBA_STATUS_ERROR_NOT_SUPPORTED Routine is not supported. * * HBA_STATUS_OK A list of LUNs were returned. * other error codes from called routines. * */ static HBA_STATUS VMS_ScsiReportLUNsV2 (HBA_HANDLE handle, HBA_WWN hbaPortwwn, HBA_WWN discoveredPortwwn, void * pRspBuffer, HBA_UINT32 * pRspBufferSize, HBA_UINT8 * pScsiStatus, void * pSenseBuffer, HBA_UINT32 * pSenseBufferSize) { HBA_STATUS ret_stat; VMS_ADAPTER_INFO * vms_hba_attr; HBA_UINT8 scsi_status; int target; unsigned short port_chan; unsigned int xfer_count; vms_check_null_arg(pRspBufferSize); if (*pRspBufferSize != 0) { vms_check_null_arg(pRspBuffer); } vms_check_null_arg(pSenseBufferSize); if (*pSenseBufferSize != 0) { vms_check_null_arg(pSenseBuffer); } ret_stat = HBA_STATUS_ERROR_INVALID_HANDLE; /* Get the target for the discovered port */ /*----------------------------------------*/ ret_stat = vms_get_target_from_wwid (handle, hbaPortwwn, discoveredPortwwn, &target, NULL, &port_chan); if (ret_stat == HBA_STATUS_OK) { int status; unsigned long list_length; status = vms_scsi_report_luns (port_chan, target, 0, 0, /* no retries */ &xfer_count, &scsi_status, &list_length, *pRspBufferSize, pRspBuffer, *pSenseBufferSize, pSenseBuffer); /* Return the SCSI status if it exists */ /*-------------------------------------*/ if (pScsiStatus != NULL) *pScsiStatus = scsi_status; ret_stat = vms_cvt_hba_scsi_status(status, scsi_status); /* Check to see if the data was truncated */ /*----------------------------------------*/ if (ret_stat == HBA_STATUS_OK) { int max_data; max_data = *pRspBufferSize; if (max_data > xfer_count) max_data = xfer_count; if ((list_length + 8) > max_data) ret_stat = HBA_STATUS_ERROR_MORE_DATA; } } return ret_stat; } /* * Routine VMS_GetSBTargetMapping (handle, portWWN, pMapping) * * Functional Description: * * This function returns the SB Target Mapping. * * It is an Optional function in the HBAAPI. * It is not currently implemeted. * * Formal Parameters: * * handle Handle number for the adapter. * portWWN port to get mapping of. * pMapping A list of the mapping. * * Return Values: * HBA_STATUS_ERROR_NOT_SUPPORTED Routine is not supported. * * HBA_STATUS_OK A list of mappings was returned. * other error codes from called routines. * */ HBA_STATUS VMS_GetSBTargetMapping (HBA_HANDLE handle, HBA_WWN portWWN, HBA_SBTARGETMAPPING *pMapping) { HBA_STATUS ret_stat; VMS_ADAPTER_INFO * vms_hba_attr; vms_check_null_arg(pMapping); ret_stat = HBA_STATUS_ERROR_INVALID_HANDLE; /* Sanity check */ /*--------------*/ vms_hba_attr = get_vms_adapter_attributes(handle); if (vms_hba_attr != NULL) { ret_stat = HBA_STATUS_ERROR_NOT_SUPPORTED; } return ret_stat; } /* * Routine VMS_GetSBStatistics (handle, pDevId, statistics) * * Functional Description: * * This function returns the SB Statistics. * * It is an Optional function in the HBAAPI. * It is not currently implemeted. * * Formal Parameters: * * handle Handle number for the adapter. * pDevId Device to get statistics of. * statistics Pointer to statisics buffer. * * Return Values: * HBA_STATUS_ERROR_NOT_SUPPORTED Routine is not supported. * * HBA_STATUS_OK A list of mappings was returned. * other error codes from called routines. * */ HBA_STATUS VMS_GetSBStatistics (HBA_HANDLE handle, const HBA_SBDEVID * pDevId, HBA_SBSTATISTICS * statistics) { HBA_STATUS ret_stat; VMS_ADAPTER_INFO * vms_hba_attr; vms_check_null_arg(pDevId); vms_check_null_arg(statistics); ret_stat = HBA_STATUS_ERROR_INVALID_HANDLE; /* Sanity check */ /*--------------*/ vms_hba_attr = get_vms_adapter_attributes(handle); if (vms_hba_attr != NULL) { ret_stat = HBA_STATUS_ERROR_NOT_SUPPORTED; } return ret_stat; } /* * Routine VMS_GetSBGetCapacity (DeviceSelfDesc, pSBDskCapacity) * * Functional Description: * * This function returns the SB Disk Capacity. * * It is an Optional function in the HBAAPI. * It is not currently implemeted. * * Formal Parameters: * * DeviceSelfDesc Descriptor for device. * pSBDskCapacity Pointer to return capacity. * * Return Values: * HBA_STATUS_ERROR_NOT_SUPPORTED Routine is not supported. * * HBA_STATUS_OK A list of mappings was returned. * other error codes from called routines. * */ /* Optional */ HBA_STATUS VMS_SBDskGetCapacity (HBA_DEVICESELFDESC DeviceSelfDesc, HBA_SBDSKCAPACITY *pSBDskCapacity) { HBA_STATUS ret_stat; vms_check_null_arg(pSBDskCapacity); ret_stat = HBA_STATUS_ERROR_NOT_SUPPORTED; return ret_stat; } /* * Routine VMS_LoadLibrary (void) * * Functional Description: * * This function is called when the library is loaded to initialize * any structures needed for subsequent calls. * * It is an manditory function in the HBAAPI. * * Formal Parameters: None. * * Return Values: * HBA_STATUS_OK A list of mappings was returned. * HBA_STATUS_ERRRO_ALREADY_LOADED Library is already loaded. * */ static int vms_library_loaded = 0; /* Manditory */ static HBA_STATUS VMS_LoadLibrary(void) { if (vms_library_loaded == 0) { /* Vendor specific intialization ...*/ /*----------------------------------*/ event_list_head.flink = &event_list_head; event_list_head.blink = &event_list_head; /* Future, malloc the table to hold the channels based on user FILLM, and system Channel count */ vms_library_loaded = 1; return HBA_STATUS_OK; } else { return HBA_STATUS_ERROR_ALREADY_LOADED; } } /* Management - Manditory */ static HBA_STATUS VMS_SendCTPassThruV2 (HBA_HANDLE handle, HBA_WWN hbaPortwwn, void * pReqBuffer, HBA_UINT32 ReqBufferSize, void * pRspBuffer, HBA_UINT32 * pRspBufferSize) { HBA_STATUS ret_stat; VMS_ADAPTER_INFO * vms_hba_attr; if (ReqBufferSize != 0) { vms_check_null_arg(pReqBuffer); } vms_check_null_arg(pRspBufferSize); if (*pRspBufferSize != 0) { vms_check_null_arg(pRspBuffer); } ret_stat = HBA_STATUS_ERROR_INVALID_HANDLE; /* Sanity check */ /*--------------*/ vms_hba_attr = get_vms_adapter_attributes(handle); if (vms_hba_attr != NULL) { ret_stat = HBA_STATUS_ERROR_NOT_SUPPORTED; } return ret_stat; } /* Management - Manditory */ static HBA_STATUS VMS_SendCTPassThru (HBA_HANDLE handle, void * pReqBuffer, HBA_UINT32 ReqBufferSize, void * pRspBuffer, HBA_UINT32 RspBufferSize) { HBA_STATUS ret_stat; VMS_ADAPTER_INFO * vms_hba_attr; HBA_WWN wwn; if (ReqBufferSize != 0) { vms_check_null_arg(pReqBuffer); } if (RspBufferSize != 0) { vms_check_null_arg(pRspBuffer); } ret_stat = HBA_STATUS_ERROR_INVALID_HANDLE; /* Sanity check */ /*--------------*/ vms_hba_attr = get_vms_adapter_attributes(handle); if (vms_hba_attr != NULL) { memset(&wwn, 0, sizeof(HBA_WWN)); ret_stat = VMS_SendCTPassThruV2 (handle, wwn, pReqBuffer, ReqBufferSize, pRspBuffer, &RspBufferSize); } return ret_stat; } /* * Routine VMS_GetSBTargetMapping (handle, portindex) * * Functional Description: * * This function is to do nothing according to the HBAAPI specification. * * It is an Optional function in the HBAAPI. * * Formal Parameters: * * handle Handle number for the adapter. * portindex Specific port to use. * * Return Values: None. * */ static void VMS_ResetStatistics(HBA_HANDLE handle, HBA_UINT32 portindex) { /* According to the specifications, this function shall have no affect */ /* As such, no error checking will be done */ } /* Management - Manditory */ static HBA_STATUS VMS_GetEventBuffer (HBA_HANDLE handle, HBA_EVENTINFO * EventBuffer, HBA_UINT32 * EventBufferCount) { HBA_STATUS ret_stat; VMS_ADAPTER_INFO * vms_hba_attr; vms_check_null_arg(EventBuffer); vms_check_null_arg(EventBufferCount); ret_stat = HBA_STATUS_ERROR_INVALID_HANDLE; /* Sanity check */ /*--------------*/ vms_hba_attr = get_vms_adapter_attributes(handle); if (vms_hba_attr != NULL) { ret_stat = HBA_STATUS_ERROR_NOT_SUPPORTED; } return ret_stat; } /* Optional */ static HBA_STATUS VMS_SetRNIDMgmtInfo (HBA_HANDLE handle, HBA_MGMTINFO * pInfo) { HBA_STATUS ret_stat; VMS_ADAPTER_INFO * vms_hba_attr; vms_check_null_arg(pInfo); ret_stat = HBA_STATUS_ERROR_INVALID_HANDLE; /* Sanity check */ /*--------------*/ vms_hba_attr = get_vms_adapter_attributes(handle); if (vms_hba_attr != NULL) { ret_stat = HBA_STATUS_ERROR_NOT_SUPPORTED; } return ret_stat; } /* * Routine VMS_GetRNIDMgmtInfo (handle, pInfo) * * Functional Description: * * This function gets the RNID MgmtInfo if the port can provide it. * * It is an Manditory function in the HBAAPI. * * Formal Parameters: * * handle Handle number for the adapter. * pInfo Pointer to put the RNID management information. * * Return Values: * * HBA_STATUS_OK Available information was returned. * other error codes from called routines. * */ static HBA_STATUS VMS_GetRNIDMgmtInfo (HBA_HANDLE handle, HBA_MGMTINFO * pInfo) { HBA_STATUS ret_stat; VMS_ADAPTER_INFO * vms_hba_attr; vms_check_null_arg(pInfo); ret_stat = HBA_STATUS_ERROR_INVALID_HANDLE; /* Sanity check */ /*--------------*/ vms_hba_attr = get_vms_adapter_attributes(handle); if (vms_hba_attr != NULL) { int status; int i; unsigned short chan; unsigned short iosb[4]; SNIA_RQ_HEADER snia_rq; int new_size = sizeof(HBA_MGMTINFO); int mp_size; void *mp; /* * The structures are filled out to a quadword, * so if it's too small, allocate a larger buffer. */ if (new_size & 0x7) { new_size = new_size + 0x7 & ~0x7; mp_size = new_size; mp = malloc(new_size); } else { mp = pInfo; mp_size = new_size; new_size = 0; } /* Get the channel */ /*-----------------*/ i = handle - 1; chan = vms_open_adapter_data[i].chan; snia_rq.command_code = FC$C_QIO_SNIA_REQUEST; snia_rq.qw_count = 1; snia_rq.sub_command = FC$C_QIO_SUB_SNIA_RNIDMGMT; status = SYS$QIOW (EFN$C_ENF, chan, /* Channel */ IO$_ACCESS, /* I/O Function Code */ iosb, /* I/O Status Block */ 0, /* AST Address - none */ 0, /* AST Parameter - none */ &snia_rq, /* Request Block */ sizeof(SNIA_RQ_HEADER), /* Request Block size */ mp, /* Returned attributes */ mp_size, /* atribute size */ 0, /* Not used */ 0); /* Not used */ if (new_size) { memcpy(pInfo, mp, sizeof(HBA_MGMTINFO)); free(mp); new_size = 0; } if ($VMS_STATUS_SUCCESS(status)) { status = iosb[0]; if ($VMS_STATUS_SUCCESS(status)) { ret_stat = HBA_STATUS_OK; } else { ret_stat = HBA_STATUS_ERROR_ARG; } } else { ret_stat = HBA_STATUS_ERROR_NOT_SUPPORTED; } } return ret_stat; } /* Management - Manditory */ static HBA_STATUS VMS_SendRNIDV2 (HBA_HANDLE handle, HBA_WWN hbaPortwwn, HBA_WWN destwwn, HBA_UINT32 destFCID, HBA_UINT32 NodeIdDataFormat, void * pRspBuffer, HBA_UINT32* pRspBufferSize) { HBA_STATUS ret_stat; VMS_ADAPTER_INFO * vms_hba_attr; vms_check_null_arg(pRspBufferSize); if (*pRspBufferSize != 0) { vms_check_null_arg(pRspBuffer); } ret_stat = HBA_STATUS_ERROR_INVALID_HANDLE; /* Sanity check */ /*--------------*/ vms_hba_attr = get_vms_adapter_attributes(handle); if (vms_hba_attr != NULL) { ret_stat = HBA_STATUS_ERROR_NOT_SUPPORTED; } return ret_stat; } /* Management - Manditory */ static HBA_STATUS VMS_SendRNID (HBA_HANDLE handle, HBA_WWN wwn, HBA_WWNTYPE wwntype, void * pRspBuffer, HBA_UINT32* pRspBufferSize) { HBA_STATUS ret_stat; VMS_ADAPTER_INFO * vms_hba_attr; vms_check_null_arg(pRspBufferSize); if (*pRspBufferSize != 0) { vms_check_null_arg(pRspBuffer); } ret_stat = HBA_STATUS_ERROR_INVALID_HANDLE; /* Sanity check */ /*--------------*/ vms_hba_attr = get_vms_adapter_attributes(handle); if (vms_hba_attr != NULL) { ret_stat = HBA_STATUS_ERROR_NOT_SUPPORTED; } return ret_stat; } /* * Routine VMS_ScsiInquiryV2 (handle, hbaPortwwn, discoveredPortwwn, * fcpLUN, CDB_Byte1, CDB_Byte2, pRspBuffer, * pRspBufferSize, pScsiStatus, pSenseBuffer, * pSenseBufferSize) * * Functional Description: * * This function returns SCSI inquiry data. * * It is an Optional function in the HBAAPI. * It will be needed to implement the HBA_GetFcpTargetMapping funtions. * * Formal Parameters: * * handle Handle number for the adapter. * hbaPortwwn local port to report the LUNs for. * discovered Portwwn discovered port to report the LUNs for. * fcpLUN LUN to get data for. * CDB_Byte1 command specfic CDB information. * CDB_Byte2 command specfic CDB information. * pRspBuffer pointer to buffer to return the LUN data. * pRspBufferSize pointer to size of the return buffer. * pScsiStatus pointer to SCSI status. * pSenseBuffer Pointer to sense buffer. * pSenseBufferSize Pointer to size of the sense buffer. * * Return Values: * HBA_STATUS_ERROR_NOT_SUPPORTED Routine is not supported. * * HBA_STATUS_OK A list of LUNs were returned. * other error codes from called routines. * */ static HBA_STATUS VMS_ScsiInquiryV2 (HBA_HANDLE handle, HBA_WWN hbaPortwwn, HBA_WWN discoveredPortwwn, HBA_UINT64 fcpLUN, HBA_UINT8 CDB_Byte1, HBA_UINT8 CDB_Byte2, void * pRspBuffer, HBA_UINT32 * pRspBufferSize, HBA_UINT8 * pScsiStatus, void * pSenseBuffer, HBA_UINT32 * pSenseBufferSize) { HBA_STATUS ret_stat; VMS_ADAPTER_INFO * vms_hba_attr; int target; HBA_UINT8 scsi_status; unsigned short port_chan; unsigned int xfer_count; vms_check_null_arg(pRspBufferSize); if (*pRspBufferSize != 0) { vms_check_null_arg(pRspBuffer); } else { return HBA_STATUS_ERROR_ARG; } vms_check_null_arg(pSenseBufferSize); if (*pSenseBufferSize != 0) { vms_check_null_arg(pSenseBuffer); } /* Get the target for the discovered port */ /*----------------------------------------*/ ret_stat = vms_get_target_from_wwid (handle, hbaPortwwn, discoveredPortwwn, &target, NULL, &port_chan); if (ret_stat == HBA_STATUS_OK) { int status; status = vms_scsi_inquiry (port_chan, target, fcpLUN, CDB_Byte1, CDB_Byte2, 0, /* no retries */ &xfer_count, &scsi_status, *pRspBufferSize, pRspBuffer, *pSenseBufferSize, pSenseBuffer); /* Return the SCSI status if it exists */ /*-------------------------------------*/ if (pScsiStatus != NULL) *pScsiStatus = scsi_status; ret_stat = vms_cvt_hba_scsi_status(status, scsi_status); /* Check to see if the data was truncated */ /*----------------------------------------*/ if (ret_stat == HBA_STATUS_OK) { INQUIRY_DATA * inq_data; int max_data; inq_data = (INQUIRY_DATA *)pRspBuffer; max_data = *pRspBufferSize; if (max_data > xfer_count) max_data = xfer_count; if ((inq_data->scsi$inq$b_add_length + 4) > max_data) ret_stat = HBA_STATUS_ERROR_MORE_DATA; #if 0 } else { printf("ScsiInquiryV2: bad status = 0x%x, scsi status = %d\n", status, scsi_status); #endif } #if 0 } else { printf("SCSIInquiryV2: failed call to vms_get_target_from_wwid()\n"); #endif } return ret_stat; } /* * Routine VMS_ScsiInquiry (handle, hbaPortwwn, discoveredPortwwn, * fcpLUN, CDB_Byte1, CDB_Byte2, pRspBuffer, * pRspBufferSize, pScsiStatus, pSenseBuffer, * pSenseBufferSize) * * Functional Description: * * This function returns SCSI inquiry data. * * It is an Optional function in the HBAAPI. * It will be needed to implement the HBA_GetFcpTargetMapping funtions. * * Formal Parameters: * * handle Handle number for the adapter. * hbaPortwwn port to report the LUNs for. * fcpLUN LUN to get data for. * EVPD Vital Page Flag. * PageCode Vital Page to return. * pRspBuffer pointer to buffer to return the LUN data. * RspBufferSize Size of the return buffer. * pSenseBuffer Pointer to sense buffer. * SenseBufferSize Size of the sense buffer. * * Return Values: * HBA_STATUS_ERROR_NOT_SUPPORTED Routine is not supported. * * HBA_STATUS_OK A list of LUNs were returned. * other error codes from called routines. * */ static HBA_STATUS VMS_ScsiInquiry (HBA_HANDLE handle, HBA_WWN Portwwn, HBA_UINT64 fcpLUN, HBA_UINT8 EVPD, HBA_UINT32 PageCode, void * pRspBuffer, HBA_UINT32 RspBufferSize, void * pSenseBuffer, HBA_UINT32 SenseBufferSize) { HBA_STATUS ret_stat; VMS_ADAPTER_INFO * vms_hba_attr; HBA_UINT8 scsi_status; HBA_UINT8 CDB_Byte1; HBA_UINT8 CDB_Byte2; int target; unsigned short port_chan; unsigned int xfer_count; if (RspBufferSize != 0) { vms_check_null_arg(pRspBuffer); } if (SenseBufferSize != 0) { vms_check_null_arg(pSenseBuffer); } /* Get the target for the discovered port */ /*----------------------------------------*/ ret_stat = vms_get_target_from_wwid (handle, NULL_WWN, Portwwn, &target, NULL, &port_chan); if (ret_stat == HBA_STATUS_OK) { int status; CDB_Byte1 = 0; CDB_Byte2 = 0; if (EVPD != 0) { CDB_Byte1 |= INQ_CMD$M_ENABLE_VPD; CDB_Byte2 = PageCode; } status = vms_scsi_inquiry (port_chan, target, fcpLUN, CDB_Byte1, CDB_Byte2, 0, /* no retries */ &xfer_count, &scsi_status, RspBufferSize, pRspBuffer, SenseBufferSize, pSenseBuffer); ret_stat = vms_cvt_hba_scsi_status(status, scsi_status); /* Check to see if the data was truncated */ /*----------------------------------------*/ if (ret_stat == HBA_STATUS_OK) { INQUIRY_DATA * inq_data; unsigned long max_data; inq_data = (INQUIRY_DATA *)pRspBuffer; max_data = RspBufferSize; if (max_data > xfer_count) max_data = xfer_count; if ((inq_data->scsi$inq$b_add_length + 4) > max_data) ret_stat = HBA_STATUS_ERROR_MORE_DATA; } } return ret_stat; } /* Optional */ static HBA_STATUS VMS_ScsiReadCapacityV2 (HBA_HANDLE handle, HBA_WWN hbaPortwwn, HBA_WWN discoveredPortwwn, HBA_UINT64 fcpLUN, void * pRspBuffer, HBA_UINT32 * pRspBufferSize, HBA_UINT8 * pScsiStatus, void * pSenseBuffer, HBA_UINT32 * pSenseBufferSize) { HBA_STATUS ret_stat; int target; HBA_UINT8 scsi_status; unsigned short port_chan; unsigned int xfer_count; vms_check_null_arg(pRspBufferSize); if (*pRspBufferSize != 0) { vms_check_null_arg(pRspBuffer); } vms_check_null_arg(pSenseBufferSize); if (*pSenseBufferSize != 0) { vms_check_null_arg(pSenseBuffer); } /* Get the target for the discovered port */ /*----------------------------------------*/ ret_stat = vms_get_target_from_wwid (handle, hbaPortwwn, discoveredPortwwn, &target, NULL, &port_chan); if (ret_stat == HBA_STATUS_OK) { int status; status = vms_scsi_read_capacity (port_chan, target, fcpLUN, 0, /* no retries */ &xfer_count, &scsi_status, *pRspBufferSize, pRspBuffer, *pSenseBufferSize, pSenseBuffer); /* Return the SCSI status if it exists */ /*-------------------------------------*/ if (pScsiStatus != NULL) *pScsiStatus = scsi_status; ret_stat = vms_cvt_hba_scsi_status(status, scsi_status); /* Check to see if the data was truncated */ /*----------------------------------------*/ if (ret_stat == HBA_STATUS_OK) { int max_data; max_data = *pRspBufferSize; if (max_data > xfer_count) max_data = xfer_count; if (max_data < 8) ret_stat = HBA_STATUS_ERROR_MORE_DATA; } } return ret_stat; } /* Optional */ static HBA_STATUS VMS_ReadCapacity (HBA_HANDLE handle, HBA_WWN Portwwn, HBA_UINT64 fcpLUN, void * pRspBuffer, HBA_UINT32 RspBufferSize, void * pSenseBuffer, HBA_UINT32 SenseBufferSize) { HBA_STATUS ret_stat; HBA_UINT8 scsi_status; int target; unsigned short port_chan; unsigned int xfer_count; if (RspBufferSize != 0) { vms_check_null_arg(pRspBuffer); } if (SenseBufferSize != 0) { vms_check_null_arg(pSenseBuffer); } /* Get the target for the discovered port */ /*----------------------------------------*/ ret_stat = vms_get_target_from_wwid (handle, NULL_WWN, Portwwn, &target, NULL, &port_chan); if (ret_stat == HBA_STATUS_OK) { int status; status = vms_scsi_read_capacity (port_chan, target, fcpLUN, 0, /* no retries */ &xfer_count, &scsi_status, RspBufferSize, pRspBuffer, SenseBufferSize, pSenseBuffer); ret_stat = vms_cvt_hba_scsi_status(status, scsi_status); /* Check to see if the data was truncated */ /*----------------------------------------*/ if (ret_stat == HBA_STATUS_OK) { unsigned long max_data; max_data = RspBufferSize; if (max_data > xfer_count) max_data = xfer_count; if (max_data < 8) ret_stat = HBA_STATUS_ERROR_MORE_DATA; } } return ret_stat; } /* * Routine VMS_RefreshAdapterConfiguration (void) * * Functional Description: * * This procedure is to cause any new adapters to be discovered. * * The HBAAPI draft states that this function is not allowed in the * vendor specific library, but that does not make sense. * * On VMS, the routine GetNumberOfAdapters checks to see if any * new adapters are present when it is run. So there is nothing * for this routine to do. * * Formal Parameters: None * * Return Values: None * */ static void VMS_RefreshAdapterConfiguration(void) { } /* * Routine VMS_GetBindingCapability (handle, wwn1, pcapability) * * Functional Description: * * This function returns the FCP Binding capabilty. * None of the current options appear applicable to OpenVMS. * * It is an Optional function in the HBAAPI. * * Formal Parameters: * * handle Handle number for the adapter. * wwn1 port to report the binding capability. * pcapability pointer to buffer to return binding information. * * Return Values: * * HBA_STATUS_OK A list of LUNs were returned. * other error codes from called routines. * */ HBA_STATUS VMS_GetBindingCapability (HBA_HANDLE handle, HBA_WWN wwn1, HBA_BIND_CAPABILITY * pcapability) { HBA_STATUS ret_stat; VMS_ADAPTER_INFO * vms_hba_attr; vms_check_null_arg(pcapability); ret_stat = HBA_STATUS_ERROR_INVALID_HANDLE; /* Sanity check */ /*--------------*/ vms_hba_attr = get_vms_adapter_attributes(handle); /* While this routine should validate the WWPN's against the */ /* local port and discovered ports, the answer will always be */ /* the same */ #if 0 if (vms_hba_attr != NULL) { VMS_FCP_PORT_INFO * fcp_ptr; ret_stat = HBA_STATUS_ERROR_ILLEGAL_WWN; fcp_ptr = vms_hba_attr->port_flink; /* Look for the port index */ /*-------------------------*/ while (fcp_ptr != (VMS_FCP_PORT_INFO *)&vms_hba_attr->port_flink) { if (memcmp(&wwn1, &fcp_ptr->portwwn, sizeof(HBA_WWN)) == 0) { /* OpenVMS currently does not allow HBALIB to affect bindings */ #endif *pcapability = 0; ret_stat = HBA_STATUS_OK; #if 0 break; } else { /* We should check the discovered port wwpn's for a match */ } } } #endif return ret_stat; } /* * Routine VMS_GetBindingSupport (handle, wwn1, pcapability) * * Functional Description: * * This function returns the FCP Binding support. * None of the current options appear applicable to OpenVMS. * * It is an Optional function in the HBAAPI. * * Formal Parameters: * * handle Handle number for the adapter. * wwn1 port to report the binding capability. * pcapability pointer to buffer to return binding information. * * Return Values: * * HBA_STATUS_OK A list of LUNs were returned. * other error codes from called routines. * */ static HBA_STATUS VMS_GetBindingSupport (HBA_HANDLE handle, HBA_WWN wwn1, HBA_BIND_CAPABILITY * pcapability) { HBA_STATUS ret_stat; VMS_ADAPTER_INFO * vms_hba_attr; vms_check_null_arg(pcapability); ret_stat = HBA_STATUS_ERROR_INVALID_HANDLE; /* Sanity check */ /*--------------*/ vms_hba_attr = get_vms_adapter_attributes(handle); /* While this routine should validate the WWPN's against the */ /* local port and discovered ports, the answer will always be */ /* the same */ #if 0 if (vms_hba_attr != NULL) { VMS_FCP_PORT_INFO * fcp_ptr; ret_stat = HBA_STATUS_ERROR_ILLEGAL_WWN; fcp_ptr = vms_hba_attr->port_flink; /* Look for the port index */ /*-------------------------*/ while (fcp_ptr != (VMS_FCP_PORT_INFO *)&vms_hba_attr->port_flink) { if (memcmp(&wwn1, &fcp_ptr->portwwn, sizeof(HBA_WWN)) == 0) { /* OpenVMS currently does not allow HBALIB to affect bindings */ #endif *pcapability = 0; ret_stat = HBA_STATUS_OK; #if 0 break; } else { /* We should check the discovered port wwpn's for a match */ } } } #endif return ret_stat; } /* * Routine VMS_SetBindingSupport (handle, wwn1, pcapability) * * Functional Description: * * This function is to set the binding support level. * None of the current options appear applicable to OpenVMS. * * It is an Optional function in the HBAAPI. * * Formal Parameters: * * handle Handle number for the adapter. * wwn1 port to report the binding capability. * pcapability pointer to buffer of new binding information. * * Return Values: * HBA_STATUS_ERROR_NOT_SUPPORTED Routine is not supported. * * HBA_STATUS_OK A list of LUNs were returned. * other error codes from called routines. * */ static HBA_STATUS VMS_SetBindingSupport (HBA_HANDLE handle, HBA_WWN wwn1, HBA_BIND_CAPABILITY pcapability) { HBA_STATUS ret_stat; VMS_ADAPTER_INFO * vms_hba_attr; ret_stat = HBA_STATUS_ERROR_INVALID_HANDLE; /* Sanity check */ /*--------------*/ vms_hba_attr = get_vms_adapter_attributes(handle); if (vms_hba_attr != NULL) { ret_stat = HBA_STATUS_ERROR_NOT_SUPPORTED; } return ret_stat; } /* * Routine VMS_SetPersistentBindingV2 (handle, wwn1, pcapability) * * Functional Description: * * This function sets the FCP Persistent Binding capabilty. * None of the current options appear applicable to OpenVMS. * * It is an Optional function in the HBAAPI. * * Formal Parameters: * * handle Handle number for the adapter. * wwn1 port to report the binding capability. * pcapability pointer to buffer to return binding information. * * Return Values: * HBA_STATUS_ERROR_NOT_SUPPORTED Routine is not supported. * * HBA_STATUS_OK A list of LUNs were returned. * other error codes from called routines. * */ static HBA_STATUS VMS_SetPersistentBindingV2 (HBA_HANDLE handle, HBA_WWN wwn1, const HBA_FCPBINDING2 * pbinding) { HBA_STATUS ret_stat; VMS_ADAPTER_INFO * vms_hba_attr; vms_check_null_arg(pbinding); ret_stat = HBA_STATUS_ERROR_INVALID_HANDLE; /* Sanity check */ /*--------------*/ vms_hba_attr = get_vms_adapter_attributes(handle); if (vms_hba_attr != NULL) { ret_stat = HBA_STATUS_ERROR_NOT_SUPPORTED; } return ret_stat; } /* * Routine VMS_GetPersistentBindingV2 (handle, wwn1, pcapability) * * Functional Description: * * This function returns the FCP Persistent Binding capabilty. * None of the current options appear applicable to OpenVMS. * * It is an Optional function in the HBAAPI. * * Formal Parameters: * * handle Handle number for the adapter. * wwn1 port to report the binding capability. * pcapability pointer to buffer to return binding information. * * Return Values: * HBA_STATUS_ERROR_NOT_SUPPORTED Routine is not supported. * * HBA_STATUS_OK A list of LUNs were returned. * other error codes from called routines. * */ static HBA_STATUS VMS_GetPersistentBindingV2 (HBA_HANDLE handle, HBA_WWN wwn1, HBA_FCPBINDING2 * pbinding) { HBA_STATUS ret_stat; VMS_ADAPTER_INFO * vms_hba_attr; vms_check_null_arg(pbinding); ret_stat = HBA_STATUS_ERROR_INVALID_HANDLE; /* Sanity check */ /*--------------*/ vms_hba_attr = get_vms_adapter_attributes(handle); if (vms_hba_attr != NULL) { ret_stat = HBA_STATUS_ERROR_NOT_SUPPORTED; } return ret_stat; } /* * Routine VMS_RemovePersistentBinding (handle, wwn1, pcapability) * * Functional Description: * * This function removes a Persistant Binding. * None of the current options appear applicable to OpenVMS. * * It is an Optional function in the HBAAPI. * * Formal Parameters: * * handle Handle number for the adapter. * wwn1 port to report the binding capability. * pcapability pointer to buffer to return binding information. * * Return Values: * HBA_STATUS_ERROR_NOT_SUPPORTED Routine is not supported. * * HBA_STATUS_OK A list of LUNs were returned. * other error codes from called routines. * */ static HBA_STATUS VMS_RemovePersistentBinding (HBA_HANDLE handle, HBA_WWN wwn1, const HBA_FCPBINDING2 * pbinding) { HBA_STATUS ret_stat; VMS_ADAPTER_INFO * vms_hba_attr; vms_check_null_arg(pbinding); #if 0 puts ("You can not create a persistet binding, and are trying to remove one?"); #endif ret_stat = HBA_STATUS_ERROR_INVALID_HANDLE; /* Sanity check */ /*--------------*/ vms_hba_attr = get_vms_adapter_attributes(handle); if (vms_hba_attr != NULL) { ret_stat = HBA_STATUS_ERROR_NOT_SUPPORTED; } return ret_stat; } /* * Routine VMS_RemoveAllPersistentBindings (handle, wwn1, pcapability) * * Functional Description: * * This function removes all the FCP Binding capabilty. * None of the current options appear applicable to OpenVMS. * * It is an Optional function in the HBAAPI. * * Formal Parameters: * * handle Handle number for the adapter. * wwn1 port to report the binding capability. * pcapability pointer to buffer to return binding information. * * Return Values: * HBA_STATUS_ERROR_NOT_SUPPORTED Routine is not supported. * * HBA_STATUS_OK A list of LUNs were returned. * other error codes from called routines. * */ static HBA_STATUS VMS_RemoveAllPersistentBindings (HBA_HANDLE handle, HBA_WWN wwn1) { HBA_STATUS ret_stat; VMS_ADAPTER_INFO * vms_hba_attr; ret_stat = HBA_STATUS_ERROR_INVALID_HANDLE; /* Sanity check */ /*--------------*/ vms_hba_attr = get_vms_adapter_attributes(handle); if (vms_hba_attr != NULL) { ret_stat = HBA_STATUS_ERROR_NOT_SUPPORTED; } return ret_stat; } /* Manditory */ static HBA_UINT32 VMS_GetVendorLibraryAttributes (HBA_LIBRARYATTRIBUTES * attributes) { HBA_UINT32 ret_stat; const char *months="JanFebMarAprMayJunJulAugSepOctNovDec"; char mon[4]; char *mon_ptr; int matchCount; vms_check_null_arg(attributes); ret_stat = HBA_LIBVERSION; if (attributes != NULL) { attributes->final = 0; /* 1 = Standard, 0 = Draft */ strncpy(attributes->LibPath,getenv("snia$lib_vms"), 255); /* fixme */ if (attributes->LibPath[0] == 0) strcpy(attributes->LibPath,"SYS$SHARE:SNIA$LIB_VMS.EXE"); attributes->LibPath[255] = 0; strcpy(attributes->VName,"HP OpenVMS"); strcpy(attributes->VVersion,"X-1"); /* fixme */ memset(&attributes->build_date, 0, sizeof(struct tm)); strncpy(mon, __DATE__, 3); mon[3]=0; mon_ptr = strstr(months, mon); attributes->build_date.tm_mon = (mon_ptr - months)/3 + 1; matchCount = sscanf(__DATE__, "%*3c %u %u", &attributes->build_date.tm_mday, &attributes->build_date.tm_year); /* And the time */ /*--------------*/ matchCount = sscanf(__TIME__, "%u:%u:%u", &attributes->build_date.tm_hour, &attributes->build_date.tm_min, &attributes->build_date.tm_sec); } return ret_stat; } typedef struct link_event_st { EVENT_LIST link; void * data; HBA_WWN * adapterWWN; HBA_UINT32 eventType; void * pRLIRBuffer; HBA_UINT32 RLIRBufferSize; unsigned short hba_chan; } LINK_EVENT; typedef struct adapter_event_st { EVENT_LIST link; void * data; HBA_WWN * portWWN; HBA_UINT32 eventType; unsigned short hba_chan; } ADAPTER_EVENT; /* Management - Manditory */ static HBA_STATUS VMS_RemoveCallback(HBA_CALLBACKHANDLE callbackHandle) { HBA_STATUS ret_stat; int rem_status; void * generic_event_ptr; ret_stat = HBA_STATUS_ERROR_INVALID_HANDLE; rem_status = __PAL_REMQUEL(callbackHandle, &generic_event_ptr); if (rem_status >= 0) {; /* Cancel the AST */ /*----------------*/ /* Free the memory */ /*-----------------*/ free(generic_event_ptr); ret_stat = HBA_STATUS_OK; /* Not yet implmented */ ret_stat = HBA_STATUS_ERROR_NOT_SUPPORTED; } return ret_stat; } /* Optional */ static HBA_STATUS VMS_RegisterForAdapterEvents( void (* callback)( void *data, HBA_WWN portWWN, HBA_UINT32 eventType), void *userData, HBA_HANDLE handle, HBA_CALLBACKHANDLE *callbackHandle) { HBA_STATUS ret_stat; VMS_ADAPTER_INFO * vms_hba_attr; ADAPTER_EVENT * adapter_event_ptr; vms_check_null_arg(callback); vms_check_null_arg(callbackHandle); ret_stat = HBA_STATUS_ERROR_INVALID_HANDLE; /* Sanity check */ /*--------------*/ vms_hba_attr = get_vms_adapter_attributes(handle); if (vms_hba_attr != NULL) { adapter_event_ptr = malloc(sizeof(ADAPTER_EVENT)); if (adapter_event_ptr != NULL) { adapter_event_ptr->data = userData; adapter_event_ptr->eventType = HBA_EVENT_ADAPTER_UNKNOWN; memset(&adapter_event_ptr->portWWN, 0, sizeof(HBA_WWN)); __PAL_INSQUEL(event_list_head.flink, &adapter_event_ptr->link); /* The forward link is the call back handle */ /*------------------------------------------*/ *callbackHandle = (HBA_CALLBACKHANDLE)&adapter_event_ptr->link; /* Do QIO to start the AST */ /*-------------------------*/ /* Implementation note, these notification events need to * persist after the HBA handle has been closed, so they * must use their own channel and their own private copies * of any information from the adapter */ ret_stat = HBA_STATUS_OK; /* Not yet implmented */ ret_stat = HBA_STATUS_ERROR_NOT_SUPPORTED; } } return ret_stat; } /* Optional */ static HBA_STATUS VMS_RegisterForAdapterAddEvents (void (* callback)(void * data, HBA_WWN portwwn, HBA_UINT32 eventType), void * userData, HBA_CALLBACKHANDLE * callbackHandle) { HBA_STATUS ret_stat; VMS_ADAPTER_INFO * vms_hba_attr; ADAPTER_EVENT * adapter_event_ptr; vms_check_null_arg(callback); vms_check_null_arg(callbackHandle); adapter_event_ptr = malloc(sizeof(ADAPTER_EVENT)); if (adapter_event_ptr != NULL) { adapter_event_ptr->data = userData; adapter_event_ptr->eventType = HBA_EVENT_ADAPTER_UNKNOWN; memset(&adapter_event_ptr->portWWN, 0, sizeof(HBA_WWN)); __PAL_INSQUEL(event_list_head.flink, &adapter_event_ptr->link); /* The forward link is the call back handle */ /*------------------------------------------*/ *callbackHandle = (HBA_CALLBACKHANDLE)&adapter_event_ptr->link; /* Do QIO to start the AST */ /*-------------------------*/ ret_stat = HBA_STATUS_OK; /* Implementation note, these notification events need to * persist after the HBA handle has been closed, so they * must use their own channel and their own private copies * of any information from the adapter */ /* Not yet implmented */ ret_stat = HBA_STATUS_ERROR_NOT_SUPPORTED; } return ret_stat; } /* Management - Manditory */ static HBA_STATUS VMS_RegisterForAdapterPortEvents (void (* callback) (void * data, HBA_WWN portwwn, HBA_UINT32 eventType, HBA_UINT32 fabricPortID), void * userData, HBA_HANDLE handle, HBA_WWN portWWN, HBA_CALLBACKHANDLE * callbackHandle) { HBA_STATUS ret_stat; VMS_ADAPTER_INFO * vms_hba_attr; #if 0 vms_check_null_arg(callback); vms_check_null_arg(userData); vms_check_null_arg(callbackHandle); ret_stat = HBA_STATUS_ERROR_INVALID_HANDLE; /* Sanity check */ /*--------------*/ vms_hba_attr = get_vms_adapter_attributes(handle); if (vms_hba_attr != NULL) { /* Implementation note, these notification events need to * persist after the HBA handle has been closed, so they * must use their own channel and their own private copies * of any information from the adapter */ #endif ret_stat = HBA_STATUS_ERROR_NOT_SUPPORTED; #if 0 } #endif return ret_stat; } /* Optional */ static HBA_STATUS VMS_RegisterForAdapterPortStatEvents (void (* callback)(void * data, HBA_WWN portwwn, HBA_UINT32 eventType), void * userData, HBA_HANDLE handle, HBA_WWN portWWN, HBA_PORTSTATISTICS stats, HBA_UINT32 statType, HBA_CALLBACKHANDLE * callbackHandle) { HBA_STATUS ret_stat; VMS_ADAPTER_INFO * vms_hba_attr; #if 0 vms_check_null_arg(callback); vms_check_null_arg(userData); vms_check_null_arg(callbackHandle); ret_stat = HBA_STATUS_ERROR_INVALID_HANDLE; /* Sanity check */ /*--------------*/ vms_hba_attr = get_vms_adapter_attributes(handle); if (vms_hba_attr != NULL) { /* Implementation note, these notification events need to * persist after the HBA handle has been closed, so they * must use their own channel and their own private copies * of any information from the adapter */ #endif ret_stat = HBA_STATUS_ERROR_NOT_SUPPORTED; #if 0 } #endif return ret_stat; } /* Optional */ static HBA_STATUS VMS_RegisterForTargetEvents (void (* callback) (void * data, HBA_WWN hbaPortWWN, HBA_WWN discoveredPortWWN, HBA_UINT32 eventType), void * userData, HBA_HANDLE handle, HBA_WWN hbaPortWWN, HBA_WWN discoveredPortWWN, HBA_CALLBACKHANDLE * callbackHandle, HBA_UINT32 foo5) { HBA_STATUS ret_stat; VMS_ADAPTER_INFO * vms_hba_attr; #if 0 vms_check_null_arg(callback); vms_check_null_arg(userData); vms_check_null_arg(callbackHandle); ret_stat = HBA_STATUS_ERROR_INVALID_HANDLE; /* Sanity check */ /*--------------*/ vms_hba_attr = get_vms_adapter_attributes(handle); if (vms_hba_attr != NULL) { /* Implementation note, these notification events need to * persist after the HBA handle has been closed, so they * must use their own channel and their own private copies * of any information from the adapter */ #endif ret_stat = HBA_STATUS_ERROR_NOT_SUPPORTED; #if 0 } #endif return ret_stat; } /* Management - Manditory */ static HBA_STATUS VMS_RegisterForLinkEvents (void (* function) (void * data, HBA_WWN adapterWWN, HBA_UINT32 eventType, void *pRLIRBuffer, HBA_UINT32 RLIRBufferSize), void * userData, void * pRLIRBuffer, HBA_UINT32 RLIRBufferSize, HBA_HANDLE handle, HBA_CALLBACKHANDLE * callbackHandle) { HBA_STATUS ret_stat; VMS_ADAPTER_INFO * vms_hba_attr; LINK_EVENT * link_event_ptr; vms_check_null_arg(function); vms_check_null_arg(callbackHandle); if (RLIRBufferSize != 0) { vms_check_null_arg(pRLIRBuffer); } ret_stat = HBA_STATUS_ERROR_INVALID_HANDLE; /* Sanity check */ /*--------------*/ vms_hba_attr = get_vms_adapter_attributes(handle); if (vms_hba_attr != NULL) { link_event_ptr = malloc(sizeof(LINK_EVENT)); if (link_event_ptr != NULL) { link_event_ptr->data = userData; link_event_ptr->pRLIRBuffer = pRLIRBuffer; link_event_ptr->RLIRBufferSize = RLIRBufferSize; link_event_ptr->eventType = HBA_EVENT_LINK_UNKNOWN; memcpy(&link_event_ptr->adapterWWN, &vms_hba_attr->nodewwn, sizeof(HBA_WWN)); __PAL_INSQUEL(event_list_head.flink, &link_event_ptr->link); /* The forward link is the call back handle */ /*------------------------------------------*/ *callbackHandle = (HBA_CALLBACKHANDLE)&link_event_ptr->link; /* Do QIO to start the AST */ /*-------------------------*/ /* Implementation note, these notification events need to * persist after the HBA handle has been closed, so they * must use their own channel and their own private copies * of any information from the adapter */ ret_stat = HBA_STATUS_OK; /* Not yet implmented */ ret_stat = HBA_STATUS_ERROR_NOT_SUPPORTED; } } return ret_stat; } /* Management - Manditory */ static HBA_STATUS VMS_SendRLS (HBA_HANDLE handle, HBA_WWN hbaPortWWN, HBA_WWN destWWN, void * pRspBuffer, HBA_UINT32 * pRspBufferSize) { HBA_STATUS ret_stat; VMS_ADAPTER_INFO * vms_hba_attr; vms_check_null_arg(pRspBufferSize); if (*pRspBufferSize != 0) { vms_check_null_arg(pRspBuffer); } ret_stat = HBA_STATUS_ERROR_INVALID_HANDLE; /* Sanity check */ /*--------------*/ vms_hba_attr = get_vms_adapter_attributes(handle); if (vms_hba_attr != NULL) { ret_stat = HBA_STATUS_ERROR_NOT_SUPPORTED; } return ret_stat; } /* Management - Manditory */ static HBA_STATUS VMS_SendRPL (HBA_HANDLE handle, HBA_WWN hbaPortWWN, HBA_WWN agent_wwn, HBA_UINT32 agent_domain, HBA_UINT32 portindex, void * pRspBuffer, HBA_UINT32 * pRspBufferSize) { HBA_STATUS ret_stat; VMS_ADAPTER_INFO * vms_hba_attr; vms_check_null_arg(pRspBufferSize); if (*pRspBufferSize != 0) { vms_check_null_arg(pRspBuffer); } ret_stat = HBA_STATUS_ERROR_INVALID_HANDLE; /* Sanity check */ /*--------------*/ vms_hba_attr = get_vms_adapter_attributes(handle); if (vms_hba_attr != NULL) { ret_stat = HBA_STATUS_ERROR_NOT_SUPPORTED; } return ret_stat; } /* Management - Manditory */ static HBA_STATUS VMS_SendRPS (HBA_HANDLE handle, HBA_WWN hbaPortWWN, HBA_WWN agent_wwn, HBA_UINT32 agent_domain, HBA_WWN object_wwn, HBA_UINT32 object_port_number, void * pRspBuffer, HBA_UINT32 * pRspBufferSize) { HBA_STATUS ret_stat; VMS_ADAPTER_INFO * vms_hba_attr; vms_check_null_arg(pRspBufferSize); if (*pRspBufferSize != 0) { vms_check_null_arg(pRspBuffer); } ret_stat = HBA_STATUS_ERROR_INVALID_HANDLE; /* Sanity check */ /*--------------*/ vms_hba_attr = get_vms_adapter_attributes(handle); if (vms_hba_attr != NULL) { ret_stat = HBA_STATUS_ERROR_NOT_SUPPORTED; } return ret_stat; } /* Management - Manditory */ static HBA_STATUS VMS_SendSRL (HBA_HANDLE handle, HBA_WWN hbaPortWWN, HBA_WWN wwn, HBA_UINT32 domain, void * pRspBuffer, HBA_UINT32 * pRspBufferSize) { HBA_STATUS ret_stat; VMS_ADAPTER_INFO * vms_hba_attr; vms_check_null_arg(pRspBufferSize); if (*pRspBufferSize != 0) { vms_check_null_arg(pRspBuffer); } ret_stat = HBA_STATUS_ERROR_INVALID_HANDLE; /* Sanity check */ /*--------------*/ vms_hba_attr = get_vms_adapter_attributes(handle); if (vms_hba_attr != NULL) { ret_stat = HBA_STATUS_ERROR_NOT_SUPPORTED; } return ret_stat; } /* Management - Manditory */ static HBA_STATUS VMS_SendLIRR (HBA_HANDLE handle, HBA_WWN sourceWWN, HBA_WWN destWWN, HBA_UINT8 function, HBA_UINT8 type, void * pRspBuffer, HBA_UINT32 * pRspBufferSize) { HBA_STATUS ret_stat; VMS_ADAPTER_INFO * vms_hba_attr; vms_check_null_arg(pRspBufferSize); if (*pRspBufferSize != 0) { vms_check_null_arg(pRspBuffer); } ret_stat = HBA_STATUS_ERROR_INVALID_HANDLE; /* Sanity check */ /*--------------*/ vms_hba_attr = get_vms_adapter_attributes(handle); if (vms_hba_attr != NULL) { ret_stat = HBA_STATUS_ERROR_NOT_SUPPORTED; } return ret_stat; } /* Optional */ static HBA_STATUS VMS_GetFC4Statistics (HBA_HANDLE handle, HBA_WWN Portwwn, HBA_UINT8 FCRtype, HBA_FC4STATISTICS * pstatistics) { HBA_STATUS ret_stat; VMS_ADAPTER_INFO * vms_hba_attr; vms_check_null_arg(pstatistics); ret_stat = HBA_STATUS_ERROR_INVALID_HANDLE; /* Sanity check */ /*--------------*/ vms_hba_attr = get_vms_adapter_attributes(handle); if (vms_hba_attr != NULL) { VMS_FCP_PORT_INFO * fcp_ptr; ret_stat = HBA_STATUS_ERROR_ILLEGAL_WWN; fcp_ptr = vms_hba_attr->port_flink; /* Look for the port wwn */ /*-----------------------*/ while (fcp_ptr != (VMS_FCP_PORT_INFO *)&vms_hba_attr->port_flink) { int test_val = memcmp(&fcp_ptr->portwwn, &Portwwn, sizeof(HBA_WWN)); if (test_val == 0) { int i; unsigned short chan; /* Get the data */ /*--------------*/ i = handle - 1; chan = vms_open_adapter_data[i].chan; /* Optional */ pstatistics->InputRequests = -1; pstatistics->OutputRequests = -1; pstatistics->ControlRequests = -1; pstatistics->InputMegabytes = -1; pstatistics->OutputMegabytes = 1; ret_stat = HBA_STATUS_OK; break; } fcp_ptr = fcp_ptr->port_flink; } /* Not yet implmented */ ret_stat = HBA_STATUS_ERROR_NOT_SUPPORTED; } return ret_stat; } /* Optional */ static HBA_STATUS VMS_GetFCPStatistics (HBA_HANDLE handle, const HBA_SCSIID * lunit, HBA_FC4STATISTICS * pstatistics) { HBA_STATUS ret_stat; VMS_ADAPTER_INFO * vms_hba_attr; vms_check_null_arg(lunit); vms_check_null_arg(pstatistics); ret_stat = HBA_STATUS_ERROR_INVALID_HANDLE; /* Sanity check */ /*--------------*/ vms_hba_attr = get_vms_adapter_attributes(handle); if (vms_hba_attr != NULL) { ret_stat = HBA_STATUS_ERROR_NOT_SUPPORTED; } return ret_stat; } /* Free up all resources any call to this library allocated */ /* Manditory */ static HBA_STATUS VMS_FreeLibrary(void) { int i; i = vms_open_adapter_count; /* Make sure all channels are closed and all memory freed. */ /*---------------------------------------------------------*/ while (i > 0) { VMS_FCP_PORT_INFO * fcp_ptr; int status; VMS_ADAPTER_INFO * vms_hba_attr; /* Free up the port information */ /*------------------------------*/ vms_hba_attr = get_vms_adapter_attributes(i); status = __PAL_REMQUEL_D ((void **)&vms_hba_attr->port_flink,(void **)&fcp_ptr); while (status >= 0) { int status2; free(fcp_ptr); status = __PAL_REMQUEL_D ((void **)&vms_hba_attr->port_flink, (void **)&fcp_ptr); } /* Free up static information */ /*----------------------------*/ if (vms_open_adapter_data[i].hba_attr != NULL) free(vms_open_adapter_data[i].hba_attr); VMS_CloseAdapter(i); i--; } vms_open_adapter_count = 0; if (vms_library_loaded != 0) { /* Must deregister any callbacks */ /*-------------------------------*/ while (event_list_head.flink != &event_list_head) { HBA_STATUS status; status = VMS_RemoveCallback ((HBA_CALLBACKHANDLE)event_list_head.flink); } vms_library_loaded = 0; return HBA_STATUS_OK; } else return HBA_STATUS_ERROR_NOT_LOADED; } /* * Rev1 Code will call this function and only get the Rev1 registration. * This prevents overrunning the data structure. */ /* Manditory */ HBA_STATUS HBA_RegisterLibrary(HBA_ENTRYPOINTS *entrypoints) { vms_check_null_arg(entrypoints); entrypoints->GetVersionHandler = VMS_GetVersion; entrypoints->LoadLibraryHandler = VMS_LoadLibrary; entrypoints->FreeLibraryHandler = VMS_FreeLibrary; entrypoints->GetNumberOfAdaptersHandler = VMS_GetNumberOfAdapters; entrypoints->GetAdapterNameHandler = VMS_GetAdapterName; entrypoints->OpenAdapterHandler = VMS_OpenAdapter; entrypoints->CloseAdapterHandler = VMS_CloseAdapter; entrypoints->GetAdapterAttributesHandler = VMS_GetAdapterAttributes; entrypoints->GetAdapterPortAttributesHandler = VMS_GetAdapterPortAttributes; entrypoints->GetPortStatisticsHandler = VMS_GetPortStatistics; entrypoints->GetDiscoveredPortAttributesHandler = VMS_GetDiscoveredPortAttrs; entrypoints->GetPortAttributesByWWNHandler = VMS_GetPortAttributesByWWN; entrypoints->SendCTPassThruHandler = VMS_SendCTPassThru; entrypoints->RefreshInformationHandler = VMS_RefreshInformation; entrypoints->ResetStatisticsHandler = VMS_ResetStatistics; entrypoints->GetFcpTargetMappingHandler = VMS_GetFcpTargetMapping; entrypoints->GetFcpPersistentBindingHandler = VMS_GetFcpPersistentBinding; entrypoints->GetEventBufferHandler = VMS_GetEventBuffer; entrypoints->SetRNIDMgmtInfoHandler = VMS_SetRNIDMgmtInfo; entrypoints->GetRNIDMgmtInfoHandler = VMS_GetRNIDMgmtInfo; entrypoints->SendRNIDHandler = VMS_SendRNID; entrypoints->ScsiInquiryHandler = VMS_ScsiInquiry; entrypoints->ReportLUNsHandler = VMS_ReportLUNs; entrypoints->ReadCapacityHandler = VMS_ReadCapacity; return HBA_STATUS_OK; } /* * Here is were Rev2 callers will try first (all done by the wrapper library), * If the machine has not Rev2 vendor library, then obviosly, this function * will not be found. */ /* Manditory */ HBA_STATUS HBA_RegisterLibraryV2(HBA_ENTRYPOINTSV2 *entrypoints) { vms_check_null_arg(entrypoints); /* have the old function do the Rev1 part */ (void) HBA_RegisterLibrary((HBA_ENTRYPOINTS *)entrypoints); entrypoints->OpenAdapterByWWNHandler = VMS_OpenAdapterByWWN; entrypoints->GetFcpTargetMappingV2Handler = VMS_GetFcpTargetMappingV2; #if 0 entrypoints->SendCTPassThruV2Handler = VMS_SendCTPassThruV2; #endif entrypoints->RefreshAdapterConfigurationHandler = VMS_RefreshAdapterConfiguration; entrypoints->GetBindingCapabilityHandler = VMS_GetBindingCapability; entrypoints->GetBindingSupportHandler = VMS_GetBindingSupport; entrypoints->SetBindingSupportHandler = VMS_SetBindingSupport; entrypoints->SetPersistentBindingV2Handler = VMS_SetPersistentBindingV2; entrypoints->GetPersistentBindingV2Handler = VMS_GetPersistentBindingV2; entrypoints->RemovePersistentBindingHandler = VMS_RemovePersistentBinding; entrypoints->RemoveAllPersistentBindingsHandler = VMS_RemoveAllPersistentBindings; entrypoints->SendRNIDV2Handler = VMS_SendRNIDV2; entrypoints->ScsiInquiryV2Handler = VMS_ScsiInquiryV2; entrypoints->ScsiReportLUNsV2Handler = VMS_ScsiReportLUNsV2; entrypoints->ScsiReadCapacityV2Handler = VMS_ScsiReadCapacityV2; entrypoints->GetVendorLibraryAttributesHandler = VMS_GetVendorLibraryAttributes; #if 0 entrypoints->RemoveCallbackHandler = VMS_RemoveCallback; #endif entrypoints->RegisterForAdapterAddEventsHandler = VMS_RegisterForAdapterAddEvents; entrypoints->RegisterForAdapterEventsHandler = VMS_RegisterForAdapterEvents; entrypoints->RegisterForAdapterPortEventsHandler = VMS_RegisterForAdapterPortEvents; entrypoints->RegisterForAdapterPortStatEventsHandler = VMS_RegisterForAdapterPortStatEvents; entrypoints->RegisterForTargetEventsHandler = VMS_RegisterForTargetEvents; entrypoints->RegisterForLinkEventsHandler = VMS_RegisterForLinkEvents; entrypoints->SendRPLHandler = VMS_SendRPL; entrypoints->SendRPSHandler = VMS_SendRPS; entrypoints->SendSRLHandler = VMS_SendSRL; entrypoints->SendLIRRHandler = VMS_SendLIRR; entrypoints->GetFC4StatisticsHandler = VMS_GetFC4Statistics; entrypoints->GetFCPStatisticsHandler = VMS_GetFCPStatistics; entrypoints->SendRLSHandler = VMS_SendRLS; entrypoints->GetSBTargetMappingHandler = VMS_GetSBTargetMapping; entrypoints->GetSBStatisticsHandler = VMS_GetSBStatistics; entrypoints->SBDskGetCapacityHandler = VMS_SBDskGetCapacity; return HBA_STATUS_OK; }