diff options
Diffstat (limited to 'usr/src/uts/common/io/i2o/i2o_scsi.c')
-rw-r--r-- | usr/src/uts/common/io/i2o/i2o_scsi.c | 4440 |
1 files changed, 0 insertions, 4440 deletions
diff --git a/usr/src/uts/common/io/i2o/i2o_scsi.c b/usr/src/uts/common/io/i2o/i2o_scsi.c deleted file mode 100644 index b880390574..0000000000 --- a/usr/src/uts/common/io/i2o/i2o_scsi.c +++ /dev/null @@ -1,4440 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - - -/* - * I2O SCSI HBA OSM - * - * I2O Scsi Host Bus Adapter Operating System Module (OSM) - * conforms to I2O and converts SCSI pkt information send by - * the target driver through SCSA to I2O message format and send it - * down to the IOP. This driver utilized the I2O messaging framework, - * i2o_msg. Currently only support on x86. - * - */ - -/* - * debugging code - */ -#ifdef DEBUG -#define I2OHBA_DEBUG -#endif - -#ifdef I2OHBA_DEBUG -int i2ohbadebugflag = 0; -int ddi_dma_alloc_hdl = 0; -int ddi_dma_alloc_mem = 0; -int ddi_dma_bind_hdl = 0; -int ddi_dma_unbind = 0; -int ddi_dma_free_mem = 0; -int ddi_dma_bind_free = 0; -int ddi_dma_bufalloc = 0; -int ddi_dma_buf_bind = 0; -int ddi_dma_buf_unbind = 0; -int ddi_dma_buf_free_hdl = 0; -#define DEBUGF(level, args) \ - { if (i2ohbadebugflag >= (level)) cmn_err args; } -#else -#define DEBUGF(leve, args) /* nothing */ -#endif - -#include <sys/types.h> -#include <sys/conf.h> -#include <sys/varargs.h> -#include <sys/modctl.h> -#include <sys/scsi/scsi.h> -#include <sys/scsi/scsi_ctl.h> -#include <sys/scsi/impl/scsi_reset_notify.h> - -#include <sys/i2o/i2obscsi.h> -#include <sys/i2o/i2oadptr.h> -#include <sys/i2o/i2omsg.h> -#include <sys/i2o/i2outil.h> - -#include "i2o_scsi_var.h" -#include "i2o_scsi_util.h" -#include "i2o_scsi_cmd.h" - -/* - * dev_ops functions prototypes - */ -static int i2ohba_info(dev_info_t *dip, ddi_info_cmd_t infocmd, - void *arg, void **result); -static int i2ohba_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); -static int i2ohba_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); - -/* - * Function prototypes - * - * SCSA functions exported by means of the transport table - */ -static int i2ohba_tran_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip, - scsi_hba_tran_t *tran, struct scsi_device *sd); -static int i2ohba_scsi_start(struct scsi_address *ap, struct scsi_pkt *pkt); -static int i2ohba_scsi_abort(struct scsi_address *ap, struct scsi_pkt *pkt); -static int i2ohba_scsi_reset(struct scsi_address *ap, int level); -static int i2ohba_scsi_getcap(struct scsi_address *ap, char *cap, int whom); -static int i2ohba_scsi_setcap(struct scsi_address *ap, char *cap, int value, - int whom); -static struct scsi_pkt *i2ohba_scsi_init_pkt(struct scsi_address *ap, - struct scsi_pkt *pkt, struct buf *bp, int cmdlen, int statuslen, - int tgtlen, int flags, int (*callback)(), caddr_t arg); -static void i2ohba_scsi_destroy_pkt(struct scsi_address *ap, - struct scsi_pkt *pkt); -static void i2ohba_scsi_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pkt); -static void i2ohba_scsi_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt); -static int i2ohba_scsi_reset_notify(struct scsi_address *ap, int flag, - void (*callback)(caddr_t), caddr_t arg); - -/* - * i2ohba's complete function for sending the SCSI pkt. - */ -static void i2ohba_callback(i2o_message_frame_t *msg, ddi_acc_handle_t - acc_handle); - - -/* - * Internal Functions - */ -/* tid map to scsi convertion function */ -static int i2ohba_i_tid_to_scsi(dev_info_t *dip, struct i2ohba *i2ohba, - i2o_lct_t *lct_buf, size_t lct_real_size, - ddi_acc_handle_t lctbuf_dmaacchandle); - -/* capability/prop functions */ -static void i2ohba_i_updatesync(struct i2ohba *i2ohba, int tgt); -static void i2ohba_i_update_props(struct i2ohba *i2ohba, int tgt); -static void i2ohba_i_update_this_prop(struct i2ohba *i2ohba, char *property, - int value); -static void i2ohba_i_initcap(struct i2ohba *i2ohba); - -/* dma engine funcitons */ -static int i2ohba_i_dma_alloc(struct i2ohba *i2ohba, struct scsi_pkt *pkt, - struct buf *bp, int flags, int (*callback)()); -static int i2ohba_i_dma_move(struct i2ohba *i2ohba, struct scsi_pkt *pkt, - struct buf *bp); - -/* timer and recovery functions */ -static void i2ohba_i_watch(void *); -static void i2ohba_i_fatal_error(struct i2ohba *i2ohba); -static int i2ohba_i_reset_interface(struct i2ohba *i2ohba, int action); -static int i2ohba_i_reset_abort(struct i2ohba *i2ohba, uint16_t tid, int action, - struct i2ohba_cmd *cmd); - -/* command processing functions */ -static void i2ohba_i_polled_cmd_start(struct i2ohba *i2ohba, - struct i2ohba_cmd *sp); -static void i2ohba_i_req_insert(struct i2ohba *i2ohba, struct i2ohba_cmd *sp); -static void i2ohba_i_req_remove(struct i2ohba *i2ohba, struct i2ohba_cmd *sp); -static void i2ohba_i_pkt_comp(i2o_single_reply_message_frame_t *reply, - ddi_acc_handle_t acc_handle, struct i2ohba_cmd *sp); -static void i2ohba_i_handle_arq(i2o_scsi_error_reply_message_frame_t *replyerr, - struct i2ohba_cmd *sp, int aqcount); -static void i2ohba_i_qflush(struct i2ohba *i2ohba, uint16_t start_tgt, - uint16_t end_tgt); -/*PRINTFLIKE3*/ -static void i2ohba_i_log(struct i2ohba *i2ohba, int level, char *fmt, ...); -static void i2ohba_i_print_state(struct i2ohba *i2ohba); - -/* utility parameter functions */ -static int i2ohba_utilparamset_msg(struct i2ohba *i2ohba, int tgt, - uint16_t tid, uint16_t group, uint16_t idx, uint16_t value); -static int i2ohba_utilparamget_msg(struct i2ohba *i2ohba, uint16_t tidx, - char flag); -static void i2ohba_utilmsg_comp(i2o_message_frame_t *msg, ddi_acc_handle_t - acc_handle); -static int i2ohba_utilclaim_msg(struct i2ohba *i2ohba, uint16_t tid, - int action); - -/* - * mutex for protecting variables shared by all instances of the driver - */ -static kmutex_t i2ohba_log_mutex; - -/* - * Local static data - */ -static void *i2ohba_state = NULL; -static clock_t i2ohba_tick; /* watch interval in HZ */ -static clock_t i2ohba_watchdog_tick = 15; /* watch interval in sec */ -static int i2ohba_scsi_reset_delay = 3000; -ddi_device_acc_attr_t dev_attr; /* dev_attr */ -static char i2ohba_log_buf[256]; /* buffer used in i2ohba_i_log */ - - - -/* - * DMA Attribute for data buffers - */ -static ddi_dma_attr_t i2ohba_dma_attr = { - DMA_ATTR_VERSION, /* dma_attr_version */ - 0, /* dma_attr_addr_lo */ - 0xffffffffull, /* dma_attr_addr_hi */ - 0x00ffffffull, /* dma_attr_count_max */ - 1, /* dma_attr_align */ - 1, /* dma_attr_burstsizes */ - 1, /* dma_attr_minxfer */ - 0xffffffffull, /* dma_attr_maxxfer */ - 0x00ffffffull, /* dma_attr_seg */ - I2OHBA_CMD_NSEGS, /* dma_attr_sgllen */ - 512, /* dma_attr_granular */ - 0 /* dma_attr_flags */ -}; - -/* - * DMA attributes for SGL buffer - */ -static ddi_dma_attr_t i2ohba_dmasgl_attr = { - DMA_ATTR_VERSION, /* dma_attr_version */ - 0, /* dma_attr_addr_lo */ - 0xffffffffull, /* dma_attr_addr_hi */ - 0x00ffffffull, /* dma_attr_count_max */ - 1, /* dma_attr_align */ - 1, /* dma_attr_burstsizes */ - 1, /* dma_attr_minxfer */ - 0xffffffffull, /* dma_attr_maxxfer */ - 0x00ffffffull, /* dma_attr_seg */ - 0x1, /* dma_attr_sgllen */ - 1, /* dma_attr_granular */ - 0 /* dma_attr_flags */ -}; - -/* - * Hotplug support - * Leaf ops (hotplug controls for target devices) - * XXXLWXXX currently doesn't support any hotpluging - */ - -static struct cb_ops i2ohba_cb_ops = { - nodev, /* open */ - nodev, /* close */ - nodev, /* strategy */ - nodev, /* print */ - nodev, /* dump */ - nodev, /* read */ - nodev, /* write */ - nodev, /* ioctl */ - nodev, /* devmap */ - nodev, /* mmap */ - nodev, /* segmap */ - nochpoll, /* poll */ - ddi_prop_op, /* prop_op */ - NULL, - D_NEW | D_MP | D_HOTPLUG -}; - -/* - * autoconfiguration routines. - */ - -static struct dev_ops i2ohba_ops = { - DEVO_REV, /* rev, */ - 0, /* refcnt */ - i2ohba_info, /* getinfo */ - nulldev, /* identify */ - nulldev, /* probe */ - i2ohba_attach, /* attach */ - i2ohba_detach, /* detach */ - nodev, /* reset */ - &i2ohba_cb_ops, /* driver operations */ - NULL, /* bus ops */ - NULL /* power ops */ -}; - -char _depends_on[] = "misc/scsi misc/i2o_msg"; - -static struct modldrv modldrv = { - &mod_driverops, /* Type of module */ - "I2O SCSI HBA OSM version %I%", /* module name */ - &i2ohba_ops, /* driver ops */ - -}; - -static struct modlinkage modlinkage = { - MODREV_1, - (void *)&modldrv, - NULL -}; - -int -_init(void) -{ - int ret; - - ret = ddi_soft_state_init(&i2ohba_state, sizeof (struct i2ohba), - I2OHBA_INITIAL_SOFT_SPACE); - - if (ret != 0) - return (ret); - - mutex_init(&i2ohba_log_mutex, NULL, MUTEX_DRIVER, NULL); - - i2ohba_tick = drv_usectohz(i2ohba_watchdog_tick * 1000000); - - if ((ret = scsi_hba_init(&modlinkage)) != 0) { - mutex_destroy(&i2ohba_log_mutex); - ddi_soft_state_fini(&i2ohba_state); - return (ret); - } - - if ((ret = mod_install(&modlinkage)) != 0) { - scsi_hba_fini(&modlinkage); - mutex_destroy(&i2ohba_log_mutex); - ddi_soft_state_fini(&i2ohba_state); - } - - return (ret); -} - -int -_info(struct modinfo *modinfop) -{ - return (mod_info(&modlinkage, modinfop)); -} - -int -_fini(void) -{ - - int ret; - - if ((ret = mod_remove(&modlinkage)) != 0) - return (ret); - - scsi_hba_fini(&modlinkage); - - mutex_destroy(&i2ohba_log_mutex); - ddi_soft_state_fini(&i2ohba_state); - - return (ret); -} - -/* - * Given the device number return the devinfo pointer - * from the scsi_device structure. - */ -/*ARGSUSED*/ -static int -i2ohba_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) -{ - return (DDI_FAILURE); -} - - -/* - * Attach an instance of an i2o hba OSM module. Allocate data structures, - * initialize the OSM and send commands to IOP to bring I2O on line. - */ -/*ARGSUSED*/ -static int -i2ohba_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) -{ - scsi_hba_tran_t *tran = NULL; - char prop_str[32]; - int i, id, tid2scsi; - int freecount = 0; - int ishdlalloc = 0; - struct i2ohba *i2ohba; - int instance; - size_t lct_size, lct_real_size, lct_rlen; - i2o_lct_t *lct_buf; - ddi_dma_handle_t lctbuf_dmahandle; - ddi_acc_handle_t lctbuf_dmaacchandle; - - instance = ddi_get_instance(dip); - - switch (cmd) { - case DDI_ATTACH: - dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; - dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; - /* currently for x86 PCI, we'll use little endian */ - dev_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; - break; - - /* XXXLWXXX will work on it more */ - case DDI_RESUME: - case DDI_PM_RESUME: - - default: - i2ohba_i_log(NULL, CE_WARN, "?i2ohba_attach%d: " - "cmd != DDI_ATTACH", instance); - return (DDI_FAILURE); - } - - /* - * I2O comes in at intr level 5 - */ - if (ddi_intr_hilevel(dip, 0) != 0) { - i2ohba_i_log(NULL, CE_WARN, "?i2ohba_attach%d: high-level " - "interrupt not supported", instance); - return (DDI_FAILURE); - } - - /* - * Allocate i2ohba data structure. - */ - if (ddi_soft_state_zalloc(i2ohba_state, instance) != DDI_SUCCESS) { - i2ohba_i_log(NULL, CE_WARN, "?i2ohba%d: Failed to alloc" - " soft state", instance); - return (DDI_FAILURE); - } - - i2ohba = ddi_get_soft_state(i2ohba_state, instance); - - if (i2ohba == (struct i2ohba *)NULL) { - i2ohba_i_log(NULL, CE_WARN, "?i2ohba%d: Bad soft state", - instance); - ddi_soft_state_free(i2ohba_state, instance); - return (DDI_FAILURE); - } - - /* - * save the dip info - */ - i2ohba->i2ohba_dip = dip; - - /* - * register OSM with message layer - */ - if (i2o_msg_osm_register(dip, &i2ohba->i2ohba_iophdl) - != DDI_SUCCESS) { - i2ohba_i_log(NULL, CE_WARN, "?i2ohba%d: Registeration Fail " - "with IOP", instance); - goto cleanup; - } - - /* - * get the LCT from iop - */ - if (i2o_msg_get_lct(i2ohba->i2ohba_iophdl, NULL, NULL, - &lct_size, NULL) != DDI_SUCCESS) { - i2ohba_i_log(NULL, CE_WARN, "?i2ohba%d: Can't get LCT SIZE " - "info from IOP", instance); - goto cleanup; - } - -retry: - /* - * first get the size from IOP, then - * DMA Allocate it. - */ - if (lct_size) { - if (!ishdlalloc) { - if (ddi_dma_alloc_handle(dip, &i2ohba_dmasgl_attr, - DDI_DMA_SLEEP, NULL, &lctbuf_dmahandle) != - DDI_SUCCESS) - goto cleanup; - } - ishdlalloc = 1; -#ifdef I2OHBA_DEBUG - ddi_dma_alloc_hdl++; -#endif - if (ddi_dma_mem_alloc(lctbuf_dmahandle, (size_t) - lct_size, &dev_attr, DDI_DMA_STREAMING, - DDI_DMA_SLEEP, NULL, (caddr_t *)&lct_buf, &lct_rlen, - &lctbuf_dmaacchandle) != DDI_SUCCESS) - goto cleanup; -#ifdef I2OHBA_DEBUG - ddi_dma_alloc_mem++; -#endif - freecount = 1; - - } else { - i2ohba_i_log(NULL, CE_WARN, "?i2ohba%d: Invalid LCT size", - instance); - goto cleanup; - } - - /* - * with the right size buffer, now get the table - */ - if (i2o_msg_get_lct(i2ohba->i2ohba_iophdl, lct_buf, lct_size, - NULL, &lct_real_size) != DDI_SUCCESS) { - i2ohba_i_log(NULL, CE_WARN, "?i2ohba%d: Getting LCT table " - "info failed", instance); - goto cleanup; - } - - /* - * partial transfer - */ - if (lct_real_size > lct_size) { - ddi_dma_mem_free(&lctbuf_dmaacchandle); -#ifdef I2OHBA_DEBUG - ddi_dma_free_mem++; -#endif - lct_size = lct_real_size; - goto retry; - } - - /* - * Set up TID->SCSI info map, query all unclaimed SCSI devices - */ - if (tid2scsi = i2ohba_i_tid_to_scsi(dip, i2ohba, lct_buf, - lct_real_size, lctbuf_dmaacchandle)) { - i2ohba_i_log(NULL, CE_WARN, "?i2ohba%d: Setup TID to SCSI " - "info map failed", instance); - goto cleanup; - } - - /* free dma, may be XXLWXX we can keep it for later LCT update */ - freecount = 0; - ddi_dma_mem_free(&lctbuf_dmaacchandle); -#ifdef I2OHBA_DEBUG - ddi_dma_free_mem++; -#endif - ishdlalloc = 0; - ddi_dma_free_handle(&lctbuf_dmahandle); -#ifdef I2OHBA_DEBUG - ddi_dma_bind_free++; -#endif - - /* - * Allocate a transport structure - */ - tran = scsi_hba_tran_alloc(dip, SCSI_HBA_CANSLEEP); - - i2ohba->i2ohba_tran = tran; - i2ohba->i2ohba_dip = dip; - - tran->tran_hba_private = i2ohba; - tran->tran_tgt_private = NULL; - tran->tran_tgt_init = i2ohba_tran_tgt_init; - tran->tran_tgt_probe = (int (*)())scsi_hba_probe; - tran->tran_tgt_free = (void (*)())NULL; - - tran->tran_start = i2ohba_scsi_start; - tran->tran_abort = i2ohba_scsi_abort; - tran->tran_reset = i2ohba_scsi_reset; - tran->tran_getcap = i2ohba_scsi_getcap; - tran->tran_setcap = i2ohba_scsi_setcap; - tran->tran_init_pkt = i2ohba_scsi_init_pkt; - tran->tran_destroy_pkt = i2ohba_scsi_destroy_pkt; - tran->tran_dmafree = i2ohba_scsi_dmafree; - tran->tran_sync_pkt = i2ohba_scsi_sync_pkt; - tran->tran_reset_notify = i2ohba_scsi_reset_notify; - tran->tran_get_bus_addr = NULL; - tran->tran_get_name = NULL; - - - /* - * Attach this instance of the hba - */ - if (scsi_hba_attach_setup(dip, &i2ohba_dma_attr, tran, - 0) != DDI_SUCCESS) { - i2ohba_i_log(NULL, CE_WARN, "?scsi_hba_attach failed"); - goto cleanup; - } - - /* - * find scsi host id property - */ - id = ddi_getprop(DDI_DEV_T_ANY, dip, 0, - "scsi-initiator-id", -1); - if (id != scsi_host_id && - (id >= 0 && id < N_I2OHBA_TARGETS_WIDE)) { - i2ohba->i2ohba_initiator_id = (uint8_t)id; - } else { - i2ohba->i2ohba_initiator_id = (uint8_t)scsi_host_id; - } - - /* - * property: look up the scsi-options property - */ - i2ohba->i2ohba_scsi_options = - ddi_getprop(DDI_DEV_T_ANY, dip, 0, "scsi-options", - I2OHBA_DEFAULT_SCSI_OPTIONS); - - /* - * property: if target<n>-scsi-options property exists, use it; - * otherwise use the i2o_scsi_options - */ - for (i = 0; i < N_I2OHBA_TARGETS_WIDE; i++) { - (void) sprintf(prop_str, "target%x-scsi-options", i); - i2ohba->i2ohba_target_scsi_option[i] = ddi_getprop( - DDI_DEV_T_ANY, dip, 0, prop_str, - i2ohba->i2ohba_scsi_options); - - if (i2ohba->i2ohba_target_scsi_option[i] != - i2ohba->i2ohba_scsi_options) { - i2ohba_i_log(NULL, CE_CONT, - "?i2ohba:target%x-scsi-options=0x%x", - i, i2ohba->i2ohba_target_scsi_option[i]); - } - } - - - i2ohba->i2ohba_scsi_reset_delay = - ddi_getprop(DDI_DEV_T_ANY, dip, 0, "scsi-reset-delay", - i2ohba_scsi_reset_delay); - - if (i2ohba->i2ohba_scsi_reset_delay != i2ohba_scsi_reset_delay) { - i2ohba_i_log(NULL, CE_CONT, - "?i2ohba_scsi-reset-delay=%d", - i2ohba->i2ohba_scsi_reset_delay); - } - - - - /* - * set up watchdog for this i2o - */ - i2ohba->i2ohba_timeout_id = timeout(i2ohba_i_watch, (caddr_t)i2ohba, - i2ohba_tick); - - /* - * initialized I2OHBA request mutex and reset mutex - */ - mutex_init(I2OHBA_REQ_MUTEX(i2ohba), NULL, MUTEX_DRIVER, NULL); - mutex_init(I2OHBA_RESET_MUTEX(i2ohba), NULL, MUTEX_DRIVER, NULL); - cv_init(I2OHBA_RESET_CV(i2ohba), NULL, CV_DRIVER, NULL); - - I2OHBA_MUTEX_ENTER(i2ohba); - /* - * Initialize the default Target Capabilites and Sync Rates - */ - (void) i2ohba_i_initcap(i2ohba); - - /* - * reset i2ohba/bus and initialize capabilities - * if (i2ohba_i_reset_interface(i2ohba, I2OHBA_FORCE_BUS_RESET)) { - * goto cleanup; - * } - */ - I2OHBA_MUTEX_EXIT(i2ohba); - - ddi_report_dev(dip); - i2ohba->i2ohba_throttle = 0; - - DEBUGF(1, (CE_CONT, "i2ohba_attach%d: Succeeded", instance)); - - return (DDI_SUCCESS); - -cleanup: - DEBUGF(1, (CE_CONT, "?i2ohba_attach%d: Unable to attach", instance)); - - if (tid2scsi) { - i2o_tid_scsi_ent_t *map = i2ohba->i2ohba_tid_scsi_map; - - /* - * if tid_to_scsi has succeeded, then at least - * we have the HBA node claimed. - */ - (void) i2ohba_utilclaim_msg(i2ohba, i2ohba->i2ohba_tid, - I2O_UTIL_CLAIM_RELEASE); - - DEBUGF(1, (CE_CONT, "?Utilunclaim %d", i2ohba->i2ohba_tid)); - - for (i = 0; i < N_I2OHBA_TARGETS_WIDE; i++) { - if (map[i].tid != 0) - (void) i2ohba_utilclaim_msg(i2ohba, - map[i].tid, - I2O_UTIL_CLAIM_RELEASE); - } - - } - - if (freecount) { - ddi_dma_mem_free(&lctbuf_dmaacchandle); - } - if (ishdlalloc) { - ddi_dma_free_handle(&lctbuf_dmahandle); - } - - if (i2ohba->i2ohba_timeout_id != 0) { - i2ohba->i2ohba_shutdown = 1; - (void) untimeout(i2ohba->i2ohba_timeout_id); - i2ohba->i2ohba_timeout_id = 0; - } - - if (tran) { - scsi_hba_tran_free(tran); - } - - if (i2ohba->i2ohba_iophdl) - i2o_msg_osm_unregister(&i2ohba->i2ohba_iophdl); - - ddi_soft_state_free(i2ohba_state, instance); - - return (DDI_FAILURE); -} - -/* - * Function name: i2ohba_i_tid_to_scsi - * - * Return Values: -1 Failed - * 0 Success - * - * Description : Take in the LCT (logical configuration table), and - * parse it through to find the appropriated SCSI target - * devices that belongs to this HBA. Then send a - * I2O_UTIL_PARAM_GET message to the target device to - * to get its parameters, ie SCSI ID and build a - * tid-to-scsi.id map. - */ -/*ARGSUSED*/ -static int -i2ohba_i_tid_to_scsi(dev_info_t *dip, struct i2ohba *i2ohba, - i2o_lct_t *lct_buf, size_t lct_real_size, - ddi_acc_handle_t lctbuf_dmaacchandle) -{ - i2o_tid_scsi_ent_t *map = i2ohba->i2ohba_tid_scsi_map; - uint_t tablesize, actualtbl; - i2o_lct_entry_t *lctentptr; - int i, count, entries = 0, rval = -1; - - /* - * translating dev_addr field in the dev_info struct to TID - */ - - i2ohba->i2ohba_tid = ddi_getprop(DDI_DEV_T_ANY, dip, 0, - "i2o-device-id", -1); - - /* - * scan the table for SCSI bus/devices - */ - tablesize = ddi_get16(lctbuf_dmaacchandle, &lct_buf->TableSize); - - if (!tablesize) { - i2ohba_i_log(NULL, CE_WARN, "?i2o_i_tid_to_scsi: Invalid " - "tablesize"); - return (rval); - } - - /* - * lct table size in WORDS - */ - actualtbl = (tablesize << 2) - sizeof (i2o_lct_t) + - sizeof (i2o_lct_entry_t); - - actualtbl = actualtbl/sizeof (i2o_lct_entry_t); - - /* scan through the table */ - for (count = 0; count < actualtbl; count++) { - uint16_t userid, parentid = 0; - - lctentptr = &(lct_buf->LCTEntry[count]); - userid = get_lct_entry_UserTID(lctentptr, lctbuf_dmaacchandle); - parentid = get_lct_entry_ParentTID(lctentptr, - lctbuf_dmaacchandle); - - /* unclaim devices */ - if (userid == 0xFFF) { - int class; - uint16_t tid; - - class = get_lct_entry_Class(lctentptr, - lctbuf_dmaacchandle); - tid = get_lct_entry_LocalTID(lctentptr, - lctbuf_dmaacchandle); - - /* - * search for SCSI Peripheral with Parent ID - * as the same as hba's TID and unclaimed devices - */ - - if ((parentid == i2ohba->i2ohba_tid) && - (class == I2O_CLASS_SCSI_PERIPHERAL)) { - /* claim it */ - if (i2ohba_utilclaim_msg(i2ohba, tid, - I2O_UTIL_CLAIM)) { - i2ohba_i_log(NULL, CE_WARN, - "?i2ohba_i_tid_to_scsi: " - "i2ohba_utilclaim_msg failed"); - } else { - i2ohba_i_log(NULL, CE_CONT, - "?utilclaim:" - "Tid: 0x%x, SCSI_PERIPHERAL", tid); - /* claim succeed */ - map[entries].tid = tid; - entries++; - } - } - - /* - * find our own bus adapter port and - * claim it as well - */ - if ((tid == i2ohba->i2ohba_tid) && - (class == I2O_CLASS_BUS_ADAPTER_PORT)) { - if (i2ohba_utilclaim_msg(i2ohba, tid, - I2O_UTIL_CLAIM)) { - i2ohba_i_log(NULL, CE_WARN, - "?i2ohba_i_tid_to_scsi: " - "i2ohba_utilclaim_msg failed"); - /* - * it is pointless to continue here - * because if we can't claim the bus port - * then we can't do anything except for - * sending utilgetparm and busreset msgs - */ - break; - } else { - i2ohba_i_log(NULL, CE_CONT, - "?utilclaim:" - "Tid: 0x%x, BUS_ADAPTER_PORT", tid); - rval = 0; - } - } - - } /* userid == 0xFFF */ - } /* for loop */ - - /* - * initialized all utilparam message's mutex's - */ - for (i = 0; i < N_I2OHBA_TARGETS_WIDE; i++) { - mutex_init(I2OHBA_UTILPARAM_MUTEX(i2ohba, i), NULL, - MUTEX_DRIVER, NULL); - cv_init(I2OHBA_UTILPARAM_CV(i2ohba, i), NULL, - CV_DRIVER, NULL); - } - - /* - * Now allocated parameter for each qualified peripheral - */ - for (i = 0; i < entries; i++) { - /* - * call i2ohba_utilparamget_msg to get - * parameters - */ - rval = i2ohba_utilparamget_msg(i2ohba, i, ALL_UTILPARAMS); - if (rval) { - i2ohba_i_log(NULL, CE_WARN, "?i2ohba_i_tid_to_scsi:" - " i2ohba_utilparamget_msg failed"); - } - - } /* for loop */ - - if (i > 0) - rval = 0; - return (rval); - -} - -/* - * Function name: i2ohba_utilcliam_msg() - * - * Return Values: 0 - success - * -1 - fail to claim the device - * - * Description : send a utilclaim or utilclaim_release msg - * to the device - * - * This function is called from i2ohba_i_tid_to_scsi() - */ -static int -i2ohba_utilclaim_msg(struct i2ohba *i2ohba, uint16_t tid, int action) -{ - int rval = -1; - i2o_util_claim_message_t *msgptr; - i2o_msg_handle_t msg_handle; - ddi_acc_handle_t acc_handle; - struct i2ohba_util *sp; - - if (i2o_msg_alloc(i2ohba->i2ohba_iophdl, I2O_MSG_SLEEP, NULL, - (void *)&msgptr, &msg_handle, &acc_handle) != DDI_SUCCESS) { - i2ohba_i_log(NULL, CE_WARN, "?i2ohba_utilclaim_msg: " - "i2o_msg_alloc failed"); - return (rval); - } - - /* - * construct a i2o_hba_bus_reset_message - */ - msgptr->StdMessageFrame.VersionOffset = 0x01; - msgptr->StdMessageFrame.MsgFlags = 0; - ddi_put16(acc_handle, &msgptr->StdMessageFrame.MessageSize, - sizeof (i2o_util_claim_message_t) >> 2); - put_msg_TargetAddress(&msgptr->StdMessageFrame, tid, acc_handle); - put_msg_InitiatorAddress(&msgptr->StdMessageFrame, I2O_OSM_TID, - acc_handle); - put_msg_Function(&msgptr->StdMessageFrame, action, acc_handle); - ddi_put32(acc_handle, - (uint32_t *)&msgptr->StdMessageFrame.InitiatorContext, - (uint32_t)i2ohba_utilmsg_comp); - ddi_put8(acc_handle, &msgptr->ClaimType, I2O_CLAIM_TYPE_PRIMARY_USER); - - /* - * allocating synchronized status buffer - */ - sp = kmem_alloc(sizeof (struct i2ohba_util), KM_SLEEP); - - ddi_put32(acc_handle, &msgptr->TransactionContext, - (uint32_t)(uintptr_t)sp); - - /* - * initialized a mutex and cond variable to - * send message to IOP, and wait for it to signal back - */ - sp->mutex = I2OHBA_UTILPARAM_MUTEX(i2ohba, 0); - sp->cv = I2OHBA_UTILPARAM_CV(i2ohba, 0); - mutex_enter(sp->mutex); - sp->wakeup = UTIL_MSG_SLEEP; - sp->status = 0; - (void) i2o_msg_send(i2ohba->i2ohba_iophdl, msgptr, msg_handle); - while (!sp->wakeup) - cv_wait(sp->cv, sp->mutex); - mutex_exit(sp->mutex); - - /* - * process reply message - */ - - switch (sp->status) { - case I2O_REPLY_STATUS_SUCCESS: - rval = 0; - DEBUGF(1, (CE_CONT, "Reset Succeeded")); - break; - default: - i2ohba_i_log(NULL, CE_CONT, "Reset Failed"); - /* - * Failed the reset for now, - * we can also parse the AdapterStatus - * and retry if needed - */ - break; - } - -cleanup: - if (sp) - kmem_free(sp, sizeof (struct i2ohba_util)); - return (rval); -} - -/* - * i2ohba_utilmsg_comp - * passed the status back to the caller to decided - * what to do with the error code. - */ -/*ARGSUSED*/ -static void -i2ohba_utilmsg_comp(i2o_message_frame_t *msg, ddi_acc_handle_t acc_handle) -{ - - i2o_single_reply_message_frame_t *reply; - int type, reqstatus, detailstatus, adptrstatus; - struct i2ohba_util *sp; - - - reply = (i2o_single_reply_message_frame_t *)msg; - sp = (struct i2ohba_util *)(uintptr_t)ddi_get32(acc_handle, - &reply->TransactionContext); - - type = get_msg_Function(&reply->StdMessageFrame, acc_handle); - - switch (type) { - /* - * Bus Reset - */ - case I2O_HBA_BUS_RESET: - detailstatus = ddi_get16(acc_handle, - &reply->DetailedStatusCode); - adptrstatus = detailstatus & I2O_SCSI_HBA_DSC_MASK; - if (adptrstatus != I2O_HBA_DSC_BUS_RESET) - reqstatus = I2O_REPLY_STATUS_TRANSACTION_ERROR; - else - reqstatus = reply->ReqStatus; - break; - - /* - * Utility Class Function - */ - case I2O_UTIL_PARAMS_GET: - case I2O_UTIL_PARAMS_SET: - case I2O_UTIL_CLAIM: - case I2O_UTIL_CLAIM_RELEASE: - /* - * Adapter Class Function - */ - case I2O_HBA_ADAPTER_RESET: - case I2O_SCSI_DEVICE_RESET: - reqstatus = reply->ReqStatus; - break; - - default: - DEBUGF(2, (CE_CONT, "Error! Not Supported")); - return; - - } - - mutex_enter(sp->mutex); - sp->wakeup = UTIL_MSG_WAKEUP; - sp->status = reqstatus; - cv_broadcast(sp->cv); - mutex_exit(sp->mutex); -} - -/*ARGSUSED*/ -static int -i2ohba_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) -{ - - struct i2ohba *i2ohba; - scsi_hba_tran_t *tran; - int instance = ddi_get_instance(dip); - int i; - - switch (cmd) { - case DDI_DETACH: - { - if ((tran = ddi_get_driver_private(dip)) == NULL) - return (DDI_FAILURE); - - i2ohba = TRAN2I2OHBA(tran); - if (!i2ohba) { - return (DDI_FAILURE); - } - - if (i2ohba->i2ohba_iophdl) - i2o_msg_osm_unregister(&i2ohba->i2ohba_iophdl); - - /* - * deallocate reset notify callback list - */ - scsi_hba_reset_notify_tear_down( - i2ohba->i2ohba_reset_notify_listf); - - if (i2ohba->i2ohba_timeout_id != 0) { - (void) untimeout(i2ohba->i2ohba_timeout_id); - i2ohba->i2ohba_timeout_id = NULL; - } - - /* - * remove device MT locks - */ - mutex_destroy(I2OHBA_REQ_MUTEX(i2ohba)); - mutex_destroy(I2OHBA_RESET_MUTEX(i2ohba)); - cv_destroy(I2OHBA_RESET_CV(i2ohba)); - - for (i = 0; i < N_I2OHBA_TARGETS_WIDE; i++) { - - mutex_destroy(I2OHBA_UTILPARAM_MUTEX(i2ohba, i)); - cv_destroy(I2OHBA_UTILPARAM_CV(i2ohba, i)); - } - - /* - * remove properties created druing attach() - */ - ddi_prop_remove_all(dip); - - /* - * Delete the DMA limits, transport vectors and remove the - * device links to the scsi_transport layer. - * -- ddi_set_driver_private(dip, NULL) - */ - (void) scsi_hba_detach(dip); - - /* - * Free the scsi_transport structure for this device. - */ - scsi_hba_tran_free(tran); - - i2ohba->i2ohba_dip = (dev_info_t *)NULL; - i2ohba->i2ohba_tran = (scsi_hba_tran_t *)NULL; - - ddi_soft_state_free(i2ohba_state, instance); - ddi_remove_minor_node(dip, NULL); - - return (DDI_SUCCESS); - } - /* XXXLWXXX */ - case DDI_SUSPEND: - case DDI_PM_SUSPEND: - default: - return (DDI_FAILURE); - } -} - - -/* - * Function name : i2ohba_tran_tgt_init - * - * Return Values : DDI_SUCCESS if target supported, DDI_FAILURE otherwise - * - */ -/*ARGSUSED*/ -static int -i2ohba_tran_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip, - scsi_hba_tran_t *tran, struct scsi_device *sd) -{ - return ((sd->sd_address.a_target < N_I2OHBA_TARGETS_WIDE && - sd->sd_address.a_lun == 0) ? DDI_SUCCESS : - DDI_FAILURE); -} - - -/* - * Function name : i2ohba_i_initcap - * - * Return Values : NONE - * Description : Initializes the default target capabilites and - * Sync Rates. - * - * Context : Called from the user thread through attach. - * - */ -static void -i2ohba_i_initcap(struct i2ohba *i2ohba) -{ - int i, option; - uint16_t cap, synch; - uint8_t offset; - i2o_tid_scsi_ent_t **map = i2ohba->i2ohba_tgt_id_map; - - for (i = 0; i < N_I2OHBA_TARGETS_WIDE; i++) { - cap = 0; - synch = 0; - option = 0; - offset = 0; - - if (map[i] == NULL) - continue; - - /* - * Check for connect/disconnect - */ - if (map[i]->scsi_info_scalar.Flags & - I2O_SCSI_ENABLE_DISCONNECT) { - option |= SCSI_OPTIONS_DR; - cap |= I2OHBA_CAP_DISCONNECT; - } else { - option &= ~SCSI_OPTIONS_DR; - } - - /* - * Check for Wide data - */ - if (map[i]->scsi_info_scalar.Flags & - I2O_SCSI_DATA_WIDTH_MASK) { - option |= SCSI_OPTIONS_WIDE; - cap |= I2OHBA_CAP_WIDE; - } else { - option &= ~SCSI_OPTIONS_WIDE; - } - - /* - * Check for synchronization - */ - if (map[i]->scsi_info_scalar.Flags & - I2O_SCSI_ENABLE_SYNC_NEGOTIATION) { - option |= SCSI_OPTIONS_SYNC; - cap |= I2OHBA_CAP_SYNC; - } else { - option &= ~SCSI_OPTIONS_SYNC; - } - - synch = (uint16_t)map[i]->scsi_info_scalar.NegSyncRate; - offset = (uint8_t)map[i]->scsi_info_scalar.NegOffset; - - /* - * Check for tag queuing capability - */ - if (map[i]->scsi_info_scalar.QueueDepth) { - option |= SCSI_OPTIONS_TAG; - cap |= I2OHBA_CAP_TAG; - } else { - option &= ~SCSI_OPTIONS_TAG; - } - - i2ohba->i2ohba_target_scsi_option[i] = option; - i2ohba->i2ohba_cap[i] = cap; - i2ohba->i2ohba_synch[i] = synch; - i2ohba->i2ohba_offset[i] = offset; - } -} - - - -/* - * Function name : i2ohba_scsi_getcap() - * - * Return Values : current value of capability, if defined - * -1 if capability is not defined - * - * Description : returns current capability value - * - * Context : Can be called from different kernel process threads. - * Can be called by interrupt thread. - */ -static int -i2ohba_scsi_getcap(struct scsi_address *ap, char *cap, int whom) -{ - struct i2ohba *i2ohba = ADDR2I2OHBA(ap); - i2o_tid_scsi_ent_t **map = i2ohba->i2ohba_tgt_id_map; - uint8_t tgt = ap->a_target; - int rval = 0; - - /* - * We don't allow inquiring about capabilities for other targets - */ - if (cap == NULL || whom == 0 || map[tgt] == NULL) { - return (-1); - } - - I2OHBA_MUTEX_ENTER(i2ohba); - - switch (scsi_hba_lookup_capstr(cap)) { - case SCSI_CAP_GEOMETRY: - { /* left this code from adp driver */ - uint32_t total_sectors, c, h, s, t; - c = 1024L; - s = 62L; - - total_sectors = i2ohba->i2ohba_totsec[tgt]; - - t = c * s; - h = total_sectors / t; - if (total_sectors % t) { - h ++; - t = c * h; - s = total_sectors / t; - if (total_sectors % t) { - s++; - t = h * s; - c = total_sectors / t; - } - } - if (c == 0) rval = 1; - - rval = ((h << 16) | s); - break; - } - case SCSI_CAP_DMA_MAX: - rval = 1 << 24; /* Limit to 16MB max transfer */ - break; - case SCSI_CAP_MSG_OUT: - rval = 1; - break; - case SCSI_CAP_DISCONNECT: - if ((i2ohba->i2ohba_target_scsi_option[tgt] & - SCSI_OPTIONS_DR) == 0) { - break; - } else if ((i2ohba->i2ohba_cap[tgt] & I2OHBA_CAP_DISCONNECT) - == 0) { - break; - } - rval = 1; - break; - case SCSI_CAP_SYNCHRONOUS: - if ((i2ohba->i2ohba_target_scsi_option[tgt] & - SCSI_OPTIONS_SYNC) == 0) { - break; - } else if ((i2ohba->i2ohba_cap[tgt] & I2OHBA_CAP_SYNC) == 0) { - break; - } - rval = 1; - break; - case SCSI_CAP_WIDE_XFER: - if ((i2ohba->i2ohba_target_scsi_option[tgt] & - SCSI_OPTIONS_WIDE) == 0) { - break; - } else if ((i2ohba->i2ohba_cap[tgt] & I2OHBA_CAP_WIDE) == 0) { - break; - } - rval = 1; - break; - case SCSI_CAP_TAGGED_QING: - if ((i2ohba->i2ohba_target_scsi_option[tgt] & - SCSI_OPTIONS_DR) == 0 || - (i2ohba->i2ohba_target_scsi_option[tgt] & - SCSI_OPTIONS_TAG) == 0) { - break; - } else if ((i2ohba->i2ohba_cap[tgt] & I2OHBA_CAP_TAG) == 0) { - break; - } - rval = 1; - break; - case SCSI_CAP_UNTAGGED_QING: - rval = 0; - break; - case SCSI_CAP_PARITY: - if (i2ohba->i2ohba_target_scsi_option[tgt] & - SCSI_OPTIONS_PARITY) { - rval = 1; - } - break; - case SCSI_CAP_INITIATOR_ID: - rval = i2ohba->i2ohba_initiator_id; - break; - case SCSI_CAP_ARQ: - rval = 1; - break; - case SCSI_CAP_LINKED_CMDS: - break; - case SCSI_CAP_RESET_NOTIFICATION: - rval = 1; - break; - default: - rval = -1; - break; - } - - I2OHBA_MUTEX_EXIT(i2ohba); - - return (rval); -} - - -/* - * Function name : i2ohba_scsi_setcap() - * - * Return Values : 1 - capability exists and can be set to new value - * 0 - capability could not be set to new value - * -1 - no such capability - * - * Description : sets a capability for a target - * - * Context : Can be called from different kernel process threads. - * Can be called by interrupt thread. - */ -static int -i2ohba_scsi_setcap(struct scsi_address *ap, char *cap, int value, int whom) -{ - struct i2ohba *i2ohba = ADDR2I2OHBA(ap); - i2o_tid_scsi_ent_t **map = i2ohba->i2ohba_tgt_id_map; - uint8_t tgt = ap->a_target; - int update = 0; - int sync = 0; - int rval = 0; - - /* - * We don't allow setting capabilities for other targets - * and the targets that are not in this OSM's control - */ - if (cap == NULL || whom == 0 || map[tgt] == NULL) { - return (-1); - } - - I2OHBA_MUTEX_ENTER(i2ohba); - - switch (scsi_hba_lookup_capstr(cap)) { - case SCSI_CAP_DMA_MAX: - case SCSI_CAP_MSG_OUT: - case SCSI_CAP_PARITY: - case SCSI_CAP_UNTAGGED_QING: - case SCSI_CAP_LINKED_CMDS: - case SCSI_CAP_RESET_NOTIFICATION: - case SCSI_CAP_GEOMETRY: - /* - * None of these are settable via - * the capability interface. - */ - break; - - case SCSI_CAP_SECTOR_SIZE: - if (value) { - i2ohba->i2ohba_secsz[tgt] = value; - rval = 1; - } - break; - - case SCSI_CAP_TOTAL_SECTORS: - if (value) { - i2ohba->i2ohba_totsec[tgt] = value; - rval = 1; - } - break; - case SCSI_CAP_ARQ: - if (value) { - i2ohba->i2ohba_cap[tgt] |= I2OHBA_CAP_AUTOSENSE; - } else { - i2ohba->i2ohba_cap[tgt] &= ~I2OHBA_CAP_AUTOSENSE; - } - rval = 1; - break; - - /* disconnect/reconncet either the target supports or doesn't */ - case SCSI_CAP_DISCONNECT: - if ((i2ohba->i2ohba_target_scsi_option[tgt] & - SCSI_OPTIONS_DR) == 0) { - break; - } else { - if (value) { - if ((i2ohba->i2ohba_cap[tgt] & - I2OHBA_CAP_DISCONNECT) == 0) { - if (i2ohba_utilparamset_msg(i2ohba, - tgt, map[tgt]->tid, - I2O_SCSI_DEVICE_INFO_GROUP_NO, 0x1, - I2O_SCSI_ENABLE_DISCONNECT) != 0) - break; - i2ohba->i2ohba_cap[tgt] |= - I2OHBA_CAP_DISCONNECT; - } - } else { - if ((i2ohba->i2ohba_cap[tgt] & - I2OHBA_CAP_DISCONNECT) == 1) { - if (i2ohba_utilparamset_msg(i2ohba, - tgt, map[tgt]->tid, - I2O_SCSI_DEVICE_INFO_GROUP_NO, 0x1, - I2O_SCSI_DISABLE_DISCONNECT) != 0) - break; - i2ohba->i2ohba_cap[tgt] &= - ~I2OHBA_CAP_DISCONNECT; - } - } - } - rval = 1; - break; - - /* these can be set through UtilParamSet message */ - case SCSI_CAP_SYNCHRONOUS: - if ((i2ohba->i2ohba_target_scsi_option[tgt] & - SCSI_OPTIONS_SYNC) == 0) { - break; - } else { - if (value) { - if ((i2ohba->i2ohba_cap[tgt] & - I2OHBA_CAP_SYNC) == 0) { - if (i2ohba_utilparamset_msg(i2ohba, - tgt, map[tgt]->tid, - I2O_SCSI_DEVICE_INFO_GROUP_NO, 0x1, - I2O_SCSI_ENABLE_SYNC_NEGOTIATION) - != 0) - break; - /* set sync speed to Max */ - if (i2ohba_utilparamset_msg(i2ohba, - tgt, map[tgt]->tid, - I2O_SCSI_DEVICE_INFO_GROUP_NO, 0xA, - 0xFFFF) != 0) - break; - /* read the set value */ - if (i2ohba_utilparamget_msg(i2ohba, - tgt, SYNC_UTILPARAM) != 0) - break; - i2ohba->i2ohba_cap[tgt] |= - I2OHBA_CAP_SYNC; - sync++; - update++; - } - } else { - if ((i2ohba->i2ohba_cap[tgt] & - I2OHBA_CAP_SYNC) == 1) { - if (i2ohba_utilparamset_msg(i2ohba, - tgt, map[tgt]->tid, - I2O_SCSI_DEVICE_INFO_GROUP_NO, 0x1, - I2O_SCSI_DISABLE_SYNC_NEGOTIATION) - != 0) - break; - i2ohba->i2ohba_cap[tgt] &= - ~I2OHBA_CAP_SYNC; - update++; - } - } - } - rval = 1; - break; - case SCSI_CAP_TAGGED_QING: - if ((i2ohba->i2ohba_target_scsi_option[tgt] & - SCSI_OPTIONS_DR) == 0 || - (i2ohba->i2ohba_target_scsi_option[tgt] & - SCSI_OPTIONS_TAG) == 0) { - break; - } else { - if (value) { - if ((i2ohba->i2ohba_cap[tgt] & - I2OHBA_CAP_TAG) == 0) { - if (i2ohba_utilparamset_msg(i2ohba, - tgt, map[tgt]->tid, - I2O_SCSI_DEVICE_INFO_GROUP_NO, 0x5, - 0) != 0) - break; - i2ohba->i2ohba_cap[tgt] |= - I2OHBA_CAP_TAG; - update++; - } - } else { - if ((i2ohba->i2ohba_cap[tgt] & - I2OHBA_CAP_TAG) == 1) { - if (i2ohba_utilparamset_msg(i2ohba, - tgt, map[tgt]->tid, - I2O_SCSI_DEVICE_INFO_GROUP_NO, 0x5, - (uint16_t)1) != 0) - break; - i2ohba->i2ohba_cap[tgt] &= - ~I2OHBA_CAP_TAG; - update++; - } - } - } - rval = 1; - break; - case SCSI_CAP_WIDE_XFER: - if ((i2ohba->i2ohba_target_scsi_option[tgt] & - SCSI_OPTIONS_WIDE) == 0) { - break; - } else { - if (value) { - if ((i2ohba->i2ohba_cap[tgt] & - I2OHBA_CAP_WIDE) == 0) { - if (i2ohba_utilparamset_msg(i2ohba, - tgt, map[tgt]->tid, - I2O_SCSI_DEVICE_INFO_GROUP_NO, 0x1, - I2O_SCSI_DATA_WIDTH_16) != 0) - break; - i2ohba->i2ohba_cap[tgt] |= - I2OHBA_CAP_WIDE; - update++; - } - } else { - if ((i2ohba->i2ohba_cap[tgt] & - I2OHBA_CAP_WIDE) == 1) { - if (i2ohba_utilparamset_msg(i2ohba, - tgt, map[tgt]->tid, - I2O_SCSI_DEVICE_INFO_GROUP_NO, 0x1, - I2O_SCSI_DATA_WIDTH_8) != 0) - break; - i2ohba->i2ohba_cap[tgt] &= - ~I2OHBA_CAP_WIDE; - update++; - } - } - } - rval = 1; - break; - case SCSI_CAP_INITIATOR_ID: - if (value < N_I2OHBA_TARGETS_WIDE) { - if (i2ohba->i2ohba_initiator_id != (uint16_t)value) { - /* - * set Initiator SCSI ID - */ - if (i2ohba_utilparamset_msg(i2ohba, - i2ohba->i2ohba_initiator_id, - i2ohba->i2ohba_tid, - I2O_HBA_SCSI_CONTROLLER_INFO_GROUP_NO, 0x4, - value) == 0) { - rval = 1; - i2ohba->i2ohba_initiator_id = value; - } - } - } - break; - - default: - rval = -1; - break; - } - - - /* - * now set flag so latter in i2ohba_i_watch(), - * we can set prop_update - */ - if ((rval == 1) && (update > 0)) { - i2ohba->i2ohba_need_prop_update |= 1 << tgt; - if (sync) - i2ohba_i_updatesync(i2ohba, tgt); - } - - I2OHBA_MUTEX_EXIT(i2ohba); - - return (rval); -} - -/* - * Function name : i2ohba_i_updatesync() - * - * Return Values : -1 failed - * 0 success - * - * Description : modifies/update target sync mode speed, widexfer, - * and TQ. - * - * Context : Can be called from different kernel process threads. - * Can not be called by interrupt thread - */ -static void -i2ohba_i_updatesync(struct i2ohba *i2ohba, int tgt) -{ - uint16_t synch; - uint8_t offset; - i2o_tid_scsi_ent_t **map = i2ohba->i2ohba_tgt_id_map; - - if (map[tgt] == NULL) - return; - - if (map[tgt]->scsi_info_scalar.Flags & - I2O_SCSI_ENABLE_SYNC_NEGOTIATION) { - synch = (uint16_t)map[tgt]->scsi_info_scalar.NegSyncRate; - offset = (uint8_t)map[tgt]->scsi_info_scalar.NegOffset; - - i2ohba->i2ohba_synch[tgt] = synch; - i2ohba->i2ohba_offset[tgt] = offset; - } -} - -/* - * Function name : i2ohba_i_update_props() - * - * Description : Creates/modifies/removes a target sync mode speed, - * wide, and TQ properties - * If offset is 0 then asynchronous mode is assumed and the - * property is removed, if it existed. - * - * Context : Can be called from different kernel process threads. - * Can not be called by interrupt thread - */ -static void -i2ohba_i_update_props(struct i2ohba *i2ohba, int tgt) -{ - static char property[32]; - int xfer_speed = 0; - int wide_enabled; - int tq_enabled; - uint16_t cap; - uint16_t synch; - uint8_t offset; - - cap = i2ohba->i2ohba_cap[tgt]; - synch = i2ohba->i2ohba_synch[tgt]; - offset = i2ohba->i2ohba_offset[tgt]; - - tq_enabled = cap & I2OHBA_CAP_TAG; - wide_enabled = cap & I2OHBA_CAP_WIDE; - - if (offset && synch) { - if (wide_enabled) { - /* double xfer speed if wide has been enabled */ - xfer_speed = ((int)synch * 2); - } else { - xfer_speed = (int)(synch); - } - } - - (void) sprintf(property, "target%x-sync-speed", tgt); - i2ohba_i_update_this_prop(i2ohba, property, xfer_speed); - - (void) sprintf(property, "target%x-wide", tgt); - i2ohba_i_update_this_prop(i2ohba, property, wide_enabled); - - (void) sprintf(property, "target%x-TQ", tgt); - i2ohba_i_update_this_prop(i2ohba, property, tq_enabled); -} - -/* - * Update a property's value - */ -static void -i2ohba_i_update_this_prop(struct i2ohba *i2ohba, char *property, int value) -{ - dev_info_t *dip = i2ohba->i2ohba_dip; - - - if (ddi_prop_update_int(DDI_DEV_T_NONE, dip, - property, value) != DDI_PROP_SUCCESS) { - i2ohba_i_log(NULL, CE_CONT, "?i2ohba_i_update_this_prop:" - " can't update %s property to 0x%x", - property, value); - } -} - - -/* - * Function name : i2ohba_scsi_init_pkt - * - * Return Values : pointer to scsi_pkt, or NULL - * Description : Called by kernel on behalf of a target driver - * calling scsi_init_pkt(9F). - * Refer to tran_init_pkt(9E) man page - * - * Context : Can be called from different kernel process threads. - * Can be called by interrupt thread. - */ -static struct scsi_pkt * -i2ohba_scsi_init_pkt(struct scsi_address *ap, struct scsi_pkt *pkt, - struct buf *bp, int cmdlen, int statuslen, int tgtlen, - int flags, int (*callback)(), caddr_t arg) -{ - struct i2ohba_cmd *sp; - struct i2ohba *i2ohba = ADDR2I2OHBA(ap); - struct scsi_pkt *new_pkt; - - ASSERT(callback == NULL_FUNC || callback == SLEEP_FUNC); - - /* - * First step of i2ohba_scsi_init_pkt: pkt allocation - */ - if (pkt == NULL) { - pkt = scsi_hba_pkt_alloc(i2ohba->i2ohba_dip, ap, cmdlen, - statuslen, tgtlen, sizeof (struct i2ohba_cmd), callback, - arg); - - if (pkt == NULL) { - return (NULL); - } - - sp = PKT2CMD(pkt); - - /* - * Initialize the new pkt - we redundantly initialize - * all the fields for illustrative purposes. - */ - sp->cmd_pkt = pkt; - sp->cmd_flags = 0; - sp->cmd_scblen = statuslen; - sp->cmd_cdblen = (uint8_t)cmdlen; - sp->cmd_privlen = tgtlen; - sp->cmd_dmahandle = NULL; - sp->cmd_dmacount = 0; - sp->cmd_cookie = 0; - pkt->pkt_address = *ap; - pkt->pkt_comp = (void (*)())NULL; - pkt->pkt_flags = 0; - pkt->pkt_time = 0; - pkt->pkt_resid = 0; - pkt->pkt_statistics = 0; - pkt->pkt_reason = 0; - - new_pkt = pkt; - } else { - sp = PKT2CMD(pkt); - new_pkt = NULL; - } - - /* - * Second step of i2ohba_scsi_init_pkt: dma allocation/move - */ - if (bp && bp->b_bcount != 0) { - if (sp->cmd_dmahandle == NULL) { - ASSERT((sp->cmd_flags & CFLAG_DMAVALID) == 0); - if (i2ohba_i_dma_alloc(i2ohba, pkt, bp, - flags, callback) == -1) { - if (new_pkt) { - scsi_hba_pkt_free(ap, new_pkt); - } - return ((struct scsi_pkt *)NULL); - } - } else { - ASSERT(new_pkt == NULL); - ASSERT(sp->cmd_flags & CFLAG_DMAVALID); - if (i2ohba_i_dma_move(i2ohba, pkt, bp) < 0) { - return ((struct scsi_pkt *)NULL); - } - } - ASSERT(sp->cmd_flags & CFLAG_DMAVALID); - DEBUGF(3, (CE_CONT, "init: bcount = %lx, resid = %lx", - bp->b_bcount, pkt->pkt_resid)); - } - - return (pkt); -} - -/* - * Function name : i2ohba_i_dma_alloc - * - * Return Values : 0 if successful, -1 if failure - * Description : allocate DMA resources - * - * Context : Can only be called from i2ohba_scsi_init_pkt() - */ -static int -i2ohba_i_dma_alloc(struct i2ohba *i2ohba, struct scsi_pkt *pkt, - struct buf *bp, int flags, int (*callback)()) -{ - struct i2ohba_cmd *sp = PKT2CMD(pkt); - int dma_flags; - int (*cb)(caddr_t); - int i; - - ASSERT(callback == NULL_FUNC || callback == SLEEP_FUNC); - - if (bp->b_flags & B_READ) { - sp->cmd_flags &= ~CFLAG_DMASEND; - dma_flags = DDI_DMA_READ; - } else { - sp->cmd_flags |= CFLAG_DMASEND; - dma_flags = DDI_DMA_WRITE; - } - - if (flags & PKT_CONSISTENT) { - sp->cmd_flags |= CFLAG_CMDIOPB; - dma_flags |= DDI_DMA_CONSISTENT; - } - - if (flags & PKT_DMA_PARTIAL) { - dma_flags |= DDI_DMA_PARTIAL; - } - - dma_flags |= DDI_DMA_REDZONE; - - cb = (callback == NULL_FUNC) ? DDI_DMA_DONTWAIT : DDI_DMA_SLEEP; - - if ((i = ddi_dma_alloc_handle(i2ohba->i2ohba_dip, - &i2ohba_dma_attr, cb, NULL, &sp->cmd_dmahandle)) - != DDI_SUCCESS) { - switch (i) { - case DDI_DMA_BADATTR: - bioerror(bp, EFAULT); - return (-1); - - case DDI_DMA_NORESOURCES: - bioerror(bp, 0); - return (-1); - - default: - i2ohba_i_log(NULL, CE_WARN, - "?ddi_dma_alloc_handle:" - " 0x%x impossible", i); - /*NOTREACHED*/ - } - } - -#ifdef I2OHBA_DEBUG - ddi_dma_bufalloc++; -#endif - - i = ddi_dma_buf_bind_handle(sp->cmd_dmahandle, bp, dma_flags, - cb, NULL, &sp->cmd_dmacookies[0], &sp->cmd_ncookies); -#ifdef I2OHBA_DEBUG - ddi_dma_buf_bind++; -#endif - - DEBUGF(3, (CE_CONT, "dma_alloc: cmd_ncookies is %d\n", - sp->cmd_ncookies)); - - switch (i) { - case DDI_DMA_PARTIAL_MAP: - ASSERT(dma_flags & DDI_DMA_PARTIAL); - - if (ddi_dma_numwin(sp->cmd_dmahandle, &sp->cmd_nwin) == - DDI_FAILURE) { - i2ohba_i_log(NULL, CE_WARN, - "?ddi_dma_numwin() failed"); - /*NOTREACHED*/ - } - - if (ddi_dma_getwin(sp->cmd_dmahandle, sp->cmd_curwin, - &sp->cmd_dma_offset, &sp->cmd_dma_len, - &sp->cmd_dmacookies[0], &sp->cmd_ncookies) == - DDI_FAILURE) { - i2ohba_i_log(NULL, CE_WARN, - "?ddi_dma_getwin() failed"); - /*NOTREACHED*/ - } - goto get_dma_cookies; - - case DDI_DMA_MAPPED: - sp->cmd_nwin = 1; - sp->cmd_dma_len = 0; - sp->cmd_dma_offset = 0; - -get_dma_cookies: - i = 0; - sp->cmd_dmacount = 0; - for (;;) { - sp->cmd_dmacount += sp->cmd_dmacookies[i++].dmac_size; - - if (i == I2OHBA_CMD_NSEGS || i == sp->cmd_ncookies) - break; - ddi_dma_nextcookie(sp->cmd_dmahandle, - &sp->cmd_dmacookies[i]); - } - - sp->cmd_cookie = i; - sp->cmd_cookiecnt = i; - - sp->cmd_flags |= CFLAG_DMAVALID; - pkt->pkt_resid = bp->b_bcount - sp->cmd_dmacount; - - DEBUGF(3, (CE_CONT, "bcount is %lx, dmacount is %lx," - " resid is %lx\n", - bp->b_bcount, sp->cmd_dmacount, pkt->pkt_resid)); - - return (0); - - case DDI_DMA_NORESOURCES: - bioerror(bp, 0); - break; - - case DDI_DMA_NOMAPPING: - bioerror(bp, EFAULT); - break; - - case DDI_DMA_TOOBIG: - bioerror(bp, EINVAL); - break; - - case DDI_DMA_INUSE: - i2ohba_i_log(NULL, CE_WARN, "?ddi_dma_buf_bind_handle:" - " DDI_DMA_INUSE impossible"); - /*NOTREACHED*/ - - default: - i2ohba_i_log(NULL, CE_WARN, "?ddi_dma_buf_bind_handle:" - " 0x%x impossible", i); - /*NOTREACHED*/ - } - - ddi_dma_free_handle(&sp->cmd_dmahandle); - sp->cmd_dmahandle = NULL; - sp->cmd_flags &= ~CFLAG_DMAVALID; - return (-1); -} - - -/* - * Function name : i2ohba_i_dma_move - * - * Return Values : 0 if successful, -1 if failure - * Description : move DMA resources to next DMA window - * - * Context : Can only be called from i2ohba_scsi_init_pkt() - */ -/*ARGSUSED*/ -static int -i2ohba_i_dma_move(struct i2ohba *i2ohba, struct scsi_pkt *pkt, struct buf *bp) -{ - struct i2ohba_cmd *sp = PKT2CMD(pkt); - int i; - - ASSERT(sp->cmd_flags & CFLAG_COMPLETED); - sp->cmd_flags &= ~CFLAG_COMPLETED; - - /* - * If there are no more cookies remaining in this window, - * must move to the next window first. - */ - if (sp->cmd_cookie == sp->cmd_ncookies) { - /* - * 1217340: cmdk reuses pkts incorrectly - */ - if (sp->cmd_curwin == sp->cmd_nwin && sp->cmd_nwin == 1) - return (0); - - /* - * At last window, cannot move - */ - if (++sp->cmd_curwin >= sp->cmd_nwin) - return (-1); - - if (ddi_dma_getwin(sp->cmd_dmahandle, sp->cmd_curwin, - &sp->cmd_dma_offset, &sp->cmd_dma_len, - &sp->cmd_dmacookies[0], &sp->cmd_ncookies) == DDI_FAILURE) - return (-1); - - sp->cmd_cookie = 0; - } else { - /* - * Still more cookies in this window - get the next one - */ - ddi_dma_nextcookie(sp->cmd_dmahandle, &sp->cmd_dmacookies[0]); - } - - /* - * Get remaining cookies in this window, up to our maximum - */ - i = 0; - for (;;) { - sp->cmd_dmacount += sp->cmd_dmacookies[i++].dmac_size; - sp->cmd_cookie++; - if (i == I2OHBA_CMD_NSEGS || sp->cmd_cookie == sp->cmd_ncookies) - break; - ddi_dma_nextcookie(sp->cmd_dmahandle, &sp->cmd_dmacookies[i]); - } - sp->cmd_cookiecnt = i; - - pkt->pkt_resid = bp->b_bcount - sp->cmd_dmacount; - return (0); -} - - -/* - * Function name : i2ohba_scsi_destroy_pkt - * - * Return Values : none - * Description : Called by kernel on behalf of a target driver - * calling scsi_destroy_pkt(9F). - * Refer to tran_destroy_pkt(9E) man page - * - * Context : Can be called from different kernel process threads. - * Can be called by interrupt thread. - */ -static void -i2ohba_scsi_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt) -{ - struct i2ohba_cmd *sp = PKT2CMD(pkt); - struct i2ohba *i2ohba = ADDR2I2OHBA(ap); - i2o_tid_scsi_ent_t **map = i2ohba->i2ohba_tgt_id_map; - uint8_t tgt = ap->a_target; - - if (map[tgt] != NULL) { - - /* - * i2o_scsi_dmafree inline to make things faster - */ - if (sp->cmd_flags & CFLAG_DMAVALID) { - /* - * Free the mapping - */ - sp->cmd_flags &= ~CFLAG_DMAVALID; - if (ddi_dma_unbind_handle(sp->cmd_dmahandle) - != DDI_SUCCESS) { - i2ohba_i_log(NULL, CE_WARN, - "?i2ohba_scsi_destroy_pkt: " - "ddi_dma_unbind_handle() for dataseg" - " failed"); - /*NOTREACHED*/ - } -#ifdef I2OHBA_DEBUG - ddi_dma_buf_unbind++; -#endif - ddi_dma_free_handle(&sp->cmd_dmahandle); -#ifdef I2OHBA_DEBUG - ddi_dma_buf_free_hdl++; -#endif - sp->cmd_dmahandle = NULL; - } - } - - /* - * Free the pkt - */ - scsi_hba_pkt_free(ap, pkt); -} - - -/* - * Function name : i2ohba_scsi_dmafree() - * - * Return Values : none - * Description : free dvma resources - * - * Context : Can be called from different kernel process threads. - * Can be called by interrupt thread. - */ -/*ARGSUSED*/ -static void -i2ohba_scsi_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt) -{ - struct i2ohba_cmd *sp = PKT2CMD(pkt); - struct i2ohba *i2ohba = ADDR2I2OHBA(ap); - i2o_tid_scsi_ent_t **map = i2ohba->i2ohba_tgt_id_map; - uint8_t tgt = ap->a_target; - - if (map[tgt] != NULL) { - if (sp->cmd_flags & CFLAG_DMAVALID) { - /* - * Free the mapping. - */ - sp->cmd_flags &= ~CFLAG_DMAVALID; - if (ddi_dma_unbind_handle(sp->cmd_dmahandle) - != DDI_SUCCESS) { - i2ohba_i_log(NULL, CE_WARN, - "?i2ohba_scsi_dmafree: " - "ddi_dma_unbind_handle() for dataseg" - " failed"); - /*NOTREACHED*/ - } -#ifdef I2OHBA_DEBUG - ddi_dma_buf_unbind++; -#endif - ddi_dma_free_handle(&sp->cmd_dmahandle); -#ifdef I2OHBA_DEBUG - ddi_dma_buf_free_hdl++; -#endif - sp->cmd_dmahandle = NULL; - } - } -} - -/* - * Function name: i2ohba_scsi_sync_pkt() - * - * Return Values: none - * Description : sync dma - * - * Context : Can be called from different kernel process threads. - * Can be called by interrupt thread. - */ -/*ARGSUSED*/ -static void -i2ohba_scsi_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pkt) -{ - int i; - struct i2ohba_cmd *sp = PKT2CMD(pkt); - struct i2ohba *i2ohba = ADDR2I2OHBA(ap); - i2o_tid_scsi_ent_t **map = i2ohba->i2ohba_tgt_id_map; - uint8_t tgt = ap->a_target; - - if (map[tgt] != NULL) { - if (sp->cmd_flags & CFLAG_DMAVALID) { - i = ddi_dma_sync(sp->cmd_dmahandle, sp->cmd_dma_offset, - sp->cmd_dma_len, - (sp->cmd_flags & CFLAG_DMASEND) ? - DDI_DMA_SYNC_FORDEV : DDI_DMA_SYNC_FORCPU); - if (i != DDI_SUCCESS) { - i2ohba_i_log(NULL, CE_WARN, - "?i2ohba_scsi_sync_pkt: sync pkt failed"); - } - } - } -} - - -/* - * routine for reset notification setup, to register or cancel. - */ -static int -i2ohba_scsi_reset_notify(struct scsi_address *ap, int flag, -void (*callback)(caddr_t), caddr_t arg) -{ - struct i2ohba *i2ohba = ADDR2I2OHBA(ap); - return (scsi_hba_reset_notify_setup(ap, flag, callback, arg, - I2OHBA_REQ_MUTEX(i2ohba), &i2ohba->i2ohba_reset_notify_listf)); -} - -/* - * Function name : i2ohba_scsi_start() - * - * Return Values : TRAN_FATAL_ERROR - i2o has been shutdown - * TRAN_BUSY - request queue is full - * TRAN_ACCEPT - pkt has been submitted to i2o - * - * Description : init pkt, start the request - * - * Context : Can be called from different kernel process threads. - * Can be called by interrupt thread. - */ -static int -i2ohba_scsi_start(struct scsi_address *ap, struct scsi_pkt *pkt) -{ - struct i2ohba_cmd *sp = PKT2CMD(pkt); - int rval = TRAN_ACCEPT; - struct i2ohba *i2ohba = ADDR2I2OHBA(ap); - dev_info_t *dip = (PKT2I2OHBA(pkt))->i2ohba_dip; - i2o_tid_scsi_ent_t **tgtmap = i2ohba->i2ohba_tgt_id_map; - i2o_scsi_scb_execute_message_t *req; - i2o_sge_chain_element_t *sgl; - i2o_sge_ignore_element_t *sgl2; - i2o_msg_handle_t msg_handle; - i2o_sge_chain_element_t *cpsgl; - ddi_acc_handle_t acc_handle; - clock_t cur_lbolt; - uint16_t tid; - uint16_t flags = 0, msgsize; - int i, val, bound = 0; - size_t sglen; - uint_t count; - - - ASSERT(I2OHBA_MUTEX_OWNED(i2ohba) == 0 || ddi_in_panic()); - - /* - * if we have a shutdown, return packet - */ - if (i2ohba->i2ohba_shutdown) { - return (TRAN_FATAL_ERROR); - } - - if (i2ohba->i2ohba_throttle) { - return (TRAN_BUSY); - } - /* - * if the target id is not in our map, don't bother composing - * the message, return fail - */ - if (tgtmap[TGT(sp)] == NULL) { - return (TRAN_FATAL_ERROR); - } else { - tid = tgtmap[TGT(sp)]->tid; - } - - i2ohba->i2ohba_counter++; - if (i2ohba->i2ohba_counter > 64) { - DEBUGF(1, (CE_CONT, "i2ohba_counter > 64\n")); - DEBUGF(1, (CE_CONT, "sp = %p\n", (void *)sp)); - i2ohba->i2ohba_counter--; - return (TRAN_BUSY); - } - - ASSERT(!(sp->cmd_flags & CFLAG_IN_TRANSPORT)); - sp->cmd_flags = (sp->cmd_flags & ~CFLAG_TRANFLAG) | - CFLAG_IN_TRANSPORT; - pkt->pkt_reason = CMD_CMPLT; - - /* - * Set up request in i2ohba_reqhead area so it is ready to - * go once we have the request mutex, - * The reason we don't allocate the msg buffer in scsi_init_pkt - * is that the msg buffer is a resource from the FIFO of the IOP - * we don't want to give that ptr around - */ - - if (i2o_msg_alloc(i2ohba->i2ohba_iophdl, I2O_MSG_DONTWAIT, - NULL, (void *)&req, &msg_handle, &acc_handle) != DDI_SUCCESS) { - i2ohba_i_log(NULL, CE_WARN, "?i2ohba_scsi_start: " - " i2o_msg_alloc failed"); - sp->cmd_flags = (sp->cmd_flags & ~CFLAG_IN_TRANSPORT); - pkt->pkt_reason = 0; - i2ohba->i2ohba_counter--; - return (TRAN_BUSY); - } - - - /* - * Constructed a scsi_scb_execute_message - */ - - /* StdMessageFrame */ - req->StdMessageFrame.VersionOffset = 0xA1; - req->StdMessageFrame.MsgFlags = 0; - - if (sp->cmd_flags & CFLAG_DMAVALID) { - msgsize = ((sizeof (i2o_scsi_scb_execute_message_t) - - sizeof (i2o_sg_element_t) + - sizeof (i2o_sge_chain_element_t) + - sizeof (i2o_sge_ignore_element_t)) >> 2); - } else { - msgsize = ((sizeof (i2o_scsi_scb_execute_message_t) - - sizeof (i2o_sg_element_t)) >> 2); - } - - /* - * To get actual allocation msg size - */ - ASSERT(msgsize <= ddi_get16(acc_handle, - &req->StdMessageFrame.MessageSize)); - - ddi_put16(acc_handle, &req->StdMessageFrame.MessageSize, msgsize); - put_msg_TargetAddress(&req->StdMessageFrame, tid, acc_handle); - put_msg_InitiatorAddress(&req->StdMessageFrame, I2O_OSM_TID, - acc_handle); - put_msg_Function(&req->StdMessageFrame, I2O_SCSI_SCB_EXEC, acc_handle); - ddi_put32(acc_handle, - (uint32_t *)&req->StdMessageFrame.InitiatorContext, - (uint32_t)i2ohba_callback); - - /* TransactionContext */ - ddi_put32(acc_handle, &req->TransactionContext, - (uint32_t)(uintptr_t)sp); - - /* Set up CDB in the request */ - - bzero(req->CDB, I2O_SCSI_CDB_LENGTH); - if (sp->cmd_cdblen > I2O_SCSI_CDB_LENGTH) { - req->CDBLength = I2O_SCSI_CDB_LENGTH; - } else { - req->CDBLength = sp->cmd_cdblen; - } - bcopy(pkt->pkt_cdbp, req->CDB, sp->cmd_cdblen); - bcopy(pkt->pkt_cdbp, sp->cmd_cdb, sp->cmd_cdblen); - -#ifdef I2OHBA_DEBUG - if (sp->cmd_cdblen == 0x6) { - DEBUGF(1, (CE_CONT, "%d: %x %x %x %x %x %x\n", - sp->cmd_cdblen, - pkt->pkt_cdbp[0], pkt->pkt_cdbp[1], - pkt->pkt_cdbp[2], pkt->pkt_cdbp[3], - pkt->pkt_cdbp[4], pkt->pkt_cdbp[5])); - } else { - DEBUGF(1, (CE_CONT, "10: %x %x %x %x %x %x %x %x %x %x\n", - pkt->pkt_cdbp[0], pkt->pkt_cdbp[1], - pkt->pkt_cdbp[2], pkt->pkt_cdbp[3], - pkt->pkt_cdbp[4], pkt->pkt_cdbp[5], - pkt->pkt_cdbp[6], pkt->pkt_cdbp[7], - pkt->pkt_cdbp[8], pkt->pkt_cdbp[9])); - } -#endif - - DEBUGF(1, (CE_CONT, "pkt_flags = 0x%x\n", pkt->pkt_flags)); - /* Tag queuing */ - if (pkt->pkt_flags & FLAG_STAG) - flags |= I2O_SCB_FLAG_SIMPLE_QUEUE_TAG; - - else if (pkt->pkt_flags & FLAG_OTAG) - flags |= I2O_SCB_FLAG_ORDERED_QUEUE_TAG; - - else if (pkt->pkt_flags & FLAG_HTAG) - flags |= I2O_SCB_FLAG_HEAD_QUEUE_TAG; - - else if (pkt->pkt_flags & FLAG_ACA) - flags |= I2O_SCB_FLAG_ACA_QUEUE_TAG; - - if ((pkt->pkt_flags & FLAG_SENSING) || - (i2ohba->i2ohba_cap[TGT(sp)] & I2OHBA_CAP_AUTOSENSE)) - flags |= I2O_SCB_FLAG_SENSE_DATA_IN_MESSAGE; - - /* DISCONNECT enable by default especially with TAGQ */ - if (pkt->pkt_flags & FLAG_NODISCON) - flags &= ~I2O_SCB_FLAG_ENABLE_DISCONNECT; - else - flags |= I2O_SCB_FLAG_ENABLE_DISCONNECT; - - if (sp->cmd_flags & CFLAG_DMASEND) { - flags |= I2O_SCB_FLAG_XFER_TO_DEVICE; - } else { - flags |= I2O_SCB_FLAG_XFER_FROM_DEVICE; - } - - ddi_put16(acc_handle, &req->SCBFlags, flags); - DEBUGF(1, (CE_CONT, "SCBflags = 0x%x\n", flags)); - - /* - * All msg are using chain pointer. - * Setup dma transfers data segments. - */ - - sgl = (i2o_sge_chain_element_t *)&req->SGL; - sgl2 = (i2o_sge_ignore_element_t *)((caddr_t)sgl + - sizeof (i2o_sge_chain_element_t)); - if (sp->cmd_flags & CFLAG_DMAVALID) { - - if (sp->cmd_flags & CFLAG_CMDIOPB) { - (void) ddi_dma_sync(sp->cmd_dmahandle, - sp->cmd_dma_offset, sp->cmd_dma_len, - DDI_DMA_SYNC_FORDEV); - } - - ASSERT(sp->cmd_cookiecnt > 0); - - /* size of the next SGL chain elements list */ - sglen = sp->cmd_cookiecnt * sizeof (i2o_sge_chain_element_t); - - /* flags */ - put_flags_count_Flags(&sgl->FlagsCount, - I2O_SGL_FLAGS_CHAIN_POINTER_ELEMENT, acc_handle); - - /* - * instead of allocating a chuck of dma - * address here like isp driver, the - * trade of speed vs managing the free - * memory list. I don't want this - * to become kmem_alloc functions. - */ - if (ddi_dma_alloc_handle(dip, &i2ohba_dmasgl_attr, - DDI_DMA_DONTWAIT, NULL, &sp->sglbuf_dmahandle) - != DDI_SUCCESS) { - i2ohba_i_log(NULL, CE_WARN, "?i2ohba_scsi_start: " - "cannot allocate SGL's chain buffer handle"); - goto cleanup; - } - bound++; -#ifdef I2OHBA_DEBUG - ddi_dma_alloc_hdl++; -#endif - - if (ddi_dma_mem_alloc(sp->sglbuf_dmahandle, (size_t) - sglen, &dev_attr, DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, - NULL, (caddr_t *)&sp->sglbuf, &sp->sglrlen, - &sp->sglbuf_dmaacchandle) != DDI_SUCCESS) { - i2ohba_i_log(NULL, CE_WARN, "?i2ohba_scsi_start: " - "cannot allocate SGL's chain buffer memory"); - goto cleanup; - } - bound++; -#ifdef I2OHBA_DEBUG - ddi_dma_alloc_mem++; -#endif - - /* - * we passed in the sgl real length in transaction - * context because we need it to free the dma, - * but we set the chain element header with sglen - */ - put_flags_count_Count(&sgl->FlagsCount, sglen, acc_handle); - - put_flags_count_Flags(&sgl2->FlagsCount, - I2O_SGL_FLAGS_IGNORE_ELEMENT | - I2O_SGL_FLAGS_LAST_ELEMENT, acc_handle); - - put_flags_count_Count(&sgl2->FlagsCount, 0x1, acc_handle); - - /* fill in the SGL chain headers */ - sp->cmd_xfercount = 0; - cpsgl = (i2o_sge_chain_element_t *)sp->sglbuf; - - for (i = 0; i < sp->cmd_cookiecnt; i++, cpsgl++) { - - put_flags_count_Flags(&cpsgl->FlagsCount, - I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT, - sp->sglbuf_dmaacchandle); - - put_flags_count_Count(&cpsgl->FlagsCount, - sp->cmd_dmacookies[i].dmac_size, - sp->sglbuf_dmaacchandle); - - ddi_put32(sp->sglbuf_dmaacchandle, - &cpsgl->PhysicalAddress, - sp->cmd_dmacookies[i].dmac_address); - - sp->cmd_xfercount += - sp->cmd_dmacookies[i].dmac_size; - } - - DEBUGF(3, (CE_CONT, "cookiecnt is %x, ncookie is %x," - "cookie# is %d\n", sp->cmd_cookiecnt, sp->cmd_ncookies, - sp->cmd_cookie)); - DEBUGF(3, (CE_CONT, "cmd_xfercount is %lx\n", - sp->cmd_xfercount)); - - - /* mark the last chain pointer header as the last one */ - - cpsgl--; - put_flags_count_Flags(&cpsgl->FlagsCount, - I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT | - I2O_SGL_FLAGS_LAST_ELEMENT | I2O_SGL_FLAGS_END_OF_BUFFER, - sp->sglbuf_dmaacchandle); - - if (ddi_dma_addr_bind_handle(sp->sglbuf_dmahandle, NULL, - (caddr_t)sp->sglbuf, sp->sglrlen, DDI_DMA_RDWR | - DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, NULL, - &sp->sglbuf_dmacookie, &count) != DDI_DMA_MAPPED) { - i2ohba_i_log(NULL, CE_WARN, "?i2ohba_scsi_start: " - "cannot bind SGL's bind handle"); - goto cleanup; - } -#ifdef I2OHBA_DEBUG - ddi_dma_bind_hdl++; -#endif - - DEBUGF(1, (CE_CONT, "start: cmd_dmacount=%lx," - " cmd_xfercount=%lx\n", - sp->cmd_dmacount, sp->cmd_xfercount)); - - ddi_put32(acc_handle, &req->ByteCount, sp->cmd_xfercount); - - ddi_put32(acc_handle, &sgl->PhysicalAddress, - (uint32_t)sp->sglbuf_dmacookie.dmac_address); - - } else { - ddi_put32(acc_handle, &req->ByteCount, 0); - put_flags_count_Flags(&sgl->FlagsCount, 0, acc_handle); - put_flags_count_Count(&sgl->FlagsCount, 0, acc_handle); - put_flags_count_Flags(&sgl2->FlagsCount, 0, acc_handle); - put_flags_count_Count(&sgl2->FlagsCount, 0, acc_handle); - } - - /* - * calculate deadline from pkt_time - * Instead of multiplying by 100 (ie. HZ), we multiply by 128 so - * we can shift and at the same time have a 28% grace period - * we ignore the rare case of pkt_time == 0 and deal with it - * in i2ohba_i_watch() - */ - cur_lbolt = ddi_get_lbolt(); - sp->cmd_deadline = cur_lbolt + (clock_t)(pkt->pkt_time * 256); - - I2OHBA_MUTEX_ENTER(i2ohba); - (void) i2ohba_i_req_insert(i2ohba, sp); - I2OHBA_MUTEX_EXIT(i2ohba); - /* - * Start the cmd. If NO_INTR, must wait for cmd reply/completion. - */ - if ((pkt->pkt_flags & FLAG_NOINTR) == 0) { - - /* - * need a list (or some sort of queue) so that - * when we need to flash the queue, ie: SCSI_BUS_RESET - * we'll have a way to do it (link list) - */ - val = i2o_msg_send(i2ohba->i2ohba_iophdl, req, msg_handle); - if (val != DDI_SUCCESS) - rval = TRAN_BUSY; /* I/O couldnot be started */ - } else { - val = i2o_msg_send(i2ohba->i2ohba_iophdl, req, msg_handle); - /* poll command */ - if (val == DDI_SUCCESS) { - i2ohba_i_polled_cmd_start(i2ohba, sp); - } else { - rval = TRAN_BUSY; - } - } - return (rval); - -cleanup: - - if (sp) { - if (bound) { - (void) ddi_dma_unbind_handle(sp->sglbuf_dmahandle); -#ifdef I2OHBA_DEBUG - ddi_dma_unbind++; -#endif - if (bound > 1) { - ddi_dma_mem_free(&sp->sglbuf_dmaacchandle); -#ifdef I2OHBA_DEBUG - ddi_dma_free_mem++; -#endif - } - ddi_dma_free_handle(&sp->sglbuf_dmahandle); -#ifdef I2OHBA_DEBUG - ddi_dma_bind_free++; -#endif - } - - sp->cmd_flags = (sp->cmd_flags & ~CFLAG_IN_TRANSPORT); - i2ohba->i2ohba_counter--; - pkt->pkt_reason = 0; - } - - /* return MFA to IOP */ - if (req) { - req->StdMessageFrame.VersionOffset = 0; - req->StdMessageFrame.MsgFlags = 0; - ddi_put16(acc_handle, &req->StdMessageFrame.MessageSize, 3); - put_msg_TargetAddress(&req->StdMessageFrame, 0, acc_handle); - put_msg_InitiatorAddress(&req->StdMessageFrame, 0, acc_handle); - put_msg_Function(&req->StdMessageFrame, I2O_UTIL_NOP, - acc_handle); - (void) i2o_msg_send(i2ohba->i2ohba_iophdl, req, msg_handle); - } - - ASSERT(I2OHBA_MUTEX_OWNED(i2ohba) == 0 || ddi_in_panic()); - return (TRAN_BUSY); -} - - -/* - * Function name : i2ohba_i_req_insert() - * - * Return Values : void - * - * Usage : called by i2ohba_scsi_start(). - * - * Description : Insert the i2ohba_cmd into the double - * link list in FIFO fashion. - * - * Context : called by SCSA frame work. - */ -static void -i2ohba_i_req_insert(struct i2ohba *i2ohba, struct i2ohba_cmd *sp) -{ - struct i2ohba_cmd *head = i2ohba->i2ohba_reqhead; - - sp->cmd_forw = head; - if (head != NULL) { - i2ohba->i2ohba_reqhead->cmd_backw = sp; - } else { - i2ohba->i2ohba_reqtail = sp; - } - i2ohba->i2ohba_reqhead = sp; - sp->cmd_backw = NULL; - -} - - -/* - * Function name : i2ohba_i_req_remove() - * - * Return Values : void - * - * Usage : called by i2ohba_callback(). - * called by i2ohba_scsi_start() if i2o_msg_send() - * failed. - * Description : remove a i2ohba_cmd from the double link list - * - * Context : called by SCSA frame work. - */ -static void -i2ohba_i_req_remove(struct i2ohba *i2ohba, struct i2ohba_cmd *sp) -{ - struct i2ohba_cmd *tail = i2ohba->i2ohba_reqtail; - struct i2ohba_cmd *tmp; - - for (tmp = tail; tmp != NULL; tmp = tmp->cmd_backw) { - if (tmp == sp) { - if (tmp->cmd_backw) - tmp->cmd_backw->cmd_forw = tmp->cmd_forw; - else - i2ohba->i2ohba_reqhead = tmp->cmd_forw; - - if (tmp->cmd_forw) - tmp->cmd_forw->cmd_backw = tmp->cmd_backw; - else - i2ohba->i2ohba_reqtail = tmp->cmd_backw; - - tmp->cmd_backw = NULL; - tmp->cmd_forw = NULL; - break; - - } - } -} - -/* - * Function name : i2ohba_callback() - * - * Return Values : None - * - * Context: : called by interrupt thread. - */ - -void -i2ohba_callback(i2o_message_frame_t *msg, ddi_acc_handle_t acc_handle) -{ - - i2o_single_reply_message_frame_t *reply; - struct i2ohba *i2ohba; - struct scsi_pkt *pkt; - struct i2ohba_cmd *sp; - uint8_t reqstatus; - - reply = (i2o_single_reply_message_frame_t *)msg; - - - ASSERT(I2O_SCSI_SCB_EXEC == get_msg_Function( - &reply->StdMessageFrame, acc_handle)); - - sp = (struct i2ohba_cmd *)(uintptr_t)ddi_get32(acc_handle, - &reply->TransactionContext); - - ASSERT(sp); - - i2ohba = CMD2I2OHBA(sp); - I2OHBA_MUTEX_ENTER(i2ohba); - (void) i2ohba_i_req_remove(i2ohba, sp); - I2OHBA_MUTEX_EXIT(i2ohba); - - if (sp->cmd_dmahandle) { - (void) ddi_dma_sync(sp->cmd_dmahandle, - sp->cmd_dma_offset, sp->cmd_dma_len, - DDI_DMA_SYNC_FORKERNEL); - } - - reqstatus = ddi_get8(acc_handle, &reply->ReqStatus); - DEBUGF(1, (CE_CONT, "reqstatus %x\n", reqstatus)); - pkt = CMD2PKT(sp); - - /* - * First filter the reqstatus - * check for any special errors - */ - switch (reqstatus) { - - case I2O_REPLY_STATUS_ERROR_PARTIAL_TRANSFER: - /* - * With paritial transfer, we want to make - * sure it is an USCSI cmd - */ - if ((pkt->pkt_flags >> 16) == 0) - pkt->pkt_reason = CMD_TRAN_ERR; - - sp->cmd_flags |= CFLAG_FINISHED; - i2ohba_i_pkt_comp(reply, acc_handle, sp); - - return; - - case I2O_REPLY_STATUS_SUCCESS: - /* - * With successful completetion, only the ReqStatus - * field is set to reflect sucessful completion, the - * DetailedStatusCode is set to zero, the TransferCount - * field indicates the actual amount of data transferred. - * There is no StatusData. - */ - - sp->cmd_flags |= CFLAG_FINISHED; - i2ohba_i_pkt_comp(reply, acc_handle, sp); - - return; - - /* XXLWXX Error code handling */ - case I2O_REPLY_STATUS_ABORT_DIRTY: - case I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER: - case I2O_REPLY_STATUS_ERROR_DIRTY: - case I2O_REPLY_STATUS_ERROR_NO_DATA_TRANSFER: - case I2O_REPLY_STATUS_PROCESS_ABORT_DIRTY: - case I2O_REPLY_STATUS_PROCESS_ABORT_NO_DATA_TRANSFER: - case I2O_REPLY_STATUS_PROCESS_ABORT_PARTIAL_TRANSFER: - case I2O_REPLY_STATUS_PROGRESS_REPORT: - /* - * If message has failed due to aborted by hosts, - * error in execution, due to system command or reconfig. - * failed the request. - */ - case I2O_REPLY_STATUS_TRANSACTION_ERROR: - default: - pkt->pkt_reason = CMD_TRAN_ERR; - sp->cmd_flags |= CFLAG_FINISHED; - i2ohba_i_pkt_comp(reply, acc_handle, sp); -#ifdef I2OHBA_DEBUG - DEBUGF(1, (CE_CONT, - "?i2ohba_callback: Reply Failed")); -#endif - break; - - } -} - -/* - * Function name : i2ohba_i_pkt_complete() - * - * Return Values : none - * - * Description : - * callback into target driver - * argument is a NULL-terminated list of packets - * copy over stuff from response packet - * - * Context : Can be called by interrupt thread. - */ -static void -i2ohba_i_pkt_comp(i2o_single_reply_message_frame_t *reply, ddi_acc_handle_t - acc_handle, struct i2ohba_cmd *sp) -{ - i2o_scsi_success_reply_message_frame_t *replysuc; - i2o_scsi_error_reply_message_frame_t *replyerr; - struct i2ohba *i2ohba; - struct scsi_pkt *pkt; - uint32_t transcount; - uint32_t autocount; - uint16_t adptrstatus; - uint16_t detailstat; - uint16_t messagesize; - uint8_t devstatus; - - i2ohba = CMD2I2OHBA(sp); - ASSERT(I2OHBA_MUTEX_OWNED(i2ohba) == 0 || ddi_in_panic()); - - pkt = CMD2PKT(sp); - - ASSERT(sp->cmd_flags & CFLAG_FINISHED); - - if (sp->cmd_flags & CFLAG_DMAVALID) { - if (ddi_dma_unbind_handle(sp->sglbuf_dmahandle) != - DDI_SUCCESS) { - i2ohba_i_log(NULL, CE_WARN, "?i2ohba_scsi_dmafree: " - "ddi_dma_unbind_handle() for sglbuf failed"); - /*NOTREACHED*/ - } -#ifdef I2OHBA_DEBUG - ddi_dma_unbind++; -#endif - ddi_dma_mem_free(&sp->sglbuf_dmaacchandle); -#ifdef I2OHBA_DEBUG - ddi_dma_free_mem++; -#endif - ddi_dma_free_handle(&sp->sglbuf_dmahandle); -#ifdef I2OHBA_DEBUG - ddi_dma_bind_free++; -#endif - sp->sglbuf_dmahandle = NULL; - } - - replysuc = (i2o_scsi_success_reply_message_frame_t *)reply; - - detailstat = ddi_get16(acc_handle, &reply->DetailedStatusCode); - devstatus = (uint8_t)(detailstat & I2O_SCSI_DEVICE_DSC_MASK); - /* this is a workaround for 0x3 and 0x9 LSB is being ORed */ - devstatus = devstatus & 0xfe; - DEBUGF(1, (CE_CONT, "devstatus %x\n", devstatus)); - adptrstatus = detailstat & I2O_SCSI_HBA_DSC_MASK; - DEBUGF(1, (CE_CONT, "adptrstatus %x\n", adptrstatus)); - - transcount = ddi_get32(acc_handle, &replysuc->TransferCount); - - if (detailstat == 0) { - pkt->pkt_scbp[0] = - (uint8_t)(detailstat & I2O_SCSI_DEVICE_DSC_MASK); - pkt->pkt_reason = CMD_CMPLT; - pkt->pkt_state |= STATE_GOT_BUS | STATE_GOT_TARGET | - STATE_SENT_CMD | STATE_XFERRED_DATA; - pkt->pkt_statistics = 0; - pkt->pkt_resid = sp->cmd_xfercount - transcount; - } else { - replyerr = (i2o_scsi_error_reply_message_frame_t *)reply; - - /* - * devstatus: SCSI_SUCESS 0, SCSI_CHECK_COND 2, - * SCSI_BUSY 8, SCSI_RES_CONFLICT 18, - * SCSI_CMD_TERM 22, SCSI_TASK_SET_FULL 28, - * SCSI_ACA_ACTIVE 30 - */ - messagesize = ddi_get16(acc_handle, - &replyerr->StdReplyFrame.StdMessageFrame.MessageSize); - - pkt->pkt_scbp[0] = devstatus; - - if (devstatus == I2O_SCSI_DSC_CHECK_CONDITION) { - pkt->pkt_reason = CMD_CMPLT; - pkt->pkt_state |= STATE_GOT_BUS | STATE_GOT_TARGET | - STATE_SENT_CMD | STATE_XFERRED_DATA; - pkt->pkt_statistics = 0; - goto arqchk; - } - - /* SYM HDM problem, can't recognized USCSI cmd well */ - if ((devstatus == I2O_SCSI_DSC_BUSY) && - (transcount != 0) && ((pkt->pkt_flags >> 16) != 0)) { - pkt->pkt_reason = CMD_CMPLT; - pkt->pkt_state |= STATE_GOT_BUS | STATE_GOT_TARGET | - STATE_SENT_CMD | STATE_XFERRED_DATA; - pkt->pkt_statistics = 0; - pkt->pkt_resid = sp->cmd_xfercount - transcount; - pkt->pkt_scbp[0] = STATUS_GOOD; - goto done; - } - - - switch (adptrstatus) { - - case I2O_SCSI_HBA_DSC_AUTOSENSE_FAILED: - pkt->pkt_reason = CMD_INCOMPLETE; - pkt->pkt_state |= STATE_ARQ_DONE; - break; - - /* bus reset */ - case I2O_SCSI_HBA_DSC_SCSI_BUS_RESET: - pkt->pkt_reason = CMD_RESET; - pkt->pkt_statistics |= STAT_BUS_RESET; - /* Do we need to call notify_callback? */ - scsi_hba_reset_notify_callback( - I2OHBA_REQ_MUTEX(i2ohba), - &i2ohba->i2ohba_reset_notify_listf); - break; - - /* cmd terminated */ - case I2O_SCSI_HBA_DSC_REQUEST_TERMINATED: - pkt->pkt_reason = CMD_TERMINATED; - - pkt->pkt_statistics |= STAT_TERMINATED; - break; - - /* request aborted */ - case I2O_SCSI_HBA_DSC_NO_NEXUS: - pkt->pkt_reason = CMD_ABORTED; - pkt->pkt_statistics |= STAT_ABORTED; - break; - - /* parity error */ - case I2O_SCSI_HBA_DSC_PARITY_ERROR_FAILURE: - pkt->pkt_reason = CMD_TRAN_ERR; - pkt->pkt_statistics |= STAT_PERR; - i2ohba_i_log(NULL, CE_WARN, "?Parity Error"); - break; - - /* data overrun */ - case I2O_SCSI_HBA_DSC_DATA_OVERRUN: - pkt->pkt_reason = CMD_DATA_OVR; - pkt->pkt_state |= STATE_GOT_BUS | - STATE_GOT_TARGET | STATE_SENT_CMD | - STATE_XFERRED_DATA; - break; - - /* cmd complete with error */ - case I2O_SCSI_HBA_DSC_LUN_ALREADY_ENABLED: - case I2O_SCSI_HBA_DSC_COMPLETE_WITH_ERROR: - /* devstatus should be busy/checkcond */ - pkt->pkt_reason = CMD_CMPLT; - break; - - /* cmd aborted by request or aborted by time */ - case I2O_SCSI_HBA_DSC_REQUEST_ABORTED: - if (sp->cmd_flags & CFLAG_DELAY_TIMEOUT) { - pkt->pkt_reason = CMD_TIMEOUT; - pkt->pkt_statistics |= STAT_TIMEOUT - | STAT_ABORTED; - } else { - pkt->pkt_reason = CMD_ABORTED; - pkt->pkt_statistics |= STAT_ABORTED; - } - break; - - /* cmd timeout */ - case I2O_SCSI_HBA_DSC_COMMAND_TIMEOUT: - pkt->pkt_reason = CMD_TIMEOUT; - pkt->pkt_statistics |= STAT_TIMEOUT; - break; - - /* CDB received */ - case I2O_SCSI_HBA_DSC_CDB_RECEIVED: - pkt->pkt_reason = CMD_INCOMPLETE; - pkt->pkt_state |= STATE_SENT_CMD | - STATE_GOT_BUS | STATE_GOT_TARGET | - STATE_XFERRED_DATA; - break; - - /* device reset msg send */ - case I2O_SCSI_HBA_DSC_BDR_MESSAGE_SENT: - pkt->pkt_reason = CMD_RESET; - pkt->pkt_statistics |= STAT_DEV_RESET; - break; - - /* unexpected bus free */ - case I2O_SCSI_HBA_DSC_UNEXPECTED_BUS_FREE: - pkt->pkt_reason = CMD_UNX_BUS_FREE; - break; - - /* cmd failed, transport error */ - case I2O_SCSI_HBA_DSC_ADAPTER_BUSY: - case I2O_SCSI_HBA_DSC_SEQUENCE_FAILURE: - case I2O_SCSI_HBA_DSC_BUS_BUSY: - case I2O_SCSI_HBA_DSC_QUEUE_FROZEN: - case I2O_SCSI_HBA_DSC_UNABLE_TO_ABORT: - case I2O_SCSI_HBA_DSC_UNABLE_TO_TERMINATE: - case I2O_SCSI_HBA_DSC_RESOURCE_UNAVAILABLE: - pkt->pkt_reason = CMD_TRAN_ERR; - break; - - /* failed command, retry? */ - case I2O_SCSI_HBA_DSC_REQUEST_INVALID: - case I2O_SCSI_HBA_DSC_PATH_INVALID: - case I2O_SCSI_HBA_DSC_INVALID_CDB: - case I2O_SCSI_HBA_DSC_LUN_INVALID: - case I2O_SCSI_HBA_DSC_SELECTION_TIMEOUT: - pkt->pkt_state |= STATE_GOT_BUS; - pkt->pkt_reason = CMD_INCOMPLETE; - break; - - case I2O_SCSI_HBA_DSC_DEVICE_NOT_PRESENT: - case I2O_SCSI_HBA_DSC_FUNCTION_UNAVAILABLE: - pkt->pkt_reason = CMD_INCOMPLETE; - break; - - /* what? NO adapter! shutdown now! */ - case I2O_SCSI_HBA_DSC_NO_ADAPTER: - i2ohba->i2ohba_shutdown = 1; - break; - - case I2O_SCSI_HBA_DSC_SCSI_TID_INVALID: - case I2O_SCSI_HBA_DSC_SCSI_IID_INVALID: - default: /* failed cmd, retry */ - pkt->pkt_state |= STATE_GOT_BUS; - pkt->pkt_reason = CMD_TRAN_ERR; - break; - - - } - - pkt->pkt_resid = sp->cmd_xfercount; - - /* - * was there auto request sense info? - */ -arqchk: if (messagesize > - sizeof (i2o_scsi_success_reply_message_frame_t)) { - autocount = ddi_get32(acc_handle, - &replyerr->AutoSenseTransferCount); - - /* currently uses the DATA_IN_MESSAGE, only 40 bytes */ - if (autocount) { - pkt->pkt_state |= STATE_ARQ_DONE; - i2ohba_i_handle_arq(replyerr, sp, autocount); - } - } - - } - - -done: DEBUGF(1, (CE_CONT, "transfer=0x%x, resid=0x%lx\n", transcount, - pkt->pkt_resid)); - - /* - * if data was xferred and this was an IOPB, we need - * to do a dma sync - */ - if ((sp->cmd_flags & CFLAG_CMDIOPB) && - (pkt->pkt_state & STATE_XFERRED_DATA)) { - (void) ddi_dma_sync(sp->cmd_dmahandle, - sp->cmd_dma_offset, sp->cmd_dma_len, - DDI_DMA_SYNC_FORCPU); - } - - - ASSERT(sp->cmd_flags & CFLAG_IN_TRANSPORT); - ASSERT(sp->cmd_flags & CFLAG_FINISHED); - ASSERT((sp->cmd_flags & CFLAG_COMPLETED) == 0); - - sp->cmd_flags = ((sp->cmd_flags & ~CFLAG_IN_TRANSPORT) & - ~CFLAG_DELAY_TIMEOUT) | CFLAG_COMPLETED; - i2ohba->i2ohba_counter--; - - /* - * Call packet completion routine if FLAG_NOINTR is not set. - * If FLAG_NOINTR is set turning on CFLAG_COMPLETED in line - * above will cause busy wait loop in - * i2ohba_i_polled_cmd_start() to exit. - */ - if (((pkt->pkt_flags & FLAG_NOINTR) == 0) && - pkt->pkt_comp) { - (*pkt->pkt_comp)(pkt); - } - - ASSERT(I2OHBA_MUTEX_OWNED(i2ohba) == 0 || ddi_in_panic()); -} - - -/* - * Function name : i2ohba_i_handle_arq() - * - * Description : called on an autorequest sense condition, sets up arqstat - * - * Context : Can be called from different kernel process threads. - * Can be called by interrupt thread. - */ -static void -i2ohba_i_handle_arq(i2o_scsi_error_reply_message_frame_t *replyerr, - struct i2ohba_cmd *sp, int aqcount) -{ - char status; - struct scsi_pkt *pkt = CMD2PKT(sp); - - if (sp->cmd_scblen >= sizeof (struct scsi_arq_status)) { - struct scsi_arq_status *arqstat; - - DEBUGF(1, (CE_CONT, "tgt %d.%d: auto request sense", - TGT(sp), LUN(sp))); - - /* clear the pkt_scbp struct */ - arqstat = (struct scsi_arq_status *)(pkt->pkt_scbp); - status = pkt->pkt_scbp[0]; - bzero(arqstat, sizeof (struct scsi_arq_status)); - - /* - * I2O does not provide statistics for request sense, - * so use same statistics as the original cmd. - */ - arqstat->sts_rqpkt_statistics = pkt->pkt_statistics; - arqstat->sts_rqpkt_state = - (STATE_GOT_BUS | STATE_GOT_TARGET | - STATE_SENT_CMD | STATE_XFERRED_DATA | STATE_GOT_STATUS); - if (aqcount < sizeof (struct scsi_extended_sense)) { - arqstat->sts_rqpkt_resid = - sizeof (struct scsi_extended_sense) - aqcount; - - } - bcopy(replyerr->SenseData, - &arqstat->sts_sensedata, - (sizeof (struct scsi_extended_sense) < - I2O_SCSI_SENSE_DATA_SZ) ? - sizeof (struct scsi_extended_sense) : - I2O_SCSI_SENSE_DATA_SZ); - - /* - * restore status which was wiped out by bzero - */ - pkt->pkt_scbp[0] = status; - - DEBUGF(1, (CE_CONT, "arq: %x %x %x %x %x %x %x", - replyerr->SenseData[0], replyerr->SenseData[1], - replyerr->SenseData[2], replyerr->SenseData[3], - replyerr->SenseData[4], replyerr->SenseData[5], - replyerr->SenseData[6])); - return; - } - /* - * Failed cmd auto sense data; can't copy over ARQ data, - */ - DEBUGF(1, (CE_CONT, "Failed cmd, possible sense data")); - DEBUGF(1, (CE_CONT, "arq: %x %x %x %x %x %x %x", - replyerr->SenseData[0], replyerr->SenseData[1], - replyerr->SenseData[2], replyerr->SenseData[3], - replyerr->SenseData[4], replyerr->SenseData[5], - replyerr->SenseData[6])); -} - - -/* - * Function name : i2ohba_i_polled_cmd_start() - * - * Return Values : TRAN_ACCEPT if transaction was accepted - * TRAN_BUSY if I/O could not be started - * TRAN_ACCEPT if I/O timed out, pkt fields indicate error - * - * Description : Busy waits for I/O to complete or timeout. - * NOTE: This function returns void because the cmd - * has already started in scsi_start() before this - * function is called. So no need to return rval. - * - * Context : Can be called from different kernel process threads. - * Can be called by interrupt thread. - */ -static void -i2ohba_i_polled_cmd_start(struct i2ohba *i2ohba, struct i2ohba_cmd *sp) -{ - int delay_loops; - struct scsi_pkt *pkt = CMD2PKT(sp); - - ASSERT(I2OHBA_MUTEX_OWNED(i2ohba) == 0 || ddi_in_panic()); - - /* - * set timeout to SCSI_POLL_TIMEOUT for non-polling - * commands that do not have this field set - */ - if (pkt->pkt_time == 0) { - pkt->pkt_time = SCSI_POLL_TIMEOUT; - } - - ASSERT(pkt->pkt_flags & FLAG_NOINTR); - - delay_loops = I2OHBA_TIMEOUT_DELAY( - (pkt->pkt_time + (2 * I2OHBA_GRACE)), - I2OHBA_NOINTR_POLL_DELAY_TIME); - - /* - * busy wait for command to finish - * ie. till CFLAG_COMPLETED is set - */ - while ((sp->cmd_flags & CFLAG_COMPLETED) == 0) { - drv_usecwait(I2OHBA_NOINTR_POLL_DELAY_TIME); - if (--delay_loops <= 0) { - - if ((i2ohba_scsi_reset(&pkt->pkt_address, - RESET_TARGET)) == 0) { - mutex_enter(I2OHBA_REQ_MUTEX(i2ohba)); - i2ohba_i_fatal_error(i2ohba); - mutex_exit(I2OHBA_REQ_MUTEX(i2ohba)); - } - pkt->pkt_reason = CMD_TIMEOUT; - pkt->pkt_statistics |= STAT_BUS_RESET | - STAT_TIMEOUT; - sp->cmd_flags = ((sp->cmd_flags & - ~CFLAG_IN_TRANSPORT) & ~CFLAG_DELAY_TIMEOUT) - | CFLAG_COMPLETED | CFLAG_FINISHED; - i2ohba->i2ohba_counter--; - break; - } - } - - ASSERT(I2OHBA_MUTEX_OWNED(i2ohba) == 0 || ddi_in_panic()); - -} - - - -/* - * Function name : i2ohba_i_watch() - * - * Return Values : none - * Description : I2OHBA deadman timer routine. - * - * Given that the i2ohba's request queue is double link list - * in FIFO fashion, the tail should be pointing at the oldest - * cmd. However, each command has different timeout value set - * by the target driver, if any of them has timeout then we - * will call fatal_error(). - * - * A hung i2ohba controller is detected by failure to complete - * cmds within a timeout interval (including grace period for - * i2ohba error recovery). All target error recovery is handled - * directly by the i2ohba. - * - * If i2ohba hungs, restart by resetting the i2ohba's HBA/BUS and - * flushing the double linked list (via i2ohba_i_qflush()). - * - * Tagged queueing gives us other headaches since we cannot know - * exactly when a command starts. For example, a command with a - * 2-hour timeout, will cause a second command with a 60-second timeout - * to be timed-out. We won't worry about it now, but will later - * - * Context : Can be called by timeout thread. - */ - -static void -i2ohba_i_watch(void *arg) -{ - struct i2ohba *i2ohba = (struct i2ohba *)arg; - clock_t cur_lbolt; - clock_t deadline; - struct i2ohba_cmd *sp; - struct scsi_pkt *pkt; - - - if (i2ohba->i2ohba_shutdown) { - return; - } - - I2OHBA_MUTEX_ENTER(i2ohba); - - if ((cur_lbolt = ddi_get_lbolt()) != 0) { - for (sp = i2ohba->i2ohba_reqtail; sp != NULL; - sp = sp->cmd_backw) { - pkt = CMD2PKT(sp); - deadline = sp->cmd_deadline; - if ((deadline - cur_lbolt <= 0) && (pkt->pkt_time)) { - if (!(sp->cmd_flags & CFLAG_DELAY_TIMEOUT)) { - /* report time out */ - i2ohba_i_log(NULL, CE_CONT, - "?i2ohba_i_watch: " - "Exend cmd timeout on target %d.%d", - TGT(sp), LUN(sp)); - /* reset timeout vaule for delay */ - sp->cmd_deadline = cur_lbolt + - (clock_t)(pkt->pkt_time * 192); - /* set DELAY_TIMEOUT indicator */ - sp->cmd_flags |= CFLAG_DELAY_TIMEOUT; - /* set throttle on */ - i2ohba->i2ohba_throttle++; - } else { - i2ohba_i_req_remove(i2ohba, sp); - pkt->pkt_reason = CMD_TIMEOUT; - pkt->pkt_statistics |= STAT_TIMEOUT; - sp->cmd_flags = ((sp->cmd_flags - & ~CFLAG_DELAY_TIMEOUT) - & ~CFLAG_IN_TRANSPORT) - | CFLAG_COMPLETED | CFLAG_FINISHED; - i2ohba_i_log(NULL, CE_WARN, - "?i2ohba_i_watch: " - "Cmd timeout on target %d.%d", - TGT(sp), LUN(sp)); - I2OHBA_MUTEX_EXIT(i2ohba); - if (((pkt->pkt_flags & FLAG_NOINTR) - == 0) && pkt->pkt_comp) { - (*pkt->pkt_comp)(pkt); - } - I2OHBA_MUTEX_ENTER(i2ohba); - } - } - } - - DEBUGF(2, (CE_CONT, "?throttle=%d", i2ohba->i2ohba_throttle)); - if ((i2ohba->i2ohba_reqtail == NULL) && - (i2ohba->i2ohba_reqhead == NULL)) { - i2ohba->i2ohba_throttle = 0; - } - - } - - if (i2ohba->i2ohba_need_prop_update) { - int i; - - for (i = 0; i < N_I2OHBA_TARGETS_WIDE; i++) { - if (i2ohba->i2ohba_need_prop_update & (1 << i)) { - i2ohba_i_update_props(i2ohba, i); - } - } - - i2ohba->i2ohba_need_prop_update = 0; - - } - - /* - * Set up next timeout - */ - i2ohba->i2ohba_timeout_id = timeout(i2ohba_i_watch, i2ohba, - i2ohba_tick); - I2OHBA_MUTEX_EXIT(i2ohba); -} - - - -/* - * Function name : i2ohba_i_fatal_error() - * - * Return Values : none - * - * Description : - * Isp fatal error recovery: - * Reset the i2o and flush the active queues and attempt restart. - * This should only happen in case of a firmware bug or hardware - * death. Flushing is from backup queue as I2O cannot be trusted. - * - * Context : Can be called from different kernel process threads. - * Can be called by interrupt thread. - * i2ohba_request_mutex is held. - */ -static void -i2ohba_i_fatal_error(struct i2ohba *i2ohba) -{ - /* - * hold off starting new requests by grabbing the request mutex - */ - ASSERT(I2OHBA_MUTEX_OWNED(i2ohba)); - - /* - * If shutdown flag is set than no need to do - * fatal error recovery. - */ - if (i2ohba->i2ohba_shutdown) { - return; - } - - i2ohba_i_log(NULL, CE_WARN, "?i2ohba_i_fatal_error: " - "Fatal error, resetting interface"); - - i2ohba_i_print_state(i2ohba); - - (void) i2ohba_i_reset_interface(i2ohba, I2OHBA_FORCE_BUS_RESET); - - i2ohba_i_qflush(i2ohba, (uint16_t)0, (uint16_t)N_I2OHBA_TARGETS_WIDE); - - (void) scsi_hba_reset_notify_callback(I2OHBA_REQ_MUTEX(i2ohba), - &i2ohba->i2ohba_reset_notify_listf); - - ASSERT(I2OHBA_MUTEX_OWNED(i2ohba)); -} - - -/* - * Function name : i2ohba_i_qflush() - * - * Return Values : none - * Description : - * Flush i2ohba queues over range specified - * from start_tgt to end_tgt. Flushing goes from oldest to newest - * to preserve some cmd ordering. - * This is used for i2o crash recovery as normally i2o takes - * care of target or bus problems. - * - * Context : Can be called from different kernel process threads. - * i2ohba_i_fatal_error() - * i2ohba_i_reset_interface() - * Can be called by interrupt thread. - */ -static void -i2ohba_i_qflush(struct i2ohba *i2ohba, uint16_t start_tgt, uint16_t end_tgt) -{ - struct i2ohba_cmd *sp; - struct scsi_pkt *pkt; - - ASSERT(start_tgt <= end_tgt); - ASSERT(I2OHBA_MUTEX_OWNED(i2ohba)); - - - /* - * If flushing active queue, start with current free slot - * ie. oldest request, to preserve some order. - */ - sp = i2ohba->i2ohba_reqtail; - for (; sp != NULL; sp = i2ohba->i2ohba_reqtail->cmd_backw) { - if ((TGT(sp) >= start_tgt) && (TGT(sp) <= end_tgt)) { - - pkt = CMD2PKT(sp); - pkt->pkt_reason = CMD_RESET; - pkt->pkt_statistics |= STAT_DEV_RESET; - (void) i2ohba_i_req_remove(i2ohba, sp); - sp->cmd_flags |= CFLAG_FINISHED; - sp->cmd_flags = ((sp->cmd_flags & ~CFLAG_IN_TRANSPORT) - & ~CFLAG_DELAY_TIMEOUT) | CFLAG_COMPLETED; - i2ohba->i2ohba_counter--; - if (((pkt->pkt_flags & FLAG_NOINTR) == 0) && - pkt->pkt_comp) { - (*pkt->pkt_comp)(pkt); - } - - } - } - - ASSERT(I2OHBA_MUTEX_OWNED(i2ohba)); -} - - -/* - * Function name : i2ohba_scsi_abort() - * - * Return Values : 0 - abort failed - * 1 - abort succeeded - * Description : - * SCSA interface routine to abort pkt(s) in progress. - * Abort the pkt specified or NULL pkt, abort ALL pkts. - * - * Context : Can be called from different kernel process threads. - * Can be called by interrupt thread. - */ -static int -i2ohba_scsi_abort(struct scsi_address *ap, struct scsi_pkt *pkt) -{ - struct i2ohba *i2ohba = ADDR2I2OHBA(ap); - struct i2ohba_cmd *sp = PKT2CMD(pkt); - uint16_t arg, tid; - int rval = 0; - - ASSERT(mutex_owned(I2OHBA_REQ_MUTEX(i2ohba)) == 0 || ddi_in_panic()); - - arg = (uint16_t)ap->a_target; - - if (i2ohba->i2ohba_tgt_id_map[arg] == NULL) - return (rval); - - tid = i2ohba->i2ohba_tgt_id_map[arg]->tid; - - /* - * hold off new requests, we need the req mutex anyway so noone - * can access the queue. - */ - I2OHBA_MUTEX_ENTER(i2ohba); - - i2ohba_i_log(NULL, CE_CONT, "?i2ohba_scsi_abort: " - "aborting pkt 0x%p", (void *)pkt); - - - if (pkt) { - if (i2ohba_i_reset_abort(i2ohba, tid, I2O_SCSI_SCB_ABORT, sp)) { - I2OHBA_MUTEX_EXIT(i2ohba); - return (0); - } - } else { - if (i2ohba_i_reset_abort(i2ohba, tid, I2O_SCSI_SCB_ABORT, 0)) { - I2OHBA_MUTEX_EXIT(i2ohba); - return (0); - } - } - - I2OHBA_MUTEX_EXIT(i2ohba); - return (1); -} - - -/* - * Function name : i2ohba_scsi_reset() - * - * Return Values : 0 - reset failed - * 1 - reset succeeded - * Description : - * SCSA interface routine to perform scsi resets on either - * a specified target or the bus (default). - * - * Context : Can be called from different kernel process threads. - * Can be called by interrupt thread. - */ -static int -i2ohba_scsi_reset(struct scsi_address *ap, int level) -{ - struct i2ohba *i2ohba = ADDR2I2OHBA(ap); - uint16_t arg, tid; - int rval = 0; - - ASSERT(mutex_owned(I2OHBA_REQ_MUTEX(i2ohba)) == 0 || ddi_in_panic()); - - arg = (uint16_t)ap->a_target; - - if (i2ohba->i2ohba_tgt_id_map[arg] == NULL) - return (rval); - - tid = i2ohba->i2ohba_tgt_id_map[arg]->tid; - - I2OHBA_MUTEX_ENTER(i2ohba); - /* - * hold off new requests, we need the req mutex. - */ - - if (level == RESET_TARGET) { - i2ohba_i_log(NULL, CE_CONT, - "?i2ohba_scsi_reset: reset target %d", ap->a_target); - - if (i2ohba_i_reset_abort(i2ohba, tid, - I2O_SCSI_DEVICE_RESET, 0)) { - return (rval); - } - } else { - i2ohba_i_log(NULL, CE_CONT, "?i2ohba_scsi_reset: reset bus"); - - tid = i2ohba->i2ohba_tid; - if (i2ohba_i_reset_abort(i2ohba, tid, I2O_HBA_BUS_RESET, 0)) { - return (rval); - } - (void) scsi_hba_reset_notify_callback( - I2OHBA_REQ_MUTEX(i2ohba), - &i2ohba->i2ohba_reset_notify_listf); - /* wait for 3 sec after a reset */ - drv_usecwait((clock_t)i2ohba->i2ohba_scsi_reset_delay * 1000); - } - I2OHBA_MUTEX_EXIT(i2ohba); - return (1); -} - -/* - * Function name: i2ohba_i_reset_abort() - * - * Return Values: 0 - success - * -1 - fail reset - * - * Description : - * Reset either the HBA Adpter or Bus Reset - * This function is called from i2ohba_i_reset_interface() - * i2ohba_scsi_abort() - * i2ohba_scsi_reset() - * - * Context : Can be called from different kernel process threads. - * Can not be called by interrupt thread because it - * waits on the reply message. - */ -static int -i2ohba_i_reset_abort(struct i2ohba *i2ohba, uint16_t tid, int action, - struct i2ohba_cmd *cmd) -{ - int rval = -1; - i2o_message_frame_t *msgptr; - i2o_scsi_scb_abort_message_t *abortmsg; - i2o_msg_handle_t msg_handle; - ddi_acc_handle_t acc_handle; - struct i2ohba_util *sp; - - if (i2o_msg_alloc(i2ohba->i2ohba_iophdl, I2O_MSG_SLEEP, NULL, - (void *)&msgptr, &msg_handle, &acc_handle) != DDI_SUCCESS) { - i2ohba_i_log(NULL, CE_WARN, "?i2ohba_i_reset_abort: " - "i2o_msg_alloc failed"); - return (rval); - } - - if ((action == I2O_SCSI_SCB_ABORT) && (cmd == NULL)) - action = I2O_SCSI_DEVICE_RESET; - - abortmsg = (i2o_scsi_scb_abort_message_t *)msgptr; - /* - * construct a i2o_hba_bus_reset_message - */ - abortmsg->StdMessageFrame.VersionOffset = 0x01; - abortmsg->StdMessageFrame.MsgFlags = 0; - if (action == I2O_SCSI_SCB_ABORT) - ddi_put16(acc_handle, &abortmsg->StdMessageFrame.MessageSize, - sizeof (i2o_scsi_scb_abort_message_t) >> 2); - else - ddi_put16(acc_handle, &abortmsg->StdMessageFrame.MessageSize, - sizeof (i2o_scsi_device_reset_message_t) >> 2); - put_msg_TargetAddress(&abortmsg->StdMessageFrame, tid, acc_handle); - put_msg_InitiatorAddress(&abortmsg->StdMessageFrame, I2O_OSM_TID, - acc_handle); - put_msg_Function(&abortmsg->StdMessageFrame, action, acc_handle); - ddi_put32(acc_handle, - (uint32_t *)&abortmsg->StdMessageFrame.InitiatorContext, - (uint32_t)i2ohba_utilmsg_comp); - - /* - * allocating synchronized status buffer - */ - sp = kmem_alloc(sizeof (struct i2ohba_util), KM_SLEEP); - - ddi_put32(acc_handle, &abortmsg->TransactionContext, - (uint32_t)(uintptr_t)sp); - - if (cmd) - ddi_put32(acc_handle, &abortmsg->TransactionContextToAbort, - (uint32_t)(uintptr_t)cmd); - - /* - * initialized a mutex and cond variable to - * send message to IOP, and wait for it to signal back - */ - sp->mutex = I2OHBA_RESET_MUTEX(i2ohba); - sp->cv = I2OHBA_RESET_CV(i2ohba); - mutex_enter(sp->mutex); - sp->wakeup = UTIL_MSG_SLEEP; - sp->status = 0; - (void) i2o_msg_send(i2ohba->i2ohba_iophdl, msgptr, msg_handle); - while (!sp->wakeup) - cv_wait(sp->cv, sp->mutex); - mutex_exit(sp->mutex); - - /* - * process reply message - */ - - switch (sp->status) { - case I2O_REPLY_STATUS_SUCCESS: - rval = 0; - break; - default: - /* - * Failed the reset for now, - * we can also parse the AdapterStatus - * and retry if needed - */ - break; - } - -cleanup: - if (sp) - kmem_free(sp, sizeof (struct i2ohba_util)); - - return (rval); -} - - -/* - * Function name : i2ohba_i_reset_interface() - * - * Return Values : 0 - success - * -1 - hw failure - * - * Description : - * Master reset routine for hardware/software. Resets softc struct, - * i2ohba; and scsi bus and the scsi adapter. The works! - * This function is called from i2ohba_attach with no mutexes held or - * from i2ohba_i_fatal_error with request mutex held - * - * NOTE: it is up to the caller to flush the response queue - * - * Context : Can be called from different kernel process threads. - * i2ohba_attach() - single thread, no mutex held - * i2ohba_i_fatal_error() - * Can be called by interrupt thread. - */ -static int -i2ohba_i_reset_interface(struct i2ohba *i2ohba, int action) -{ - int i; - int rval = -1; - - /* - * Handle reset recovery; reset the bus before we reset the - * adapter chip - */ - /* - * send command Bus Reset - */ - DEBUGF(1, (CE_CONT, "Resetting i2o SCSI BUS")); - - if (action == I2OHBA_FORCE_BUS_RESET) { - if (i2ohba_i_reset_abort(i2ohba, i2ohba->i2ohba_tid, - I2O_HBA_BUS_RESET, 0)) { - i2ohba_i_log(NULL, CE_WARN, - "?i2ohba_i_reset_interface: bus reset failed"); - goto cleanup; - } - (void) scsi_hba_reset_notify_callback( - I2OHBA_REQ_MUTEX(i2ohba), - &i2ohba->i2ohba_reset_notify_listf); - drv_usecwait((clock_t)i2ohba->i2ohba_scsi_reset_delay * 1000); - } - - /* - * Handle resetting i2o host adapter. - */ - DEBUGF(1, (CE_CONT, "Resetting i2o SCSI Host Adapter")); - - /* - * Reset the i2o host adapter. - */ - if (i2ohba_i_reset_abort(i2ohba, i2ohba->i2ohba_tid, - I2O_HBA_ADAPTER_RESET, 0)) { - i2ohba_i_log(NULL, CE_WARN, "?i2ohba_i_reset_interface: " - "adapter reset failed"); - goto cleanup; - } - drv_usecwait((clock_t)i2ohba->i2ohba_scsi_reset_delay * 1000); - - - /* - * set Initiator SCSI ID using utilparamset - */ - -/* - * DEBUGF(1, (CE_CONT, "Initializing SCSI HBA ID")); - * - * i = i2ohba->i2ohba_initiator_id; - * if (i2ohba_utilparamset_msg(i2ohba, 7, i2ohba->i2ohba_tid, - * I2O_HBA_SCSI_CONTROLLER_INFO_GROUP_NO, 0x4, i) != 0) { - * i2ohba_i_log(NULL, CE_WARN, "?i2ohba_i_reset_interface: " - * "resetting initiator id failed"); - * goto cleanup; - * } - * - */ - - /* - * Update sync/offset from i2ohba utilparmas to - * global per target sync area. - */ - DEBUGF(1, (CE_CONT, "Initializing i2ohba capabilities")); - - for (i = 0; i < N_I2OHBA_TARGETS_WIDE; i++) { - (void) i2ohba_i_updatesync(i2ohba, i); - } - rval = 0; - -cleanup: - if (rval) { - DEBUGF(1, (CE_WARN, "reset interface failed")); - i2ohba->i2ohba_shutdown = 1; - DEBUGF(1, (CE_WARN, "interface going offline")); - i2ohba_i_qflush(i2ohba, (uint16_t)0, - (uint16_t)N_I2OHBA_TARGETS_WIDE); - } - - return (rval); -} - - - -static void -i2ohba_i_print_state(struct i2ohba *i2ohba) -{ - char buf[128]; - int i; - - - /* - * Print out sync scsi info and suppress trailing zero - * period and offset entries. - */ - if (i2ohba->i2ohba_scsi_options & SCSI_OPTIONS_SYNC) { - (void) sprintf(buf, "period/offset:"); - for (i = 0; i < N_I2OHBA_TARGETS; i++) { - (void) sprintf(&buf[strlen(buf)], " %d/%d", - i2ohba->i2ohba_synch[i], i2ohba->i2ohba_offset[i]); - } - DEBUGF(1, (CE_CONT, buf)); - (void) sprintf(buf, "period/offset:"); - for (i = N_I2OHBA_TARGETS; i < N_I2OHBA_TARGETS_WIDE; i++) { - (void) sprintf(&buf[strlen(buf)], " %d/%d", - i2ohba->i2ohba_synch[i], i2ohba->i2ohba_offset[i]); - } - DEBUGF(1, (CE_CONT, buf)); - } -} - -/* - * Function name: i2ohba_utilparamset_msg() - * - * Return Values: 0 - success - * -1 - set prarmeter failed - * Description : common UtilParamSet function. - * However, only one param at a time. Pass in - * the Tid, GroupNumber, and the FieldIdx, and - * value, then compose the Message frame, - * then send it off through i2o_message_send(). - * - * Message Format: - * - * Building a param_set message requires: - * Buffer#1 SGL-immediate data (Request) - * 1. i2o_param_operations_list_header_t(1W) - * u16 OperationCount (1) - * u16 Reserved - * 2. i2o_param_operation_specific_template_t(2W) - * u16 Operation (FIELD_SET) - * u16 GroupNumber (group) - * u16 FieldCount 0x1 - * u16 FieldIdx (idx) - * u16 value of idx - * - * Buffer#2 SGL-Simple addressing (Reply) - * 1. i2o_param_results_list_header_t(1W) - * u16 ResultCount - * u16 Reserved - * 2. i2o_param_modify_operation_result_t(9W) - * u16 BlockSize - * u8 BlockStatus - * u8 ErrorInfoSize - * ... ErrorInformation - * - * - * Context : Can be called from i2ohba_i_reset_interface() - * Can be called from i2ohba_i_updatecap() or - * i2ohba_scsi_setcap() - */ - - -static int -i2ohba_utilparamset_msg(struct i2ohba *i2ohba, int tgt, uint16_t tid, - uint16_t group, uint16_t idx, uint16_t value) -{ - - i2o_setparam_t *msgptr; - i2o_msg_handle_t msg_handle; - ddi_acc_handle_t acc_handle; - struct i2ohba_util *sp = NULL; - uint_t count; - int rval = -1; - int bound = 0; - uint16_t allocmsgsize; - - - /* - * allocate a message frame - */ - if (i2o_msg_alloc(i2ohba->i2ohba_iophdl, I2O_MSG_SLEEP, - NULL, (void *)&msgptr, &msg_handle, &acc_handle) - != DDI_SUCCESS) { - i2ohba_i_log(NULL, CE_WARN, "?i2ohba_utilparamset_msg: " - "i2o_msg_alloc failed"); - return (rval); - } - - /* - * To get the actual allocation msg size - */ - allocmsgsize = (ddi_get16(acc_handle, &msgptr->MessageSize) << 2); - - if (allocmsgsize < sizeof (i2o_setparam_t)) { - i2ohba_i_log(NULL, CE_WARN, "?i2ohba_utilparamset_msg: " - "msg size alloc is smaller than what setparam needed"); - goto fail; - } - - /* - * Construct a utilparamset message - */ - msgptr->VersionOffset = ContextSize32; - msgptr->MsgFlags = 0; - ddi_put16(acc_handle, &msgptr->MessageSize, - (sizeof (i2o_setparam_t) >> 2)); - put_msg_TargetAddress(msgptr, tid, acc_handle); - put_msg_InitiatorAddress(msgptr, I2O_OSM_TID, acc_handle); - put_msg_Function(msgptr, I2O_UTIL_PARAMS_SET, acc_handle); - ddi_put32(acc_handle, (uint32_t *)&msgptr->InitiatorContext, - (uint32_t)i2ohba_utilmsg_comp); - - /* - * allocating sychronize status buffer - */ - sp = kmem_alloc(sizeof (struct i2ohba_util), KM_SLEEP); - - ddi_put32(acc_handle, &msgptr->TransactionContext, - (uint32_t)(uintptr_t)sp); - - /* - * First message buffer's SGL and operation parameters - */ - - /* - * Buf1 SGL header: - * Immediate Data for the operation - */ - put_flags_count_Flags(&msgptr->FlagsCount1, - I2O_SGL_FLAGS_IMMEDIATE_DATA_ELEMENT - | I2O_SGL_FLAGS_END_OF_BUFFER, acc_handle); - put_flags_count_Count(&msgptr->FlagsCount1, ONE_PARAM_BLOCK, - acc_handle); - - /* - * Fill in the modify operation param for in the sgl1 payload - */ - - ddi_put16(acc_handle, &msgptr->OperationCount, 1); - ddi_put16(acc_handle, &msgptr->Operation, - I2O_PARAMS_OPERATION_FIELD_SET); - ddi_put16(acc_handle, &msgptr->GroupNumber, group); - ddi_put16(acc_handle, &msgptr->FieldCount, 0x1); - ddi_put16(acc_handle, &msgptr->FieldIdx, idx); - ddi_put16(acc_handle, &msgptr->Value, value); - - - /* - * Buf2 SGL header: - * Simple addressing - * 1. allocate the buffer for reply msg - * 2. setup the SGL header - */ - - sp->i2ohba_util_buffer = NULL; - - if (ddi_dma_alloc_handle(i2ohba->i2ohba_dip, &i2ohba_dmasgl_attr, - DDI_DMA_SLEEP, NULL, &sp->dmahandle) != - DDI_SUCCESS) { - i2ohba_i_log(NULL, CE_WARN, "?i2ohba_utilparam_set: " - "cannot alloc dma handle"); - goto fail; - } - bound++; - if (ddi_dma_mem_alloc(sp->dmahandle, (size_t) - sizeof (i2o_param_results_list_header_t) + (size_t) - sizeof (i2o_param_modify_operation_result_t), - &dev_attr, DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, - (caddr_t *)&sp->i2ohba_util_buffer, &sp->rlen, - &sp->dma_acc_handle) != DDI_SUCCESS) { - i2ohba_i_log(NULL, CE_WARN, "?i2ohba_utilparamset_msg: " - "cannot allocate param buffer"); - goto fail; - } - bound++; - put_flags_count_Flags(&msgptr->FlagsCount2, - I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT | - I2O_SGL_FLAGS_END_OF_BUFFER | - I2O_SGL_FLAGS_LAST_ELEMENT, acc_handle); - - put_flags_count_Count(&msgptr->FlagsCount2, sp->rlen, acc_handle); - - - if (ddi_dma_addr_bind_handle(sp->dmahandle, NULL, - sp->i2ohba_util_buffer, (size_t) - sizeof (i2o_param_results_list_header_t) + (size_t) - sizeof (i2o_param_modify_operation_result_t) + (size_t) - sizeof (i2o_scsi_device_info_scalar_t), - DDI_DMA_RDWR|DDI_DMA_STREAMING, DDI_DMA_SLEEP, - NULL, &sp->dmacookie, &count) != DDI_DMA_MAPPED) { - /* - * currently assume simple - * addring with one physical - * continuous address buffer. - */ - i2ohba_i_log(NULL, CE_WARN, "?i2ohba_utilparamset_msg: " - "cannot bind buffer"); - goto fail; - } - - ddi_put32(acc_handle, &msgptr->PhysicalAddress, - (uint32_t)sp->dmacookie.dmac_address); - /* - * initialized a mutex and condvariable to - * send message to IOP, and wait for it - * to signal back - */ - sp->mutex = I2OHBA_UTILPARAM_MUTEX(i2ohba, tgt); - sp->cv = I2OHBA_UTILPARAM_CV(i2ohba, tgt); - mutex_enter(sp->mutex); - sp->wakeup = UTIL_MSG_SLEEP; - sp->status = 0; - (void) i2o_msg_send(i2ohba->i2ohba_iophdl, msgptr, msg_handle); - while (!sp->wakeup) - cv_wait(sp->cv, sp->mutex); - mutex_exit(sp->mutex); - - /* clear msg pointer */ - msgptr = NULL; - - /* - * process the data - */ - switch (sp->status) { - - i2o_setparam_reply_t *result; - uint16_t count; - uint8_t blockstatus, errinfosize; - - case I2O_REPLY_STATUS_SUCCESS: - /* - * since the reply is successful, will check - * for the opeation reulsts - */ - result = (i2o_setparam_reply_t *)sp->i2ohba_util_buffer; - count = ddi_get16(sp->dma_acc_handle, - &result->ResultCount); - if (!count) { - i2ohba_i_log(NULL, CE_WARN, - "?i2ohba_utilparamset_msg: No Results"); - break; - } - - blockstatus = ddi_get8(sp->dma_acc_handle, - &result->BlockStatus); - - errinfosize = ddi_get8(sp->dma_acc_handle, - &result->ErrorInfoSize); - - if ((blockstatus != 0) || (errinfosize != 0)) { - i2ohba_i_log(NULL, CE_WARN, - "?i2ohba_utilparamset_msg: Error " - "occured during Modify Operation"); - /* - * retrived errorinfo and possibily retry - * XXLWLXX - */ - break; - } - rval = 0; - break; - - default: - rval = -1; - break; - } - -fail: - - if (sp) { - if (bound) { - (void) ddi_dma_unbind_handle(sp->dmahandle); - if (bound > 1) - (void) ddi_dma_mem_free(&sp->dma_acc_handle); - (void) ddi_dma_free_handle(&sp->dmahandle); - } - kmem_free(sp, sizeof (struct i2ohba_util)); - } - - /* return MFA to IOP */ - if (msgptr) { - msgptr->VersionOffset = 0; - msgptr->MsgFlags = 0; - ddi_put16(acc_handle, &msgptr->MessageSize, 3); - put_msg_TargetAddress(msgptr, 0, acc_handle); - put_msg_InitiatorAddress(msgptr, 0, acc_handle); - put_msg_Function(msgptr, I2O_UTIL_NOP, acc_handle); - (void) i2o_msg_send(i2ohba->i2ohba_iophdl, msgptr, msg_handle); - } - return (rval); -} - -/* - * Function name: i2ohba_utilparamget_msg() - * - * Return Values: 0 - success - * -1 - get prarmeter failed - * - * Description : common UtilParamGet function. - * However, only one param at a time. Pass in - * the Tid, GroupNumber, and the FieldIdx, and - * value, then compose the Message frame, - * then send it off through i2o_message_send(). - * - * Message Format: - * - * building a param_get message requires - * Buffer#1 SGL-immediate data - * 1. i2o_param_operations_list_header_t(1W) - * u16 OperationCount - * u16 Reserved - * 2. i2o_param_operation_speicific_template_t(2W) - * u16 Operation (FIELD_GET) - * u16 GroupNumber - * u16 FieldCount 0xFFFF - * u16 Pad - * - * Buffer#2 SGL-Simple addressing - * Reply Message: - * 1. i2o_param_results_list_header_t(1W) - * u16 ResultCount - * u16 Reserved - * 2. i2o_param_read_operation_result_t(9W) - * u16 BlockSize - * u8 BlockStatus - * u8 ErrorInfoSize - * ... Total 8W for (ALL_PARAM_BLOCK) - * u32 Identifier - * u64 LUN - * ... - * OR Total 9 bytes (ONE_PARAM_BLOCK) - * u8 NegOffset - * u64 NegSynch - */ - -static int -i2ohba_utilparamget_msg(struct i2ohba *i2ohba, uint16_t tidx, char flag) -{ - - i2o_tid_scsi_ent_t *map = i2ohba->i2ohba_tid_scsi_map; - i2o_tid_scsi_ent_t **tgtmap = i2ohba->i2ohba_tgt_id_map; - - i2o_getsyncparam_t *msgptr; - i2o_msg_handle_t msg_handle; - ddi_acc_handle_t acc_handle; - struct i2ohba_util *sp = NULL; - uint_t count; - uint16_t allocmsgsize; - uint16_t tid; - int rval = -1; - int bound = 0; - - /* - * allocate a message frame - */ - if (i2o_msg_alloc(i2ohba->i2ohba_iophdl, I2O_MSG_SLEEP, - NULL, (void *)&msgptr, &msg_handle, &acc_handle) - != DDI_SUCCESS) { - i2ohba_i_log(NULL, CE_WARN, "?i2ohba_utilparamget_msg: " - "i2o_msg_alloc failed"); - return (rval); - } - - /* - * NOTE: - * "tidx" is either the entry number for the tid to scsi map - * or tidx is the target id, which needs tgt to id map to - * find the tid. - */ - if (flag == ALL_UTILPARAMS) { - tid = map[tidx].tid; - } else { - tid = tgtmap[tidx]->tid; - } - - /* - * To get the actual allocation msg - * size (in WORDS) - */ - allocmsgsize = (ddi_get16(acc_handle, &msgptr->MessageSize) << 2); - - - /* - * Construct a utilparamget message - */ - /* msgptr->VersionOffset = ContextSize32; */ - msgptr->VersionOffset = I2O_VERSION_11; - msgptr->MsgFlags = 0; - put_msg_TargetAddress(msgptr, tid, acc_handle); - put_msg_InitiatorAddress(msgptr, I2O_OSM_TID, acc_handle); - put_msg_Function(msgptr, I2O_UTIL_PARAMS_GET, acc_handle); - ddi_put32(acc_handle, - (uint32_t *)&msgptr->InitiatorContext.initiator_context_32bits, - (uint32_t)i2ohba_utilmsg_comp); - /* - * allocating sychroniz status buffer - */ - sp = kmem_alloc(sizeof (struct i2ohba_util), KM_SLEEP); - - ddi_put32(acc_handle, &msgptr->TransactionContext, - (uint32_t)(uintptr_t)sp); - - /* - * Buf1 SGL header: - * Immediate Data - */ - put_flags_count_Flags(&msgptr->FlagsCount1, - I2O_SGL_FLAGS_IMMEDIATE_DATA_ELEMENT | - I2O_SGL_FLAGS_END_OF_BUFFER, acc_handle); - - /* - * Fill in the read operation param for - * in the payload - */ - - ddi_put16(acc_handle, &msgptr->OperationCount, 1); - - ddi_put16(acc_handle, &msgptr->Operation, - I2O_PARAMS_OPERATION_FIELD_GET); - - ddi_put16(acc_handle, &msgptr->GroupNumber, - I2O_SCSI_DEVICE_INFO_GROUP_NO); - - /* - * End of message sending - */ - - /* - * Buf2 SGL header: - * Simple Addressing - * 1. allocating the buffer - * 2. set up the SGL header - */ - - sp->i2ohba_util_buffer = NULL; - - if (ddi_dma_alloc_handle(i2ohba->i2ohba_dip, &i2ohba_dmasgl_attr, - DDI_DMA_SLEEP, NULL, &sp->dmahandle) != - DDI_SUCCESS) { - i2ohba_i_log(NULL, CE_WARN, "?i2ohba_utilparamget_msg: " - "cannot alloc dma handle"); - goto fail; - } - bound++; - if (flag == ALL_UTILPARAMS) { - - if (allocmsgsize < sizeof (i2o_getallparam_t)) - return (rval); - - if (ddi_dma_mem_alloc(sp->dmahandle, (size_t) - sizeof (i2o_getallparam_reply_t), &dev_attr, - DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, - (caddr_t *)&sp->i2ohba_util_buffer, &sp->rlen, - &sp->dma_acc_handle) != DDI_SUCCESS) { - i2ohba_i_log(NULL, CE_WARN, - "?i2ohba_utilparamget_msg: " - "cannot allocate param buffer"); - goto fail; - } - bound++; - /* StdMessageFrame */ - ddi_put16(acc_handle, &msgptr->MessageSize, - (sizeof (i2o_getallparam_t) >> 2)); - - /* i2o_sge_immediate_data_element */ - put_flags_count_Count(&msgptr->FlagsCount1, ALL_PARAM_BLOCK, - acc_handle); - - /* i2o_param_operation_all_template */ - ddi_put16(acc_handle, &msgptr->FieldCount, 0xFFFF); - - /* i2o_sge_simple_element */ - put_flags_count_Flags( - &((i2o_getallparam_t *)msgptr)->FlagsCount2, - I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT | - I2O_SGL_FLAGS_END_OF_BUFFER | - I2O_SGL_FLAGS_LAST_ELEMENT, acc_handle); - - put_flags_count_Count( - &((i2o_getallparam_t *)msgptr)->FlagsCount2, - sp->rlen, acc_handle); - - if (ddi_dma_addr_bind_handle(sp->dmahandle, NULL, - sp->i2ohba_util_buffer, (size_t) - sizeof (i2o_getallparam_reply_t), - DDI_DMA_READ|DDI_DMA_STREAMING, DDI_DMA_SLEEP, - NULL, &sp->dmacookie, &count) != DDI_SUCCESS) { - /* - * currently assume simple - * addring with one physical - * continuous address buffer. - */ - i2ohba_i_log(NULL, CE_WARN, - "?i2ohba_utilparamget_msg: " - "cannot bind buffer"); - goto fail; - } - - ddi_put32(acc_handle, - &((i2o_getallparam_t *)msgptr)->PhysicalAddress, - (uint32_t)sp->dmacookie.dmac_address); - - /* - * initialized the target param_mutex and cv. - * note: given that we don't have target id - * yet, (that is why we are here), we'll just - * use target[0]'s mutex & cv. - */ - sp->mutex = I2OHBA_UTILPARAM_MUTEX(i2ohba, 0); - sp->cv = I2OHBA_UTILPARAM_CV(i2ohba, 0); - } else { - if (allocmsgsize < sizeof (i2o_getsyncparam_t)) - return (rval); - - if (ddi_dma_mem_alloc(sp->dmahandle, (size_t) - sizeof (i2o_getsyncparam_reply_t), &dev_attr, - DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, - (void *)&sp->i2ohba_util_buffer, &sp->rlen, - &sp->dma_acc_handle) != DDI_SUCCESS) { - i2ohba_i_log(NULL, CE_WARN, - "?i2ohba_utilparamget_msg: " - "cannot allocate param buffer"); - goto fail; - } - bound++; - /* StdMessageFrame */ - ddi_put16(acc_handle, &msgptr->MessageSize, - (sizeof (i2o_getsyncparam_t) >> 2)); - - /* i2o_sge_immediate_data_element */ - put_flags_count_Count(&msgptr->FlagsCount1, ONE_PARAM_BLOCK, - acc_handle); - - /* i2o_param_operation_specific_template */ - ddi_put16(acc_handle, &msgptr->FieldCount, 0x0002); - ddi_put16(acc_handle, &msgptr->FieldIdx, 0x000A); - ddi_put16(acc_handle, &msgptr->FieldIdx, 0x0007); - - /* i2o_sge_simple_element */ - put_flags_count_Flags(&msgptr->FlagsCount2, - I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT | - I2O_SGL_FLAGS_END_OF_BUFFER | - I2O_SGL_FLAGS_LAST_ELEMENT, acc_handle); - - put_flags_count_Count(&msgptr->FlagsCount2, sp->rlen, - acc_handle); - - if (ddi_dma_addr_bind_handle(sp->dmahandle, NULL, - sp->i2ohba_util_buffer, (size_t) - sizeof (i2o_getsyncparam_reply_t), - DDI_DMA_RDWR|DDI_DMA_STREAMING, DDI_DMA_SLEEP, - NULL, &sp->dmacookie, &count) != DDI_DMA_MAPPED) { - /* - * currently assume simple - * addring with one physical - * continuous address buffer. - */ - i2ohba_i_log(NULL, CE_WARN, - "?i2ohba_utilparamget_msg: " - "cannot bind buffer"); - goto fail; - } - - ddi_put32(acc_handle, &msgptr->PhysicalAddress, - (uint32_t)sp->dmacookie.dmac_address); - - /* - * initialized the target param_mutex and cv - * tidx holds the target id number - */ - sp->mutex = I2OHBA_UTILPARAM_MUTEX(i2ohba, tidx); - sp->cv = I2OHBA_UTILPARAM_CV(i2ohba, tidx); - } - -#ifdef I2OHBA_DEBUG - DEBUGF(2, (CE_CONT, "\nmsgptr: 0x%p\n", (void *)msgptr)); - DEBUGF(2, (CE_CONT, "msgptr->VersionOffset: %x\n", - msgptr->VersionOffset)); - DEBUGF(2, (CE_CONT, "msgptr->MsgFlags: %x\n", msgptr->MsgFlags)); - DEBUGF(2, (CE_CONT, "msgptr->MessageSize: %x\n", ddi_get16(acc_handle, - &msgptr->MessageSize))); - DEBUGF(2, (CE_CONT, "msgptr->TargetAddress: %x\n", - get_msg_TargetAddress(msgptr, acc_handle))); - DEBUGF(2, (CE_CONT, "msgptr->InitiatorAddress: %x\n", - get_msg_InitiatorAddress(msgptr, acc_handle))); - DEBUGF(2, (CE_CONT, "msgptr->Function: %x\n", - get_msg_Function(msgptr, acc_handle))); - DEBUGF(2, (CE_CONT, "msgptr->InitContext: %x\n", - ddi_get32(acc_handle, - &msgptr->InitiatorContext.initiator_context_32bits))); - DEBUGF(2, (CE_CONT, "msgptr->TransContext: %x\n", - ddi_get32(acc_handle, &msgptr->TransactionContext))); - DEBUGF(2, (CE_CONT, "msgptr->OperationFlags: Resevered\n")); - DEBUGF(2, (CE_CONT, "msgptr->FlagsCount1.Flags: %x\n", - get_flags_count_Flags(&msgptr->FlagsCount1, acc_handle))); - DEBUGF(2, (CE_CONT, "msgptr->FlagsCount1.Count: %x\n", - get_flags_count_Count(&msgptr->FlagsCount1, acc_handle))); - DEBUGF(2, (CE_CONT, "msgptr->OperationCount: %x\n", - ddi_get16(acc_handle, &msgptr->OperationCount))); - DEBUGF(2, (CE_CONT, "msgptr->Operation: %x\n", - ddi_get16(acc_handle, &msgptr->Operation))); - DEBUGF(2, (CE_CONT, "msgptr->GroupNumber: %x\n", - ddi_get16(acc_handle, &msgptr->GroupNumber))); - DEBUGF(2, (CE_CONT, "msgptr->FieldCount: %x\n", - ddi_get16(acc_handle, &msgptr->FieldCount))); - DEBUGF(2, (CE_CONT, "msgptr->FlagsCount2.Flags: %x\n", - get_flags_count_Flags(&((i2o_getallparam_t *)msgptr)->FlagsCount2, - acc_handle))); - DEBUGF(2, (CE_CONT, "msgptr->FlagsCount2.Count: %x\n", - get_flags_count_Count(&((i2o_getallparam_t *)msgptr)->FlagsCount2, - acc_handle))); - DEBUGF(2, (CE_CONT, "msgptr->PhyAddr: %x\n", ddi_get32(acc_handle, - &((i2o_getallparam_t *)msgptr)->PhysicalAddress))); -#endif - /* - * initialized a mutex and condvariable to - * send message to IOP, and wait for it - * to signal back - */ - mutex_enter(sp->mutex); - sp->wakeup = UTIL_MSG_SLEEP; - sp->status = 0; - (void) i2o_msg_send(i2ohba->i2ohba_iophdl, msgptr, msg_handle); - while (!sp->wakeup) - cv_wait(sp->cv, sp->mutex); - mutex_exit(sp->mutex); - - msgptr = NULL; - - /* - * process the data - */ - switch (sp->status) { - case I2O_REPLY_STATUS_SUCCESS: - /* - * Success: - * 0) read the reply headers XXLWXX - * 1) copy buffer over to the map - * 2) unbind dma buffer - */ - - if (sp->i2ohba_util_buffer) { - uint_t tgtid; - - if (flag == ALL_UTILPARAMS) { - i2o_getallparam_reply_t *reply; - - reply = (i2o_getallparam_reply_t *) - sp->i2ohba_util_buffer; - map[tidx].scsi_info_scalar.DeviceType = - reply->DeviceType; - DEBUGF(2, (CE_CONT, "/tDeviceType:" - " 0x%x", reply->DeviceType)); - map[tidx].scsi_info_scalar.Flags = - reply->Flags; - DEBUGF(2, (CE_CONT, "/tFlags:" - " 0x%x", reply->Flags)); - map[tidx].scsi_info_scalar.Identifier = - tgtid = - ddi_get32(sp->dma_acc_handle, - &reply->Identifier); - DEBUGF(2, (CE_CONT, "/tSCSI Id: 0x%x", - tgtid)); - map[tidx].scsi_info_scalar.LunInfo[0] = 0; - map[tidx].scsi_info_scalar.QueueDepth = - ddi_get32(sp->dma_acc_handle, - &reply->QueueDepth); - DEBUGF(2, (CE_CONT, "/tQueueDepth: 0x%x", - map[tidx].scsi_info_scalar.QueueDepth)); - map[tidx].scsi_info_scalar.NegOffset = - reply->NegOffset; - DEBUGF(2, (CE_CONT, "/tQueueDepth: 0x%x", - reply->NegOffset)); - map[tidx].scsi_info_scalar.NegDataWidth = - reply->NegDataWidth; - DEBUGF(2, (CE_CONT, "/tNegDataWidth: 0x%x", - reply->NegDataWidth)); - map[tidx].scsi_info_scalar.NegSyncRate = - ddi_get64(sp->dma_acc_handle, - &reply->NegSyncRate); - DEBUGF(2, (CE_CONT, "/tNegSyncRate: 0x%x", - (uint32_t) - map[tidx].scsi_info_scalar.NegSyncRate)); - - tgtmap[tgtid] = &map[tidx]; - - } else { - i2o_getsyncparam_reply_t *reply; - - reply = (i2o_getsyncparam_reply_t *) - sp->i2ohba_util_buffer; - tgtmap[tidx]->scsi_info_scalar.NegSyncRate = - ddi_get64(sp->dma_acc_handle, - &reply->NegSyncRate); - DEBUGF(2, (CE_CONT, "/tNegSyncRate: 0x%x", - (uint32_t) - map[tidx].scsi_info_scalar.NegSyncRate)); - tgtmap[tidx]->scsi_info_scalar.NegOffset = - reply->NegOffset; - DEBUGF(2, (CE_CONT, "/tNegOffset: 0x%x", - reply->NegOffset)); - } - } - rval = 0; - break; - - case I2O_REPLY_STATUS_ERROR_NO_DATA_TRANSFER: - case I2O_REPLY_STATUS_ERROR_PARTIAL_TRANSFER: - default: - i2ohba_i_log(NULL, CE_WARN, "?I2O_PARAM_UTIL_GET on " - "Target %d failed", tidx); - break; - - } - -fail: - - if (sp) { - if (bound) { - (void) ddi_dma_unbind_handle(sp->dmahandle); - if (bound > 1) - (void) ddi_dma_mem_free(&sp->dma_acc_handle); - (void) ddi_dma_free_handle(&sp->dmahandle); - - } - kmem_free(sp, sizeof (struct i2ohba_util)); - } - - /* return MFA to IOP */ - if (msgptr) { - msgptr->VersionOffset = 0; - msgptr->MsgFlags = 0; - ddi_put16(acc_handle, &msgptr->MessageSize, 3); - put_msg_TargetAddress(msgptr, 0, acc_handle); - put_msg_InitiatorAddress(msgptr, 0, acc_handle); - put_msg_Function(msgptr, I2O_UTIL_NOP, acc_handle); - (void) i2o_msg_send(i2ohba->i2ohba_iophdl, msgptr, msg_handle); - } - - return (rval); -} - -/*PRINTFLIKE3*/ -static void -i2ohba_i_log(struct i2ohba *i2ohba, int level, char *fmt, ...) -{ - dev_info_t *dip; - va_list ap; - - ASSERT((mutex_owned(&i2ohba_log_mutex)) == 0 || ddi_in_panic()); - - if (i2ohba) { - dip = i2ohba->i2ohba_dip; - } else { - dip = 0; - } - - mutex_enter(&i2ohba_log_mutex); - va_start(ap, fmt); - (void) vsprintf(i2ohba_log_buf, fmt, ap); - va_end(ap); - - if (level == CE_WARN) { - scsi_log(dip, "i2o_scsi", level, "%s", i2ohba_log_buf); - } else { - scsi_log(dip, "i2o_scsi", level, "%s\n", i2ohba_log_buf); - } - mutex_exit(&i2ohba_log_mutex); -} |