3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * CDDL HEADER START
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * The contents of this file are subject to the terms of the
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * Common Development and Distribution License (the "License").
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * You may not use this file except in compliance with the License.
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * See the License for the specific language governing permissions
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * and limitations under the License.
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * When distributing Covered Code, include this CDDL HEADER in each
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * If applicable, add the following below this CDDL HEADER, with the
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * fields enclosed by brackets "[]" replaced with your own identifying
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * information: Portions Copyright [yyyy] [name of copyright owner]
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * CDDL HEADER END
9c57abc8d70cb139020be846baec0a9c4d9a73cdsrivijitha dugganapalli * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * Use is subject to license terms.
89b43686db1fe9681d80a7cf5662730cb9378caeBayard Bell * Copyright (c) 2011 Bayard G. Bell. All rights reserved.
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * sf - Solaris Fibre Channel driver
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * This module implements some of the Fibre Channel FC-4 layer, converting
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * from FC frames to SCSI and back. (Note: no sequence management is done
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * here, though.)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * Need to use the ugly RAID LUN mappings in FCP Annex D
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * to prevent SCSA from barfing. This *REALLY* needs to
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * be addressed by the standards committee.
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic int sf_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic int sf_scsi_bus_config(dev_info_t *parent, uint_t flag,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel ddi_bus_config_op_t op, void *arg, dev_info_t **childp);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic int sf_scsi_bus_unconfig(dev_info_t *parent, uint_t flag,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic int sf_scsi_tgt_init(dev_info_t *, dev_info_t *,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic void sf_scsi_tgt_free(dev_info_t *, dev_info_t *,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic int sf_pkt_alloc_extern(struct sf *, struct sf_pkt *,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel int, int, int);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic void sf_pkt_destroy_extern(struct sf *, struct sf_pkt *);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic struct scsi_pkt *sf_scsi_init_pkt(struct scsi_address *,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel struct scsi_pkt *, struct buf *, int, int, int, int, int (*)(), caddr_t);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic void sf_scsi_destroy_pkt(struct scsi_address *, struct scsi_pkt *);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic void sf_scsi_dmafree(struct scsi_address *, struct scsi_pkt *);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic void sf_scsi_sync_pkt(struct scsi_address *, struct scsi_pkt *);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic int sf_scsi_reset_notify(struct scsi_address *, int,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic int sf_scsi_get_name(struct scsi_device *, char *, int);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic int sf_scsi_get_bus_addr(struct scsi_device *, char *, int);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic int sf_cr_alloc(struct sf *, struct sf_pkt *, int (*)());
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic void sf_cr_free(struct sf_cr_pool *, struct sf_pkt *);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic int sf_kmem_cache_constructor(void *, void *, int);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic void sf_kmem_cache_destructor(void *, void *);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic void sf_statec_callback(void *, int);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic int sf_login(struct sf *, uchar_t, uchar_t, uint_t, int);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic int sf_els_transport(struct sf *, struct sf_els_hdr *);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic int sf_do_prli(struct sf *, struct sf_els_hdr *, struct la_els_logi *);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic int sf_do_adisc(struct sf *, struct sf_els_hdr *);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic int sf_do_reportlun(struct sf *, struct sf_els_hdr *,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic void sf_reportlun_callback(struct fcal_packet *);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic int sf_do_inquiry(struct sf *, struct sf_els_hdr *,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic struct fcal_packet *sf_els_alloc(struct sf *, uchar_t, int, int,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic struct sf_target *sf_create_target(struct sf *,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic struct sf_target *sf_lookup_target(struct sf *, uchar_t *, int);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic struct sf_target *sf_lookup_target(struct sf *, uchar_t *, int64_t);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic void sf_offline_target(struct sf *, struct sf_target *);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic void sf_create_devinfo(struct sf *, struct sf_target *, int);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic int sf_create_props(dev_info_t *, struct sf_target *, int);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic int sf_commoncap(struct scsi_address *, char *, int, int, int);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic int sf_getcap(struct scsi_address *, char *, int);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic int sf_setcap(struct scsi_address *, char *, int, int);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic int sf_abort(struct scsi_address *, struct scsi_pkt *);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic void sf_abort_all(struct sf *, struct sf_target *, int, int, int);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic int sf_start(struct scsi_address *, struct scsi_pkt *);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic int sf_start_internal(struct sf *, struct sf_pkt *);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic void sf_fill_ids(struct sf *, struct sf_pkt *, struct sf_target *);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic int sf_prepare_pkt(struct sf *, struct sf_pkt *, struct sf_target *);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic void sf_watch(void *);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic void sf_check_reset_delay(void *);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic int sf_target_timeout(struct sf *, struct sf_pkt *);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic void sf_unsol_els_callback(void *, soc_response_t *, caddr_t);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic struct sf_els_hdr *sf_els_timeout(struct sf *, struct sf_els_hdr *);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel/*PRINTFLIKE3*/
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic void sf_log(struct sf *, int, const char *, ...);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic int sf_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic struct sf_target *sf_get_target_from_dip(struct sf *, dev_info_t *);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic int sf_bus_get_eventcookie(dev_info_t *, dev_info_t *, char *,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic int sf_bus_add_eventcall(dev_info_t *, dev_info_t *,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel ddi_eventcookie_t, void (*)(), void *, ddi_callback_id_t *cb_id);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic int sf_bus_remove_eventcall(dev_info_t *devi, ddi_callback_id_t cb_id);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic int sf_bus_post_event(dev_info_t *, dev_info_t *,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic void sf_hp_daemon(void *);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * this is required to be able to supply a control node
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * where ioctls can be executed
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel 0, /* streamtab */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * autoconfiguration routines.
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel 0, /* refcnt */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel#define SF_NAME "FC-AL FCP Nexus Driver" /* Name of the module. */
193974072f41a843678abf5f61979c748687e66bSherry Moorestatic char sf_version[] = "1.72 08/19/2008"; /* version of the module */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel &mod_driverops, /* Type of module. This one is a driver */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel/* XXXXXX The following is here to handle broken targets -- remove it later */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel/* XXXXXX */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelint *sf_token = NULL; /* Must not be static or lint complains. */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel{ SF_EVENT_TAG_INSERT, FCAL_INSERT_EVENT, EPL_KERNEL, 0 },
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel{ SF_EVENT_TAG_REMOVE, FCAL_REMOVE_EVENT, EPL_INTERRUPT, 0 }
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel (sizeof (sf_event_defs) / sizeof (ndi_event_definition_t))
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic int sf_reset_flag = 1; /* bool: to allow reset after LIP */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic int sf_abort_flag = 0; /* bool: to do just one abort */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * for converting between target number (switch) and hard address/AL_PA
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel 0xef, 0xe8, 0xe4, 0xe2, 0xe1, 0xe0, 0xdc, 0xda, 0xd9, 0xd6,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xce, 0xcd, 0xcc, 0xcb, 0xca,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel 0xc9, 0xc7, 0xc6, 0xc5, 0xc3, 0xbc, 0xba, 0xb9, 0xb6, 0xb5,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel 0xb4, 0xb3, 0xb2, 0xb1, 0xae, 0xad, 0xac, 0xab, 0xaa, 0xa9,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel 0xa7, 0xa6, 0xa5, 0xa3, 0x9f, 0x9e, 0x9d, 0x9b, 0x98, 0x97,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel 0x90, 0x8f, 0x88, 0x84, 0x82, 0x81, 0x80, 0x7c, 0x7a, 0x79,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel 0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x6e, 0x6d, 0x6c, 0x6b,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel 0x6a, 0x69, 0x67, 0x66, 0x65, 0x63, 0x5c, 0x5a, 0x59, 0x56,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel 0x55, 0x54, 0x53, 0x52, 0x51, 0x4e, 0x4d, 0x4c, 0x4b, 0x4a,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel 0x49, 0x47, 0x46, 0x45, 0x43, 0x3c, 0x3a, 0x39, 0x36, 0x35,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel 0x34, 0x33, 0x32, 0x31, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel 0x27, 0x26, 0x25, 0x23, 0x1f, 0x1e, 0x1d, 0x1b, 0x18, 0x17,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel 0x00, 0x7d, 0x7c, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x7a, 0x00,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x78, 0x00, 0x00, 0x00,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel 0x00, 0x00, 0x00, 0x77, 0x76, 0x00, 0x00, 0x75, 0x00, 0x74,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel 0x73, 0x72, 0x00, 0x00, 0x00, 0x71, 0x00, 0x70, 0x6f, 0x6e,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel 0x00, 0x6d, 0x6c, 0x6b, 0x6a, 0x69, 0x68, 0x00, 0x00, 0x67,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel 0x66, 0x65, 0x64, 0x63, 0x62, 0x00, 0x00, 0x61, 0x60, 0x00,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel 0x5c, 0x5b, 0x00, 0x5a, 0x59, 0x58, 0x57, 0x56, 0x55, 0x00,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel 0x00, 0x54, 0x53, 0x52, 0x51, 0x50, 0x4f, 0x00, 0x00, 0x4e,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel 0x4d, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4b,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel 0x00, 0x4a, 0x49, 0x48, 0x00, 0x47, 0x46, 0x45, 0x44, 0x43,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel 0x42, 0x00, 0x00, 0x41, 0x40, 0x3f, 0x3e, 0x3d, 0x3c, 0x00,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel 0x00, 0x3b, 0x3a, 0x00, 0x39, 0x00, 0x00, 0x00, 0x38, 0x37,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel 0x36, 0x00, 0x35, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel 0x00, 0x00, 0x00, 0x33, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel 0x00, 0x31, 0x30, 0x00, 0x00, 0x2f, 0x00, 0x2e, 0x2d, 0x2c,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel 0x00, 0x00, 0x00, 0x2b, 0x00, 0x2a, 0x29, 0x28, 0x00, 0x27,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel 0x26, 0x25, 0x24, 0x23, 0x22, 0x00, 0x00, 0x21, 0x20, 0x1f,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel 0x1e, 0x1d, 0x1c, 0x00, 0x00, 0x1b, 0x1a, 0x00, 0x19, 0x00,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x17, 0x16, 0x15,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel 0x00, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x00, 0x00, 0x0e,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x00, 0x00, 0x08, 0x07, 0x00,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel 0x06, 0x00, 0x00, 0x00, 0x05, 0x04, 0x03, 0x00, 0x02, 0x00,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * these macros call the proper transport-layer function given
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * a particular transport
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel#define soc_transport(a, b, c, d) (*a->fcal_ops->fcal_transport)(b, c, d)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel#define soc_take_core(a, b) (*a->fcal_ops->fcal_take_core)(b)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel/* power management property defines (should be in a common include file?) */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel#define PM_NEEDS_SUSPEND_RESUME "needs-suspend-resume"
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel/* node properties */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * initialize this driver and install this module
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel i = ddi_soft_state_init(&sf_state, sizeof (struct sf),
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (i != 0)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel return (i);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel return (i);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel mutex_init(&sf_global_mutex, NULL, MUTEX_DRIVER, NULL);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel return (i);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel return (i);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * remove this driver module from the system
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel return (i);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * Given the device number return the devinfo pointer or instance
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel/*ARGSUSED*/
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelsf_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * either attach or resume this driver
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel switch ((int)cmd) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * we've previously been SF_STATE_OFFLINEd by a DDI_SUSPEND,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * so time to undo that and get going again by forcing a
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * clear suspended flag so that normal operations can resume
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * force a login by setting our state to offline
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sf->sf_timer = sf_watchdog_time + SF_OFFLINE_TIMEOUT;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * call transport routine to register state change and
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * ELS callback routines (to register us as a ULP)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sf_statec_callback, sf_unsol_els_callback, NULL, sf);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * call transport routine to force loop initialization
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * increment watchdog init flag, setting watchdog timeout
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * if we are the first (since somebody has to do it)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * this instance attaching for the first time
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel cmn_err(CE_WARN, "sf%d: failed to allocate soft state",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* this shouldn't happen since we just allocated it */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * from this point on, if there's an error, we must de-allocate
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * soft state before returning DDI_FAILURE
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "sf%d: failed to obtain transport handle",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* fill in our soft state structure */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* create a command/response buffer pool for this instance */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "sf%d: failed to allocate command/response pool",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* create a a cache for this instance */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel cmn_err(CE_WARN, "sf%d: failed to allocate kmem cache",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* set up a handle and allocate memory for DMA */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (ddi_dma_alloc_handle(sf->sf_dip, sf->sf_sochandle->
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "sf%d: failed to allocate dma handle for lilp map",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel fcal_accattr, DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel cmn_err(CE_WARN, "sf%d: failed to allocate lilp map",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* no error message ??? */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * set up the address for the DMA transfers (getting a cookie)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (ddi_dma_addr_bind_handle(sf->sf_lilp_dmahandle, NULL,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel DDI_DMA_READ | DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel &sf->sf_lilp_dmacookie, &ccount) != DDI_DMA_MAPPED) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "sf%d: failed to bind dma handle for lilp map",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* ensure only one cookie was allocated */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* ensure LILP map and DMA cookie addresses are even?? */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sf->sf_lilp_map = (struct fcal_lilp_map *)(((uintptr_t)sf->
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* set up all of our mutexes and condition variables */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel mutex_init(&sf->sf_cmd_mutex, NULL, MUTEX_DRIVER, NULL);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel mutex_init(&sf->sf_cr_mutex, NULL, MUTEX_DRIVER, NULL);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel mutex_init(&sf->sf_hp_daemon_mutex, NULL, MUTEX_DRIVER, NULL);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel cv_init(&sf->sf_hp_daemon_cv, NULL, CV_DRIVER, NULL);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* create our devctl minor node */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel cmn_err(CE_WARN, "sf%d: ddi_create_minor_node failed"
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* create fc minor node */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel SF_INST2FC_MINOR(instance), DDI_NT_FC_ATTACHMENT_POINT,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel cmn_err(CE_WARN, "sf%d: ddi_create_minor_node failed"
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* allocate a SCSI transport structure */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* remove all minor nodes created */
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth /* Indicate that we are 'sizeof (scsi_*(9S))' clean. */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* save ptr to new transport structure and fill it in */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * register event notification routines with scsa
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel tran->tran_remove_eventcall = sf_bus_remove_eventcall;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * register bus configure/unconfigure
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * allocate an ndi event handle
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* setup and attach SCSI hba transport */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel fcal_dmaattr, tran, SCSI_HBA_TRAN_CLONE) != DDI_SUCCESS) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel cmn_err(CE_WARN, "sf%d: scsi_hba_attach_setup failed",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* set up kstats */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if ((sf->sf_ksp = kstat_create("sf", instance, "statistics",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "controller", KSTAT_TYPE_RAW, sizeof (struct sf_stats),
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* create the hotplug thread */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel (void (*)())sf_hp_daemon, sf, 0, &p0, TS_RUN, minclsyspri);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* add this soft state instance to the head of the list */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * find entry in list that has the same FC-AL handle (if any)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel break; /* found matching entry */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* if we found a matching entry keep track of it */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * increment watchdog init flag, setting watchdog timeout
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * if we are the first (since somebody has to do it)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * set up matching entry to be our sibling
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * create this property so that PM code knows we want
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * to be suspended at PM time
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* log the fact that we have a new device */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * force a login by setting our state to offline
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sf->sf_timer = sf_watchdog_time + SF_OFFLINE_TIMEOUT;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * call transport routine to register state change and
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * ELS callback routines (to register us as a ULP)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sf_statec_callback, sf_unsol_els_callback, NULL, sf);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * call transport routine to force loop initialization
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel cmn_err(CE_WARN, "sf%d: failed to attach", instance);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * Unbind and free event set
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel kmem_free(sf->sf_event_defs, sizeof (sf_event_defs));
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * kill off the watchdog if we are the last instance
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* remove all minor nodes */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel/* ARGSUSED */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* NO OTHER THREADS ARE RUNNING */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if ((sf = ddi_get_soft_state(sf_state, instance)) == NULL) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel cmn_err(CE_WARN, "sf_detach, sf%d: bad soft state", instance);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * suspend our instance
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * There is a race condition in socal where while doing
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * callbacks if a ULP removes it self from the callback list
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * the for loop in socal may panic as cblist is junk and
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * while trying to get cblist->next the system will panic.
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* call transport to remove our unregister our callbacks */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * begin process of clearing outstanding commands
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * by issuing a lip
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * toggle the device OFFLINE in order to cause
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * outstanding commands to drain
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sf->sf_timer = sf_watchdog_time + SF_OFFLINE_TIMEOUT;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sf->sf_state = (SF_STATE_OFFLINE | SF_STATE_SUSPENDED);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel for (i = 0; i < sf_max_targets; i++) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* do this for all LUNs as well */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * kill off the watchdog if we are the last instance
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * detach this instance
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* remove this "sf" from the list of sf softstates */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * prior to taking any DDI_DETACH actions, toggle the
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * device OFFLINE in order to cause outstanding
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * commands to drain
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sf->sf_timer = sf_watchdog_time + SF_OFFLINE_TIMEOUT;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel for (i = 0; i < sf_max_targets; i++) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* call transport to remove and unregister our callbacks */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * kill off the watchdog if we are the last instance
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* signal sf_hp_daemon() to exit and wait for exit */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel thread_join(sf->sf_hp_tid); /* wait for hotplug to exit */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * Unbind and free event set
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel kmem_free(sf->sf_event_defs, sizeof (sf_event_defs));
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* detach this instance of the HBA driver */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* deallocate/unbind DMA handle for lilp map */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * the kmem cache must be destroyed before free'ing
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * up the crpools
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * our finagle of "ntot" and "nfree"
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * causes an ASSERT failure in "sf_cr_free()"
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * if the kmem cache is free'd after invoking
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * "sf_crpool_free()".
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "sf_detach: sf_crpool_free() for instance 0x%x\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * set ntot to nfree for this particular entry
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * this causes sf_crpool_free() to update
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * the cr_pool list when deallocating this entry
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * now that the cr_pool's are gone it's safe
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * to destroy all softstate mutex's and cv's
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* remove all minor nodes from the device tree */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* remove properties created during attach() */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* remove kstat's if present */
193974072f41a843678abf5f61979c748687e66bSherry Moore "sf_detach: ddi_soft_state_free() for instance 0x%x\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel SF_DEBUG(2, (sf, CE_CONT, "sf_detach: sf%d unknown cmd %x\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * sf_softstate_unlink() - remove an sf instance from the list of softstates
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* Busy working the list -- wait */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * we have a sibling so NULL out its reference to us
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* remove our instance from the global list */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* we were at at head of the list */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* find us in the list */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* remember this place */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel ddi_bus_config_op_t op, void *arg, dev_info_t **childp)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sf = ddi_get_soft_state(sf_state, ddi_get_instance(parent));
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel reset_delay = (int64_t)(USEC_TO_TICK(SF_INIT_WAIT_TIMEOUT)) -
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel return (ndi_busop_bus_unconfig(parent, flag, op, arg));
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * called by transport to initialize a SCSI target
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel/* ARGSUSED */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelsf_scsi_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel struct sf *sf = (struct sf *)hba_tran->tran_hba_private;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* get and validate our SCSI target ID */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* get our port WWN property */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (ddi_prop_op(DDI_DEV_T_ANY, tgt_dip, PROP_LEN_AND_VAL_BUF,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, PORT_WWN_PROP,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* no port WWN property - ignore the OBP stub node */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* get our LIP count property */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (ddi_prop_op(DDI_DEV_T_ANY, tgt_dip, PROP_LEN_AND_VAL_BUF,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* and our LUN property */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (ddi_prop_op(DDI_DEV_T_ANY, tgt_dip, PROP_LEN_AND_VAL_BUF,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* find the target structure for this instance */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if ((target = sf_lookup_target(sf, wwn, lun)) == NULL) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if ((sf->sf_lip_cnt == lip_cnt) && !(target->sft_state
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * set links between HBA transport and target structures
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * and set done flag
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* already initialized ?? */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * called by transport to free a target
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel/* ARGSUSED */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelsf_scsi_tgt_free(dev_info_t *hba_dip, dev_info_t *tgt_dip,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel struct sf_target *target = hba_tran->tran_tgt_private;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * allocator for non-std size cdb/pkt_private/status -- return TRUE iff
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * success, else return FALSE
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel/*ARGSUSED*/
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelsf_pkt_alloc_extern(struct sf *sf, struct sf_pkt *cmd,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if ((scbp = kmem_zalloc((size_t)statuslen, kf)) == NULL) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * deallocator for non-std size cdb/pkt_private/status
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelsf_pkt_destroy_extern(struct sf *sf, struct sf_pkt *cmd)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "sf_scsi_impl_pktfree: freeing free packet");
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* NOTREACHED */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * create or initialize a SCSI packet -- called internally and
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * by the transport
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic struct scsi_pkt *
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelsf_scsi_init_pkt(struct scsi_address *ap, struct scsi_pkt *pkt,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel struct buf *bp, int cmdlen, int statuslen, int tgtlen,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * If we've already allocated a pkt once,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * this request is for dma allocation only.
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * First step of sf_scsi_init_pkt: pkt allocation
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if ((cmd = kmem_cache_alloc(sf->sf_pkt_cache, kf)) != NULL) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * Selective zeroing of the pkt.
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sizeof (struct sf_pkt) + sizeof (struct
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel cmd->cmd_fp_pkt = (struct fcal_packet *)((char *)cmd +
193974072f41a843678abf5f61979c748687e66bSherry Moore sizeof (struct sf_pkt));
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel cmd->cmd_pkt->pkt_scbp = (opaque_t)cmd->cmd_scsi_scb;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* zero pkt_private */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* need to allocate more space */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* allocate cmd/response pool buffers */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* fill in the FC-AL packet */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sizeof (struct fcp_cmd);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* Fill in the Fabric Channel Header */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* Establish the LUN */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel cmd->cmd_forw = (struct sf_pkt *)&target->sft_pkt_head;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* pkt already exists -- just a request for DMA allocation */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* zero cdb (bzero is too slow) */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * Second step of sf_scsi_init_pkt: dma allocation
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * Set up dma info
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* there is a buffer and some data to transfer */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* set up command and DMA flags */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* a read */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* a write */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* ensure we have a DMA handle */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (rval == 0) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* bind our DMA handle to our buffer */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel rval = ddi_dma_buf_bind_handle(cmd->cmd_dmahandle, bp,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (rval != 0) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* DMA failure */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel SF_DEBUG(2, (sf, CE_CONT, "ddi_dma_buf.. failed\n"));
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* clear valid flag */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* destroy packet if we just created it */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* set up amt to transfer and set valid flag */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* set up FC-AL packet */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* DMA write */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* DMA read */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* not a read or write */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel fpkt->fcal_socal_request.sr_cqhdr.cq_hdr_type = CQ_TYPE_SIMPLE;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sizeof (struct fcp_cmd);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * destroy a SCSI packet -- called internally and by the transport
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelsf_scsi_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* DMA was set up -- clean up */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* take this packet off the doubly-linked list */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* free the packet */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel (CFLAG_FREE | CFLAG_PRIVEXTERN | CFLAG_SCBEXTERN)) == 0) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* just a regular packet */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* a packet with extra memory */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * called by transport to unbind DMA handle
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel/* ARGSUSED */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelsf_scsi_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * called by transport to synchronize CPU and I/O views of memory
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel/* ARGSUSED */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelsf_scsi_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (ddi_dma_sync(cmd->cmd_dmahandle, (off_t)0, (size_t)0,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * routine for reset notification setup, to register or cancel. -- called
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * by transport
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelsf_scsi_reset_notify(struct scsi_address *ap, int flag,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel return (scsi_hba_reset_notify_setup(ap, flag, callback, arg,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * called by transport to get port WWN property (except sun4u)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel/* ARGSUSED */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelsf_scsi_get_name(struct scsi_device *sd, char *name, int len)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel i = sizeof (wwn);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (ddi_prop_op(DDI_DEV_T_ANY, tgt_dip, PROP_LEN_AND_VAL_BUF,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, PORT_WWN_PROP,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel return (0);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel i = sizeof (lun);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (ddi_prop_op(DDI_DEV_T_ANY, tgt_dip, PROP_LEN_AND_VAL_BUF,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel return (0);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel for (i = 0; i < FC_WWN_SIZE; i++)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel return (1);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * called by transport to get target soft AL-PA (except sun4u)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel/* ARGSUSED */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelsf_scsi_get_bus_addr(struct scsi_device *sd, char *name, int len)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel struct sf_target *target = ADDR2TARGET(&sd->sd_address);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel return (0);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel return (1);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * add to the command/response buffer pool for this sf instance
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* allocate room for the pool */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if ((ptr = kmem_zalloc(sizeof (struct sf_cr_pool), KM_NOSLEEP)) ==
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* allocate a DMA handle for the command pool */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (ddi_dma_alloc_handle(sf->sf_dip, sf->sf_sochandle->fcal_dmaattr,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel DDI_DMA_DONTWAIT, NULL, &ptr->cmd_dma_handle) != DDI_SUCCESS) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * Get a piece of memory in which to put commands
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel cmd_buf_size = (sizeof (struct fcp_cmd) * SF_ELEMS_IN_POOL + 7) & ~7;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (ddi_dma_mem_alloc(ptr->cmd_dma_handle, cmd_buf_size,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel &real_cmd_buf_size, &ptr->cmd_acc_handle) != DDI_SUCCESS) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* bind the DMA handle to an address */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (ddi_dma_addr_bind_handle(ptr->cmd_dma_handle, NULL,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel DDI_DMA_WRITE | DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* ensure only one cookie was allocated */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* allocate a DMA handle for the response pool */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (ddi_dma_alloc_handle(sf->sf_dip, sf->sf_sochandle->fcal_dmaattr,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel DDI_DMA_DONTWAIT, NULL, &ptr->rsp_dma_handle) != DDI_SUCCESS) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * Get a piece of memory in which to put responses
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel rsp_buf_size = FCP_MAX_RSP_IU_SIZE * SF_ELEMS_IN_POOL;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (ddi_dma_mem_alloc(ptr->rsp_dma_handle, rsp_buf_size,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel &real_rsp_buf_size, &ptr->rsp_acc_handle) != DDI_SUCCESS) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* bind the DMA handle to an address */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (ddi_dma_addr_bind_handle(ptr->rsp_dma_handle, NULL,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* ensure only one cookie was allocated */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * Generate a (cmd/rsp structure) free list
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* ensure ptr points to start of long word (8-byte block) */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel dptr = (caddr_t)((uintptr_t)(ptr->cmd_base) + 7 & ~7);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* keep track of actual size after moving pointer */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* set actual total number of entries */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel ptr->ntot = min((real_cmd_buf_size / sizeof (struct fcp_cmd)),
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* set up DMA for each pair of entries */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* terminate the list */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* add this list at front of current one */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* we failed so clean up */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * allocate a command/response buffer from the pool, allocating more
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * in the pool as needed
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelsf_cr_alloc(struct sf *sf, struct sf_pkt *cmd, int (*func)())
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* find a free buffer in the existing pool */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* did we find a free buffer ? */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* we found a free buffer -- take it off the free list */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* set up the command to use the buffer pair */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* no free buffer available -- can we allocate more ? */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* we need to allocate more buffer pairs */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* somebody already allocating for this instance */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* user wants to wait */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* we've been woken so go try again */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* user does not want to wait */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* set flag saying we're allocating */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* add to our pool */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* couldn't add to our pool for some reason */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * clear flag saying we're allocating and tell all other
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * that care
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* now that we have more buffers try again */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* we don't have room to allocate any more buffers */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * free a cmd/response buffer pair in our pool
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * free our pool of cmd/response buffers
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel/* ARGSUSED */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelsf_kmem_cache_constructor(void *buf, void *arg, int size)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel mutex_init(&cmd->cmd_abort_mutex, NULL, MUTEX_DRIVER, NULL);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel return (0);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel/* ARGSUSED */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * called by transport when a state change occurs
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * the loop has gone online
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* scan each target hash queue */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel for (i = 0; i < SF_NUM_HASH_QUEUES; i++) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * foreach target, if it's not offline then
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * mark it as busy
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * for debugging, print out info on any
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * pending commands (left hanging)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "cmd 0x%p pending "
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "after lip\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * since the loop has just gone online get a new map from
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * the transport
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if ((ret = soc_get_lilp_map(sf->sf_sochandle, sf->sf_socp,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sf_lilp_dmacookie.dmac_address, 1)) != FCAL_SUCCESS) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sf->sf_timer = sf_watchdog_time + SF_OFFLINE_TIMEOUT;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* ensure consistent view of DMA memory */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel (void) ddi_dma_sync(sf->sf_lilp_dmahandle, (off_t)0, (size_t)0,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* how many entries in map ? */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "!lilp map has %d entries, al_pa is %x\n", cnt, al_pa));
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * since the last entry of the map may be mine (common) check
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * for that, and if it is we have one less entry to look at
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (sf->sf_lilp_map->lilp_alpalist[cnt-1] == al_pa) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* If we didn't get a valid loop map enable all targets */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (sf->sf_lilp_map->lilp_magic == FCAL_BADLILP_MAGIC) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel for (i = 0; i < sizeof (sf_switch_to_alpa); i++)
193974072f41a843678abf5f61979c748687e66bSherry Moore "!statec_callback: starting with %d targets\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* scan loop map, logging into all ports (except mine) */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel for (i = 0; i < cnt; i++) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "!lilp map entry %d = %x,%x\n", i,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* is this entry for somebody else ? */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* do a PLOGI to this port */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* a problem logging in */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * problem not from a new LIP
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * loop has gone offline due to an error
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sf->sf_timer = sf_watchdog_time + SF_OFFLINE_TIMEOUT;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * if we are suspended, preserve the SF_STATE_SUSPENDED flag,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * since throttling logic in sf_watch() depends on
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * preservation of this flag while device is suspended
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "sf_statec_callback, sf%d: "
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "got FCAL_STATE_OFFLINE during DDI_SUSPEND\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* scan each possible target on the loop */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel for (i = 0; i < sf_max_targets; i++) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel struct sf_els_hdr *head; /* to save our private list */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * a transport reset
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * if we are suspended, preserve the SF_STATE_SUSPENDED flag,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * since throttling logic in sf_watch() depends on
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * preservation of this flag while device is suspended
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "sf_statec_callback, sf%d: "
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "got FCAL_STATE_RESET during DDI_SUSPEND\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * scan each possible target on the loop, looking for targets
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * that need callbacks ran
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel for (i = 0; i < sf_max_targets; i++) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * run remove event callbacks for lun
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * We have a nasty race condition here
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * 'cause we're dropping this mutex to
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * run the callback and expect the
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * linked list to be the same.
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * scan for ELS commands that are in transport, not complete,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * and have a valid timeout, building a private list
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if ((fpkt->fcal_cmd_state & FCAL_CMD_IN_TRANSPORT) &&
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * cmd in transport && not complete &&
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * timeout valid
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * move this entry from ELS input list to our
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * private list
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* push this on private list head */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* remove this entry from input list */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * remove this entry from somewhere in
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * the middle of the list
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * remove this entry from the head
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * of the list
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * foreach cmd in our list free the ELS packet associated
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * scan for commands from each possible target
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel for (i = 0; i < sf_max_targets; i++) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * scan all active commands for this target,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * looking for commands that have been issued,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * are in transport, and are not yet complete
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * (so we can terminate them because of the
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* a command to be reset */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* get next command */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * get packet queue for this target, resetting all remaining
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * called to send a PLOGI (N_port login) ELS request to a destination ID,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * returning TRUE upon success, else returning FALSE
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelsf_login(struct sf *sf, uchar_t els_code, uchar_t dest_id, uint_t arg1,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (sf_els_alloc(sf, dest_id, sizeof (struct sf_els_hdr),
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sizeof (union sf_els_cmd), sizeof (union sf_els_rsp),
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sf_log(sf, CE_WARN, "Cannot allocate PLOGI for target %x "
193974072f41a843678abf5f61979c748687e66bSherry Moore "due to DVMA shortage.\n", sf_alpa_to_switch[dest_id]);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel (caddr_t)&logi->common_service, sizeof (struct la_els_logi)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel (caddr_t)&(((struct la_els_logo *)logi)->nport_ww_name), 8);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * send an ELS IU via the transport,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * returning TRUE upon success, else returning FALSE
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelsf_els_transport(struct sf *sf, struct sf_els_hdr *privp)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel (void) ddi_dma_sync(privp->cmd_dma_handle, (off_t)0, (size_t)0,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* call the transport to send a packet */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (soc_transport(sf->sf_sochandle, fpkt, FCAL_NOSLEEP,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * called as the pkt_comp routine for ELS FC packets
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel struct la_els_logi *ptr = (struct la_els_logi *)privp->rsp;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel struct la_els_adisc *adisc = (struct la_els_adisc *)ptr;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * we've received an ELS callback, i.e. an ELS packet has arrived
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* take the current packet off of the queue */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* get # pkts in this callback */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* sync idea of memory */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel (void) ddi_dma_sync(privp->rsp_dma_handle, (off_t)0, (size_t)0,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* was this an OK ACC msg ?? */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * this was an OK ACC pkt
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * was able to to an N_port login
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "!PLOGI to al_pa %x succeeded, wwn %x%x\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* try to do a process login */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * was able to do a process login
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "!PRLI to al_pa %x succeeded\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* try to do address discovery */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * found a target via ADISC
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "!ADISC to al_pa %x succeeded\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* create the target info */
193974072f41a843678abf5f61979c748687e66bSherry Moore sf_alpa_to_switch[(uchar_t)adisc->hard_address],
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * ensure address discovered matches what we thought
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * it would be
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "target 0x%x, AL-PA 0x%x and "
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "hard address 0x%x don't match\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * get inquiry data from the target
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "!ELS %x to al_pa %x succeeded\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * oh oh -- this was not an OK ACC packet
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* get target ID from dest loop address */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel tgt_id = sf_alpa_to_switch[(uchar_t)privp->dest_nport_id];
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* keep track of failures */
193974072f41a843678abf5f61979c748687e66bSherry Moore fpkt->fcal_pkt_status != FCAL_STATUS_OPEN_FAIL) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "!ELS %x to al_pa %x failed, retrying",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* device busy? wait a bit ... */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* call the transport to send a pkt */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel SF_DEBUG(2, (sf, CE_NOTE, "ELS %x to al_pa %x failed",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "LS_RJT reason = %x\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "fc packet status = %x",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel return; /* success */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * send a PRLI (process login) ELS IU via the transport,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * returning TRUE upon success, else returning FALSE
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelsf_do_prli(struct sf *sf, struct sf_els_hdr *privp, struct la_els_logi *ptr)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel struct la_els_prli *prli = (struct la_els_prli *)privp->cmd;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sizeof (struct la_els_prli);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel bcopy((caddr_t)&ptr->nport_ww_name, (caddr_t)&privp->port_wwn,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel bcopy((caddr_t)&ptr->node_ww_name, (caddr_t)&privp->node_wwn,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * send an ADISC (address discovery) ELS IU via the transport,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * returning TRUE upon success, else returning FALSE
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel struct la_els_adisc *adisc = (struct la_els_adisc *)privp->cmd;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sizeof (struct la_els_adisc);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel (caddr_t)&adisc->port_wwn, sizeof (adisc->port_wwn));
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel (caddr_t)&adisc->node_wwn, sizeof (adisc->node_wwn));
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic struct fcal_packet *
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelsf_els_alloc(struct sf *sf, uchar_t dest_id, int priv_size, int cmd_size,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "Could not allocate fcal_packet for ELS\n"));
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if ((privp = (struct sf_els_hdr *)kmem_zalloc(priv_size,
193974072f41a843678abf5f61979c748687e66bSherry Moore "Could not allocate sf_els_hdr for ELS\n"));
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (ddi_dma_alloc_handle(sf->sf_dip, sf->sf_sochandle->fcal_dmaattr,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel DDI_DMA_DONTWAIT, NULL, &cmd_dma_handle) != DDI_SUCCESS) {
193974072f41a843678abf5f61979c748687e66bSherry Moore "Could not allocate DMA handle for ELS\n"));
193974072f41a843678abf5f61979c748687e66bSherry Moore "Could not allocate DMA memory for ELS\n"));
193974072f41a843678abf5f61979c748687e66bSherry Moore "DMA memory too small for ELS\n"));
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel DDI_DMA_DONTWAIT, NULL, &pcookie, &ccount) != DDI_DMA_MAPPED) {
193974072f41a843678abf5f61979c748687e66bSherry Moore "Could not bind DMA memory for ELS\n"));
193974072f41a843678abf5f61979c748687e66bSherry Moore "Wrong cookie count for ELS\n"));
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (ddi_dma_alloc_handle(sf->sf_dip, sf->sf_sochandle->fcal_dmaattr,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel DDI_DMA_DONTWAIT, NULL, &rsp_dma_handle) != DDI_SUCCESS) {
193974072f41a843678abf5f61979c748687e66bSherry Moore "Could not allocate DMA handle for ELS rsp\n"));
193974072f41a843678abf5f61979c748687e66bSherry Moore "Could not allocate DMA memory for ELS rsp\n"));
193974072f41a843678abf5f61979c748687e66bSherry Moore "DMA memory too small for ELS rsp\n"));
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel DDI_DMA_DONTWAIT, NULL, &rcookie, &ccount) != DDI_DMA_MAPPED) {
193974072f41a843678abf5f61979c748687e66bSherry Moore "Could not bind DMA memory for ELS rsp\n"));
193974072f41a843678abf5f61979c748687e66bSherry Moore "Wrong cookie count for ELS rsp\n"));
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel (ushort_t)(SOC_FC_HEADER | sf->sf_sochandle->fcal_portno);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel fpkt->fcal_socal_request.sr_soc_hdr.sh_byte_cnt = cmd_size;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel fpkt->fcal_socal_request.sr_cqhdr.cq_hdr_type = CQ_TYPE_SIMPLE;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel fpkt->fcal_socal_request.sr_dataseg[0].fc_base = (uint32_t)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel fpkt->fcal_socal_request.sr_dataseg[0].fc_count = cmd_size;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel fpkt->fcal_socal_request.sr_dataseg[1].fc_base = (uint32_t)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel fpkt->fcal_socal_request.sr_dataseg[1].fc_count = rsp_size;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* Fill in the Fabric Channel Header */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel (void) ddi_dma_unbind_handle(privp->data_dma_handle);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic struct sf_target *
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelsf_create_target(struct sf *sf, struct sf_els_hdr *privp, int tnum, int64_t lun)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel struct sf_target *target, *ntarget, *otarget, *ptarget;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* XXXX Work around SCSA limitations. */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel ntarget = kmem_zalloc(sizeof (struct sf_target), KM_NOSLEEP);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (lun != 0) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * Since LUNs != 0 are queued up after LUN == 0, find LUN == 0
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * and enqueue the new LUN.
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * Yeep -- no LUN 0?
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (target != NULL && ptarget->sft_lip_cnt == sf->sf_lip_cnt &&
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* LUN 0 already finished, duplicate its state */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * LUN 0 online or not examined yet.
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * Try to bring the LUN back online
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* Initialize new target structure */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel (caddr_t)&ntarget->sft_node_wwn, sizeof (privp->node_wwn));
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel (caddr_t)&ntarget->sft_port_wwn, sizeof (privp->port_wwn));
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel mutex_init(&ntarget->sft_mutex, NULL, MUTEX_DRIVER, NULL);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel mutex_init(&ntarget->sft_pkt_mutex, NULL, MUTEX_DRIVER, NULL);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* Don't let anyone use this till we finishup init. */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* Traverse the list looking for this target */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (target != NULL && target->sft_lip_cnt == sf->sf_lip_cnt) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* It's been touched this LIP -- duplicate WWNs */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sf_offline_target(sf, target); /* And all the baby targets */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sf_log(sf, CE_WARN, "target 0x%x, duplicate port wwns\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* Someone else is in our slot */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (bcmp((caddr_t)&privp->port_wwn, (caddr_t)&otarget->
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sizeof (struct sf_target_stats));
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel (caddr_t)&ntarget->sft_node_wwn, sizeof (privp->node_wwn));
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel (caddr_t)&ntarget->sft_port_wwn, sizeof (privp->port_wwn));
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel mutex_init(&ntarget->sft_mutex, NULL, MUTEX_DRIVER, NULL);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel mutex_init(&ntarget->sft_pkt_mutex, NULL, MUTEX_DRIVER, NULL);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel target->sft_state &= ~(SF_TARGET_OFFLINE|SF_TARGET_MARK);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * find the target for a given sf instance
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel/* ARGSUSED */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic struct sf_target *
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelsf_lookup_target(struct sf *sf, uchar_t *wwn, int lun)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelsf_lookup_target(struct sf *sf, uchar_t *wwn, int64_t lun)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (bcmp((caddr_t)wwn, (caddr_t)&target->sft_port_wwn,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (bcmp((caddr_t)wwn, (caddr_t)&target->sft_port_wwn,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * Send out a REPORT_LUNS command.
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelsf_do_reportlun(struct sf *sf, struct sf_els_hdr *privp,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel fc_frame_header_t *hp = &fpkt->fcal_socal_request.sr_fc_frame_hdr;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel struct fcp_cmd *reportlun = (struct fcp_cmd *)privp->cmd;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (ddi_dma_alloc_handle(sf->sf_dip, sf->sf_sochandle->fcal_dmaattr,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel DDI_DMA_DONTWAIT, NULL, &lun_dma_handle) != DDI_SUCCESS) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (ddi_dma_mem_alloc(lun_dma_handle, REPORT_LUNS_SIZE,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel fpkt->fcal_socal_request.sr_cqhdr.cq_hdr_type = CQ_TYPE_IO_READ;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sizeof (struct fcp_cmd);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel fpkt->fcal_socal_request.sr_dataseg[2].fc_count = pcookie.dmac_size;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel fpkt->fcal_socal_request.sr_soc_hdr.sh_byte_cnt = pcookie.dmac_size;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel ((union scsi_cdb *)reportlun->fcp_cdb)->scc_cmd = SCMD_REPORT_LUNS;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* Now set the buffer size. If DDI gave us extra, that's O.K. */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel ((union scsi_cdb *)reportlun->fcp_cdb)->scc5_count0 =
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel ((union scsi_cdb *)reportlun->fcp_cdb)->scc5_count1 =
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel ((union scsi_cdb *)reportlun->fcp_cdb)->scc5_count2 =
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel ((union scsi_cdb *)reportlun->fcp_cdb)->scc5_count3 =
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel (void) ddi_dma_sync(lun_dma_handle, 0, 0, DDI_DMA_SYNC_FORDEV);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* We know he's there, so this should be fast */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel return (1);
193974072f41a843678abf5f61979c748687e66bSherry Moore "%s failure for REPORTLUN to target 0x%x\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel return (0);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * Handle the results of a REPORT_LUNS command:
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * Create additional targets if necessary
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * Initiate INQUIRYs on all LUNs.
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel struct sf_els_hdr *privp = (struct sf_els_hdr *)fpkt->
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel int tid = sf_alpa_to_switch[target->sft_hard_address];
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* use as temporary state variable */
193974072f41a843678abf5f61979c748687e66bSherry Moore "!REPORTLUN to al_pa %x pkt status %x scsi status %x\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* See if target simply does not support REPORT_LUNS. */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (rsp && rsp->fcp_u.fcp_status.scsi_status == STATUS_CHECK &&
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel offsetof(struct scsi_extended_sense, es_qual_code)) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* Fake LUN 0 */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "!REPORTLUN Faking good "
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "completion for alpa %x\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "!REPORTLUN device alpa %x "
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "key %x code %x\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "!REPORTLUN device alpa %x was reset\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "!REPORTLUN device alpa %x "
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "key %x code %x\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel/* XXXXXX The following is here to handle broken targets -- remove it later */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel/* XXXXXX */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (rsp && rsp->fcp_u.fcp_status.scsi_status == STATUS_GOOD) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* Convert from #bytes to #ints */
193974072f41a843678abf5f61979c748687e66bSherry Moore "!REPORTLUN to al_pa %x succeeded: %d LUNs\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* No LUNs? Ya gotta be kidding... */
193974072f41a843678abf5f61979c748687e66bSherry Moore "SCSI violation -- "
193974072f41a843678abf5f61979c748687e66bSherry Moore "target 0x%x reports no LUNs\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel for (i = 0; i < ptr->lun_list_len && privp->lip_cnt ==
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* LUN 0 is already in `target' */
193974072f41a843678abf5f61979c748687e66bSherry Moore sizeof (struct sf_els_hdr),
193974072f41a843678abf5f61979c748687e66bSherry Moore sizeof (union sf_els_cmd),
193974072f41a843678abf5f61979c748687e66bSherry Moore sizeof (union sf_els_rsp),
193974072f41a843678abf5f61979c748687e66bSherry Moore "!REPORTLUN al_pa %x fcp failure, "
193974072f41a843678abf5f61979c748687e66bSherry Moore "fcp_rsp_code %x scsi status %x\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (rsp && ((rsp->fcp_u.fcp_status.scsi_status == STATUS_BUSY) ||
193974072f41a843678abf5f61979c748687e66bSherry Moore (rsp->fcp_u.fcp_status.scsi_status == STATUS_QFULL))) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel (delayed_retry && privp->retries < SF_BSY_RETRIES)) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel/* XXXXXX The following is here to handle broken targets -- remove it later */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel/* XXXXXX */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "!REPORTLUN to al_pa %x failed, retrying\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (!delayed_retry && soc_transport(sf->sf_sochandle,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* REPORT_LUN failed -- try inquiry */
193974072f41a843678abf5f61979c748687e66bSherry Moore "!REPORTLUN to target 0x%x failed\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelsf_do_inquiry(struct sf *sf, struct sf_els_hdr *privp,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel fc_frame_header_t *hp = &fpkt->fcal_socal_request.sr_fc_frame_hdr;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (ddi_dma_alloc_handle(sf->sf_dip, sf->sf_sochandle->fcal_dmaattr,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel DDI_DMA_DONTWAIT, NULL, &inq_dma_handle) != DDI_SUCCESS) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel inq_buf, real_size, DDI_DMA_READ | DDI_DMA_CONSISTENT,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel DDI_DMA_DONTWAIT, NULL, &pcookie, &ccount) != DDI_DMA_MAPPED) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel fpkt->fcal_socal_request.sr_cqhdr.cq_hdr_type = CQ_TYPE_IO_READ;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sizeof (struct fcp_cmd);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel fpkt->fcal_socal_request.sr_dataseg[2].fc_count = pcookie.dmac_size;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel fpkt->fcal_socal_request.sr_soc_hdr.sh_byte_cnt = pcookie.dmac_size;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel ((union scsi_cdb *)inq->fcp_cdb)->scc_cmd = SCMD_INQUIRY;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel ((union scsi_cdb *)inq->fcp_cdb)->g0_count0 = SUN_INQSIZE;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel bcopy((caddr_t)&target->sft_lun.b, (caddr_t)&inq->fcp_ent_addr,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel (void) ddi_dma_sync(inq_dma_handle, (off_t)0, (size_t)0,
193974072f41a843678abf5f61979c748687e66bSherry Moore "!Sending INQUIRY to al_pa %x lun %" PRIx64 "\n",
193974072f41a843678abf5f61979c748687e66bSherry Moore "%s failure for INQUIRY to target 0x%x\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * called as the pkt_comp routine for INQ packets
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel struct sf_els_hdr *privp = (struct sf_els_hdr *)fpkt->
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel struct scsi_inquiry *prt = (struct scsi_inquiry *)privp->data_buf;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* use as temporary state variable */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "!INQUIRY to al_pa %x scsi status %x",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel privp->dest_nport_id, rsp->fcp_u.fcp_status.scsi_status));
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if ((rsp->fcp_u.fcp_status.scsi_status == STATUS_GOOD) &&
193974072f41a843678abf5f61979c748687e66bSherry Moore ((SUN_INQSIZE - rsp->fcp_resid) >= SUN_MIN_INQLEN))) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel " succeeded\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sizeof (*prt));
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel (rsp->fcp_u.fcp_status.scsi_status == STATUS_QFULL) ||
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel (rsp->fcp_u.fcp_status.scsi_status == STATUS_CHECK)) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel SF_DEBUG(2, (sf, CE_CONT, "!INQUIRY to al_pa %x fc status %x",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel (delayed_retry && privp->retries < SF_BSY_RETRIES)) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (fpkt->fcal_pkt_status == FCAL_STATUS_MAX_XCHG_EXCEEDED) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "INQUIRY to al_pa %x failed, retrying",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* if not delayed call transport to send a pkt */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "Retry Count: %d\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel int i; /* loop index */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel struct sf_hp_elem *elem; /* hotplug element created */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* scan all hash queues */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel for (i = 0; i < SF_NUM_HASH_QUEUES; i++) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* see if target is not offline */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * target already offline
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * target is not already offline -- see if it has
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * already been marked as ready to go offline
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * target already marked, so take it offline
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* clear target busy flag */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* is target init not yet done ?? */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* get pointer to target dip */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * target init not yet done &&
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * devinfo not yet created
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * target init already done || devinfo already created
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* a problem creating properties */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* create a new element for the hotplug list */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* fill in the new element */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* add the new element into the hotplug list */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* this is the first element in list */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* could not allocate memory for element ?? */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* ensure no new LIPs have occurred */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* done scanning all targets in this queue */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* done with all hash queues */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * create devinfo node
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelsf_create_devinfo(struct sf *sf, struct sf_target *target, int lip_cnt)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* get the 'scsi-binding-set' property */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (ddi_prop_lookup_string(DDI_DEV_T_ANY, sf->sf_dip,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel DDI_PROP_NOTPROM | DDI_PROP_DONTPASS, "scsi-binding-set",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* determine the node name and compatible */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel scsi_hba_nodename_compatible_get(inq, scsi_binding_set,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel inq->inq_dtype, NULL, &nname, &compatible, &ncompatible);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* if nodename can't be determined then print a message and skip it */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "@w%02x%02x%02x%02x%02x%02x%02x%02x,%x\n"
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel " compatible: %s",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel ddi_driver_name(sf->sf_dip), ddi_get_instance(sf->sf_dip),
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "@w%02x%02x%02x%02x%02x%02x%02x%02x,%x\n"
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel " compatible: %s",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel ddi_driver_name(sf->sf_dip), ddi_get_instance(sf->sf_dip),
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* allocate the node */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* decorate the node with compatible */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (ndi_prop_update_string_array(DDI_DEV_T_NONE, cdip,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "compatible", compatible, ncompatible) != DDI_PROP_SUCCESS) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* add addressing properties to the node */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel scsi_hba_nodename_compatible_free(nname, compatible);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel scsi_hba_nodename_compatible_free(nname, compatible);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel (void) ndi_prop_remove(DDI_DEV_T_NONE, cdip, NODE_WWN_PROP);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel (void) ndi_prop_remove(DDI_DEV_T_NONE, cdip, PORT_WWN_PROP);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel (void) ndi_prop_remove(DDI_DEV_T_NONE, cdip, LIP_CNT_PROP);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel (void) ndi_prop_remove(DDI_DEV_T_NONE, cdip, TARGET_PROP);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel (void) ndi_prop_remove(DDI_DEV_T_NONE, cdip, LUN_PROP);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * create required properties, returning TRUE iff we succeed, else
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * returning FALSE
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelsf_create_props(dev_info_t *cdip, struct sf_target *target, int lip_cnt)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel cdip, NODE_WWN_PROP, target->sft_node_wwn, FC_WWN_SIZE) !=
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel cdip, PORT_WWN_PROP, target->sft_port_wwn, FC_WWN_SIZE) !=
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel cdip, LUN_PROP, target->sft_lun.l) != DDI_PROP_SUCCESS) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel return (0);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel cdip, LUN_PROP, target->sft_raid_lun) != DDI_PROP_SUCCESS) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel return (0);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * called by the transport to offline a target
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel/* ARGSUSED */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelsf_offline_target(struct sf *sf, struct sf_target *target)
193974072f41a843678abf5f61979c748687e66bSherry Moore "!target 0x%x al_pa 0x%x lun %" PRIx64 " offlined\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel target->sft_state &= ~(SF_TARGET_BUSY|SF_TARGET_MARK);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* XXXX if this is LUN 0, offline all other LUNs */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* abort all cmds for this target */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sf_abort_all(sf, target, FALSE, sf->sf_lip_cnt, FALSE);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* don't do NDI_DEVI_REMOVE for now */
193974072f41a843678abf5f61979c748687e66bSherry Moore "device offline failed",
193974072f41a843678abf5f61979c748687e66bSherry Moore "device offline succeeded\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * routine to get/set a capability
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * returning:
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * 1 (TRUE) boolean capability is true (on get)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * 0 (FALSE) invalid capability, can't set capability (on set),
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * or boolean capability is false (on get)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * -1 (UNDEFINED) can't find capability (SCSA) or unsupported capability
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * 3 when getting SCSI version number
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * AL_PA when getting port initiator ID
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel SF_DEBUG(3, (sf, CE_WARN, "sf_commoncap: invalid arg"));
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* get index of capability string */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* can't find capability */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * Process setcap request.
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * At present, we can only set binary (0/1) values
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "set cap: cap=%s,val=0x%x,tgtonly=0x%x"
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel ",doset=0x%x,rval=%d\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * Process getcap request.
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel break; /* don't' have this capability */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "sf_scsi_getcap: unsupported"));
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "get cap: cap=%s,val=0x%x,tgtonly=0x%x,"
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "doset=0x%x,rval=%d\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * called by the transport to get a capability
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelsf_getcap(struct scsi_address *ap, char *cap, int whom)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * called by the transport to set a capability
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelsf_setcap(struct scsi_address *ap, char *cap, int value, int whom)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * called by the transport to abort a target
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelsf_abort(struct scsi_address *ap, struct scsi_pkt *pkt)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* call transport to abort command */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "Command Abort failed\n"));
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* prepare the packet for transport */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (sf_prepare_pkt(sf, cmd, target) == TRAN_ACCEPT) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * call transport to send a pkt polled
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * if that fails call the transport to abort it
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (((struct fcp_rsp_info *)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* abort cmds for this targ */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "Target %d Abort Task "
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "sf_abort failed, "
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "initiating LIP\n");
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * called by the transport and internally to reset a target
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel struct sf_target *target = ADDR2TARGET(ap), *ntarget;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* We don't support RESET_LUN yet. */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if ((p = kmem_alloc(sizeof (struct sf_reset_list), KM_NOSLEEP))
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* All target resets go to LUN 0 */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel target = sf_lookup_target(sf, target->sft_port_wwn, 0);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * XXXX If we supported RESET_LUN we should check here
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * to see if any LUN were being reset and somehow fail
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * that operation.
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* prepare the packet for transport */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (sf_prepare_pkt(sf, cmd, target) == TRAN_ACCEPT) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* call transport to send a pkt polled */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "!sf%d: Target 0x%x Reset "
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "successful\n",
193974072f41a843678abf5f61979c748687e66bSherry Moore "!sf%d: Target 0x%x "
193974072f41a843678abf5f61979c748687e66bSherry Moore "Reset failed."
193974072f41a843678abf5f61979c748687e66bSherry Moore "Status code 0x%x "
193974072f41a843678abf5f61979c748687e66bSherry Moore "Resp code 0x%x\n",
193974072f41a843678abf5f61979c748687e66bSherry Moore "0x%x Reset Failed. Ret=%x\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* call the transport to abort a cmd */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "!sf%d: Target 0x%x Reset "
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "failed. Abort Failed, "
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "forcing LIP\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * Defer releasing the packet if we abort returned with
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * a BAD_ABORT or timed out, because there is a
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * possibility that the ucode might return it.
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * We wait for at least 20s and let it be released
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * by the sf_watch thread
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* for cache */
193974072f41a843678abf5f61979c748687e66bSherry Moore "Resource allocation error.\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * We are currently in a lip, so let this one
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * finish before forcing another one.
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sf_log(sf, CE_NOTE, "!sf:Target driver initiated lip\n");
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * abort all commands for a target
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * if try_abort is set then send an abort
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * if abort is set then this is abort, else this is a reset
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelsf_abort_all(struct sf *sf, struct sf_target *target, int abort, int
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel struct sf_pkt *cmd, *head = NULL, *tail = NULL, *pcmd = NULL, *tcmd;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * First pull all commands for all LUNs on this target out of the
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * overflow list. We can tell it's the same target by comparing
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * the node WWN.
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * Now complete all the commands on our list. In the process,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * the completion routine may take the commands off the target
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * call the packet completion routine only for
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * non-polled commands. Ignore the polled commands as
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * they timeout and will be handled differently
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if ((pkt->pkt_comp) && !(pkt->pkt_flags & FLAG_NOINTR))
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * Finally get all outstanding commands for each LUN, and abort them if
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * they've been issued, and call the completion routine.
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * For the case where sf_offline_target is called from sf_watch
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * due to a Offline Timeout, it is quite possible that the soc+
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * ucode is hosed and therefore cannot return the commands.
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * Clear up all the issued commands as well.
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * Try_abort will be false only if sf_abort_all is coming from
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * sf_target_offline.
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel while (cmd != (struct sf_pkt *)&target->sft_pkt_head) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* call the transport to abort a pkt */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * called by the transport to start a packet
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelsf_start(struct scsi_address *ap, struct scsi_pkt *pkt)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* prepare the packet for transport */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if ((rval = sf_prepare_pkt(sf, cmd, target)) != TRAN_ACCEPT) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (target->sft_state & (SF_TARGET_BUSY|SF_TARGET_OFFLINE)) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* if no interrupts then do polled I/O */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* regular interrupt-driven I/O */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* locking no needed */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* call the transport to send a pkt */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel FCAL_NOSLEEP, CQ_REQUEST_1) != FCAL_TRANSPORT_SUCCESS) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* regular I/O using locking */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * either we're throttling back or there are already commands
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * on the queue, so enqueue this one for later
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* add to the queue */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* this is the first entry in the queue */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * start this packet now
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* still have cmd mutex */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * internal routine to start a packet from the queue now
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * enter with cmd mutex held and leave with it released
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* we have the cmd mutex */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel cmd->cmd_timeout = cmd->cmd_pkt->pkt_time ? sf_watchdog_time +
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* call transport to send the pkt */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (soc_transport(sf->sf_sochandle, cmd->cmd_fp_pkt, FCAL_NOSLEEP,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * prepare a packet for transport
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelsf_prepare_pkt(struct sf *sf, struct sf_pkt *cmd, struct sf_target *target)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel/* XXXX Need to set the LUN ? */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* invalidate imp field(s) of rsp block */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel cmd->cmd_rsp_block->fcp_u.i_fcp_status = SF_BAD_DMA_MAGIC;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* set up amt of I/O to do */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* set up the Tagged Queuing type */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * Sync the cmd segment
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel (void) ddi_dma_sync(cmd->cmd_cr_pool->cmd_dma_handle,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * fill in packet hdr source and destination IDs and hdr byte count
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelsf_fill_ids(struct sf *sf, struct sf_pkt *cmd, struct sf_target *target)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * do polled I/O using transport
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel timeout = cmd->cmd_pkt->pkt_time ? cmd->cmd_pkt->pkt_time
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* call transport to send a pkt polled */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel rval = soc_transport_poll(sf->sf_sochandle, cmd->cmd_fp_pkt,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel/* a shortcut for defining debug messages below */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * the pkt_comp callback for command packets
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel struct sf_pkt *cmd = (struct sf_pkt *)fpkt->fcal_pkt_private;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel struct sf_target *target = ADDR2TARGET(&pkt->pkt_address);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel cmn_err(CE_PANIC, "sf: completing idle packet 0x%p\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* cmd already being aborted -- nothing to do */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel (void) ddi_dma_sync(cmd->cmd_cr_pool->rsp_dma_handle,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel (caddr_t)cmd->cmd_rsp_block - cmd->cmd_cr_pool->rsp_base,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * The next two checks make sure that if there
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * is no sense data or a valid response and
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * the command came back with check condition,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * the command should be retried
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * Update the transfer resid, if appropriate
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * Check to see if the SCSI command failed.
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * First see if we got a FCP protocol error.
193974072f41a843678abf5f61979c748687e66bSherry Moore "fields invalid");
193974072f41a843678abf5f61979c748687e66bSherry Moore "Management Function"
193974072f41a843678abf5f61979c748687e66bSherry Moore "Not Supported");
193974072f41a843678abf5f61979c748687e66bSherry Moore "Management Function"
193974072f41a843678abf5f61979c748687e66bSherry Moore "mismatch with "
193974072f41a843678abf5f61979c748687e66bSherry Moore "FCP_XFER_RDY DATA_RO");
193974072f41a843678abf5f61979c748687e66bSherry Moore "different than BURST_LEN");
193974072f41a843678abf5f61979c748687e66bSherry Moore "RSP_CODE");
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * See if we got a SCSI error with sense data
193974072f41a843678abf5f61979c748687e66bSherry Moore sizeof (struct scsi_extended_sense));
193974072f41a843678abf5f61979c748687e66bSherry Moore sizeof (struct fcp_rsp) +
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* REPORT_LUNS_HAS_CHANGED */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "!REPORT_LUNS_HAS_CHANGED\n");
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sizeof (struct scsi_arq_status))) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * copy out sense information
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sizeof (struct scsi_extended_sense) -
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * The firmware returns the number of bytes actually
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * xfered into/out of host. Compare this with what
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * we asked and if it is different, we lost frames ?
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if ((pkt->pkt_reason == 0) && (pkt->pkt_resid == 0) &&
193974072f41a843678abf5f61979c748687e66bSherry Moore "!sf_cmd_callback: Lost Frame: "
193974072f41a843678abf5f61979c748687e66bSherry Moore "(write) received 0x%x expected"
193974072f41a843678abf5f61979c748687e66bSherry Moore " 0x%x target 0x%x\n",
193974072f41a843678abf5f61979c748687e66bSherry Moore "!sf_cmd_callback: "
193974072f41a843678abf5f61979c748687e66bSherry Moore "Lost Frame: (read) "
193974072f41a843678abf5f61979c748687e66bSherry Moore "received 0x%x expected 0x%x "
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* pkt status was not ok */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "INCOMPLETE DMA XFER due to bad SOC+ card, replace HBA";
193974072f41a843678abf5f61979c748687e66bSherry Moore "!Open failure to target 0x%x "
193974072f41a843678abf5f61979c748687e66bSherry Moore "forcing LIP\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * msg1 will be non-NULL if we've detected some sort of error
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "!Transport error on cmd=0x%p target=0x%x: %s\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sf_log(sf, CE_WARN, "!Transport error on target=0x%x: %s\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * start throttling for this instance
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* this command is busy -- go to next */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* this cmd not busy and not issued */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* remove this packet from the queue */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* this was the first packet */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* this was the last packet */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* some packet in the middle of the queue */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * called when the max exchange value is exceeded to throttle back commands
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * This case is just a safeguard, should not really
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * happen(ncmds < SF_DECR_DELTA and MAX_EXCHG exceed
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * sf watchdog routine, called for a timeout
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel/*ARGSUSED*/
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* disable throttling while we're suspended */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "sf_watch, sf%d:throttle disabled "
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "due to DDI_SUSPEND\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sf->sf_ncmds_exp_avg = (sf->sf_ncmds + sf->sf_ncmds_exp_avg)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if ((sf->sf_ncmds <= (sf->sf_throttle - SF_LO_CMD_DELTA)) &&
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "use lock flag off\n"));
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (sf->sf_state == SF_STATE_ONLINE && sf->sf_pkt_head &&
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* timeout this command */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel for (i = 0; i < sf_max_targets; i++) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "Unstable: Failed to bring "
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "Loop Online\n");
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel for (i = 0; i < sf_max_targets; i++) {
193974072f41a843678abf5f61979c748687e66bSherry Moore "!Offline Timeout\n");
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* reset timeout */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sf_watchdog_id = timeout(sf_watch, (caddr_t)0, sf_watchdog_tick);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* signal waiting thread */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * called during a timeout to check targets
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* check scan all possible targets */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel for (i = 0; i < sf_max_targets; i++) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel while (cmd != (struct sf_pkt *)&target->sft_pkt_head) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* prevent reset from getting at this packet */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * if the abort and lip fail, a reset will be carried out.
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * But the reset will ignore this packet. We have waited at least
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * 20 seconds after the initial timeout. Now, complete it here.
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * This also takes care of spurious bad aborts.
193974072f41a843678abf5f61979c748687e66bSherry Moore "Command 0x%p to sft 0x%p"
193974072f41a843678abf5f61979c748687e66bSherry Moore " delayed release\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* handle deferred_destroy case */
193974072f41a843678abf5f61979c748687e66bSherry Moore /* for cache */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * a command to a target has timed out
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * return TRUE iff cmd abort failed or timed out, else return FALSE
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel SF_DEBUG(1, (sf, CE_NOTE, "Command 0x%p to target %x timed out\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel (void *)cmd->cmd_fp_pkt, cmd->cmd_pkt->pkt_address.a_target));
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* call the transport to abort a command */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel SF_DEBUG(1, (sf, CE_NOTE, "Command Abort succeeded\n"));
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel break; /* success */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel SF_DEBUG(1, (sf, CE_NOTE, "Command Abort failed at target\n"));
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sf_token = (int *)(uintptr_t)fpkt->fcal_socal_request.\
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel SF_DEBUG(1, (sf, CE_NOTE, "Command Abort bad abort\n"));
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel cmd->cmd_timeout = sf_watchdog_time + cmd->cmd_pkt->pkt_time
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "Command Abort failed target 0x%x, forcing a LIP\n", tgt_id);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sf_token = (int *)(uintptr_t)fpkt->fcal_socal_request.\
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * an ELS command has timed out
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * return ???
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic struct sf_els_hdr *
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelsf_els_timeout(struct sf *sf, struct sf_els_hdr *privp)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* use as temporary state variable */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * take socal core if required. Timeouts for IB and hosts
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * are not very interesting, so we take socal core only
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * if the timeout is *not* for a IB or host.
193974072f41a843678abf5f61979c748687e66bSherry Moore 0x0d) != 0x0d) && ((privp->dest_nport_id != 1) ||
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sf_token = (int *)(uintptr_t)fpkt->fcal_socal_request.\
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel } else if (privp->fpkt->fcal_pkt_comp == sf_reportlun_callback) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (sf_core && (sf_core & SF_CORE_REPORTLUN_TIMEOUT)) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sf_token = (int *)(uintptr_t)fpkt->fcal_socal_request.\
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel } else if (privp->fpkt->fcal_pkt_comp == sf_inq_callback) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (sf_core && (sf_core & SF_CORE_INQUIRY_TIMEOUT)) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* delayed retry */
193974072f41a843678abf5f61979c748687e66bSherry Moore "!sf%d: %s to target %x delayed retry\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sf_log(sf, CE_NOTE, "!%s to target 0x%x alpa 0x%x timed out\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel rval = soc_abort(sf->sf_sochandle, sf->sf_socp, sf->sf_sochandle
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (rval == FCAL_ABORTED || rval == FCAL_ABORT_FAILED) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel SF_DEBUG(1, (sf, CE_NOTE, "!%s abort to al_pa %x succeeded\n",
193974072f41a843678abf5f61979c748687e66bSherry Moore "!%s to target 0x%x retrying\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sf_log(sf, CE_NOTE, "%s abort to target 0x%x failed. "
193974072f41a843678abf5f61979c748687e66bSherry Moore sf_alpa_to_switch[privp->dest_nport_id], rval);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * called by timeout when a reset times out
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel/*ARGSUSED*/
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* is this type cast needed? */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* abort all cmds for this target */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (reset_timeout_flag && (sf_reset_timeout_id == 0)) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * called to "reset the bus", i.e. force loop initialization (and address
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * re-negotiation)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* disable restart of lip if we're suspended */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "sf_force_lip, sf%d: lip restart disabled "
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "due to DDI_SUSPEND\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel for (i = 0; i < sf_max_targets; i++) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sf->sf_timer = sf_watchdog_time + SF_OFFLINE_TIMEOUT;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* are we allowing LIPs ?? */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* call the transport to force loop initialization */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (((i = soc_force_lip(sf->sf_sochandle, sf->sf_socp,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* force LIP failed */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* are we allowing reset after LIP failed ?? */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* restart socal after resetting it */
193974072f41a843678abf5f61979c748687e66bSherry Moore "!Force lip failed Status code 0x%x."
193974072f41a843678abf5f61979c748687e66bSherry Moore " Reseting\n", i);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* call transport to force a reset */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * called by the transport when an unsolicited ELS is received
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelsf_unsol_els_callback(void *arg, soc_response_t *srp, caddr_t payload)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if ((els == NULL) || ((i = srp->sr_soc_hdr.sh_byte_cnt) == 0)) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * logout received -- log the fact
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sf_log(sf, CE_NOTE, "!LOGO recvd from target %x, %s\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel default: /* includes LA_ELS_PLOGI */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * something besides a logout received -- we don't handle
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * this so send back a reject saying its unsupported
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sf_log(sf, CE_NOTE, "!ELS 0x%x recvd from target 0x%x\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* allocate room for a response */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (sf_els_alloc(sf, dest_id, sizeof (struct sf_els_hdr),
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sizeof (struct la_els_rjt), sizeof (union sf_els_rsp),
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* fill in pkt header */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* fill in response */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel ((struct la_els_logi *)privp->rsp)->ls_code = LA_ELS_ACC;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * Error logging, printing, and debug print routines
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel/*PRINTFLIKE3*/
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelsf_log(struct sf *sf, int level, const char *fmt, ...)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * called to get some sf kstats -- return 0 on success else return errno
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* can't write */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel return (0); /* success */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * Unix Entry Points
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * driver entry point for opens on control device
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel/* ARGSUSED */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelsf_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* just ensure soft state exists for this device */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sf = ddi_get_soft_state(sf_state, SF_MINOR2INST(getminor(dev)));
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel return (0);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * driver entry point for last close on control device
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel/* ARGSUSED */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelsf_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sf = ddi_get_soft_state(sf_state, SF_MINOR2INST(getminor(dev)));
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (!sf->sf_check_n_close) { /* if this flag is zero */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel cmn_err(CE_WARN, "sf%d: trying to close unopened instance",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel return (0);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * driver entry point for sf ioctl commands
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel/* ARGSUSED */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel int cmd, intptr_t arg, int mode, cred_t *cred_p, int *rval_p)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sf = ddi_get_soft_state(sf_state, SF_MINOR2INST(getminor(dev)));
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* handle all ioctls */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * We can use the generic implementation for these ioctls
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel return (ndi_devctl_ioctl(sf->sf_dip, cmd, arg, mode, 0));
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * return FC map
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if ((sf->sf_lilp_map->lilp_magic != FCAL_LILP_MAGIC &&
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sf->sf_lilp_map->lilp_magic != FCAL_BADLILP_MAGIC) ||
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (sf->sf_lilp_map->lilp_magic == FCAL_BADLILP_MAGIC) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel int i, j = 0;
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* Need to generate a fake lilp map */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel for (i = 0; i < sf_max_targets; i++) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel for (i = 0; i < cnt; i++) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * handle device control ioctls
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if ((target = sf_get_target_from_dip(sf, cdip)) == NULL) {
602ca9ea8f9ce0933f0944601cc5d230e91a950dcth /* This is ugly */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * get the target given a DIP
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelstatic struct sf_target *
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelsf_get_target_from_dip(struct sf *sf, dev_info_t *dip)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* scan each hash queue for the DIP in question */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel for (i = 0; i < SF_NUM_HASH_QUEUES; i++) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * called by the transport to get an event cookie
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelsf_bus_get_eventcookie(dev_info_t *dip, dev_info_t *rdip, char *name,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sf = ddi_get_soft_state(sf_state, ddi_get_instance(dip));
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* can't find instance for this device */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel return (ndi_event_retrieve_cookie(sf->sf_event_hdl, rdip, name,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * called by the transport to add an event callback
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelsf_bus_add_eventcall(dev_info_t *dip, dev_info_t *rdip,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel ddi_eventcookie_t eventid, void (*callback)(dev_info_t *dip,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel ddi_eventcookie_t event, void *arg, void *impl_data), void *arg,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sf = ddi_get_soft_state(sf_state, ddi_get_instance(dip));
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* can't find instance for this device */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel return (ndi_event_add_callback(sf->sf_event_hdl, rdip,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * called by the transport to remove an event callback
3d19cdae966d9ac4218dd9859640463bd7da19d8stevelsf_bus_remove_eventcall(dev_info_t *devi, ddi_callback_id_t cb_id)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel sf = ddi_get_soft_state(sf_state, ddi_get_instance(devi));
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* can't find instance for this device */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel return (ndi_event_remove_callback(sf->sf_event_hdl, cb_id));
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * called by the transport to post an event
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* is this a remove event ?? */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel struct sf *sf = ddi_get_soft_state(sf_state, ddi_get_instance(dip));
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel remove_cookie = ndi_event_tag_to_cookie(sf->sf_event_hdl,
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* handle remove event */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* no sf instance for this device */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* get the target for this event */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if ((target = sf_get_target_from_dip(sf, rdip)) != NULL) {
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * clear device info for this target and mark as
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* no target for this event */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* an insertion event */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel if (ndi_busop_get_eventcookie(dip, rdip, FCAL_INSERT_EVENT, &cookie)
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel return (ndi_post_event(dip, rdip, cookie, impldata));
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel * the sf hotplug daemon, one thread per sf instance
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* save ptr to head of list */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* take element off of list */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* element only one in list -- list now empty */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* remove element from head of list */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* online this target */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* offline this target */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* don't do NDI_DEVI_REMOVE for now */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel "device offline succeeded\n",
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* if exit is not already signaled */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* wait to be signaled by work or exit */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel cv_wait(&sf->sf_hp_daemon_cv, &sf->sf_hp_daemon_mutex);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel CALLB_CPR_SAFE_END(&cprinfo, &sf->sf_hp_daemon_mutex);
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* sf_hp_daemon_mutex is dropped by CALLB_CPR_EXIT */
3d19cdae966d9ac4218dd9859640463bd7da19d8stevel /* NOTREACHED */