1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright (c) 2011 Bayard G. Bell. All rights reserved.
25 */
26
27 /*
28 * sf - Solaris Fibre Channel driver
29 *
30 * This module implements some of the Fibre Channel FC-4 layer, converting
31 * from FC frames to SCSI and back. (Note: no sequence management is done
32 * here, though.)
33 */
34
35 #if defined(lint) && !defined(DEBUG)
36 #define DEBUG 1
37 #endif
38
39 /*
40 * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
41 * Need to use the ugly RAID LUN mappings in FCP Annex D
42 * to prevent SCSA from barfing. This *REALLY* needs to
43 * be addressed by the standards committee.
44 */
45 #define RAID_LUNS 1
46
47 #ifdef DEBUG
48 static int sfdebug = 0;
49 #include <sys/debug.h>
50
51 #define SF_DEBUG(level, args) \
52 if (sfdebug >= (level)) sf_log args
53 #else
54 #define SF_DEBUG(level, args)
55 #endif
56
57 static int sf_bus_config_debug = 0;
58
59 /* Why do I have to do this? */
60 #if defined(__GNUC__)
61 #define offsetof(s, m) __builtin_offsetof(s, m)
62 #else
63 #define offsetof(s, m) ((size_t)(&(((s *)0)->m)))
64 #endif
65
66 #include <sys/scsi/scsi.h>
67 #include <sys/fc4/fcal.h>
68 #include <sys/fc4/fcp.h>
69 #include <sys/fc4/fcal_linkapp.h>
70 #include <sys/socal_cq_defs.h>
71 #include <sys/fc4/fcal_transport.h>
72 #include <sys/fc4/fcio.h>
73 #include <sys/scsi/adapters/sfvar.h>
74 #include <sys/scsi/impl/scsi_reset_notify.h>
75 #include <sys/stat.h>
76 #include <sys/varargs.h>
77 #include <sys/var.h>
78 #include <sys/thread.h>
79 #include <sys/proc.h>
80 #include <sys/kstat.h>
81 #include <sys/devctl.h>
82 #include <sys/scsi/targets/ses.h>
83 #include <sys/callb.h>
84
85 static int sf_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
86 static int sf_attach(dev_info_t *, ddi_attach_cmd_t);
87 static int sf_detach(dev_info_t *, ddi_detach_cmd_t);
88 static void sf_softstate_unlink(struct sf *);
89 static int sf_scsi_bus_config(dev_info_t *parent, uint_t flag,
90 ddi_bus_config_op_t op, void *arg, dev_info_t **childp);
91 static int sf_scsi_bus_unconfig(dev_info_t *parent, uint_t flag,
92 ddi_bus_config_op_t op, void *arg);
93 static int sf_scsi_tgt_init(dev_info_t *, dev_info_t *,
94 scsi_hba_tran_t *, struct scsi_device *);
95 static void sf_scsi_tgt_free(dev_info_t *, dev_info_t *,
96 scsi_hba_tran_t *, struct scsi_device *);
97 static int sf_pkt_alloc_extern(struct sf *, struct sf_pkt *,
98 int, int, int);
99 static void sf_pkt_destroy_extern(struct sf *, struct sf_pkt *);
100 static struct scsi_pkt *sf_scsi_init_pkt(struct scsi_address *,
101 struct scsi_pkt *, struct buf *, int, int, int, int, int (*)(), caddr_t);
102 static void sf_scsi_destroy_pkt(struct scsi_address *, struct scsi_pkt *);
103 static void sf_scsi_dmafree(struct scsi_address *, struct scsi_pkt *);
104 static void sf_scsi_sync_pkt(struct scsi_address *, struct scsi_pkt *);
105 static int sf_scsi_reset_notify(struct scsi_address *, int,
106 void (*)(caddr_t), caddr_t);
107 static int sf_scsi_get_name(struct scsi_device *, char *, int);
108 static int sf_scsi_get_bus_addr(struct scsi_device *, char *, int);
109 static int sf_add_cr_pool(struct sf *);
110 static int sf_cr_alloc(struct sf *, struct sf_pkt *, int (*)());
111 static void sf_cr_free(struct sf_cr_pool *, struct sf_pkt *);
112 static void sf_crpool_free(struct sf *);
113 static int sf_kmem_cache_constructor(void *, void *, int);
114 static void sf_kmem_cache_destructor(void *, void *);
115 static void sf_statec_callback(void *, int);
116 static int sf_login(struct sf *, uchar_t, uchar_t, uint_t, int);
117 static int sf_els_transport(struct sf *, struct sf_els_hdr *);
118 static void sf_els_callback(struct fcal_packet *);
119 static int sf_do_prli(struct sf *, struct sf_els_hdr *, struct la_els_logi *);
120 static int sf_do_adisc(struct sf *, struct sf_els_hdr *);
121 static int sf_do_reportlun(struct sf *, struct sf_els_hdr *,
122 struct sf_target *);
123 static void sf_reportlun_callback(struct fcal_packet *);
124 static int sf_do_inquiry(struct sf *, struct sf_els_hdr *,
125 struct sf_target *);
126 static void sf_inq_callback(struct fcal_packet *);
127 static struct fcal_packet *sf_els_alloc(struct sf *, uchar_t, int, int,
128 int, caddr_t *, caddr_t *);
129 static void sf_els_free(struct fcal_packet *);
130 static struct sf_target *sf_create_target(struct sf *,
131 struct sf_els_hdr *, int, int64_t);
132 #ifdef RAID_LUNS
133 static struct sf_target *sf_lookup_target(struct sf *, uchar_t *, int);
134 #else
135 static struct sf_target *sf_lookup_target(struct sf *, uchar_t *, int64_t);
136 #endif
137 static void sf_finish_init(struct sf *, int);
138 static void sf_offline_target(struct sf *, struct sf_target *);
139 static void sf_create_devinfo(struct sf *, struct sf_target *, int);
140 static int sf_create_props(dev_info_t *, struct sf_target *, int);
141 static int sf_commoncap(struct scsi_address *, char *, int, int, int);
142 static int sf_getcap(struct scsi_address *, char *, int);
143 static int sf_setcap(struct scsi_address *, char *, int, int);
144 static int sf_abort(struct scsi_address *, struct scsi_pkt *);
145 static int sf_reset(struct scsi_address *, int);
146 static void sf_abort_all(struct sf *, struct sf_target *, int, int, int);
147 static int sf_start(struct scsi_address *, struct scsi_pkt *);
148 static int sf_start_internal(struct sf *, struct sf_pkt *);
149 static void sf_fill_ids(struct sf *, struct sf_pkt *, struct sf_target *);
150 static int sf_prepare_pkt(struct sf *, struct sf_pkt *, struct sf_target *);
151 static int sf_dopoll(struct sf *, struct sf_pkt *);
152 static void sf_cmd_callback(struct fcal_packet *);
153 static void sf_throttle(struct sf *);
154 static void sf_watch(void *);
155 static void sf_throttle_start(struct sf *);
156 static void sf_check_targets(struct sf *);
157 static void sf_check_reset_delay(void *);
158 static int sf_target_timeout(struct sf *, struct sf_pkt *);
159 static void sf_force_lip(struct sf *);
160 static void sf_unsol_els_callback(void *, soc_response_t *, caddr_t);
161 static struct sf_els_hdr *sf_els_timeout(struct sf *, struct sf_els_hdr *);
162 /*PRINTFLIKE3*/
163 static void sf_log(struct sf *, int, const char *, ...);
164 static int sf_kstat_update(kstat_t *, int);
165 static int sf_open(dev_t *, int, int, cred_t *);
166 static int sf_close(dev_t, int, int, cred_t *);
167 static int sf_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
168 static struct sf_target *sf_get_target_from_dip(struct sf *, dev_info_t *);
169 static int sf_bus_get_eventcookie(dev_info_t *, dev_info_t *, char *,
170 ddi_eventcookie_t *);
171 static int sf_bus_add_eventcall(dev_info_t *, dev_info_t *,
172 ddi_eventcookie_t, void (*)(), void *, ddi_callback_id_t *cb_id);
173 static int sf_bus_remove_eventcall(dev_info_t *devi, ddi_callback_id_t cb_id);
174 static int sf_bus_post_event(dev_info_t *, dev_info_t *,
175 ddi_eventcookie_t, void *);
176
177 static void sf_hp_daemon(void *);
178
179 /*
180 * this is required to be able to supply a control node
181 * where ioctls can be executed
182 */
183 struct cb_ops sf_cb_ops = {
184 sf_open, /* open */
185 sf_close, /* close */
186 nodev, /* strategy */
187 nodev, /* print */
188 nodev, /* dump */
189 nodev, /* read */
190 nodev, /* write */
191 sf_ioctl, /* ioctl */
192 nodev, /* devmap */
193 nodev, /* mmap */
194 nodev, /* segmap */
195 nochpoll, /* poll */
196 ddi_prop_op, /* cb_prop_op */
197 0, /* streamtab */
198 D_MP | D_NEW | D_HOTPLUG /* driver flags */
199
200 };
201
202 /*
203 * autoconfiguration routines.
204 */
205 static struct dev_ops sf_ops = {
206 DEVO_REV, /* devo_rev, */
207 0, /* refcnt */
208 sf_info, /* info */
209 nulldev, /* identify */
210 nulldev, /* probe */
211 sf_attach, /* attach */
212 sf_detach, /* detach */
213 nodev, /* reset */
214 &sf_cb_ops, /* driver operations */
215 NULL, /* bus operations */
216 NULL, /* power management */
217 ddi_quiesce_not_supported, /* devo_quiesce */
218 };
219
220 #define SF_NAME "FC-AL FCP Nexus Driver" /* Name of the module. */
221 static char sf_version[] = "1.72 08/19/2008"; /* version of the module */
222
223 static struct modldrv modldrv = {
224 &mod_driverops, /* Type of module. This one is a driver */
225 SF_NAME,
226 &sf_ops, /* driver ops */
227 };
228
229 static struct modlinkage modlinkage = {
230 MODREV_1, (void *)&modldrv, NULL
231 };
232
233 /* XXXXXX The following is here to handle broken targets -- remove it later */
234 static int sf_reportlun_forever = 0;
235 /* XXXXXX */
236 static int sf_lip_on_plogo = 0;
237 static int sf_els_retries = SF_ELS_RETRIES;
238 static struct sf *sf_head = NULL;
239 static int sf_target_scan_cnt = 4;
240 static int sf_pkt_scan_cnt = 5;
241 static int sf_pool_scan_cnt = 1800;
242 static void *sf_state = NULL;
243 static int sf_watchdog_init = 0;
244 static int sf_watchdog_time = 0;
245 static int sf_watchdog_timeout = 1;
246 static int sf_watchdog_tick;
247 static int sf_watch_running = 0;
248 static timeout_id_t sf_watchdog_id;
249 static timeout_id_t sf_reset_timeout_id;
250 static int sf_max_targets = SF_MAX_TARGETS;
251 static kmutex_t sf_global_mutex;
252 static int sf_core = 0;
253 int *sf_token = NULL; /* Must not be static or lint complains. */
254 static kcondvar_t sf_watch_cv;
255 extern pri_t minclsyspri;
256 static ddi_eventcookie_t sf_insert_eid;
257 static ddi_eventcookie_t sf_remove_eid;
258
259 static ndi_event_definition_t sf_event_defs[] = {
260 { SF_EVENT_TAG_INSERT, FCAL_INSERT_EVENT, EPL_KERNEL, 0 },
261 { SF_EVENT_TAG_REMOVE, FCAL_REMOVE_EVENT, EPL_INTERRUPT, 0 }
262 };
263
264 #define SF_N_NDI_EVENTS \
265 (sizeof (sf_event_defs) / sizeof (ndi_event_definition_t))
266
267 #ifdef DEBUG
268 static int sf_lip_flag = 1; /* bool: to allow LIPs */
269 static int sf_reset_flag = 1; /* bool: to allow reset after LIP */
270 static int sf_abort_flag = 0; /* bool: to do just one abort */
271 #endif
272
273 extern int64_t ddi_get_lbolt64(void);
274
275 /*
276 * for converting between target number (switch) and hard address/AL_PA
277 */
278 static uchar_t sf_switch_to_alpa[] = {
279 0xef, 0xe8, 0xe4, 0xe2, 0xe1, 0xe0, 0xdc, 0xda, 0xd9, 0xd6,
280 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xce, 0xcd, 0xcc, 0xcb, 0xca,
281 0xc9, 0xc7, 0xc6, 0xc5, 0xc3, 0xbc, 0xba, 0xb9, 0xb6, 0xb5,
282 0xb4, 0xb3, 0xb2, 0xb1, 0xae, 0xad, 0xac, 0xab, 0xaa, 0xa9,
283 0xa7, 0xa6, 0xa5, 0xa3, 0x9f, 0x9e, 0x9d, 0x9b, 0x98, 0x97,
284 0x90, 0x8f, 0x88, 0x84, 0x82, 0x81, 0x80, 0x7c, 0x7a, 0x79,
285 0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x6e, 0x6d, 0x6c, 0x6b,
286 0x6a, 0x69, 0x67, 0x66, 0x65, 0x63, 0x5c, 0x5a, 0x59, 0x56,
287 0x55, 0x54, 0x53, 0x52, 0x51, 0x4e, 0x4d, 0x4c, 0x4b, 0x4a,
288 0x49, 0x47, 0x46, 0x45, 0x43, 0x3c, 0x3a, 0x39, 0x36, 0x35,
289 0x34, 0x33, 0x32, 0x31, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29,
290 0x27, 0x26, 0x25, 0x23, 0x1f, 0x1e, 0x1d, 0x1b, 0x18, 0x17,
291 0x10, 0x0f, 0x08, 0x04, 0x02, 0x01
292 };
293
294 static uchar_t sf_alpa_to_switch[] = {
295 0x00, 0x7d, 0x7c, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x7a, 0x00,
296 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x78, 0x00, 0x00, 0x00,
297 0x00, 0x00, 0x00, 0x77, 0x76, 0x00, 0x00, 0x75, 0x00, 0x74,
298 0x73, 0x72, 0x00, 0x00, 0x00, 0x71, 0x00, 0x70, 0x6f, 0x6e,
299 0x00, 0x6d, 0x6c, 0x6b, 0x6a, 0x69, 0x68, 0x00, 0x00, 0x67,
300 0x66, 0x65, 0x64, 0x63, 0x62, 0x00, 0x00, 0x61, 0x60, 0x00,
301 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d,
302 0x5c, 0x5b, 0x00, 0x5a, 0x59, 0x58, 0x57, 0x56, 0x55, 0x00,
303 0x00, 0x54, 0x53, 0x52, 0x51, 0x50, 0x4f, 0x00, 0x00, 0x4e,
304 0x4d, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4b,
305 0x00, 0x4a, 0x49, 0x48, 0x00, 0x47, 0x46, 0x45, 0x44, 0x43,
306 0x42, 0x00, 0x00, 0x41, 0x40, 0x3f, 0x3e, 0x3d, 0x3c, 0x00,
307 0x00, 0x3b, 0x3a, 0x00, 0x39, 0x00, 0x00, 0x00, 0x38, 0x37,
308 0x36, 0x00, 0x35, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
309 0x00, 0x00, 0x00, 0x33, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00,
310 0x00, 0x31, 0x30, 0x00, 0x00, 0x2f, 0x00, 0x2e, 0x2d, 0x2c,
311 0x00, 0x00, 0x00, 0x2b, 0x00, 0x2a, 0x29, 0x28, 0x00, 0x27,
312 0x26, 0x25, 0x24, 0x23, 0x22, 0x00, 0x00, 0x21, 0x20, 0x1f,
313 0x1e, 0x1d, 0x1c, 0x00, 0x00, 0x1b, 0x1a, 0x00, 0x19, 0x00,
314 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x17, 0x16, 0x15,
315 0x00, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x00, 0x00, 0x0e,
316 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x00, 0x00, 0x08, 0x07, 0x00,
317 0x06, 0x00, 0x00, 0x00, 0x05, 0x04, 0x03, 0x00, 0x02, 0x00,
318 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
319 };
320
321 /*
322 * these macros call the proper transport-layer function given
323 * a particular transport
324 */
325 #define soc_transport(a, b, c, d) (*a->fcal_ops->fcal_transport)(b, c, d)
326 #define soc_transport_poll(a, b, c, d)\
327 (*a->fcal_ops->fcal_transport_poll)(b, c, d)
328 #define soc_get_lilp_map(a, b, c, d, e)\
329 (*a->fcal_ops->fcal_lilp_map)(b, c, d, e)
330 #define soc_force_lip(a, b, c, d, e)\
331 (*a->fcal_ops->fcal_force_lip)(b, c, d, e)
332 #define soc_abort(a, b, c, d, e)\
333 (*a->fcal_ops->fcal_abort_cmd)(b, c, d, e)
334 #define soc_force_reset(a, b, c, d)\
335 (*a->fcal_ops->fcal_force_reset)(b, c, d)
336 #define soc_add_ulp(a, b, c, d, e, f, g, h)\
337 (*a->fcal_ops->fcal_add_ulp)(b, c, d, e, f, g, h)
338 #define soc_remove_ulp(a, b, c, d, e)\
339 (*a->fcal_ops->fcal_remove_ulp)(b, c, d, e)
340 #define soc_take_core(a, b) (*a->fcal_ops->fcal_take_core)(b)
341
342
343 /* power management property defines (should be in a common include file?) */
344 #define PM_HARDWARE_STATE_PROP "pm-hardware-state"
345 #define PM_NEEDS_SUSPEND_RESUME "needs-suspend-resume"
346
347
348 /* node properties */
349 #define NODE_WWN_PROP "node-wwn"
350 #define PORT_WWN_PROP "port-wwn"
351 #define LIP_CNT_PROP "lip-count"
352 #define TARGET_PROP "target"
353 #define LUN_PROP "lun"
354
355
356 /*
357 * initialize this driver and install this module
358 */
359 int
360 _init(void)
361 {
362 int i;
363
364 i = ddi_soft_state_init(&sf_state, sizeof (struct sf),
365 SF_INIT_ITEMS);
366 if (i != 0)
367 return (i);
368
369 if ((i = scsi_hba_init(&modlinkage)) != 0) {
370 ddi_soft_state_fini(&sf_state);
371 return (i);
372 }
373
374 mutex_init(&sf_global_mutex, NULL, MUTEX_DRIVER, NULL);
375 sf_watch_running = 0;
376 cv_init(&sf_watch_cv, NULL, CV_DRIVER, NULL);
377
378 if ((i = mod_install(&modlinkage)) != 0) {
379 mutex_destroy(&sf_global_mutex);
380 cv_destroy(&sf_watch_cv);
381 scsi_hba_fini(&modlinkage);
382 ddi_soft_state_fini(&sf_state);
383 return (i);
384 }
385
386 return (i);
387 }
388
389
390 /*
391 * remove this driver module from the system
392 */
393 int
394 _fini(void)
395 {
396 int i;
397
398 if ((i = mod_remove(&modlinkage)) == 0) {
399 scsi_hba_fini(&modlinkage);
400 mutex_destroy(&sf_global_mutex);
401 cv_destroy(&sf_watch_cv);
402 ddi_soft_state_fini(&sf_state);
403 }
404 return (i);
405 }
406
407
408 int
409 _info(struct modinfo *modinfop)
410 {
411 return (mod_info(&modlinkage, modinfop));
412 }
413
414 /*
415 * Given the device number return the devinfo pointer or instance
416 */
417 /*ARGSUSED*/
418 static int
419 sf_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
420 {
421 int instance = SF_MINOR2INST(getminor((dev_t)arg));
422 struct sf *sf;
423
424 switch (infocmd) {
425 case DDI_INFO_DEVT2DEVINFO:
426 sf = ddi_get_soft_state(sf_state, instance);
427 if (sf != NULL)
428 *result = sf->sf_dip;
429 else {
430 *result = NULL;
431 return (DDI_FAILURE);
432 }
433 break;
434
435 case DDI_INFO_DEVT2INSTANCE:
436 *result = (void *)(uintptr_t)instance;
437 break;
438 default:
439 return (DDI_FAILURE);
440 }
441 return (DDI_SUCCESS);
442 }
443
444 /*
445 * either attach or resume this driver
446 */
447 static int
448 sf_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
449 {
450 int instance;
451 int mutex_initted = FALSE;
452 uint_t ccount;
453 size_t i, real_size;
454 struct fcal_transport *handle;
455 char buf[64];
456 struct sf *sf, *tsf;
457 scsi_hba_tran_t *tran = NULL;
458 int handle_bound = FALSE;
459 kthread_t *tp;
460
461
462 switch ((int)cmd) {
463
464 case DDI_RESUME:
465
466 /*
467 * we've previously been SF_STATE_OFFLINEd by a DDI_SUSPEND,
468 * so time to undo that and get going again by forcing a
469 * lip
470 */
471
472 instance = ddi_get_instance(dip);
473
474 sf = ddi_get_soft_state(sf_state, instance);
475 SF_DEBUG(2, (sf, CE_CONT,
476 "sf_attach: DDI_RESUME for sf%d\n", instance));
477 if (sf == NULL) {
478 cmn_err(CE_WARN, "sf%d: bad soft state", instance);
479 return (DDI_FAILURE);
480 }
481
482 /*
483 * clear suspended flag so that normal operations can resume
484 */
485 mutex_enter(&sf->sf_mutex);
486 sf->sf_state &= ~SF_STATE_SUSPENDED;
487 mutex_exit(&sf->sf_mutex);
488
489 /*
490 * force a login by setting our state to offline
491 */
492 sf->sf_timer = sf_watchdog_time + SF_OFFLINE_TIMEOUT;
493 sf->sf_state = SF_STATE_OFFLINE;
494
495 /*
496 * call transport routine to register state change and
497 * ELS callback routines (to register us as a ULP)
498 */
499 soc_add_ulp(sf->sf_sochandle, sf->sf_socp,
500 sf->sf_sochandle->fcal_portno, TYPE_SCSI_FCP,
501 sf_statec_callback, sf_unsol_els_callback, NULL, sf);
502
503 /*
504 * call transport routine to force loop initialization
505 */
506 (void) soc_force_lip(sf->sf_sochandle, sf->sf_socp,
507 sf->sf_sochandle->fcal_portno, 0, FCAL_NO_LIP);
508
509 /*
510 * increment watchdog init flag, setting watchdog timeout
511 * if we are the first (since somebody has to do it)
512 */
513 mutex_enter(&sf_global_mutex);
514 if (!sf_watchdog_init++) {
515 mutex_exit(&sf_global_mutex);
516 sf_watchdog_id = timeout(sf_watch,
517 (caddr_t)0, sf_watchdog_tick);
518 } else {
519 mutex_exit(&sf_global_mutex);
520 }
521
522 return (DDI_SUCCESS);
523
524 case DDI_ATTACH:
525
526 /*
527 * this instance attaching for the first time
528 */
529
530 instance = ddi_get_instance(dip);
531
532 if (ddi_soft_state_zalloc(sf_state, instance) !=
533 DDI_SUCCESS) {
534 cmn_err(CE_WARN, "sf%d: failed to allocate soft state",
535 instance);
536 return (DDI_FAILURE);
537 }
538
539 sf = ddi_get_soft_state(sf_state, instance);
540 SF_DEBUG(4, (sf, CE_CONT,
541 "sf_attach: DDI_ATTACH for sf%d\n", instance));
542 if (sf == NULL) {
543 /* this shouldn't happen since we just allocated it */
544 cmn_err(CE_WARN, "sf%d: bad soft state", instance);
545 return (DDI_FAILURE);
546 }
547
548 /*
549 * from this point on, if there's an error, we must de-allocate
550 * soft state before returning DDI_FAILURE
551 */
552
553 if ((handle = ddi_get_parent_data(dip)) == NULL) {
554 cmn_err(CE_WARN,
555 "sf%d: failed to obtain transport handle",
556 instance);
557 goto fail;
558 }
559
560 /* fill in our soft state structure */
561 sf->sf_dip = dip;
562 sf->sf_state = SF_STATE_INIT;
563 sf->sf_throttle = handle->fcal_cmdmax;
564 sf->sf_sochandle = handle;
565 sf->sf_socp = handle->fcal_handle;
566 sf->sf_check_n_close = 0;
567
568 /* create a command/response buffer pool for this instance */
569 if (sf_add_cr_pool(sf) != DDI_SUCCESS) {
570 cmn_err(CE_WARN,
571 "sf%d: failed to allocate command/response pool",
572 instance);
573 goto fail;
574 }
575
576 /* create a a cache for this instance */
577 (void) sprintf(buf, "sf%d_cache", instance);
578 sf->sf_pkt_cache = kmem_cache_create(buf,
579 sizeof (fcal_packet_t) + sizeof (struct sf_pkt) +
580 scsi_pkt_size(), 8,
581 sf_kmem_cache_constructor, sf_kmem_cache_destructor,
582 NULL, NULL, NULL, 0);
583 if (sf->sf_pkt_cache == NULL) {
584 cmn_err(CE_WARN, "sf%d: failed to allocate kmem cache",
585 instance);
586 goto fail;
587 }
588
589 /* set up a handle and allocate memory for DMA */
590 if (ddi_dma_alloc_handle(sf->sf_dip, sf->sf_sochandle->
591 fcal_dmaattr, DDI_DMA_DONTWAIT, NULL, &sf->
592 sf_lilp_dmahandle) != DDI_SUCCESS) {
593 cmn_err(CE_WARN,
594 "sf%d: failed to allocate dma handle for lilp map",
595 instance);
596 goto fail;
597 }
598 i = sizeof (struct fcal_lilp_map) + 1;
599 if (ddi_dma_mem_alloc(sf->sf_lilp_dmahandle,
600 i, sf->sf_sochandle->
601 fcal_accattr, DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
602 (caddr_t *)&sf->sf_lilp_map, &real_size,
603 &sf->sf_lilp_acchandle) != DDI_SUCCESS) {
604 cmn_err(CE_WARN, "sf%d: failed to allocate lilp map",
605 instance);
606 goto fail;
607 }
608 if (real_size < i) {
609 /* no error message ??? */
610 goto fail; /* trouble allocating memory */
611 }
612
613 /*
614 * set up the address for the DMA transfers (getting a cookie)
615 */
616 if (ddi_dma_addr_bind_handle(sf->sf_lilp_dmahandle, NULL,
617 (caddr_t)sf->sf_lilp_map, real_size,
618 DDI_DMA_READ | DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
619 &sf->sf_lilp_dmacookie, &ccount) != DDI_DMA_MAPPED) {
620 cmn_err(CE_WARN,
621 "sf%d: failed to bind dma handle for lilp map",
622 instance);
623 goto fail;
624 }
625 handle_bound = TRUE;
626 /* ensure only one cookie was allocated */
627 if (ccount != 1) {
628 goto fail;
629 }
630
631 /* ensure LILP map and DMA cookie addresses are even?? */
632 sf->sf_lilp_map = (struct fcal_lilp_map *)(((uintptr_t)sf->
633 sf_lilp_map + 1) & ~1);
634 sf->sf_lilp_dmacookie.dmac_address = (sf->
635 sf_lilp_dmacookie.dmac_address + 1) & ~1;
636
637 /* set up all of our mutexes and condition variables */
638 mutex_init(&sf->sf_mutex, NULL, MUTEX_DRIVER, NULL);
639 mutex_init(&sf->sf_cmd_mutex, NULL, MUTEX_DRIVER, NULL);
640 mutex_init(&sf->sf_cr_mutex, NULL, MUTEX_DRIVER, NULL);
641 mutex_init(&sf->sf_hp_daemon_mutex, NULL, MUTEX_DRIVER, NULL);
642 cv_init(&sf->sf_cr_cv, NULL, CV_DRIVER, NULL);
643 cv_init(&sf->sf_hp_daemon_cv, NULL, CV_DRIVER, NULL);
644
645 mutex_initted = TRUE;
646
647 /* create our devctl minor node */
648 if (ddi_create_minor_node(dip, "devctl", S_IFCHR,
649 SF_INST2DEVCTL_MINOR(instance),
650 DDI_NT_NEXUS, 0) != DDI_SUCCESS) {
651 cmn_err(CE_WARN, "sf%d: ddi_create_minor_node failed"
652 " for devctl", instance);
653 goto fail;
654 }
655
656 /* create fc minor node */
657 if (ddi_create_minor_node(dip, "fc", S_IFCHR,
658 SF_INST2FC_MINOR(instance), DDI_NT_FC_ATTACHMENT_POINT,
659 0) != DDI_SUCCESS) {
660 cmn_err(CE_WARN, "sf%d: ddi_create_minor_node failed"
661 " for fc", instance);
662 goto fail;
663 }
664 /* allocate a SCSI transport structure */
665 tran = scsi_hba_tran_alloc(dip, 0);
666 if (tran == NULL) {
667 /* remove all minor nodes created */
668 ddi_remove_minor_node(dip, NULL);
669 cmn_err(CE_WARN, "sf%d: scsi_hba_tran_alloc failed",
670 instance);
671 goto fail;
672 }
673
674 /* Indicate that we are 'sizeof (scsi_*(9S))' clean. */
675 scsi_size_clean(dip); /* SCSI_SIZE_CLEAN_VERIFY ok */
676
677 /* save ptr to new transport structure and fill it in */
678 sf->sf_tran = tran;
679
680 tran->tran_hba_private = sf;
681 tran->tran_tgt_private = NULL;
682 tran->tran_tgt_init = sf_scsi_tgt_init;
683 tran->tran_tgt_probe = NULL;
684 tran->tran_tgt_free = sf_scsi_tgt_free;
685
686 tran->tran_start = sf_start;
687 tran->tran_abort = sf_abort;
688 tran->tran_reset = sf_reset;
689 tran->tran_getcap = sf_getcap;
690 tran->tran_setcap = sf_setcap;
691 tran->tran_init_pkt = sf_scsi_init_pkt;
692 tran->tran_destroy_pkt = sf_scsi_destroy_pkt;
693 tran->tran_dmafree = sf_scsi_dmafree;
694 tran->tran_sync_pkt = sf_scsi_sync_pkt;
695 tran->tran_reset_notify = sf_scsi_reset_notify;
696
697 /*
698 * register event notification routines with scsa
699 */
700 tran->tran_get_eventcookie = sf_bus_get_eventcookie;
701 tran->tran_add_eventcall = sf_bus_add_eventcall;
702 tran->tran_remove_eventcall = sf_bus_remove_eventcall;
703 tran->tran_post_event = sf_bus_post_event;
704
705 /*
706 * register bus configure/unconfigure
707 */
708 tran->tran_bus_config = sf_scsi_bus_config;
709 tran->tran_bus_unconfig = sf_scsi_bus_unconfig;
710
711 /*
712 * allocate an ndi event handle
713 */
714 sf->sf_event_defs = (ndi_event_definition_t *)
715 kmem_zalloc(sizeof (sf_event_defs), KM_SLEEP);
716
717 bcopy(sf_event_defs, sf->sf_event_defs,
718 sizeof (sf_event_defs));
719
720 (void) ndi_event_alloc_hdl(dip, NULL,
721 &sf->sf_event_hdl, NDI_SLEEP);
722
723 sf->sf_events.ndi_events_version = NDI_EVENTS_REV1;
724 sf->sf_events.ndi_n_events = SF_N_NDI_EVENTS;
725 sf->sf_events.ndi_event_defs = sf->sf_event_defs;
726
727 if (ndi_event_bind_set(sf->sf_event_hdl,
728 &sf->sf_events, NDI_SLEEP) != NDI_SUCCESS) {
729 goto fail;
730 }
731
732 tran->tran_get_name = sf_scsi_get_name;
733 tran->tran_get_bus_addr = sf_scsi_get_bus_addr;
734
735 /* setup and attach SCSI hba transport */
736 if (scsi_hba_attach_setup(dip, sf->sf_sochandle->
737 fcal_dmaattr, tran, SCSI_HBA_TRAN_CLONE) != DDI_SUCCESS) {
738 cmn_err(CE_WARN, "sf%d: scsi_hba_attach_setup failed",
739 instance);
740 goto fail;
741 }
742
743 /* set up kstats */
744 if ((sf->sf_ksp = kstat_create("sf", instance, "statistics",
745 "controller", KSTAT_TYPE_RAW, sizeof (struct sf_stats),
746 KSTAT_FLAG_VIRTUAL)) == NULL) {
747 cmn_err(CE_WARN, "sf%d: failed to create kstat",
748 instance);
749 } else {
750 sf->sf_stats.version = 2;
751 (void) sprintf(sf->sf_stats.drvr_name,
752 "%s: %s", SF_NAME, sf_version);
753 sf->sf_ksp->ks_data = (void *)&sf->sf_stats;
754 sf->sf_ksp->ks_private = sf;
755 sf->sf_ksp->ks_update = sf_kstat_update;
756 kstat_install(sf->sf_ksp);
757 }
758
759 /* create the hotplug thread */
760 mutex_enter(&sf->sf_hp_daemon_mutex);
761 tp = thread_create(NULL, 0,
762 (void (*)())sf_hp_daemon, sf, 0, &p0, TS_RUN, minclsyspri);
763 sf->sf_hp_tid = tp->t_did;
764 mutex_exit(&sf->sf_hp_daemon_mutex);
765
766 /* add this soft state instance to the head of the list */
767 mutex_enter(&sf_global_mutex);
768 sf->sf_next = sf_head;
769 tsf = sf_head;
770 sf_head = sf;
771
772 /*
773 * find entry in list that has the same FC-AL handle (if any)
774 */
775 while (tsf != NULL) {
776 if (tsf->sf_socp == sf->sf_socp) {
777 break; /* found matching entry */
778 }
779 tsf = tsf->sf_next;
780 }
781
782 if (tsf != NULL) {
783 /* if we found a matching entry keep track of it */
784 sf->sf_sibling = tsf;
785 }
786
787 /*
788 * increment watchdog init flag, setting watchdog timeout
789 * if we are the first (since somebody has to do it)
790 */
791 if (!sf_watchdog_init++) {
792 mutex_exit(&sf_global_mutex);
793 sf_watchdog_tick = sf_watchdog_timeout *
794 drv_usectohz(1000000);
795 sf_watchdog_id = timeout(sf_watch,
796 NULL, sf_watchdog_tick);
797 } else {
798 mutex_exit(&sf_global_mutex);
799 }
800
801 if (tsf != NULL) {
802 /*
803 * set up matching entry to be our sibling
804 */
805 mutex_enter(&tsf->sf_mutex);
806 tsf->sf_sibling = sf;
807 mutex_exit(&tsf->sf_mutex);
808 }
809
810 /*
811 * create this property so that PM code knows we want
812 * to be suspended at PM time
813 */
814 (void) ddi_prop_update_string(DDI_DEV_T_NONE, dip,
815 PM_HARDWARE_STATE_PROP, PM_NEEDS_SUSPEND_RESUME);
816
817 /* log the fact that we have a new device */
818 ddi_report_dev(dip);
819
820 /*
821 * force a login by setting our state to offline
822 */
823 sf->sf_timer = sf_watchdog_time + SF_OFFLINE_TIMEOUT;
824 sf->sf_state = SF_STATE_OFFLINE;
825
826 /*
827 * call transport routine to register state change and
828 * ELS callback routines (to register us as a ULP)
829 */
830 soc_add_ulp(sf->sf_sochandle, sf->sf_socp,
831 sf->sf_sochandle->fcal_portno, TYPE_SCSI_FCP,
832 sf_statec_callback, sf_unsol_els_callback, NULL, sf);
833
834 /*
835 * call transport routine to force loop initialization
836 */
837 (void) soc_force_lip(sf->sf_sochandle, sf->sf_socp,
838 sf->sf_sochandle->fcal_portno, 0, FCAL_NO_LIP);
839 sf->sf_reset_time = ddi_get_lbolt64();
840 return (DDI_SUCCESS);
841
842 default:
843 return (DDI_FAILURE);
844 }
845
846 fail:
847 cmn_err(CE_WARN, "sf%d: failed to attach", instance);
848
849 /*
850 * Unbind and free event set
851 */
852 if (sf->sf_event_hdl) {
853 (void) ndi_event_unbind_set(sf->sf_event_hdl,
854 &sf->sf_events, NDI_SLEEP);
855 (void) ndi_event_free_hdl(sf->sf_event_hdl);
856 }
857
858 if (sf->sf_event_defs) {
859 kmem_free(sf->sf_event_defs, sizeof (sf_event_defs));
860 }
861
862 if (sf->sf_tran != NULL) {
863 scsi_hba_tran_free(sf->sf_tran);
864 }
865 while (sf->sf_cr_pool != NULL) {
866 sf_crpool_free(sf);
867 }
868 if (sf->sf_lilp_dmahandle != NULL) {
869 if (handle_bound) {
870 (void) ddi_dma_unbind_handle(sf->sf_lilp_dmahandle);
871 }
872 ddi_dma_free_handle(&sf->sf_lilp_dmahandle);
873 }
874 if (sf->sf_pkt_cache != NULL) {
875 kmem_cache_destroy(sf->sf_pkt_cache);
876 }
877 if (sf->sf_lilp_map != NULL) {
878 ddi_dma_mem_free(&sf->sf_lilp_acchandle);
879 }
880 if (sf->sf_ksp != NULL) {
881 kstat_delete(sf->sf_ksp);
882 }
883 if (mutex_initted) {
884 mutex_destroy(&sf->sf_mutex);
885 mutex_destroy(&sf->sf_cmd_mutex);
886 mutex_destroy(&sf->sf_cr_mutex);
887 mutex_destroy(&sf->sf_hp_daemon_mutex);
888 cv_destroy(&sf->sf_cr_cv);
889 cv_destroy(&sf->sf_hp_daemon_cv);
890 }
891 mutex_enter(&sf_global_mutex);
892
893 /*
894 * kill off the watchdog if we are the last instance
895 */
896 if (!--sf_watchdog_init) {
897 timeout_id_t tid = sf_watchdog_id;
898 mutex_exit(&sf_global_mutex);
899 (void) untimeout(tid);
900 } else {
901 mutex_exit(&sf_global_mutex);
902 }
903
904 ddi_soft_state_free(sf_state, instance);
905
906 if (tran != NULL) {
907 /* remove all minor nodes */
908 ddi_remove_minor_node(dip, NULL);
909 }
910
911 return (DDI_FAILURE);
912 }
913
914
915 /* ARGSUSED */
916 static int
917 sf_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
918 {
919 struct sf *sf;
920 int instance;
921 int i;
922 struct sf_target *target;
923 timeout_id_t tid;
924
925
926
927 /* NO OTHER THREADS ARE RUNNING */
928
929 instance = ddi_get_instance(dip);
930
931 if ((sf = ddi_get_soft_state(sf_state, instance)) == NULL) {
932 cmn_err(CE_WARN, "sf_detach, sf%d: bad soft state", instance);
933 return (DDI_FAILURE);
934 }
935
936 switch (cmd) {
937
938 case DDI_SUSPEND:
939 /*
940 * suspend our instance
941 */
942
943 SF_DEBUG(2, (sf, CE_CONT,
944 "sf_detach: DDI_SUSPEND for sf%d\n", instance));
945 /*
946 * There is a race condition in socal where while doing
947 * callbacks if a ULP removes it self from the callback list
948 * the for loop in socal may panic as cblist is junk and
949 * while trying to get cblist->next the system will panic.
950 */
951
952 /* call transport to remove our unregister our callbacks */
953 soc_remove_ulp(sf->sf_sochandle, sf->sf_socp,
954 sf->sf_sochandle->fcal_portno, TYPE_SCSI_FCP, sf);
955
956 /*
957 * begin process of clearing outstanding commands
958 * by issuing a lip
959 */
960 sf_force_lip(sf);
961
962 /*
963 * toggle the device OFFLINE in order to cause
964 * outstanding commands to drain
965 */
966 mutex_enter(&sf->sf_mutex);
967 sf->sf_lip_cnt++;
968 sf->sf_timer = sf_watchdog_time + SF_OFFLINE_TIMEOUT;
969 sf->sf_state = (SF_STATE_OFFLINE | SF_STATE_SUSPENDED);
970 for (i = 0; i < sf_max_targets; i++) {
971 target = sf->sf_targets[i];
972 if (target != NULL) {
973 struct sf_target *ntarget;
974
975 mutex_enter(&target->sft_mutex);
976 if (!(target->sft_state & SF_TARGET_OFFLINE)) {
977 target->sft_state |=
978 (SF_TARGET_BUSY | SF_TARGET_MARK);
979 }
980 /* do this for all LUNs as well */
981 for (ntarget = target->sft_next_lun;
982 ntarget;
983 ntarget = ntarget->sft_next_lun) {
984 mutex_enter(&ntarget->sft_mutex);
985 if (!(ntarget->sft_state &
986 SF_TARGET_OFFLINE)) {
987 ntarget->sft_state |=
988 (SF_TARGET_BUSY |
989 SF_TARGET_MARK);
990 }
991 mutex_exit(&ntarget->sft_mutex);
992 }
993 mutex_exit(&target->sft_mutex);
994 }
995 }
996 mutex_exit(&sf->sf_mutex);
997 mutex_enter(&sf_global_mutex);
998
999 /*
1000 * kill off the watchdog if we are the last instance
1001 */
1002 if (!--sf_watchdog_init) {
1003 tid = sf_watchdog_id;
1004 mutex_exit(&sf_global_mutex);
1005 (void) untimeout(tid);
1006 } else {
1007 mutex_exit(&sf_global_mutex);
1008 }
1009
1010 return (DDI_SUCCESS);
1011
1012 case DDI_DETACH:
1013 /*
1014 * detach this instance
1015 */
1016
1017 SF_DEBUG(2, (sf, CE_CONT,
1018 "sf_detach: DDI_DETACH for sf%d\n", instance));
1019
1020 /* remove this "sf" from the list of sf softstates */
1021 sf_softstate_unlink(sf);
1022
1023 /*
1024 * prior to taking any DDI_DETACH actions, toggle the
1025 * device OFFLINE in order to cause outstanding
1026 * commands to drain
1027 */
1028 mutex_enter(&sf->sf_mutex);
1029 sf->sf_lip_cnt++;
1030 sf->sf_timer = sf_watchdog_time + SF_OFFLINE_TIMEOUT;
1031 sf->sf_state = SF_STATE_OFFLINE;
1032 for (i = 0; i < sf_max_targets; i++) {
1033 target = sf->sf_targets[i];
1034 if (target != NULL) {
1035 struct sf_target *ntarget;
1036
1037 mutex_enter(&target->sft_mutex);
1038 if (!(target->sft_state & SF_TARGET_OFFLINE)) {
1039 target->sft_state |=
1040 (SF_TARGET_BUSY | SF_TARGET_MARK);
1041 }
1042 for (ntarget = target->sft_next_lun;
1043 ntarget;
1044 ntarget = ntarget->sft_next_lun) {
1045 mutex_enter(&ntarget->sft_mutex);
1046 if (!(ntarget->sft_state &
1047 SF_TARGET_OFFLINE)) {
1048 ntarget->sft_state |=
1049 (SF_TARGET_BUSY |
1050 SF_TARGET_MARK);
1051 }
1052 mutex_exit(&ntarget->sft_mutex);
1053 }
1054 mutex_exit(&target->sft_mutex);
1055 }
1056 }
1057 mutex_exit(&sf->sf_mutex);
1058
1059 /* call transport to remove and unregister our callbacks */
1060 soc_remove_ulp(sf->sf_sochandle, sf->sf_socp,
1061 sf->sf_sochandle->fcal_portno, TYPE_SCSI_FCP, sf);
1062
1063 /*
1064 * kill off the watchdog if we are the last instance
1065 */
1066 mutex_enter(&sf_global_mutex);
1067 if (!--sf_watchdog_init) {
1068 tid = sf_watchdog_id;
1069 mutex_exit(&sf_global_mutex);
1070 (void) untimeout(tid);
1071 } else {
1072 mutex_exit(&sf_global_mutex);
1073 }
1074
1075 /* signal sf_hp_daemon() to exit and wait for exit */
1076 mutex_enter(&sf->sf_hp_daemon_mutex);
1077 ASSERT(sf->sf_hp_tid);
1078 sf->sf_hp_exit = 1; /* flag exit */
1079 cv_signal(&sf->sf_hp_daemon_cv);
1080 mutex_exit(&sf->sf_hp_daemon_mutex);
1081 thread_join(sf->sf_hp_tid); /* wait for hotplug to exit */
1082
1083 /*
1084 * Unbind and free event set
1085 */
1086 if (sf->sf_event_hdl) {
1087 (void) ndi_event_unbind_set(sf->sf_event_hdl,
1088 &sf->sf_events, NDI_SLEEP);
1089 (void) ndi_event_free_hdl(sf->sf_event_hdl);
1090 }
1091
1092 if (sf->sf_event_defs) {
1093 kmem_free(sf->sf_event_defs, sizeof (sf_event_defs));
1094 }
1095
1096 /* detach this instance of the HBA driver */
1097 (void) scsi_hba_detach(dip);
1098 scsi_hba_tran_free(sf->sf_tran);
1099
1100 /* deallocate/unbind DMA handle for lilp map */
1101 if (sf->sf_lilp_map != NULL) {
1102 (void) ddi_dma_unbind_handle(sf->sf_lilp_dmahandle);
1103 if (sf->sf_lilp_dmahandle != NULL) {
1104 ddi_dma_free_handle(&sf->sf_lilp_dmahandle);
1105 }
1106 ddi_dma_mem_free(&sf->sf_lilp_acchandle);
1107 }
1108
1109 /*
1110 * the kmem cache must be destroyed before free'ing
1111 * up the crpools
1112 *
1113 * our finagle of "ntot" and "nfree"
1114 * causes an ASSERT failure in "sf_cr_free()"
1115 * if the kmem cache is free'd after invoking
1116 * "sf_crpool_free()".
1117 */
1118 kmem_cache_destroy(sf->sf_pkt_cache);
1119
1120 SF_DEBUG(2, (sf, CE_CONT,
1121 "sf_detach: sf_crpool_free() for instance 0x%x\n",
1122 instance));
1123 while (sf->sf_cr_pool != NULL) {
1124 /*
1125 * set ntot to nfree for this particular entry
1126 *
1127 * this causes sf_crpool_free() to update
1128 * the cr_pool list when deallocating this entry
1129 */
1130 sf->sf_cr_pool->ntot = sf->sf_cr_pool->nfree;
1131 sf_crpool_free(sf);
1132 }
1133
1134 /*
1135 * now that the cr_pool's are gone it's safe
1136 * to destroy all softstate mutex's and cv's
1137 */
1138 mutex_destroy(&sf->sf_mutex);
1139 mutex_destroy(&sf->sf_cmd_mutex);
1140 mutex_destroy(&sf->sf_cr_mutex);
1141 mutex_destroy(&sf->sf_hp_daemon_mutex);
1142 cv_destroy(&sf->sf_cr_cv);
1143 cv_destroy(&sf->sf_hp_daemon_cv);
1144
1145 /* remove all minor nodes from the device tree */
1146 ddi_remove_minor_node(dip, NULL);
1147
1148 /* remove properties created during attach() */
1149 ddi_prop_remove_all(dip);
1150
1151 /* remove kstat's if present */
1152 if (sf->sf_ksp != NULL) {
1153 kstat_delete(sf->sf_ksp);
1154 }
1155
1156 SF_DEBUG(2, (sf, CE_CONT,
1157 "sf_detach: ddi_soft_state_free() for instance 0x%x\n",
1158 instance));
1159 ddi_soft_state_free(sf_state, instance);
1160 return (DDI_SUCCESS);
1161
1162 default:
1163 SF_DEBUG(2, (sf, CE_CONT, "sf_detach: sf%d unknown cmd %x\n",
1164 instance, (int)cmd));
1165 return (DDI_FAILURE);
1166 }
1167 }
1168
1169
1170 /*
1171 * sf_softstate_unlink() - remove an sf instance from the list of softstates
1172 */
1173 static void
1174 sf_softstate_unlink(struct sf *sf)
1175 {
1176 struct sf *sf_ptr;
1177 struct sf *sf_found_sibling;
1178 struct sf *sf_reposition = NULL;
1179
1180
1181 mutex_enter(&sf_global_mutex);
1182 while (sf_watch_running) {
1183 /* Busy working the list -- wait */
1184 cv_wait(&sf_watch_cv, &sf_global_mutex);
1185 }
1186 if ((sf_found_sibling = sf->sf_sibling) != NULL) {
1187 /*
1188 * we have a sibling so NULL out its reference to us
1189 */
1190 mutex_enter(&sf_found_sibling->sf_mutex);
1191 sf_found_sibling->sf_sibling = NULL;
1192 mutex_exit(&sf_found_sibling->sf_mutex);
1193 }
1194
1195 /* remove our instance from the global list */
1196 if (sf == sf_head) {
1197 /* we were at at head of the list */
1198 sf_head = sf->sf_next;
1199 } else {
1200 /* find us in the list */
1201 for (sf_ptr = sf_head;
1202 sf_ptr != NULL;
1203 sf_ptr = sf_ptr->sf_next) {
1204 if (sf_ptr == sf) {
1205 break;
1206 }
1207 /* remember this place */
1208 sf_reposition = sf_ptr;
1209 }
1210 ASSERT(sf_ptr == sf);
1211 ASSERT(sf_reposition != NULL);
1212
1213 sf_reposition->sf_next = sf_ptr->sf_next;
1214 }
1215 mutex_exit(&sf_global_mutex);
1216 }
1217
1218
1219 static int
1220 sf_scsi_bus_config(dev_info_t *parent, uint_t flag,
1221 ddi_bus_config_op_t op, void *arg, dev_info_t **childp)
1222 {
1223 int64_t reset_delay;
1224 struct sf *sf;
1225
1226 sf = ddi_get_soft_state(sf_state, ddi_get_instance(parent));
1227 ASSERT(sf);
1228
1229 reset_delay = (int64_t)(USEC_TO_TICK(SF_INIT_WAIT_TIMEOUT)) -
1230 (ddi_get_lbolt64() - sf->sf_reset_time);
1231 if (reset_delay < 0)
1232 reset_delay = 0;
1233
1234 if (sf_bus_config_debug)
1235 flag |= NDI_DEVI_DEBUG;
1236
1237 return (ndi_busop_bus_config(parent, flag, op,
1238 arg, childp, (clock_t)reset_delay));
1239 }
1240
1241 static int
1242 sf_scsi_bus_unconfig(dev_info_t *parent, uint_t flag,
1243 ddi_bus_config_op_t op, void *arg)
1244 {
1245 if (sf_bus_config_debug)
1246 flag |= NDI_DEVI_DEBUG;
1247
1248 return (ndi_busop_bus_unconfig(parent, flag, op, arg));
1249 }
1250
1251
1252 /*
1253 * called by transport to initialize a SCSI target
1254 */
1255 /* ARGSUSED */
1256 static int
1257 sf_scsi_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip,
1258 scsi_hba_tran_t *hba_tran, struct scsi_device *sd)
1259 {
1260 #ifdef RAID_LUNS
1261 int lun;
1262 #else
1263 int64_t lun;
1264 #endif
1265 struct sf_target *target;
1266 struct sf *sf = (struct sf *)hba_tran->tran_hba_private;
1267 int i, t_len;
1268 unsigned int lip_cnt;
1269 unsigned char wwn[FC_WWN_SIZE];
1270
1271
1272 /* get and validate our SCSI target ID */
1273 i = sd->sd_address.a_target;
1274 if (i >= sf_max_targets) {
1275 return (DDI_NOT_WELL_FORMED);
1276 }
1277
1278 /* get our port WWN property */
1279 t_len = sizeof (wwn);
1280 if (ddi_prop_op(DDI_DEV_T_ANY, tgt_dip, PROP_LEN_AND_VAL_BUF,
1281 DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, PORT_WWN_PROP,
1282 (caddr_t)&wwn, &t_len) != DDI_SUCCESS) {
1283 /* no port WWN property - ignore the OBP stub node */
1284 return (DDI_NOT_WELL_FORMED);
1285 }
1286
1287 /* get our LIP count property */
1288 t_len = sizeof (lip_cnt);
1289 if (ddi_prop_op(DDI_DEV_T_ANY, tgt_dip, PROP_LEN_AND_VAL_BUF,
1290 DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, LIP_CNT_PROP,
1291 (caddr_t)&lip_cnt, &t_len) != DDI_SUCCESS) {
1292 return (DDI_FAILURE);
1293 }
1294 /* and our LUN property */
1295 t_len = sizeof (lun);
1296 if (ddi_prop_op(DDI_DEV_T_ANY, tgt_dip, PROP_LEN_AND_VAL_BUF,
1297 DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "lun",
1298 (caddr_t)&lun, &t_len) != DDI_SUCCESS) {
1299 return (DDI_FAILURE);
1300 }
1301
1302 /* find the target structure for this instance */
1303 mutex_enter(&sf->sf_mutex);
1304 if ((target = sf_lookup_target(sf, wwn, lun)) == NULL) {
1305 mutex_exit(&sf->sf_mutex);
1306 return (DDI_FAILURE);
1307 }
1308
1309 mutex_enter(&target->sft_mutex);
1310 if ((sf->sf_lip_cnt == lip_cnt) && !(target->sft_state
1311 & SF_TARGET_INIT_DONE)) {
1312 /*
1313 * set links between HBA transport and target structures
1314 * and set done flag
1315 */
1316 hba_tran->tran_tgt_private = target;
1317 target->sft_tran = hba_tran;
1318 target->sft_state |= SF_TARGET_INIT_DONE;
1319 } else {
1320 /* already initialized ?? */
1321 mutex_exit(&target->sft_mutex);
1322 mutex_exit(&sf->sf_mutex);
1323 return (DDI_FAILURE);
1324 }
1325 mutex_exit(&target->sft_mutex);
1326 mutex_exit(&sf->sf_mutex);
1327
1328 return (DDI_SUCCESS);
1329 }
1330
1331
1332 /*
1333 * called by transport to free a target
1334 */
1335 /* ARGSUSED */
1336 static void
1337 sf_scsi_tgt_free(dev_info_t *hba_dip, dev_info_t *tgt_dip,
1338 scsi_hba_tran_t *hba_tran, struct scsi_device *sd)
1339 {
1340 struct sf_target *target = hba_tran->tran_tgt_private;
1341
1342 if (target != NULL) {
1343 mutex_enter(&target->sft_mutex);
1344 target->sft_tran = NULL;
1345 target->sft_state &= ~SF_TARGET_INIT_DONE;
1346 mutex_exit(&target->sft_mutex);
1347 }
1348 }
1349
1350
1351 /*
1352 * allocator for non-std size cdb/pkt_private/status -- return TRUE iff
1353 * success, else return FALSE
1354 */
1355 /*ARGSUSED*/
1356 static int
1357 sf_pkt_alloc_extern(struct sf *sf, struct sf_pkt *cmd,
1358 int tgtlen, int statuslen, int kf)
1359 {
1360 caddr_t scbp, tgt;
1361 int failure = FALSE;
1362 struct scsi_pkt *pkt = CMD2PKT(cmd);
1363
1364
1365 tgt = scbp = NULL;
1366
1367 if (tgtlen > PKT_PRIV_LEN) {
1368 if ((tgt = kmem_zalloc(tgtlen, kf)) == NULL) {
1369 failure = TRUE;
1370 } else {
1371 cmd->cmd_flags |= CFLAG_PRIVEXTERN;
1372 pkt->pkt_private = tgt;
1373 }
1374 }
1375 if (statuslen > EXTCMDS_STATUS_SIZE) {
1376 if ((scbp = kmem_zalloc((size_t)statuslen, kf)) == NULL) {
1377 failure = TRUE;
1378 } else {
1379 cmd->cmd_flags |= CFLAG_SCBEXTERN;
1380 pkt->pkt_scbp = (opaque_t)scbp;
1381 }
1382 }
1383 if (failure) {
1384 sf_pkt_destroy_extern(sf, cmd);
1385 }
1386 return (failure);
1387 }
1388
1389
1390 /*
1391 * deallocator for non-std size cdb/pkt_private/status
1392 */
1393 static void
1394 sf_pkt_destroy_extern(struct sf *sf, struct sf_pkt *cmd)
1395 {
1396 struct scsi_pkt *pkt = CMD2PKT(cmd);
1397
1398 if (cmd->cmd_flags & CFLAG_FREE) {
1399 cmn_err(CE_PANIC,
1400 "sf_scsi_impl_pktfree: freeing free packet");
1401 _NOTE(NOT_REACHED)
1402 /* NOTREACHED */
1403 }
1404 if (cmd->cmd_flags & CFLAG_SCBEXTERN) {
1405 kmem_free((caddr_t)pkt->pkt_scbp,
1406 (size_t)cmd->cmd_scblen);
1407 }
1408 if (cmd->cmd_flags & CFLAG_PRIVEXTERN) {
1409 kmem_free((caddr_t)pkt->pkt_private,
1410 (size_t)cmd->cmd_privlen);
1411 }
1412
1413 cmd->cmd_flags = CFLAG_FREE;
1414 kmem_cache_free(sf->sf_pkt_cache, (void *)cmd);
1415 }
1416
1417
1418 /*
1419 * create or initialize a SCSI packet -- called internally and
1420 * by the transport
1421 */
1422 static struct scsi_pkt *
1423 sf_scsi_init_pkt(struct scsi_address *ap, struct scsi_pkt *pkt,
1424 struct buf *bp, int cmdlen, int statuslen, int tgtlen,
1425 int flags, int (*callback)(), caddr_t arg)
1426 {
1427 int kf;
1428 int failure = FALSE;
1429 struct sf_pkt *cmd;
1430 struct sf *sf = ADDR2SF(ap);
1431 struct sf_target *target = ADDR2TARGET(ap);
1432 struct sf_pkt *new_cmd = NULL;
1433 struct fcal_packet *fpkt;
1434 fc_frame_header_t *hp;
1435 struct fcp_cmd *fcmd;
1436
1437
1438 /*
1439 * If we've already allocated a pkt once,
1440 * this request is for dma allocation only.
1441 */
1442 if (pkt == NULL) {
1443
1444 /*
1445 * First step of sf_scsi_init_pkt: pkt allocation
1446 */
1447 if (cmdlen > FCP_CDB_SIZE) {
1448 return (NULL);
1449 }
1450
1451 kf = (callback == SLEEP_FUNC)? KM_SLEEP: KM_NOSLEEP;
1452
1453 if ((cmd = kmem_cache_alloc(sf->sf_pkt_cache, kf)) != NULL) {
1454 /*
1455 * Selective zeroing of the pkt.
1456 */
1457
1458 cmd->cmd_flags = 0;
1459 cmd->cmd_forw = 0;
1460 cmd->cmd_back = 0;
1461 cmd->cmd_next = 0;
1462 cmd->cmd_pkt = (struct scsi_pkt *)((char *)cmd +
1463 sizeof (struct sf_pkt) + sizeof (struct
1464 fcal_packet));
1465 cmd->cmd_fp_pkt = (struct fcal_packet *)((char *)cmd +
1466 sizeof (struct sf_pkt));
1467 cmd->cmd_fp_pkt->fcal_pkt_private = (opaque_t)cmd;
1468 cmd->cmd_state = SF_STATE_IDLE;
1469 cmd->cmd_pkt->pkt_ha_private = (opaque_t)cmd;
1470 cmd->cmd_pkt->pkt_scbp = (opaque_t)cmd->cmd_scsi_scb;
1471 cmd->cmd_pkt->pkt_comp = NULL;
1472 cmd->cmd_pkt->pkt_flags = 0;
1473 cmd->cmd_pkt->pkt_time = 0;
1474 cmd->cmd_pkt->pkt_resid = 0;
1475 cmd->cmd_pkt->pkt_reason = 0;
1476 cmd->cmd_cdblen = (uchar_t)cmdlen;
1477 cmd->cmd_scblen = statuslen;
1478 cmd->cmd_privlen = tgtlen;
1479 cmd->cmd_pkt->pkt_address = *ap;
1480
1481 /* zero pkt_private */
1482 (int *)(cmd->cmd_pkt->pkt_private =
1483 cmd->cmd_pkt_private);
1484 bzero((caddr_t)cmd->cmd_pkt->pkt_private,
1485 PKT_PRIV_LEN);
1486 } else {
1487 failure = TRUE;
1488 }
1489
1490 if (failure ||
1491 (tgtlen > PKT_PRIV_LEN) ||
1492 (statuslen > EXTCMDS_STATUS_SIZE)) {
1493 if (!failure) {
1494 /* need to allocate more space */
1495 failure = sf_pkt_alloc_extern(sf, cmd,
1496 tgtlen, statuslen, kf);
1497 }
1498 if (failure) {
1499 return (NULL);
1500 }
1501 }
1502
1503 fpkt = cmd->cmd_fp_pkt;
1504 if (cmd->cmd_block == NULL) {
1505
1506 /* allocate cmd/response pool buffers */
1507 if (sf_cr_alloc(sf, cmd, callback) == DDI_FAILURE) {
1508 sf_pkt_destroy_extern(sf, cmd);
1509 return (NULL);
1510 }
1511
1512 /* fill in the FC-AL packet */
1513 fpkt->fcal_pkt_cookie = sf->sf_socp;
1514 fpkt->fcal_pkt_comp = sf_cmd_callback;
1515 fpkt->fcal_pkt_flags = 0;
1516 fpkt->fcal_magic = FCALP_MAGIC;
1517 fpkt->fcal_socal_request.sr_soc_hdr.sh_flags =
1518 (ushort_t)(SOC_FC_HEADER |
1519 sf->sf_sochandle->fcal_portno);
1520 fpkt->fcal_socal_request.sr_soc_hdr.sh_class = 3;
1521 fpkt->fcal_socal_request.sr_cqhdr.cq_hdr_count = 1;
1522 fpkt->fcal_socal_request.sr_cqhdr.cq_hdr_flags = 0;
1523 fpkt->fcal_socal_request.sr_cqhdr.cq_hdr_seqno = 0;
1524 fpkt->fcal_socal_request.sr_dataseg[0].fc_base =
1525 (uint32_t)cmd->cmd_dmac;
1526 fpkt->fcal_socal_request.sr_dataseg[0].fc_count =
1527 sizeof (struct fcp_cmd);
1528 fpkt->fcal_socal_request.sr_dataseg[1].fc_base =
1529 (uint32_t)cmd->cmd_rsp_dmac;
1530 fpkt->fcal_socal_request.sr_dataseg[1].fc_count =
1531 FCP_MAX_RSP_IU_SIZE;
1532
1533 /* Fill in the Fabric Channel Header */
1534 hp = &fpkt->fcal_socal_request.sr_fc_frame_hdr;
1535 hp->r_ctl = R_CTL_COMMAND;
1536 hp->type = TYPE_SCSI_FCP;
1537 hp->f_ctl = F_CTL_SEQ_INITIATIVE | F_CTL_FIRST_SEQ;
1538 hp->reserved1 = 0;
1539 hp->seq_id = 0;
1540 hp->df_ctl = 0;
1541 hp->seq_cnt = 0;
1542 hp->ox_id = 0xffff;
1543 hp->rx_id = 0xffff;
1544 hp->ro = 0;
1545
1546 /* Establish the LUN */
1547 bcopy((caddr_t)&target->sft_lun.b,
1548 (caddr_t)&cmd->cmd_block->fcp_ent_addr,
1549 FCP_LUN_SIZE);
1550 *((int32_t *)&cmd->cmd_block->fcp_cntl) = 0;
1551 }
1552 cmd->cmd_pkt->pkt_cdbp = cmd->cmd_block->fcp_cdb;
1553
1554 mutex_enter(&target->sft_pkt_mutex);
1555
1556 target->sft_pkt_tail->cmd_forw = cmd;
1557 cmd->cmd_back = target->sft_pkt_tail;
1558 cmd->cmd_forw = (struct sf_pkt *)&target->sft_pkt_head;
1559 target->sft_pkt_tail = cmd;
1560
1561 mutex_exit(&target->sft_pkt_mutex);
1562 new_cmd = cmd; /* for later cleanup if needed */
1563 } else {
1564 /* pkt already exists -- just a request for DMA allocation */
1565 cmd = PKT2CMD(pkt);
1566 fpkt = cmd->cmd_fp_pkt;
1567 }
1568
1569 /* zero cdb (bzero is too slow) */
1570 bzero((caddr_t)cmd->cmd_pkt->pkt_cdbp, cmdlen);
1571
1572 /*
1573 * Second step of sf_scsi_init_pkt: dma allocation
1574 * Set up dma info
1575 */
1576 if ((bp != NULL) && (bp->b_bcount != 0)) {
1577 int cmd_flags, dma_flags;
1578 int rval = 0;
1579 uint_t dmacookie_count;
1580
1581 /* there is a buffer and some data to transfer */
1582
1583 /* set up command and DMA flags */
1584 cmd_flags = cmd->cmd_flags;
1585 if (bp->b_flags & B_READ) {
1586 /* a read */
1587 cmd_flags &= ~CFLAG_DMASEND;
1588 dma_flags = DDI_DMA_READ;
1589 } else {
1590 /* a write */
1591 cmd_flags |= CFLAG_DMASEND;
1592 dma_flags = DDI_DMA_WRITE;
1593 }
1594 if (flags & PKT_CONSISTENT) {
1595 cmd_flags |= CFLAG_CMDIOPB;
1596 dma_flags |= DDI_DMA_CONSISTENT;
1597 }
1598
1599 /* ensure we have a DMA handle */
1600 if (cmd->cmd_dmahandle == NULL) {
1601 rval = ddi_dma_alloc_handle(sf->sf_dip,
1602 sf->sf_sochandle->fcal_dmaattr, callback, arg,
1603 &cmd->cmd_dmahandle);
1604 }
1605
1606 if (rval == 0) {
1607 /* bind our DMA handle to our buffer */
1608 rval = ddi_dma_buf_bind_handle(cmd->cmd_dmahandle, bp,
1609 dma_flags, callback, arg, &cmd->cmd_dmacookie,
1610 &dmacookie_count);
1611 }
1612
1613 if (rval != 0) {
1614 /* DMA failure */
1615 SF_DEBUG(2, (sf, CE_CONT, "ddi_dma_buf.. failed\n"));
1616 switch (rval) {
1617 case DDI_DMA_NORESOURCES:
1618 bioerror(bp, 0);
1619 break;
1620 case DDI_DMA_BADATTR:
1621 case DDI_DMA_NOMAPPING:
1622 bioerror(bp, EFAULT);
1623 break;
1624 case DDI_DMA_TOOBIG:
1625 default:
1626 bioerror(bp, EINVAL);
1627 break;
1628 }
1629 /* clear valid flag */
1630 cmd->cmd_flags = cmd_flags & ~CFLAG_DMAVALID;
1631 if (new_cmd != NULL) {
1632 /* destroy packet if we just created it */
1633 sf_scsi_destroy_pkt(ap, new_cmd->cmd_pkt);
1634 }
1635 return (NULL);
1636 }
1637
1638 ASSERT(dmacookie_count == 1);
1639 /* set up amt to transfer and set valid flag */
1640 cmd->cmd_dmacount = bp->b_bcount;
1641 cmd->cmd_flags = cmd_flags | CFLAG_DMAVALID;
1642
1643 ASSERT(cmd->cmd_dmahandle != NULL);
1644 }
1645
1646 /* set up FC-AL packet */
1647 fcmd = cmd->cmd_block;
1648
1649 if (cmd->cmd_flags & CFLAG_DMAVALID) {
1650 if (cmd->cmd_flags & CFLAG_DMASEND) {
1651 /* DMA write */
1652 fcmd->fcp_cntl.cntl_read_data = 0;
1653 fcmd->fcp_cntl.cntl_write_data = 1;
1654 fpkt->fcal_socal_request.sr_cqhdr.cq_hdr_type =
1655 CQ_TYPE_IO_WRITE;
1656 } else {
1657 /* DMA read */
1658 fcmd->fcp_cntl.cntl_read_data = 1;
1659 fcmd->fcp_cntl.cntl_write_data = 0;
1660 fpkt->fcal_socal_request.sr_cqhdr.cq_hdr_type =
1661 CQ_TYPE_IO_READ;
1662 }
1663 fpkt->fcal_socal_request.sr_dataseg[2].fc_base =
1664 (uint32_t)cmd->cmd_dmacookie.dmac_address;
1665 fpkt->fcal_socal_request.sr_dataseg[2].fc_count =
1666 cmd->cmd_dmacookie.dmac_size;
1667 fpkt->fcal_socal_request.sr_soc_hdr.sh_seg_cnt = 3;
1668 fpkt->fcal_socal_request.sr_soc_hdr.sh_byte_cnt =
1669 cmd->cmd_dmacookie.dmac_size;
1670 fcmd->fcp_data_len = cmd->cmd_dmacookie.dmac_size;
1671 } else {
1672 /* not a read or write */
1673 fcmd->fcp_cntl.cntl_read_data = 0;
1674 fcmd->fcp_cntl.cntl_write_data = 0;
1675 fpkt->fcal_socal_request.sr_cqhdr.cq_hdr_type = CQ_TYPE_SIMPLE;
1676 fpkt->fcal_socal_request.sr_soc_hdr.sh_seg_cnt = 2;
1677 fpkt->fcal_socal_request.sr_soc_hdr.sh_byte_cnt =
1678 sizeof (struct fcp_cmd);
1679 fcmd->fcp_data_len = 0;
1680 }
1681 fcmd->fcp_cntl.cntl_qtype = FCP_QTYPE_SIMPLE;
1682
1683 return (cmd->cmd_pkt);
1684 }
1685
1686
1687 /*
1688 * destroy a SCSI packet -- called internally and by the transport
1689 */
1690 static void
1691 sf_scsi_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
1692 {
1693 struct sf_pkt *cmd = PKT2CMD(pkt);
1694 struct sf *sf = ADDR2SF(ap);
1695 struct sf_target *target = ADDR2TARGET(ap);
1696 struct fcal_packet *fpkt = cmd->cmd_fp_pkt;
1697
1698
1699 if (cmd->cmd_flags & CFLAG_DMAVALID) {
1700 /* DMA was set up -- clean up */
1701 (void) ddi_dma_unbind_handle(cmd->cmd_dmahandle);
1702 cmd->cmd_flags ^= CFLAG_DMAVALID;
1703 }
1704
1705 /* take this packet off the doubly-linked list */
1706 mutex_enter(&target->sft_pkt_mutex);
1707 cmd->cmd_back->cmd_forw = cmd->cmd_forw;
1708 cmd->cmd_forw->cmd_back = cmd->cmd_back;
1709 mutex_exit(&target->sft_pkt_mutex);
1710
1711 fpkt->fcal_pkt_flags = 0;
1712 /* free the packet */
1713 if ((cmd->cmd_flags &
1714 (CFLAG_FREE | CFLAG_PRIVEXTERN | CFLAG_SCBEXTERN)) == 0) {
1715 /* just a regular packet */
1716 ASSERT(cmd->cmd_state != SF_STATE_ISSUED);
1717 cmd->cmd_flags = CFLAG_FREE;
1718 kmem_cache_free(sf->sf_pkt_cache, (void *)cmd);
1719 } else {
1720 /* a packet with extra memory */
1721 sf_pkt_destroy_extern(sf, cmd);
1722 }
1723 }
1724
1725
1726 /*
1727 * called by transport to unbind DMA handle
1728 */
1729 /* ARGSUSED */
1730 static void
1731 sf_scsi_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt)
1732 {
1733 struct sf_pkt *cmd = PKT2CMD(pkt);
1734
1735
1736 if (cmd->cmd_flags & CFLAG_DMAVALID) {
1737 (void) ddi_dma_unbind_handle(cmd->cmd_dmahandle);
1738 cmd->cmd_flags ^= CFLAG_DMAVALID;
1739 }
1740
1741 }
1742
1743
1744 /*
1745 * called by transport to synchronize CPU and I/O views of memory
1746 */
1747 /* ARGSUSED */
1748 static void
1749 sf_scsi_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
1750 {
1751 struct sf_pkt *cmd = PKT2CMD(pkt);
1752
1753
1754 if (cmd->cmd_flags & CFLAG_DMAVALID) {
1755 if (ddi_dma_sync(cmd->cmd_dmahandle, (off_t)0, (size_t)0,
1756 (cmd->cmd_flags & CFLAG_DMASEND) ?
1757 DDI_DMA_SYNC_FORDEV : DDI_DMA_SYNC_FORCPU) !=
1758 DDI_SUCCESS) {
1759 cmn_err(CE_WARN, "sf: sync pkt failed");
1760 }
1761 }
1762 }
1763
1764
1765 /*
1766 * routine for reset notification setup, to register or cancel. -- called
1767 * by transport
1768 */
1769 static int
1770 sf_scsi_reset_notify(struct scsi_address *ap, int flag,
1771 void (*callback)(caddr_t), caddr_t arg)
1772 {
1773 struct sf *sf = ADDR2SF(ap);
1774
1775 return (scsi_hba_reset_notify_setup(ap, flag, callback, arg,
1776 &sf->sf_mutex, &sf->sf_reset_notify_listf));
1777 }
1778
1779
1780 /*
1781 * called by transport to get port WWN property (except sun4u)
1782 */
1783 /* ARGSUSED */
1784 static int
1785 sf_scsi_get_name(struct scsi_device *sd, char *name, int len)
1786 {
1787 char tbuf[(FC_WWN_SIZE*2)+1];
1788 unsigned char wwn[FC_WWN_SIZE];
1789 int i, lun;
1790 dev_info_t *tgt_dip;
1791
1792 tgt_dip = sd->sd_dev;
1793 i = sizeof (wwn);
1794 if (ddi_prop_op(DDI_DEV_T_ANY, tgt_dip, PROP_LEN_AND_VAL_BUF,
1795 DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, PORT_WWN_PROP,
1796 (caddr_t)&wwn, &i) != DDI_SUCCESS) {
1797 name[0] = '\0';
1798 return (0);
1799 }
1800 i = sizeof (lun);
1801 if (ddi_prop_op(DDI_DEV_T_ANY, tgt_dip, PROP_LEN_AND_VAL_BUF,
1802 DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "lun",
1803 (caddr_t)&lun, &i) != DDI_SUCCESS) {
1804 name[0] = '\0';
1805 return (0);
1806 }
1807 for (i = 0; i < FC_WWN_SIZE; i++)
1808 (void) sprintf(&tbuf[i << 1], "%02x", wwn[i]);
1809 (void) sprintf(name, "w%s,%x", tbuf, lun);
1810 return (1);
1811 }
1812
1813
1814 /*
1815 * called by transport to get target soft AL-PA (except sun4u)
1816 */
1817 /* ARGSUSED */
1818 static int
1819 sf_scsi_get_bus_addr(struct scsi_device *sd, char *name, int len)
1820 {
1821 struct sf_target *target = ADDR2TARGET(&sd->sd_address);
1822
1823 if (target == NULL)
1824 return (0);
1825
1826 (void) sprintf(name, "%x", target->sft_al_pa);
1827 return (1);
1828 }
1829
1830
1831 /*
1832 * add to the command/response buffer pool for this sf instance
1833 */
1834 static int
1835 sf_add_cr_pool(struct sf *sf)
1836 {
1837 int cmd_buf_size;
1838 size_t real_cmd_buf_size;
1839 int rsp_buf_size;
1840 size_t real_rsp_buf_size;
1841 uint_t i, ccount;
1842 struct sf_cr_pool *ptr;
1843 struct sf_cr_free_elem *cptr;
1844 caddr_t dptr, eptr;
1845 ddi_dma_cookie_t cmd_cookie;
1846 ddi_dma_cookie_t rsp_cookie;
1847 int cmd_bound = FALSE, rsp_bound = FALSE;
1848
1849
1850 /* allocate room for the pool */
1851 if ((ptr = kmem_zalloc(sizeof (struct sf_cr_pool), KM_NOSLEEP)) ==
1852 NULL) {
1853 return (DDI_FAILURE);
1854 }
1855
1856 /* allocate a DMA handle for the command pool */
1857 if (ddi_dma_alloc_handle(sf->sf_dip, sf->sf_sochandle->fcal_dmaattr,
1858 DDI_DMA_DONTWAIT, NULL, &ptr->cmd_dma_handle) != DDI_SUCCESS) {
1859 goto fail;
1860 }
1861
1862 /*
1863 * Get a piece of memory in which to put commands
1864 */
1865 cmd_buf_size = (sizeof (struct fcp_cmd) * SF_ELEMS_IN_POOL + 7) & ~7;
1866 if (ddi_dma_mem_alloc(ptr->cmd_dma_handle, cmd_buf_size,
1867 sf->sf_sochandle->fcal_accattr, DDI_DMA_CONSISTENT,
1868 DDI_DMA_DONTWAIT, NULL, (caddr_t *)&ptr->cmd_base,
1869 &real_cmd_buf_size, &ptr->cmd_acc_handle) != DDI_SUCCESS) {
1870 goto fail;
1871 }
1872
1873 /* bind the DMA handle to an address */
1874 if (ddi_dma_addr_bind_handle(ptr->cmd_dma_handle, NULL,
1875 ptr->cmd_base, real_cmd_buf_size,
1876 DDI_DMA_WRITE | DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT,
1877 NULL, &cmd_cookie, &ccount) != DDI_DMA_MAPPED) {
1878 goto fail;
1879 }
1880 cmd_bound = TRUE;
1881 /* ensure only one cookie was allocated */
1882 if (ccount != 1) {
1883 goto fail;
1884 }
1885
1886 /* allocate a DMA handle for the response pool */
1887 if (ddi_dma_alloc_handle(sf->sf_dip, sf->sf_sochandle->fcal_dmaattr,
1888 DDI_DMA_DONTWAIT, NULL, &ptr->rsp_dma_handle) != DDI_SUCCESS) {
1889 goto fail;
1890 }
1891
1892 /*
1893 * Get a piece of memory in which to put responses
1894 */
1895 rsp_buf_size = FCP_MAX_RSP_IU_SIZE * SF_ELEMS_IN_POOL;
1896 if (ddi_dma_mem_alloc(ptr->rsp_dma_handle, rsp_buf_size,
1897 sf->sf_sochandle->fcal_accattr, DDI_DMA_CONSISTENT,
1898 DDI_DMA_DONTWAIT, NULL, (caddr_t *)&ptr->rsp_base,
1899 &real_rsp_buf_size, &ptr->rsp_acc_handle) != DDI_SUCCESS) {
1900 goto fail;
1901 }
1902
1903 /* bind the DMA handle to an address */
1904 if (ddi_dma_addr_bind_handle(ptr->rsp_dma_handle, NULL,
1905 ptr->rsp_base, real_rsp_buf_size,
1906 DDI_DMA_READ | DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT,
1907 NULL, &rsp_cookie, &ccount) != DDI_DMA_MAPPED) {
1908 goto fail;
1909 }
1910 rsp_bound = TRUE;
1911 /* ensure only one cookie was allocated */
1912 if (ccount != 1) {
1913 goto fail;
1914 }
1915
1916 /*
1917 * Generate a (cmd/rsp structure) free list
1918 */
1919 /* ensure ptr points to start of long word (8-byte block) */
1920 dptr = (caddr_t)((uintptr_t)(ptr->cmd_base) + 7 & ~7);
1921 /* keep track of actual size after moving pointer */
1922 real_cmd_buf_size -= (dptr - ptr->cmd_base);
1923 eptr = ptr->rsp_base;
1924
1925 /* set actual total number of entries */
1926 ptr->ntot = min((real_cmd_buf_size / sizeof (struct fcp_cmd)),
1927 (real_rsp_buf_size / FCP_MAX_RSP_IU_SIZE));
1928 ptr->nfree = ptr->ntot;
1929 ptr->free = (struct sf_cr_free_elem *)ptr->cmd_base;
1930 ptr->sf = sf;
1931
1932 /* set up DMA for each pair of entries */
1933 i = 0;
1934 while (i < ptr->ntot) {
1935 cptr = (struct sf_cr_free_elem *)dptr;
1936 dptr += sizeof (struct fcp_cmd);
1937
1938 cptr->next = (struct sf_cr_free_elem *)dptr;
1939 cptr->rsp = eptr;
1940
1941 cptr->cmd_dmac = cmd_cookie.dmac_address +
1942 (uint32_t)((caddr_t)cptr - ptr->cmd_base);
1943
1944 cptr->rsp_dmac = rsp_cookie.dmac_address +
1945 (uint32_t)((caddr_t)eptr - ptr->rsp_base);
1946
1947 eptr += FCP_MAX_RSP_IU_SIZE;
1948 i++;
1949 }
1950
1951 /* terminate the list */
1952 cptr->next = NULL;
1953
1954 /* add this list at front of current one */
1955 mutex_enter(&sf->sf_cr_mutex);
1956 ptr->next = sf->sf_cr_pool;
1957 sf->sf_cr_pool = ptr;
1958 sf->sf_cr_pool_cnt++;
1959 mutex_exit(&sf->sf_cr_mutex);
1960
1961 return (DDI_SUCCESS);
1962
1963 fail:
1964 /* we failed so clean up */
1965 if (ptr->cmd_dma_handle != NULL) {
1966 if (cmd_bound) {
1967 (void) ddi_dma_unbind_handle(ptr->cmd_dma_handle);
1968 }
1969 ddi_dma_free_handle(&ptr->cmd_dma_handle);
1970 }
1971
1972 if (ptr->rsp_dma_handle != NULL) {
1973 if (rsp_bound) {
1974 (void) ddi_dma_unbind_handle(ptr->rsp_dma_handle);
1975 }
1976 ddi_dma_free_handle(&ptr->rsp_dma_handle);
1977 }
1978
1979 if (ptr->cmd_base != NULL) {
1980 ddi_dma_mem_free(&ptr->cmd_acc_handle);
1981 }
1982
1983 if (ptr->rsp_base != NULL) {
1984 ddi_dma_mem_free(&ptr->rsp_acc_handle);
1985 }
1986
1987 kmem_free((caddr_t)ptr, sizeof (struct sf_cr_pool));
1988 return (DDI_FAILURE);
1989 }
1990
1991
1992 /*
1993 * allocate a command/response buffer from the pool, allocating more
1994 * in the pool as needed
1995 */
1996 static int
1997 sf_cr_alloc(struct sf *sf, struct sf_pkt *cmd, int (*func)())
1998 {
1999 struct sf_cr_pool *ptr;
2000 struct sf_cr_free_elem *cptr;
2001
2002
2003 mutex_enter(&sf->sf_cr_mutex);
2004
2005 try_again:
2006
2007 /* find a free buffer in the existing pool */
2008 ptr = sf->sf_cr_pool;
2009 while (ptr != NULL) {
2010 if (ptr->nfree != 0) {
2011 ptr->nfree--;
2012 break;
2013 } else {
2014 ptr = ptr->next;
2015 }
2016 }
2017
2018 /* did we find a free buffer ? */
2019 if (ptr != NULL) {
2020 /* we found a free buffer -- take it off the free list */
2021 cptr = ptr->free;
2022 ptr->free = cptr->next;
2023 mutex_exit(&sf->sf_cr_mutex);
2024 /* set up the command to use the buffer pair */
2025 cmd->cmd_block = (struct fcp_cmd *)cptr;
2026 cmd->cmd_dmac = cptr->cmd_dmac;
2027 cmd->cmd_rsp_dmac = cptr->rsp_dmac;
2028 cmd->cmd_rsp_block = (struct fcp_rsp *)cptr->rsp;
2029 cmd->cmd_cr_pool = ptr;
2030 return (DDI_SUCCESS); /* success */
2031 }
2032
2033 /* no free buffer available -- can we allocate more ? */
2034 if (sf->sf_cr_pool_cnt < SF_CR_POOL_MAX) {
2035 /* we need to allocate more buffer pairs */
2036 if (sf->sf_cr_flag) {
2037 /* somebody already allocating for this instance */
2038 if (func == SLEEP_FUNC) {
2039 /* user wants to wait */
2040 cv_wait(&sf->sf_cr_cv, &sf->sf_cr_mutex);
2041 /* we've been woken so go try again */
2042 goto try_again;
2043 }
2044 /* user does not want to wait */
2045 mutex_exit(&sf->sf_cr_mutex);
2046 sf->sf_stats.cralloc_failures++;
2047 return (DDI_FAILURE); /* give up */
2048 }
2049 /* set flag saying we're allocating */
2050 sf->sf_cr_flag = 1;
2051 mutex_exit(&sf->sf_cr_mutex);
2052 /* add to our pool */
2053 if (sf_add_cr_pool(sf) != DDI_SUCCESS) {
2054 /* couldn't add to our pool for some reason */
2055 mutex_enter(&sf->sf_cr_mutex);
2056 sf->sf_cr_flag = 0;
2057 cv_broadcast(&sf->sf_cr_cv);
2058 mutex_exit(&sf->sf_cr_mutex);
2059 sf->sf_stats.cralloc_failures++;
2060 return (DDI_FAILURE); /* give up */
2061 }
2062 /*
2063 * clear flag saying we're allocating and tell all other
2064 * that care
2065 */
2066 mutex_enter(&sf->sf_cr_mutex);
2067 sf->sf_cr_flag = 0;
2068 cv_broadcast(&sf->sf_cr_cv);
2069 /* now that we have more buffers try again */
2070 goto try_again;
2071 }
2072
2073 /* we don't have room to allocate any more buffers */
2074 mutex_exit(&sf->sf_cr_mutex);
2075 sf->sf_stats.cralloc_failures++;
2076 return (DDI_FAILURE); /* give up */
2077 }
2078
2079
2080 /*
2081 * free a cmd/response buffer pair in our pool
2082 */
2083 static void
2084 sf_cr_free(struct sf_cr_pool *cp, struct sf_pkt *cmd)
2085 {
2086 struct sf *sf = cp->sf;
2087 struct sf_cr_free_elem *elem;
2088
2089 elem = (struct sf_cr_free_elem *)cmd->cmd_block;
2090 elem->rsp = (caddr_t)cmd->cmd_rsp_block;
2091 elem->cmd_dmac = cmd->cmd_dmac;
2092 elem->rsp_dmac = cmd->cmd_rsp_dmac;
2093
2094 mutex_enter(&sf->sf_cr_mutex);
2095 cp->nfree++;
2096 ASSERT(cp->nfree <= cp->ntot);
2097
2098 elem->next = cp->free;
2099 cp->free = elem;
2100 mutex_exit(&sf->sf_cr_mutex);
2101 }
2102
2103
2104 /*
2105 * free our pool of cmd/response buffers
2106 */
2107 static void
2108 sf_crpool_free(struct sf *sf)
2109 {
2110 struct sf_cr_pool *cp, *prev;
2111
2112 prev = NULL;
2113 mutex_enter(&sf->sf_cr_mutex);
2114 cp = sf->sf_cr_pool;
2115 while (cp != NULL) {
2116 if (cp->nfree == cp->ntot) {
2117 if (prev != NULL) {
2118 prev->next = cp->next;
2119 } else {
2120 sf->sf_cr_pool = cp->next;
2121 }
2122 sf->sf_cr_pool_cnt--;
2123 mutex_exit(&sf->sf_cr_mutex);
2124
2125 (void) ddi_dma_unbind_handle(cp->cmd_dma_handle);
2126 ddi_dma_free_handle(&cp->cmd_dma_handle);
2127 (void) ddi_dma_unbind_handle(cp->rsp_dma_handle);
2128 ddi_dma_free_handle(&cp->rsp_dma_handle);
2129 ddi_dma_mem_free(&cp->cmd_acc_handle);
2130 ddi_dma_mem_free(&cp->rsp_acc_handle);
2131 kmem_free((caddr_t)cp, sizeof (struct sf_cr_pool));
2132 return;
2133 }
2134 prev = cp;
2135 cp = cp->next;
2136 }
2137 mutex_exit(&sf->sf_cr_mutex);
2138 }
2139
2140
2141 /* ARGSUSED */
2142 static int
2143 sf_kmem_cache_constructor(void *buf, void *arg, int size)
2144 {
2145 struct sf_pkt *cmd = buf;
2146
2147 mutex_init(&cmd->cmd_abort_mutex, NULL, MUTEX_DRIVER, NULL);
2148 cmd->cmd_block = NULL;
2149 cmd->cmd_dmahandle = NULL;
2150 return (0);
2151 }
2152
2153
2154 /* ARGSUSED */
2155 static void
2156 sf_kmem_cache_destructor(void *buf, void *size)
2157 {
2158 struct sf_pkt *cmd = buf;
2159
2160 if (cmd->cmd_dmahandle != NULL) {
2161 ddi_dma_free_handle(&cmd->cmd_dmahandle);
2162 }
2163
2164 if (cmd->cmd_block != NULL) {
2165 sf_cr_free(cmd->cmd_cr_pool, cmd);
2166 }
2167 mutex_destroy(&cmd->cmd_abort_mutex);
2168 }
2169
2170
2171 /*
2172 * called by transport when a state change occurs
2173 */
2174 static void
2175 sf_statec_callback(void *arg, int msg)
2176 {
2177 struct sf *sf = (struct sf *)arg;
2178 struct sf_target *target;
2179 int i;
2180 struct sf_pkt *cmd;
2181 struct scsi_pkt *pkt;
2182
2183
2184
2185 switch (msg) {
2186
2187 case FCAL_STATUS_LOOP_ONLINE: {
2188 uchar_t al_pa; /* to save AL-PA */
2189 int ret; /* ret value from getmap */
2190 int lip_cnt; /* to save current count */
2191 int cnt; /* map length */
2192
2193 /*
2194 * the loop has gone online
2195 */
2196 SF_DEBUG(1, (sf, CE_CONT, "sf%d: loop online\n",
2197 ddi_get_instance(sf->sf_dip)));
2198 mutex_enter(&sf->sf_mutex);
2199 sf->sf_lip_cnt++;
2200 sf->sf_state = SF_STATE_ONLINING;
2201 mutex_exit(&sf->sf_mutex);
2202
2203 /* scan each target hash queue */
2204 for (i = 0; i < SF_NUM_HASH_QUEUES; i++) {
2205 target = sf->sf_wwn_lists[i];
2206 while (target != NULL) {
2207 /*
2208 * foreach target, if it's not offline then
2209 * mark it as busy
2210 */
2211 mutex_enter(&target->sft_mutex);
2212 if (!(target->sft_state & SF_TARGET_OFFLINE))
2213 target->sft_state |= (SF_TARGET_BUSY
2214 | SF_TARGET_MARK);
2215 #ifdef DEBUG
2216 /*
2217 * for debugging, print out info on any
2218 * pending commands (left hanging)
2219 */
2220 cmd = target->sft_pkt_head;
2221 while (cmd != (struct sf_pkt *)&target->
2222 sft_pkt_head) {
2223 if (cmd->cmd_state ==
2224 SF_STATE_ISSUED) {
2225 SF_DEBUG(1, (sf, CE_CONT,
2226 "cmd 0x%p pending "
2227 "after lip\n",
2228 (void *)cmd->cmd_fp_pkt));
2229 }
2230 cmd = cmd->cmd_forw;
2231 }
2232 #endif
2233 mutex_exit(&target->sft_mutex);
2234 target = target->sft_next;
2235 }
2236 }
2237
2238 /*
2239 * since the loop has just gone online get a new map from
2240 * the transport
2241 */
2242 if ((ret = soc_get_lilp_map(sf->sf_sochandle, sf->sf_socp,
2243 sf->sf_sochandle->fcal_portno, (uint32_t)sf->
2244 sf_lilp_dmacookie.dmac_address, 1)) != FCAL_SUCCESS) {
2245 if (sf_core && (sf_core & SF_CORE_LILP_FAILED)) {
2246 (void) soc_take_core(sf->sf_sochandle,
2247 sf->sf_socp);
2248 sf_core = 0;
2249 }
2250 sf_log(sf, CE_WARN,
2251 "!soc lilp map failed status=0x%x\n", ret);
2252 mutex_enter(&sf->sf_mutex);
2253 sf->sf_timer = sf_watchdog_time + SF_OFFLINE_TIMEOUT;
2254 sf->sf_lip_cnt++;
2255 sf->sf_state = SF_STATE_OFFLINE;
2256 mutex_exit(&sf->sf_mutex);
2257 return;
2258 }
2259
2260 /* ensure consistent view of DMA memory */
2261 (void) ddi_dma_sync(sf->sf_lilp_dmahandle, (off_t)0, (size_t)0,
2262 DDI_DMA_SYNC_FORKERNEL);
2263
2264 /* how many entries in map ? */
2265 cnt = sf->sf_lilp_map->lilp_length;
2266 if (cnt >= SF_MAX_LILP_ENTRIES) {
2267 sf_log(sf, CE_WARN, "invalid lilp map\n");
2268 return;
2269 }
2270
2271 mutex_enter(&sf->sf_mutex);
2272 sf->sf_device_count = cnt - 1;
2273 sf->sf_al_pa = sf->sf_lilp_map->lilp_myalpa;
2274 lip_cnt = sf->sf_lip_cnt;
2275 al_pa = sf->sf_al_pa;
2276
2277 SF_DEBUG(1, (sf, CE_CONT,
2278 "!lilp map has %d entries, al_pa is %x\n", cnt, al_pa));
2279
2280 /*
2281 * since the last entry of the map may be mine (common) check
2282 * for that, and if it is we have one less entry to look at
2283 */
2284 if (sf->sf_lilp_map->lilp_alpalist[cnt-1] == al_pa) {
2285 cnt--;
2286 }
2287 /* If we didn't get a valid loop map enable all targets */
2288 if (sf->sf_lilp_map->lilp_magic == FCAL_BADLILP_MAGIC) {
2289 for (i = 0; i < sizeof (sf_switch_to_alpa); i++)
2290 sf->sf_lilp_map->lilp_alpalist[i] =
2291 sf_switch_to_alpa[i];
2292 cnt = i;
2293 sf->sf_device_count = cnt - 1;
2294 }
2295 if (sf->sf_device_count == 0) {
2296 sf_finish_init(sf, lip_cnt);
2297 mutex_exit(&sf->sf_mutex);
2298 break;
2299 }
2300 mutex_exit(&sf->sf_mutex);
2301
2302 SF_DEBUG(2, (sf, CE_WARN,
2303 "!statec_callback: starting with %d targets\n",
2304 sf->sf_device_count));
2305
2306 /* scan loop map, logging into all ports (except mine) */
2307 for (i = 0; i < cnt; i++) {
2308 SF_DEBUG(1, (sf, CE_CONT,
2309 "!lilp map entry %d = %x,%x\n", i,
2310 sf->sf_lilp_map->lilp_alpalist[i],
2311 sf_alpa_to_switch[
2312 sf->sf_lilp_map->lilp_alpalist[i]]));
2313 /* is this entry for somebody else ? */
2314 if (sf->sf_lilp_map->lilp_alpalist[i] != al_pa) {
2315 /* do a PLOGI to this port */
2316 if (!sf_login(sf, LA_ELS_PLOGI,
2317 sf->sf_lilp_map->lilp_alpalist[i],
2318 sf->sf_lilp_map->lilp_alpalist[cnt-1],
2319 lip_cnt)) {
2320 /* a problem logging in */
2321 mutex_enter(&sf->sf_mutex);
2322 if (lip_cnt == sf->sf_lip_cnt) {
2323 /*
2324 * problem not from a new LIP
2325 */
2326 sf->sf_device_count--;
2327 ASSERT(sf->sf_device_count
2328 >= 0);
2329 if (sf->sf_device_count == 0) {
2330 sf_finish_init(sf,
2331 lip_cnt);
2332 }
2333 }
2334 mutex_exit(&sf->sf_mutex);
2335 }
2336 }
2337 }
2338 break;
2339 }
2340
2341 case FCAL_STATUS_ERR_OFFLINE:
2342 /*
2343 * loop has gone offline due to an error
2344 */
2345 SF_DEBUG(1, (sf, CE_CONT, "sf%d: loop offline\n",
2346 ddi_get_instance(sf->sf_dip)));
2347 mutex_enter(&sf->sf_mutex);
2348 sf->sf_lip_cnt++;
2349 sf->sf_timer = sf_watchdog_time + SF_OFFLINE_TIMEOUT;
2350 if (!sf->sf_online_timer) {
2351 sf->sf_online_timer = sf_watchdog_time +
2352 SF_ONLINE_TIMEOUT;
2353 }
2354 /*
2355 * if we are suspended, preserve the SF_STATE_SUSPENDED flag,
2356 * since throttling logic in sf_watch() depends on
2357 * preservation of this flag while device is suspended
2358 */
2359 if (sf->sf_state & SF_STATE_SUSPENDED) {
2360 sf->sf_state |= SF_STATE_OFFLINE;
2361 SF_DEBUG(1, (sf, CE_CONT,
2362 "sf_statec_callback, sf%d: "
2363 "got FCAL_STATE_OFFLINE during DDI_SUSPEND\n",
2364 ddi_get_instance(sf->sf_dip)));
2365 } else {
2366 sf->sf_state = SF_STATE_OFFLINE;
2367 }
2368
2369 /* scan each possible target on the loop */
2370 for (i = 0; i < sf_max_targets; i++) {
2371 target = sf->sf_targets[i];
2372 while (target != NULL) {
2373 mutex_enter(&target->sft_mutex);
2374 if (!(target->sft_state & SF_TARGET_OFFLINE))
2375 target->sft_state |= (SF_TARGET_BUSY
2376 | SF_TARGET_MARK);
2377 mutex_exit(&target->sft_mutex);
2378 target = target->sft_next_lun;
2379 }
2380 }
2381 mutex_exit(&sf->sf_mutex);
2382 break;
2383
2384 case FCAL_STATE_RESET: {
2385 struct sf_els_hdr *privp; /* ptr to private list */
2386 struct sf_els_hdr *tmpp1; /* tmp prev hdr ptr */
2387 struct sf_els_hdr *tmpp2; /* tmp next hdr ptr */
2388 struct sf_els_hdr *head; /* to save our private list */
2389 struct fcal_packet *fpkt; /* ptr to pkt in hdr */
2390
2391 /*
2392 * a transport reset
2393 */
2394 SF_DEBUG(1, (sf, CE_CONT, "!sf%d: soc reset\n",
2395 ddi_get_instance(sf->sf_dip)));
2396 tmpp1 = head = NULL;
2397 mutex_enter(&sf->sf_mutex);
2398 sf->sf_lip_cnt++;
2399 sf->sf_timer = sf_watchdog_time + SF_RESET_TIMEOUT;
2400 /*
2401 * if we are suspended, preserve the SF_STATE_SUSPENDED flag,
2402 * since throttling logic in sf_watch() depends on
2403 * preservation of this flag while device is suspended
2404 */
2405 if (sf->sf_state & SF_STATE_SUSPENDED) {
2406 sf->sf_state |= SF_STATE_OFFLINE;
2407 SF_DEBUG(1, (sf, CE_CONT,
2408 "sf_statec_callback, sf%d: "
2409 "got FCAL_STATE_RESET during DDI_SUSPEND\n",
2410 ddi_get_instance(sf->sf_dip)));
2411 } else {
2412 sf->sf_state = SF_STATE_OFFLINE;
2413 }
2414
2415 /*
2416 * scan each possible target on the loop, looking for targets
2417 * that need callbacks ran
2418 */
2419 for (i = 0; i < sf_max_targets; i++) {
2420 target = sf->sf_targets[i];
2421 while (target != NULL) {
2422 if (!(target->sft_state & SF_TARGET_OFFLINE)) {
2423 target->sft_state |= (SF_TARGET_BUSY
2424 | SF_TARGET_MARK);
2425 mutex_exit(&sf->sf_mutex);
2426 /*
2427 * run remove event callbacks for lun
2428 *
2429 * We have a nasty race condition here
2430 * 'cause we're dropping this mutex to
2431 * run the callback and expect the
2432 * linked list to be the same.
2433 */
2434 (void) ndi_event_retrieve_cookie(
2435 sf->sf_event_hdl, target->sft_dip,
2436 FCAL_REMOVE_EVENT, &sf_remove_eid,
2437 NDI_EVENT_NOPASS);
2438 (void) ndi_event_run_callbacks(
2439 sf->sf_event_hdl,
2440 target->sft_dip,
2441 sf_remove_eid, NULL);
2442 mutex_enter(&sf->sf_mutex);
2443 }
2444 target = target->sft_next_lun;
2445 }
2446 }
2447
2448 /*
2449 * scan for ELS commands that are in transport, not complete,
2450 * and have a valid timeout, building a private list
2451 */
2452 privp = sf->sf_els_list;
2453 while (privp != NULL) {
2454 fpkt = privp->fpkt;
2455 if ((fpkt->fcal_cmd_state & FCAL_CMD_IN_TRANSPORT) &&
2456 (!(fpkt->fcal_cmd_state & FCAL_CMD_COMPLETE)) &&
2457 (privp->timeout != SF_INVALID_TIMEOUT)) {
2458 /*
2459 * cmd in transport && not complete &&
2460 * timeout valid
2461 *
2462 * move this entry from ELS input list to our
2463 * private list
2464 */
2465
2466 tmpp2 = privp->next; /* save ptr to next */
2467
2468 /* push this on private list head */
2469 privp->next = head;
2470 head = privp;
2471
2472 /* remove this entry from input list */
2473 if (tmpp1 != NULL) {
2474 /*
2475 * remove this entry from somewhere in
2476 * the middle of the list
2477 */
2478 tmpp1->next = tmpp2;
2479 if (tmpp2 != NULL) {
2480 tmpp2->prev = tmpp1;
2481 }
2482 } else {
2483 /*
2484 * remove this entry from the head
2485 * of the list
2486 */
2487 sf->sf_els_list = tmpp2;
2488 if (tmpp2 != NULL) {
2489 tmpp2->prev = NULL;
2490 }
2491 }
2492 privp = tmpp2; /* skip to next entry */
2493 } else {
2494 tmpp1 = privp; /* save ptr to prev entry */
2495 privp = privp->next; /* skip to next entry */
2496 }
2497 }
2498
2499 mutex_exit(&sf->sf_mutex);
2500
2501 /*
2502 * foreach cmd in our list free the ELS packet associated
2503 * with it
2504 */
2505 privp = head;
2506 while (privp != NULL) {
2507 fpkt = privp->fpkt;
2508 privp = privp->next;
2509 sf_els_free(fpkt);
2510 }
2511
2512 /*
2513 * scan for commands from each possible target
2514 */
2515 for (i = 0; i < sf_max_targets; i++) {
2516 target = sf->sf_targets[i];
2517 while (target != NULL) {
2518 /*
2519 * scan all active commands for this target,
2520 * looking for commands that have been issued,
2521 * are in transport, and are not yet complete
2522 * (so we can terminate them because of the
2523 * reset)
2524 */
2525 mutex_enter(&target->sft_pkt_mutex);
2526 cmd = target->sft_pkt_head;
2527 while (cmd != (struct sf_pkt *)&target->
2528 sft_pkt_head) {
2529 fpkt = cmd->cmd_fp_pkt;
2530 mutex_enter(&cmd->cmd_abort_mutex);
2531 if ((cmd->cmd_state ==
2532 SF_STATE_ISSUED) &&
2533 (fpkt->fcal_cmd_state &
2534 FCAL_CMD_IN_TRANSPORT) &&
2535 (!(fpkt->fcal_cmd_state &
2536 FCAL_CMD_COMPLETE))) {
2537 /* a command to be reset */
2538 pkt = cmd->cmd_pkt;
2539 pkt->pkt_reason = CMD_RESET;
2540 pkt->pkt_statistics |=
2541 STAT_BUS_RESET;
2542 cmd->cmd_state = SF_STATE_IDLE;
2543 mutex_exit(&cmd->
2544 cmd_abort_mutex);
2545 mutex_exit(&target->
2546 sft_pkt_mutex);
2547 if (pkt->pkt_comp != NULL) {
2548 (*pkt->pkt_comp)(pkt);
2549 }
2550 mutex_enter(&target->
2551 sft_pkt_mutex);
2552 cmd = target->sft_pkt_head;
2553 } else {
2554 mutex_exit(&cmd->
2555 cmd_abort_mutex);
2556 /* get next command */
2557 cmd = cmd->cmd_forw;
2558 }
2559 }
2560 mutex_exit(&target->sft_pkt_mutex);
2561 target = target->sft_next_lun;
2562 }
2563 }
2564
2565 /*
2566 * get packet queue for this target, resetting all remaining
2567 * commands
2568 */
2569 mutex_enter(&sf->sf_mutex);
2570 cmd = sf->sf_pkt_head;
2571 sf->sf_pkt_head = NULL;
2572 mutex_exit(&sf->sf_mutex);
2573
2574 while (cmd != NULL) {
2575 pkt = cmd->cmd_pkt;
2576 cmd = cmd->cmd_next;
2577 pkt->pkt_reason = CMD_RESET;
2578 pkt->pkt_statistics |= STAT_BUS_RESET;
2579 if (pkt->pkt_comp != NULL) {
2580 (*pkt->pkt_comp)(pkt);
2581 }
2582 }
2583 break;
2584 }
2585
2586 default:
2587 break;
2588 }
2589 }
2590
2591
2592 /*
2593 * called to send a PLOGI (N_port login) ELS request to a destination ID,
2594 * returning TRUE upon success, else returning FALSE
2595 */
2596 static int
2597 sf_login(struct sf *sf, uchar_t els_code, uchar_t dest_id, uint_t arg1,
2598 int lip_cnt)
2599 {
2600 struct la_els_logi *logi;
2601 struct sf_els_hdr *privp;
2602
2603
2604 if (sf_els_alloc(sf, dest_id, sizeof (struct sf_els_hdr),
2605 sizeof (union sf_els_cmd), sizeof (union sf_els_rsp),
2606 (caddr_t *)&privp, (caddr_t *)&logi) == NULL) {
2607 sf_log(sf, CE_WARN, "Cannot allocate PLOGI for target %x "
2608 "due to DVMA shortage.\n", sf_alpa_to_switch[dest_id]);
2609 return (FALSE);
2610 }
2611
2612 privp->lip_cnt = lip_cnt;
2613 if (els_code == LA_ELS_PLOGI) {
2614 bcopy((caddr_t)sf->sf_sochandle->fcal_loginparms,
2615 (caddr_t)&logi->common_service, sizeof (struct la_els_logi)
2616 - 4);
2617 bcopy((caddr_t)&sf->sf_sochandle->fcal_p_wwn,
2618 (caddr_t)&logi->nport_ww_name, sizeof (la_wwn_t));
2619 bcopy((caddr_t)&sf->sf_sochandle->fcal_n_wwn,
2620 (caddr_t)&logi->node_ww_name, sizeof (la_wwn_t));
2621 bzero((caddr_t)&logi->reserved, 16);
2622 } else if (els_code == LA_ELS_LOGO) {
2623 bcopy((caddr_t)&sf->sf_sochandle->fcal_p_wwn,
2624 (caddr_t)&(((struct la_els_logo *)logi)->nport_ww_name), 8);
2625 ((struct la_els_logo *)logi)->reserved = 0;
2626 ((struct la_els_logo *)logi)->nport_id[0] = 0;
2627 ((struct la_els_logo *)logi)->nport_id[1] = 0;
2628 ((struct la_els_logo *)logi)->nport_id[2] = arg1;
2629 }
2630
2631 privp->els_code = els_code;
2632 logi->ls_code = els_code;
2633 logi->mbz[0] = 0;
2634 logi->mbz[1] = 0;
2635 logi->mbz[2] = 0;
2636
2637 privp->timeout = sf_watchdog_time + SF_ELS_TIMEOUT;
2638 return (sf_els_transport(sf, privp));
2639 }
2640
2641
2642 /*
2643 * send an ELS IU via the transport,
2644 * returning TRUE upon success, else returning FALSE
2645 */
2646 static int
2647 sf_els_transport(struct sf *sf, struct sf_els_hdr *privp)
2648 {
2649 struct fcal_packet *fpkt = privp->fpkt;
2650
2651
2652 (void) ddi_dma_sync(privp->cmd_dma_handle, (off_t)0, (size_t)0,
2653 DDI_DMA_SYNC_FORDEV);
2654 privp->prev = NULL;
2655 mutex_enter(&sf->sf_mutex);
2656 privp->next = sf->sf_els_list;
2657 if (sf->sf_els_list != NULL) {
2658 sf->sf_els_list->prev = privp;
2659 }
2660 sf->sf_els_list = privp;
2661 mutex_exit(&sf->sf_mutex);
2662
2663 /* call the transport to send a packet */
2664 if (soc_transport(sf->sf_sochandle, fpkt, FCAL_NOSLEEP,
2665 CQ_REQUEST_1) != FCAL_TRANSPORT_SUCCESS) {
2666 mutex_enter(&sf->sf_mutex);
2667 if (privp->prev != NULL) {
2668 privp->prev->next = privp->next;
2669 }
2670 if (privp->next != NULL) {
2671 privp->next->prev = privp->prev;
2672 }
2673 if (sf->sf_els_list == privp) {
2674 sf->sf_els_list = privp->next;
2675 }
2676 mutex_exit(&sf->sf_mutex);
2677 sf_els_free(fpkt);
2678 return (FALSE); /* failure */
2679 }
2680 return (TRUE); /* success */
2681 }
2682
2683
2684 /*
2685 * called as the pkt_comp routine for ELS FC packets
2686 */
2687 static void
2688 sf_els_callback(struct fcal_packet *fpkt)
2689 {
2690 struct sf_els_hdr *privp = fpkt->fcal_pkt_private;
2691 struct sf *sf = privp->sf;
2692 struct sf *tsf;
2693 int tgt_id;
2694 struct la_els_logi *ptr = (struct la_els_logi *)privp->rsp;
2695 struct la_els_adisc *adisc = (struct la_els_adisc *)ptr;
2696 struct sf_target *target;
2697 short ncmds;
2698 short free_pkt = TRUE;
2699
2700
2701 /*
2702 * we've received an ELS callback, i.e. an ELS packet has arrived
2703 */
2704
2705 /* take the current packet off of the queue */
2706 mutex_enter(&sf->sf_mutex);
2707 if (privp->timeout == SF_INVALID_TIMEOUT) {
2708 mutex_exit(&sf->sf_mutex);
2709 return;
2710 }
2711 if (privp->prev != NULL) {
2712 privp->prev->next = privp->next;
2713 }
2714 if (privp->next != NULL) {
2715 privp->next->prev = privp->prev;
2716 }
2717 if (sf->sf_els_list == privp) {
2718 sf->sf_els_list = privp->next;
2719 }
2720 privp->prev = privp->next = NULL;
2721 mutex_exit(&sf->sf_mutex);
2722
2723 /* get # pkts in this callback */
2724 ncmds = fpkt->fcal_ncmds;
2725 ASSERT(ncmds >= 0);
2726 mutex_enter(&sf->sf_cmd_mutex);
2727 sf->sf_ncmds = ncmds;
2728 mutex_exit(&sf->sf_cmd_mutex);
2729
2730 /* sync idea of memory */
2731 (void) ddi_dma_sync(privp->rsp_dma_handle, (off_t)0, (size_t)0,
2732 DDI_DMA_SYNC_FORKERNEL);
2733
2734 /* was this an OK ACC msg ?? */
2735 if ((fpkt->fcal_pkt_status == FCAL_STATUS_OK) &&
2736 (ptr->ls_code == LA_ELS_ACC)) {
2737
2738 /*
2739 * this was an OK ACC pkt
2740 */
2741
2742 switch (privp->els_code) {
2743 case LA_ELS_PLOGI:
2744 /*
2745 * was able to to an N_port login
2746 */
2747 SF_DEBUG(2, (sf, CE_CONT,
2748 "!PLOGI to al_pa %x succeeded, wwn %x%x\n",
2749 privp->dest_nport_id,
2750 *((int *)&ptr->nport_ww_name.raw_wwn[0]),
2751 *((int *)&ptr->nport_ww_name.raw_wwn[4])));
2752 /* try to do a process login */
2753 if (!sf_do_prli(sf, privp, ptr)) {
2754 free_pkt = FALSE;
2755 goto fail; /* PRLI failed */
2756 }
2757 break;
2758 case LA_ELS_PRLI:
2759 /*
2760 * was able to do a process login
2761 */
2762 SF_DEBUG(2, (sf, CE_CONT,
2763 "!PRLI to al_pa %x succeeded\n",
2764 privp->dest_nport_id));
2765 /* try to do address discovery */
2766 if (sf_do_adisc(sf, privp) != 1) {
2767 free_pkt = FALSE;
2768 goto fail; /* ADISC failed */
2769 }
2770 break;
2771 case LA_ELS_ADISC:
2772 /*
2773 * found a target via ADISC
2774 */
2775
2776 SF_DEBUG(2, (sf, CE_CONT,
2777 "!ADISC to al_pa %x succeeded\n",
2778 privp->dest_nport_id));
2779
2780 /* create the target info */
2781 if ((target = sf_create_target(sf, privp,
2782 sf_alpa_to_switch[(uchar_t)adisc->hard_address],
2783 (int64_t)0))
2784 == NULL) {
2785 goto fail; /* can't create target */
2786 }
2787
2788 /*
2789 * ensure address discovered matches what we thought
2790 * it would be
2791 */
2792 if ((uchar_t)adisc->hard_address !=
2793 privp->dest_nport_id) {
2794 sf_log(sf, CE_WARN,
2795 "target 0x%x, AL-PA 0x%x and "
2796 "hard address 0x%x don't match\n",
2797 sf_alpa_to_switch[
2798 (uchar_t)privp->dest_nport_id],
2799 privp->dest_nport_id,
2800 (uchar_t)adisc->hard_address);
2801 mutex_enter(&sf->sf_mutex);
2802 sf_offline_target(sf, target);
2803 mutex_exit(&sf->sf_mutex);
2804 goto fail; /* addr doesn't match */
2805 }
2806 /*
2807 * get inquiry data from the target
2808 */
2809 if (!sf_do_reportlun(sf, privp, target)) {
2810 mutex_enter(&sf->sf_mutex);
2811 sf_offline_target(sf, target);
2812 mutex_exit(&sf->sf_mutex);
2813 free_pkt = FALSE;
2814 goto fail; /* inquiry failed */
2815 }
2816 break;
2817 default:
2818 SF_DEBUG(2, (sf, CE_CONT,
2819 "!ELS %x to al_pa %x succeeded\n",
2820 privp->els_code, privp->dest_nport_id));
2821 sf_els_free(fpkt);
2822 break;
2823 }
2824
2825 } else {
2826
2827 /*
2828 * oh oh -- this was not an OK ACC packet
2829 */
2830
2831 /* get target ID from dest loop address */
2832 tgt_id = sf_alpa_to_switch[(uchar_t)privp->dest_nport_id];
2833
2834 /* keep track of failures */
2835 sf->sf_stats.tstats[tgt_id].els_failures++;
2836 if (++(privp->retries) < sf_els_retries &&
2837 fpkt->fcal_pkt_status != FCAL_STATUS_OPEN_FAIL) {
2838 if (fpkt->fcal_pkt_status ==
2839 FCAL_STATUS_MAX_XCHG_EXCEEDED) {
2840 tsf = sf->sf_sibling;
2841 if (tsf != NULL) {
2842 mutex_enter(&tsf->sf_cmd_mutex);
2843 tsf->sf_flag = 1;
2844 tsf->sf_throttle = SF_DECR_DELTA;
2845 mutex_exit(&tsf->sf_cmd_mutex);
2846 }
2847 }
2848 privp->timeout = sf_watchdog_time + SF_ELS_TIMEOUT;
2849 privp->prev = NULL;
2850
2851 mutex_enter(&sf->sf_mutex);
2852
2853 if (privp->lip_cnt == sf->sf_lip_cnt) {
2854 SF_DEBUG(1, (sf, CE_WARN,
2855 "!ELS %x to al_pa %x failed, retrying",
2856 privp->els_code, privp->dest_nport_id));
2857 privp->next = sf->sf_els_list;
2858 if (sf->sf_els_list != NULL) {
2859 sf->sf_els_list->prev = privp;
2860 }
2861
2862 sf->sf_els_list = privp;
2863
2864 mutex_exit(&sf->sf_mutex);
2865 /* device busy? wait a bit ... */
2866 if (fpkt->fcal_pkt_status ==
2867 FCAL_STATUS_MAX_XCHG_EXCEEDED) {
2868 privp->delayed_retry = 1;
2869 return;
2870 }
2871 /* call the transport to send a pkt */
2872 if (soc_transport(sf->sf_sochandle, fpkt,
2873 FCAL_NOSLEEP, CQ_REQUEST_1) !=
2874 FCAL_TRANSPORT_SUCCESS) {
2875 mutex_enter(&sf->sf_mutex);
2876 if (privp->prev != NULL) {
2877 privp->prev->next =
2878 privp->next;
2879 }
2880 if (privp->next != NULL) {
2881 privp->next->prev =
2882 privp->prev;
2883 }
2884 if (sf->sf_els_list == privp) {
2885 sf->sf_els_list = privp->next;
2886 }
2887 mutex_exit(&sf->sf_mutex);
2888 goto fail;
2889 } else
2890 return;
2891 } else {
2892 mutex_exit(&sf->sf_mutex);
2893 goto fail;
2894 }
2895 } else {
2896 #ifdef DEBUG
2897 if (fpkt->fcal_pkt_status != 0x36 || sfdebug > 4) {
2898 SF_DEBUG(2, (sf, CE_NOTE, "ELS %x to al_pa %x failed",
2899 privp->els_code, privp->dest_nport_id));
2900 if (fpkt->fcal_pkt_status == FCAL_STATUS_OK) {
2901 SF_DEBUG(2, (sf, CE_NOTE,
2902 "els reply code = %x", ptr->ls_code));
2903 if (ptr->ls_code == LA_ELS_RJT)
2904 SF_DEBUG(1, (sf, CE_CONT,
2905 "LS_RJT reason = %x\n",
2906 *(((uint_t *)ptr) + 1)));
2907 } else
2908 SF_DEBUG(2, (sf, CE_NOTE,
2909 "fc packet status = %x",
2910 fpkt->fcal_pkt_status));
2911 }
2912 #endif
2913 goto fail;
2914 }
2915 }
2916 return; /* success */
2917 fail:
2918 mutex_enter(&sf->sf_mutex);
2919 if (sf->sf_lip_cnt == privp->lip_cnt) {
2920 sf->sf_device_count--;
2921 ASSERT(sf->sf_device_count >= 0);
2922 if (sf->sf_device_count == 0) {
2923 sf_finish_init(sf, privp->lip_cnt);
2924 }
2925 }
2926 mutex_exit(&sf->sf_mutex);
2927 if (free_pkt) {
2928 sf_els_free(fpkt);
2929 }
2930 }
2931
2932
2933 /*
2934 * send a PRLI (process login) ELS IU via the transport,
2935 * returning TRUE upon success, else returning FALSE
2936 */
2937 static int
2938 sf_do_prli(struct sf *sf, struct sf_els_hdr *privp, struct la_els_logi *ptr)
2939 {
2940 struct la_els_prli *prli = (struct la_els_prli *)privp->cmd;
2941 struct fcp_prli *fprli;
2942 struct fcal_packet *fpkt = privp->fpkt;
2943
2944
2945 fpkt->fcal_socal_request.sr_dataseg[0].fc_count =
2946 sizeof (struct la_els_prli);
2947 privp->els_code = LA_ELS_PRLI;
2948 fprli = (struct fcp_prli *)prli->service_params;
2949 prli->ls_code = LA_ELS_PRLI;
2950 prli->page_length = 0x10;
2951 prli->payload_length = sizeof (struct la_els_prli);
2952 fprli->type = 0x08; /* no define here? */
2953 fprli->resvd1 = 0;
2954 fprli->orig_process_assoc_valid = 0;
2955 fprli->resp_process_assoc_valid = 0;
2956 fprli->establish_image_pair = 1;
2957 fprli->resvd2 = 0;
2958 fprli->resvd3 = 0;
2959 fprli->data_overlay_allowed = 0;
2960 fprli->initiator_fn = 1;
2961 fprli->target_fn = 0;
2962 fprli->cmd_data_mixed = 0;
2963 fprli->data_resp_mixed = 0;
2964 fprli->read_xfer_rdy_disabled = 1;
2965 fprli->write_xfer_rdy_disabled = 0;
2966
2967 bcopy((caddr_t)&ptr->nport_ww_name, (caddr_t)&privp->port_wwn,
2968 sizeof (privp->port_wwn));
2969 bcopy((caddr_t)&ptr->node_ww_name, (caddr_t)&privp->node_wwn,
2970 sizeof (privp->node_wwn));
2971
2972 privp->timeout = sf_watchdog_time + SF_ELS_TIMEOUT;
2973 return (sf_els_transport(sf, privp));
2974 }
2975
2976
2977 /*
2978 * send an ADISC (address discovery) ELS IU via the transport,
2979 * returning TRUE upon success, else returning FALSE
2980 */
2981 static int
2982 sf_do_adisc(struct sf *sf, struct sf_els_hdr *privp)
2983 {
2984 struct la_els_adisc *adisc = (struct la_els_adisc *)privp->cmd;
2985 struct fcal_packet *fpkt = privp->fpkt;
2986
2987 privp->els_code = LA_ELS_ADISC;
2988 adisc->ls_code = LA_ELS_ADISC;
2989 adisc->mbz[0] = 0;
2990 adisc->mbz[1] = 0;
2991 adisc->mbz[2] = 0;
2992 adisc->hard_address = 0; /* ??? */
2993 fpkt->fcal_socal_request.sr_dataseg[0].fc_count =
2994 sizeof (struct la_els_adisc);
2995 bcopy((caddr_t)&sf->sf_sochandle->fcal_p_wwn,
2996 (caddr_t)&adisc->port_wwn, sizeof (adisc->port_wwn));
2997 bcopy((caddr_t)&sf->sf_sochandle->fcal_n_wwn,
2998 (caddr_t)&adisc->node_wwn, sizeof (adisc->node_wwn));
2999 adisc->nport_id = sf->sf_al_pa;
3000
3001 privp->timeout = sf_watchdog_time + SF_ELS_TIMEOUT;
3002 return (sf_els_transport(sf, privp));
3003 }
3004
3005
3006 static struct fcal_packet *
3007 sf_els_alloc(struct sf *sf, uchar_t dest_id, int priv_size, int cmd_size,
3008 int rsp_size, caddr_t *rprivp, caddr_t *cmd_buf)
3009 {
3010 struct fcal_packet *fpkt;
3011 ddi_dma_cookie_t pcookie;
3012 ddi_dma_cookie_t rcookie;
3013 struct sf_els_hdr *privp;
3014 ddi_dma_handle_t cmd_dma_handle = NULL;
3015 ddi_dma_handle_t rsp_dma_handle = NULL;
3016 ddi_acc_handle_t cmd_acc_handle = NULL;
3017 ddi_acc_handle_t rsp_acc_handle = NULL;
3018 size_t real_size;
3019 uint_t ccount;
3020 fc_frame_header_t *hp;
3021 int cmd_bound = FALSE, rsp_bound = FALSE;
3022 caddr_t cmd = NULL;
3023 caddr_t rsp = NULL;
3024
3025 if ((fpkt = (struct fcal_packet *)kmem_zalloc(
3026 sizeof (struct fcal_packet), KM_NOSLEEP)) == NULL) {
3027 SF_DEBUG(1, (sf, CE_WARN,
3028 "Could not allocate fcal_packet for ELS\n"));
3029 return (NULL);
3030 }
3031
3032 if ((privp = (struct sf_els_hdr *)kmem_zalloc(priv_size,
3033 KM_NOSLEEP)) == NULL) {
3034 SF_DEBUG(1, (sf, CE_WARN,
3035 "Could not allocate sf_els_hdr for ELS\n"));
3036 goto fail;
3037 }
3038
3039 privp->size = priv_size;
3040 fpkt->fcal_pkt_private = (caddr_t)privp;
3041
3042 if (ddi_dma_alloc_handle(sf->sf_dip, sf->sf_sochandle->fcal_dmaattr,
3043 DDI_DMA_DONTWAIT, NULL, &cmd_dma_handle) != DDI_SUCCESS) {
3044 SF_DEBUG(1, (sf, CE_WARN,
3045 "Could not allocate DMA handle for ELS\n"));
3046 goto fail;
3047 }
3048
3049 if (ddi_dma_mem_alloc(cmd_dma_handle, cmd_size,
3050 sf->sf_sochandle->fcal_accattr, DDI_DMA_CONSISTENT,
3051 DDI_DMA_DONTWAIT, NULL, &cmd,
3052 &real_size, &cmd_acc_handle) != DDI_SUCCESS) {
3053 SF_DEBUG(1, (sf, CE_WARN,
3054 "Could not allocate DMA memory for ELS\n"));
3055 goto fail;
3056 }
3057
3058 if (real_size < cmd_size) {
3059 SF_DEBUG(1, (sf, CE_WARN,
3060 "DMA memory too small for ELS\n"));
3061 goto fail;
3062 }
3063
3064 if (ddi_dma_addr_bind_handle(cmd_dma_handle, NULL,
3065 cmd, real_size, DDI_DMA_WRITE | DDI_DMA_CONSISTENT,
3066 DDI_DMA_DONTWAIT, NULL, &pcookie, &ccount) != DDI_DMA_MAPPED) {
3067 SF_DEBUG(1, (sf, CE_WARN,
3068 "Could not bind DMA memory for ELS\n"));
3069 goto fail;
3070 }
3071 cmd_bound = TRUE;
3072
3073 if (ccount != 1) {
3074 SF_DEBUG(1, (sf, CE_WARN,
3075 "Wrong cookie count for ELS\n"));
3076 goto fail;
3077 }
3078
3079 if (ddi_dma_alloc_handle(sf->sf_dip, sf->sf_sochandle->fcal_dmaattr,
3080 DDI_DMA_DONTWAIT, NULL, &rsp_dma_handle) != DDI_SUCCESS) {
3081 SF_DEBUG(1, (sf, CE_WARN,
3082 "Could not allocate DMA handle for ELS rsp\n"));
3083 goto fail;
3084 }
3085 if (ddi_dma_mem_alloc(rsp_dma_handle, rsp_size,
3086 sf->sf_sochandle->fcal_accattr, DDI_DMA_CONSISTENT,
3087 DDI_DMA_DONTWAIT, NULL, &rsp,
3088 &real_size, &rsp_acc_handle) != DDI_SUCCESS) {
3089 SF_DEBUG(1, (sf, CE_WARN,
3090 "Could not allocate DMA memory for ELS rsp\n"));
3091 goto fail;
3092 }
3093
3094 if (real_size < rsp_size) {
3095 SF_DEBUG(1, (sf, CE_WARN,
3096 "DMA memory too small for ELS rsp\n"));
3097 goto fail;
3098 }
3099
3100 if (ddi_dma_addr_bind_handle(rsp_dma_handle, NULL,
3101 rsp, real_size, DDI_DMA_READ | DDI_DMA_CONSISTENT,
3102 DDI_DMA_DONTWAIT, NULL, &rcookie, &ccount) != DDI_DMA_MAPPED) {
3103 SF_DEBUG(1, (sf, CE_WARN,
3104 "Could not bind DMA memory for ELS rsp\n"));
3105 goto fail;
3106 }
3107 rsp_bound = TRUE;
3108
3109 if (ccount != 1) {
3110 SF_DEBUG(1, (sf, CE_WARN,
3111 "Wrong cookie count for ELS rsp\n"));
3112 goto fail;
3113 }
3114
3115 privp->cmd = cmd;
3116 privp->sf = sf;
3117 privp->cmd_dma_handle = cmd_dma_handle;
3118 privp->cmd_acc_handle = cmd_acc_handle;
3119 privp->rsp = rsp;
3120 privp->rsp_dma_handle = rsp_dma_handle;
3121 privp->rsp_acc_handle = rsp_acc_handle;
3122 privp->dest_nport_id = dest_id;
3123 privp->fpkt = fpkt;
3124
3125 fpkt->fcal_pkt_cookie = sf->sf_socp;
3126 fpkt->fcal_pkt_comp = sf_els_callback;
3127 fpkt->fcal_magic = FCALP_MAGIC;
3128 fpkt->fcal_pkt_flags = 0;
3129 fpkt->fcal_socal_request.sr_soc_hdr.sh_flags =
3130 (ushort_t)(SOC_FC_HEADER | sf->sf_sochandle->fcal_portno);
3131 fpkt->fcal_socal_request.sr_soc_hdr.sh_class = 3;
3132 fpkt->fcal_socal_request.sr_soc_hdr.sh_seg_cnt = 2;
3133 fpkt->fcal_socal_request.sr_soc_hdr.sh_byte_cnt = cmd_size;
3134 fpkt->fcal_socal_request.sr_cqhdr.cq_hdr_count = 1;
3135 fpkt->fcal_socal_request.sr_cqhdr.cq_hdr_flags = 0;
3136 fpkt->fcal_socal_request.sr_cqhdr.cq_hdr_seqno = 0;
3137 fpkt->fcal_socal_request.sr_cqhdr.cq_hdr_type = CQ_TYPE_SIMPLE;
3138 fpkt->fcal_socal_request.sr_dataseg[0].fc_base = (uint32_t)
3139 pcookie.dmac_address;
3140 fpkt->fcal_socal_request.sr_dataseg[0].fc_count = cmd_size;
3141 fpkt->fcal_socal_request.sr_dataseg[1].fc_base = (uint32_t)
3142 rcookie.dmac_address;
3143 fpkt->fcal_socal_request.sr_dataseg[1].fc_count = rsp_size;
3144
3145 /* Fill in the Fabric Channel Header */
3146 hp = &fpkt->fcal_socal_request.sr_fc_frame_hdr;
3147 hp->r_ctl = R_CTL_ELS_REQ;
3148 hp->d_id = dest_id;
3149 hp->s_id = sf->sf_al_pa;
3150 hp->type = TYPE_EXTENDED_LS;
3151 hp->reserved1 = 0;
3152 hp->f_ctl = F_CTL_SEQ_INITIATIVE | F_CTL_FIRST_SEQ;
3153 hp->seq_id = 0;
3154 hp->df_ctl = 0;
3155 hp->seq_cnt = 0;
3156 hp->ox_id = 0xffff;
3157 hp->rx_id = 0xffff;
3158 hp->ro = 0;
3159
3160 *rprivp = (caddr_t)privp;
3161 *cmd_buf = cmd;
3162 return (fpkt);
3163
3164 fail:
3165 if (cmd_dma_handle != NULL) {
3166 if (cmd_bound) {
3167 (void) ddi_dma_unbind_handle(cmd_dma_handle);
3168 }
3169 ddi_dma_free_handle(&cmd_dma_handle);
3170 privp->cmd_dma_handle = NULL;
3171 }
3172 if (rsp_dma_handle != NULL) {
3173 if (rsp_bound) {
3174 (void) ddi_dma_unbind_handle(rsp_dma_handle);
3175 }
3176 ddi_dma_free_handle(&rsp_dma_handle);
3177 privp->rsp_dma_handle = NULL;
3178 }
3179 sf_els_free(fpkt);
3180 return (NULL);
3181 }
3182
3183
3184 static void
3185 sf_els_free(struct fcal_packet *fpkt)
3186 {
3187 struct sf_els_hdr *privp = fpkt->fcal_pkt_private;
3188
3189 if (privp != NULL) {
3190 if (privp->cmd_dma_handle != NULL) {
3191 (void) ddi_dma_unbind_handle(privp->cmd_dma_handle);
3192 ddi_dma_free_handle(&privp->cmd_dma_handle);
3193 }
3194 if (privp->cmd != NULL) {
3195 ddi_dma_mem_free(&privp->cmd_acc_handle);
3196 }
3197
3198 if (privp->rsp_dma_handle != NULL) {
3199 (void) ddi_dma_unbind_handle(privp->rsp_dma_handle);
3200 ddi_dma_free_handle(&privp->rsp_dma_handle);
3201 }
3202
3203 if (privp->rsp != NULL) {
3204 ddi_dma_mem_free(&privp->rsp_acc_handle);
3205 }
3206 if (privp->data_dma_handle) {
3207 (void) ddi_dma_unbind_handle(privp->data_dma_handle);
3208 ddi_dma_free_handle(&privp->data_dma_handle);
3209 }
3210 if (privp->data_buf) {
3211 ddi_dma_mem_free(&privp->data_acc_handle);
3212 }
3213 kmem_free(privp, privp->size);
3214 }
3215 kmem_free(fpkt, sizeof (struct fcal_packet));
3216 }
3217
3218
3219 static struct sf_target *
3220 sf_create_target(struct sf *sf, struct sf_els_hdr *privp, int tnum, int64_t lun)
3221 {
3222 struct sf_target *target, *ntarget, *otarget, *ptarget;
3223 int hash;
3224 #ifdef RAID_LUNS
3225 int64_t orig_lun = lun;
3226
3227 /* XXXX Work around SCSA limitations. */
3228 lun = *((short *)&lun);
3229 #endif
3230 ntarget = kmem_zalloc(sizeof (struct sf_target), KM_NOSLEEP);
3231 mutex_enter(&sf->sf_mutex);
3232 if (sf->sf_lip_cnt != privp->lip_cnt) {
3233 mutex_exit(&sf->sf_mutex);
3234 if (ntarget != NULL)
3235 kmem_free(ntarget, sizeof (struct sf_target));
3236 return (NULL);
3237 }
3238
3239 target = sf_lookup_target(sf, privp->port_wwn, lun);
3240 if (lun != 0) {
3241 /*
3242 * Since LUNs != 0 are queued up after LUN == 0, find LUN == 0
3243 * and enqueue the new LUN.
3244 */
3245 if ((ptarget = sf_lookup_target(sf, privp->port_wwn,
3246 (int64_t)0)) == NULL) {
3247 /*
3248 * Yeep -- no LUN 0?
3249 */
3250 mutex_exit(&sf->sf_mutex);
3251 sf_log(sf, CE_WARN, "target 0x%x "
3252 "lun %" PRIx64 ": No LUN 0\n", tnum, lun);
3253 if (ntarget != NULL)
3254 kmem_free(ntarget, sizeof (struct sf_target));
3255 return (NULL);
3256 }
3257 mutex_enter(&ptarget->sft_mutex);
3258 if (target != NULL && ptarget->sft_lip_cnt == sf->sf_lip_cnt &&
3259 ptarget->sft_state&SF_TARGET_OFFLINE) {
3260 /* LUN 0 already finished, duplicate its state */
3261 mutex_exit(&ptarget->sft_mutex);
3262 sf_offline_target(sf, target);
3263 mutex_exit(&sf->sf_mutex);
3264 if (ntarget != NULL)
3265 kmem_free(ntarget, sizeof (struct sf_target));
3266 return (target);
3267 } else if (target != NULL) {
3268 /*
3269 * LUN 0 online or not examined yet.
3270 * Try to bring the LUN back online
3271 */
3272 mutex_exit(&ptarget->sft_mutex);
3273 mutex_enter(&target->sft_mutex);
3274 target->sft_lip_cnt = privp->lip_cnt;
3275 target->sft_state |= SF_TARGET_BUSY;
3276 target->sft_state &= ~(SF_TARGET_OFFLINE|
3277 SF_TARGET_MARK);
3278 target->sft_al_pa = (uchar_t)privp->dest_nport_id;
3279 target->sft_hard_address = sf_switch_to_alpa[tnum];
3280 mutex_exit(&target->sft_mutex);
3281 mutex_exit(&sf->sf_mutex);
3282 if (ntarget != NULL)
3283 kmem_free(ntarget, sizeof (struct sf_target));
3284 return (target);
3285 }
3286 mutex_exit(&ptarget->sft_mutex);
3287 if (ntarget == NULL) {
3288 mutex_exit(&sf->sf_mutex);
3289 return (NULL);
3290 }
3291 /* Initialize new target structure */
3292 bcopy((caddr_t)&privp->node_wwn,
3293 (caddr_t)&ntarget->sft_node_wwn, sizeof (privp->node_wwn));
3294 bcopy((caddr_t)&privp->port_wwn,
3295 (caddr_t)&ntarget->sft_port_wwn, sizeof (privp->port_wwn));
3296 ntarget->sft_lun.l = lun;
3297 #ifdef RAID_LUNS
3298 ntarget->sft_lun.l = orig_lun;
3299 ntarget->sft_raid_lun = (uint_t)lun;
3300 #endif
3301 mutex_init(&ntarget->sft_mutex, NULL, MUTEX_DRIVER, NULL);
3302 mutex_init(&ntarget->sft_pkt_mutex, NULL, MUTEX_DRIVER, NULL);
3303 /* Don't let anyone use this till we finishup init. */
3304 mutex_enter(&ntarget->sft_mutex);
3305 mutex_enter(&ntarget->sft_pkt_mutex);
3306
3307 hash = SF_HASH(privp->port_wwn, lun);
3308 ntarget->sft_next = sf->sf_wwn_lists[hash];
3309 sf->sf_wwn_lists[hash] = ntarget;
3310
3311 ntarget->sft_lip_cnt = privp->lip_cnt;
3312 ntarget->sft_al_pa = (uchar_t)privp->dest_nport_id;
3313 ntarget->sft_hard_address = sf_switch_to_alpa[tnum];
3314 ntarget->sft_device_type = DTYPE_UNKNOWN;
3315 ntarget->sft_state = SF_TARGET_BUSY;
3316 ntarget->sft_pkt_head = (struct sf_pkt *)&ntarget->
3317 sft_pkt_head;
3318 ntarget->sft_pkt_tail = (struct sf_pkt *)&ntarget->
3319 sft_pkt_head;
3320
3321 mutex_enter(&ptarget->sft_mutex);
3322 /* Traverse the list looking for this target */
3323 for (target = ptarget; target->sft_next_lun;
3324 target = target->sft_next_lun) {
3325 otarget = target->sft_next_lun;
3326 }
3327 ntarget->sft_next_lun = target->sft_next_lun;
3328 target->sft_next_lun = ntarget;
3329 mutex_exit(&ptarget->sft_mutex);
3330 mutex_exit(&ntarget->sft_pkt_mutex);
3331 mutex_exit(&ntarget->sft_mutex);
3332 mutex_exit(&sf->sf_mutex);
3333 return (ntarget);
3334
3335 }
3336 if (target != NULL && target->sft_lip_cnt == sf->sf_lip_cnt) {
3337 /* It's been touched this LIP -- duplicate WWNs */
3338 sf_offline_target(sf, target); /* And all the baby targets */
3339 mutex_exit(&sf->sf_mutex);
3340 sf_log(sf, CE_WARN, "target 0x%x, duplicate port wwns\n",
3341 tnum);
3342 if (ntarget != NULL) {
3343 kmem_free(ntarget, sizeof (struct sf_target));
3344 }
3345 return (NULL);
3346 }
3347
3348 if ((otarget = sf->sf_targets[tnum]) != NULL) {
3349 /* Someone else is in our slot */
3350 mutex_enter(&otarget->sft_mutex);
3351 if (otarget->sft_lip_cnt == sf->sf_lip_cnt) {
3352 mutex_exit(&otarget->sft_mutex);
3353 sf_offline_target(sf, otarget);
3354 if (target != NULL)
3355 sf_offline_target(sf, target);
3356 mutex_exit(&sf->sf_mutex);
3357 sf_log(sf, CE_WARN,
3358 "target 0x%x, duplicate switch settings\n", tnum);
3359 if (ntarget != NULL)
3360 kmem_free(ntarget, sizeof (struct sf_target));
3361 return (NULL);
3362 }
3363 mutex_exit(&otarget->sft_mutex);
3364 if (bcmp((caddr_t)&privp->port_wwn, (caddr_t)&otarget->
3365 sft_port_wwn, sizeof (privp->port_wwn))) {
3366 sf_offline_target(sf, otarget);
3367 mutex_exit(&sf->sf_mutex);
3368 sf_log(sf, CE_WARN, "wwn changed on target 0x%x\n",
3369 tnum);
3370 bzero((caddr_t)&sf->sf_stats.tstats[tnum],
3371 sizeof (struct sf_target_stats));
3372 mutex_enter(&sf->sf_mutex);
3373 }
3374 }
3375
3376 sf->sf_targets[tnum] = target;
3377 if ((target = sf->sf_targets[tnum]) == NULL) {
3378 if (ntarget == NULL) {
3379 mutex_exit(&sf->sf_mutex);
3380 return (NULL);
3381 }
3382 bcopy((caddr_t)&privp->node_wwn,
3383 (caddr_t)&ntarget->sft_node_wwn, sizeof (privp->node_wwn));
3384 bcopy((caddr_t)&privp->port_wwn,
3385 (caddr_t)&ntarget->sft_port_wwn, sizeof (privp->port_wwn));
3386 ntarget->sft_lun.l = lun;
3387 #ifdef RAID_LUNS
3388 ntarget->sft_lun.l = orig_lun;
3389 ntarget->sft_raid_lun = (uint_t)lun;
3390 #endif
3391 mutex_init(&ntarget->sft_mutex, NULL, MUTEX_DRIVER, NULL);
3392 mutex_init(&ntarget->sft_pkt_mutex, NULL, MUTEX_DRIVER, NULL);
3393 mutex_enter(&ntarget->sft_mutex);
3394 mutex_enter(&ntarget->sft_pkt_mutex);
3395 hash = SF_HASH(privp->port_wwn, lun); /* lun 0 */
3396 ntarget->sft_next = sf->sf_wwn_lists[hash];
3397 sf->sf_wwn_lists[hash] = ntarget;
3398
3399 target = ntarget;
3400 target->sft_lip_cnt = privp->lip_cnt;
3401 target->sft_al_pa = (uchar_t)privp->dest_nport_id;
3402 target->sft_hard_address = sf_switch_to_alpa[tnum];
3403 target->sft_device_type = DTYPE_UNKNOWN;
3404 target->sft_state = SF_TARGET_BUSY;
3405 target->sft_pkt_head = (struct sf_pkt *)&target->
3406 sft_pkt_head;
3407 target->sft_pkt_tail = (struct sf_pkt *)&target->
3408 sft_pkt_head;
3409 sf->sf_targets[tnum] = target;
3410 mutex_exit(&ntarget->sft_mutex);
3411 mutex_exit(&ntarget->sft_pkt_mutex);
3412 mutex_exit(&sf->sf_mutex);
3413 } else {
3414 mutex_enter(&target->sft_mutex);
3415 target->sft_lip_cnt = privp->lip_cnt;
3416 target->sft_state |= SF_TARGET_BUSY;
3417 target->sft_state &= ~(SF_TARGET_OFFLINE|SF_TARGET_MARK);
3418 target->sft_al_pa = (uchar_t)privp->dest_nport_id;
3419 target->sft_hard_address = sf_switch_to_alpa[tnum];
3420 mutex_exit(&target->sft_mutex);
3421 mutex_exit(&sf->sf_mutex);
3422 if (ntarget != NULL)
3423 kmem_free(ntarget, sizeof (struct sf_target));
3424 }
3425 return (target);
3426 }
3427
3428
3429 /*
3430 * find the target for a given sf instance
3431 */
3432 /* ARGSUSED */
3433 static struct sf_target *
3434 #ifdef RAID_LUNS
3435 sf_lookup_target(struct sf *sf, uchar_t *wwn, int lun)
3436 #else
3437 sf_lookup_target(struct sf *sf, uchar_t *wwn, int64_t lun)
3438 #endif
3439 {
3440 int hash;
3441 struct sf_target *target;
3442
3443 ASSERT(mutex_owned(&sf->sf_mutex));
3444 hash = SF_HASH(wwn, lun);
3445
3446 target = sf->sf_wwn_lists[hash];
3447 while (target != NULL) {
3448
3449 #ifndef RAID_LUNS
3450 if (bcmp((caddr_t)wwn, (caddr_t)&target->sft_port_wwn,
3451 sizeof (target->sft_port_wwn)) == 0 &&
3452 target->sft_lun.l == lun)
3453 break;
3454 #else
3455 if (bcmp((caddr_t)wwn, (caddr_t)&target->sft_port_wwn,
3456 sizeof (target->sft_port_wwn)) == 0 &&
3457 target->sft_raid_lun == lun)
3458 break;
3459 #endif
3460 target = target->sft_next;
3461 }
3462
3463 return (target);
3464 }
3465
3466
3467 /*
3468 * Send out a REPORT_LUNS command.
3469 */
3470 static int
3471 sf_do_reportlun(struct sf *sf, struct sf_els_hdr *privp,
3472 struct sf_target *target)
3473 {
3474 struct fcal_packet *fpkt = privp->fpkt;
3475 ddi_dma_cookie_t pcookie;
3476 ddi_dma_handle_t lun_dma_handle = NULL;
3477 ddi_acc_handle_t lun_acc_handle;
3478 uint_t ccount;
3479 size_t real_size;
3480 caddr_t lun_buf = NULL;
3481 int handle_bound = 0;
3482 fc_frame_header_t *hp = &fpkt->fcal_socal_request.sr_fc_frame_hdr;
3483 struct fcp_cmd *reportlun = (struct fcp_cmd *)privp->cmd;
3484 char *msg = "Transport";
3485
3486 if (ddi_dma_alloc_handle(sf->sf_dip, sf->sf_sochandle->fcal_dmaattr,
3487 DDI_DMA_DONTWAIT, NULL, &lun_dma_handle) != DDI_SUCCESS) {
3488 msg = "ddi_dma_alloc_handle()";
3489 goto fail;
3490 }
3491
3492 if (ddi_dma_mem_alloc(lun_dma_handle, REPORT_LUNS_SIZE,
3493 sf->sf_sochandle->fcal_accattr, DDI_DMA_CONSISTENT,
3494 DDI_DMA_DONTWAIT, NULL, &lun_buf,
3495 &real_size, &lun_acc_handle) != DDI_SUCCESS) {
3496 msg = "ddi_dma_mem_alloc()";
3497 goto fail;
3498 }
3499
3500 if (real_size < REPORT_LUNS_SIZE) {
3501 msg = "DMA mem < REPORT_LUNS_SIZE";
3502 goto fail;
3503 }
3504
3505 if (ddi_dma_addr_bind_handle(lun_dma_handle, NULL,
3506 lun_buf, real_size, DDI_DMA_READ |
3507 DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT,
3508 NULL, &pcookie, &ccount) != DDI_DMA_MAPPED) {
3509 msg = "ddi_dma_addr_bind_handle()";
3510 goto fail;
3511 }
3512 handle_bound = 1;
3513
3514 if (ccount != 1) {
3515 msg = "ccount != 1";
3516 goto fail;
3517 }
3518 privp->els_code = 0;
3519 privp->target = target;
3520 privp->data_dma_handle = lun_dma_handle;
3521 privp->data_acc_handle = lun_acc_handle;
3522 privp->data_buf = lun_buf;
3523
3524 fpkt->fcal_pkt_comp = sf_reportlun_callback;
3525 fpkt->fcal_socal_request.sr_soc_hdr.sh_seg_cnt = 3;
3526 fpkt->fcal_socal_request.sr_cqhdr.cq_hdr_type = CQ_TYPE_IO_READ;
3527 fpkt->fcal_socal_request.sr_dataseg[0].fc_count =
3528 sizeof (struct fcp_cmd);
3529 fpkt->fcal_socal_request.sr_dataseg[2].fc_base =
3530 (uint32_t)pcookie.dmac_address;
3531 fpkt->fcal_socal_request.sr_dataseg[2].fc_count = pcookie.dmac_size;
3532 fpkt->fcal_socal_request.sr_soc_hdr.sh_byte_cnt = pcookie.dmac_size;
3533 hp->r_ctl = R_CTL_COMMAND;
3534 hp->type = TYPE_SCSI_FCP;
3535 bzero((caddr_t)reportlun, sizeof (struct fcp_cmd));
3536 ((union scsi_cdb *)reportlun->fcp_cdb)->scc_cmd = SCMD_REPORT_LUNS;
3537 /* Now set the buffer size. If DDI gave us extra, that's O.K. */
3538 ((union scsi_cdb *)reportlun->fcp_cdb)->scc5_count0 =
3539 (real_size&0x0ff);
3540 ((union scsi_cdb *)reportlun->fcp_cdb)->scc5_count1 =
3541 (real_size>>8)&0x0ff;
3542 ((union scsi_cdb *)reportlun->fcp_cdb)->scc5_count2 =
3543 (real_size>>16)&0x0ff;
3544 ((union scsi_cdb *)reportlun->fcp_cdb)->scc5_count3 =
3545 (real_size>>24)&0x0ff;
3546 reportlun->fcp_cntl.cntl_read_data = 1;
3547 reportlun->fcp_cntl.cntl_write_data = 0;
3548 reportlun->fcp_data_len = pcookie.dmac_size;
3549 reportlun->fcp_cntl.cntl_qtype = FCP_QTYPE_SIMPLE;
3550
3551 (void) ddi_dma_sync(lun_dma_handle, 0, 0, DDI_DMA_SYNC_FORDEV);
3552 /* We know he's there, so this should be fast */
3553 privp->timeout = sf_watchdog_time + SF_FCP_TIMEOUT;
3554 if (sf_els_transport(sf, privp) == 1)
3555 return (1);
3556
3557 fail:
3558 sf_log(sf, CE_WARN,
3559 "%s failure for REPORTLUN to target 0x%x\n",
3560 msg, sf_alpa_to_switch[privp->dest_nport_id]);
3561 sf_els_free(fpkt);
3562 if (lun_dma_handle != NULL) {
3563 if (handle_bound)
3564 (void) ddi_dma_unbind_handle(lun_dma_handle);
3565 ddi_dma_free_handle(&lun_dma_handle);
3566 }
3567 if (lun_buf != NULL) {
3568 ddi_dma_mem_free(&lun_acc_handle);
3569 }
3570 return (0);
3571 }
3572
3573 /*
3574 * Handle the results of a REPORT_LUNS command:
3575 * Create additional targets if necessary
3576 * Initiate INQUIRYs on all LUNs.
3577 */
3578 static void
3579 sf_reportlun_callback(struct fcal_packet *fpkt)
3580 {
3581 struct sf_els_hdr *privp = (struct sf_els_hdr *)fpkt->
3582 fcal_pkt_private;
3583 struct scsi_report_luns *ptr =
3584 (struct scsi_report_luns *)privp->data_buf;
3585 struct sf *sf = privp->sf;
3586 struct sf_target *target = privp->target;
3587 struct fcp_rsp *rsp = NULL;
3588 int delayed_retry = 0;
3589 int tid = sf_alpa_to_switch[target->sft_hard_address];
3590 int i, free_pkt = 1;
3591 short ncmds;
3592
3593 mutex_enter(&sf->sf_mutex);
3594 /* use as temporary state variable */
3595 if (privp->timeout == SF_INVALID_TIMEOUT) {
3596 mutex_exit(&sf->sf_mutex);
3597 return;
3598 }
3599 if (privp->prev)
3600 privp->prev->next = privp->next;
3601 if (privp->next)
3602 privp->next->prev = privp->prev;
3603 if (sf->sf_els_list == privp)
3604 sf->sf_els_list = privp->next;
3605 privp->prev = privp->next = NULL;
3606 mutex_exit(&sf->sf_mutex);
3607 ncmds = fpkt->fcal_ncmds;
3608 ASSERT(ncmds >= 0);
3609 mutex_enter(&sf->sf_cmd_mutex);
3610 sf->sf_ncmds = ncmds;
3611 mutex_exit(&sf->sf_cmd_mutex);
3612
3613 if (fpkt->fcal_pkt_status == FCAL_STATUS_OK) {
3614 (void) ddi_dma_sync(privp->rsp_dma_handle, 0,
3615 0, DDI_DMA_SYNC_FORKERNEL);
3616
3617 rsp = (struct fcp_rsp *)privp->rsp;
3618 }
3619 SF_DEBUG(1, (sf, CE_CONT,
3620 "!REPORTLUN to al_pa %x pkt status %x scsi status %x\n",
3621 privp->dest_nport_id,
3622 fpkt->fcal_pkt_status,
3623 rsp?rsp->fcp_u.fcp_status.scsi_status:0));
3624
3625 /* See if target simply does not support REPORT_LUNS. */
3626 if (rsp && rsp->fcp_u.fcp_status.scsi_status == STATUS_CHECK &&
3627 rsp->fcp_u.fcp_status.sense_len_set &&
3628 rsp->fcp_sense_len >=
3629 offsetof(struct scsi_extended_sense, es_qual_code)) {
3630 struct scsi_extended_sense *sense;
3631 sense = (struct scsi_extended_sense *)
3632 ((caddr_t)rsp + sizeof (struct fcp_rsp)
3633 + rsp->fcp_response_len);
3634 if (sense->es_key == KEY_ILLEGAL_REQUEST) {
3635 if (sense->es_add_code == 0x20) {
3636 /* Fake LUN 0 */
3637 SF_DEBUG(1, (sf, CE_CONT,
3638 "!REPORTLUN Faking good "
3639 "completion for alpa %x\n",
3640 privp->dest_nport_id));
3641 ptr->lun_list_len = FCP_LUN_SIZE;
3642 ptr->lun[0] = 0;
3643 rsp->fcp_u.fcp_status.scsi_status =
3644 STATUS_GOOD;
3645 } else if (sense->es_add_code == 0x25) {
3646 SF_DEBUG(1, (sf, CE_CONT,
3647 "!REPORTLUN device alpa %x "
3648 "key %x code %x\n",
3649 privp->dest_nport_id,
3650 sense->es_key, sense->es_add_code));
3651 goto fail;
3652 }
3653 } else if (sense->es_key ==
3654 KEY_UNIT_ATTENTION &&
3655 sense->es_add_code == 0x29) {
3656 SF_DEBUG(1, (sf, CE_CONT,
3657 "!REPORTLUN device alpa %x was reset\n",
3658 privp->dest_nport_id));
3659 } else {
3660 SF_DEBUG(1, (sf, CE_CONT,
3661 "!REPORTLUN device alpa %x "
3662 "key %x code %x\n",
3663 privp->dest_nport_id,
3664 sense->es_key, sense->es_add_code));
3665 /* XXXXXX The following is here to handle broken targets -- remove it later */
3666 if (sf_reportlun_forever &&
3667 sense->es_key == KEY_UNIT_ATTENTION)
3668 goto retry;
3669 /* XXXXXX */
3670 if (sense->es_key == KEY_NOT_READY)
3671 delayed_retry = 1;
3672 }
3673 }
3674
3675 if (rsp && rsp->fcp_u.fcp_status.scsi_status == STATUS_GOOD) {
3676 struct fcp_rsp_info *bep;
3677
3678 bep = (struct fcp_rsp_info *)(&rsp->
3679 fcp_response_len + 1);
3680 if (!rsp->fcp_u.fcp_status.rsp_len_set ||
3681 bep->rsp_code == FCP_NO_FAILURE) {
3682 (void) ddi_dma_sync(privp->data_dma_handle,
3683 0, 0, DDI_DMA_SYNC_FORKERNEL);
3684
3685 /* Convert from #bytes to #ints */
3686 ptr->lun_list_len = ptr->lun_list_len >> 3;
3687 SF_DEBUG(2, (sf, CE_CONT,
3688 "!REPORTLUN to al_pa %x succeeded: %d LUNs\n",
3689 privp->dest_nport_id, ptr->lun_list_len));
3690 if (!ptr->lun_list_len) {
3691 /* No LUNs? Ya gotta be kidding... */
3692 sf_log(sf, CE_WARN,
3693 "SCSI violation -- "
3694 "target 0x%x reports no LUNs\n",
3695 sf_alpa_to_switch[
3696 privp->dest_nport_id]);
3697 ptr->lun_list_len = 1;
3698 ptr->lun[0] = 0;
3699 }
3700
3701 mutex_enter(&sf->sf_mutex);
3702 if (sf->sf_lip_cnt == privp->lip_cnt) {
3703 sf->sf_device_count += ptr->lun_list_len - 1;
3704 }
3705
3706 mutex_exit(&sf->sf_mutex);
3707 for (i = 0; i < ptr->lun_list_len && privp->lip_cnt ==
3708 sf->sf_lip_cnt; i++) {
3709 struct sf_els_hdr *nprivp;
3710 struct fcal_packet *nfpkt;
3711
3712 /* LUN 0 is already in `target' */
3713 if (ptr->lun[i] != 0) {
3714 target = sf_create_target(sf,
3715 privp, tid, ptr->lun[i]);
3716 }
3717 nprivp = NULL;
3718 nfpkt = NULL;
3719 if (target) {
3720 nfpkt = sf_els_alloc(sf,
3721 target->sft_al_pa,
3722 sizeof (struct sf_els_hdr),
3723 sizeof (union sf_els_cmd),
3724 sizeof (union sf_els_rsp),
3725 (caddr_t *)&nprivp,
3726 (caddr_t *)&rsp);
3727 if (nprivp)
3728 nprivp->lip_cnt =
3729 privp->lip_cnt;
3730 }
3731 if (nfpkt && nprivp &&
3732 (sf_do_inquiry(sf, nprivp, target) ==
3733 0)) {
3734 mutex_enter(&sf->sf_mutex);
3735 if (sf->sf_lip_cnt == privp->
3736 lip_cnt) {
3737 sf->sf_device_count --;
3738 }
3739 sf_offline_target(sf, target);
3740 mutex_exit(&sf->sf_mutex);
3741 }
3742 }
3743 sf_els_free(fpkt);
3744 return;
3745 } else {
3746 SF_DEBUG(1, (sf, CE_CONT,
3747 "!REPORTLUN al_pa %x fcp failure, "
3748 "fcp_rsp_code %x scsi status %x\n",
3749 privp->dest_nport_id, bep->rsp_code,
3750 rsp ? rsp->fcp_u.fcp_status.scsi_status:0));
3751 goto fail;
3752 }
3753 }
3754 if (rsp && ((rsp->fcp_u.fcp_status.scsi_status == STATUS_BUSY) ||
3755 (rsp->fcp_u.fcp_status.scsi_status == STATUS_QFULL))) {
3756 delayed_retry = 1;
3757 }
3758
3759 if (++(privp->retries) < sf_els_retries ||
3760 (delayed_retry && privp->retries < SF_BSY_RETRIES)) {
3761 /* XXXXXX The following is here to handle broken targets -- remove it later */
3762 retry:
3763 /* XXXXXX */
3764 if (delayed_retry) {
3765 privp->retries--;
3766 privp->timeout = sf_watchdog_time + SF_BSY_TIMEOUT;
3767 privp->delayed_retry = 1;
3768 } else {
3769 privp->timeout = sf_watchdog_time + SF_FCP_TIMEOUT;
3770 }
3771
3772 privp->prev = NULL;
3773 mutex_enter(&sf->sf_mutex);
3774 if (privp->lip_cnt == sf->sf_lip_cnt) {
3775 if (!delayed_retry)
3776 SF_DEBUG(1, (sf, CE_WARN,
3777 "!REPORTLUN to al_pa %x failed, retrying\n",
3778 privp->dest_nport_id));
3779 privp->next = sf->sf_els_list;
3780 if (sf->sf_els_list != NULL)
3781 sf->sf_els_list->prev = privp;
3782 sf->sf_els_list = privp;
3783 mutex_exit(&sf->sf_mutex);
3784 if (!delayed_retry && soc_transport(sf->sf_sochandle,
3785 fpkt, FCAL_NOSLEEP, CQ_REQUEST_1) !=
3786 FCAL_TRANSPORT_SUCCESS) {
3787 mutex_enter(&sf->sf_mutex);
3788 if (privp->prev)
3789 privp->prev->next = privp->next;
3790 if (privp->next)
3791 privp->next->prev = privp->prev;
3792 if (sf->sf_els_list == privp)
3793 sf->sf_els_list = privp->next;
3794 mutex_exit(&sf->sf_mutex);
3795 goto fail;
3796 } else
3797 return;
3798 } else {
3799 mutex_exit(&sf->sf_mutex);
3800 }
3801 } else {
3802 fail:
3803
3804 /* REPORT_LUN failed -- try inquiry */
3805 if (sf_do_inquiry(sf, privp, target) != 0) {
3806 return;
3807 } else {
3808 free_pkt = 0;
3809 }
3810 mutex_enter(&sf->sf_mutex);
3811 if (sf->sf_lip_cnt == privp->lip_cnt) {
3812 sf_log(sf, CE_WARN,
3813 "!REPORTLUN to target 0x%x failed\n",
3814 sf_alpa_to_switch[privp->dest_nport_id]);
3815 sf_offline_target(sf, target);
3816 sf->sf_device_count--;
3817 ASSERT(sf->sf_device_count >= 0);
3818 if (sf->sf_device_count == 0)
3819 sf_finish_init(sf, privp->lip_cnt);
3820 }
3821 mutex_exit(&sf->sf_mutex);
3822 }
3823 if (free_pkt) {
3824 sf_els_free(fpkt);
3825 }
3826 }
3827
3828 static int
3829 sf_do_inquiry(struct sf *sf, struct sf_els_hdr *privp,
3830 struct sf_target *target)
3831 {
3832 struct fcal_packet *fpkt = privp->fpkt;
3833 ddi_dma_cookie_t pcookie;
3834 ddi_dma_handle_t inq_dma_handle = NULL;
3835 ddi_acc_handle_t inq_acc_handle;
3836 uint_t ccount;
3837 size_t real_size;
3838 caddr_t inq_buf = NULL;
3839 int handle_bound = FALSE;
3840 fc_frame_header_t *hp = &fpkt->fcal_socal_request.sr_fc_frame_hdr;
3841 struct fcp_cmd *inq = (struct fcp_cmd *)privp->cmd;
3842 char *msg = "Transport";
3843
3844
3845 if (ddi_dma_alloc_handle(sf->sf_dip, sf->sf_sochandle->fcal_dmaattr,
3846 DDI_DMA_DONTWAIT, NULL, &inq_dma_handle) != DDI_SUCCESS) {
3847 msg = "ddi_dma_alloc_handle()";
3848 goto fail;
3849 }
3850
3851 if (ddi_dma_mem_alloc(inq_dma_handle, SUN_INQSIZE,
3852 sf->sf_sochandle->fcal_accattr, DDI_DMA_CONSISTENT,
3853 DDI_DMA_DONTWAIT, NULL, &inq_buf,
3854 &real_size, &inq_acc_handle) != DDI_SUCCESS) {
3855 msg = "ddi_dma_mem_alloc()";
3856 goto fail;
3857 }
3858
3859 if (real_size < SUN_INQSIZE) {
3860 msg = "DMA mem < inquiry size";
3861 goto fail;
3862 }
3863
3864 if (ddi_dma_addr_bind_handle(inq_dma_handle, NULL,
3865 inq_buf, real_size, DDI_DMA_READ | DDI_DMA_CONSISTENT,
3866 DDI_DMA_DONTWAIT, NULL, &pcookie, &ccount) != DDI_DMA_MAPPED) {
3867 msg = "ddi_dma_addr_bind_handle()";
3868 goto fail;
3869 }
3870 handle_bound = TRUE;
3871
3872 if (ccount != 1) {
3873 msg = "ccount != 1";
3874 goto fail;
3875 }
3876 privp->els_code = 0; /* not an ELS command */
3877 privp->target = target;
3878 privp->data_dma_handle = inq_dma_handle;
3879 privp->data_acc_handle = inq_acc_handle;
3880 privp->data_buf = inq_buf;
3881 fpkt->fcal_pkt_comp = sf_inq_callback;
3882 fpkt->fcal_socal_request.sr_soc_hdr.sh_seg_cnt = 3;
3883 fpkt->fcal_socal_request.sr_cqhdr.cq_hdr_type = CQ_TYPE_IO_READ;
3884 fpkt->fcal_socal_request.sr_dataseg[0].fc_count =
3885 sizeof (struct fcp_cmd);
3886 fpkt->fcal_socal_request.sr_dataseg[2].fc_base =
3887 (uint32_t)pcookie.dmac_address;
3888 fpkt->fcal_socal_request.sr_dataseg[2].fc_count = pcookie.dmac_size;
3889 fpkt->fcal_socal_request.sr_soc_hdr.sh_byte_cnt = pcookie.dmac_size;
3890 hp->r_ctl = R_CTL_COMMAND;
3891 hp->type = TYPE_SCSI_FCP;
3892 bzero((caddr_t)inq, sizeof (struct fcp_cmd));
3893 ((union scsi_cdb *)inq->fcp_cdb)->scc_cmd = SCMD_INQUIRY;
3894 ((union scsi_cdb *)inq->fcp_cdb)->g0_count0 = SUN_INQSIZE;
3895 bcopy((caddr_t)&target->sft_lun.b, (caddr_t)&inq->fcp_ent_addr,
3896 FCP_LUN_SIZE);
3897 inq->fcp_cntl.cntl_read_data = 1;
3898 inq->fcp_cntl.cntl_write_data = 0;
3899 inq->fcp_data_len = pcookie.dmac_size;
3900 inq->fcp_cntl.cntl_qtype = FCP_QTYPE_SIMPLE;
3901
3902 (void) ddi_dma_sync(inq_dma_handle, (off_t)0, (size_t)0,
3903 DDI_DMA_SYNC_FORDEV);
3904 privp->timeout = sf_watchdog_time + SF_FCP_TIMEOUT;
3905 SF_DEBUG(5, (sf, CE_WARN,
3906 "!Sending INQUIRY to al_pa %x lun %" PRIx64 "\n",
3907 privp->dest_nport_id,
3908 SCSA_LUN(target)));
3909 return (sf_els_transport(sf, privp));
3910
3911 fail:
3912 sf_log(sf, CE_WARN,
3913 "%s failure for INQUIRY to target 0x%x\n",
3914 msg, sf_alpa_to_switch[privp->dest_nport_id]);
3915 sf_els_free(fpkt);
3916 if (inq_dma_handle != NULL) {
3917 if (handle_bound) {
3918 (void) ddi_dma_unbind_handle(inq_dma_handle);
3919 }
3920 ddi_dma_free_handle(&inq_dma_handle);
3921 }
3922 if (inq_buf != NULL) {
3923 ddi_dma_mem_free(&inq_acc_handle);
3924 }
3925 return (FALSE);
3926 }
3927
3928
3929 /*
3930 * called as the pkt_comp routine for INQ packets
3931 */
3932 static void
3933 sf_inq_callback(struct fcal_packet *fpkt)
3934 {
3935 struct sf_els_hdr *privp = (struct sf_els_hdr *)fpkt->
3936 fcal_pkt_private;
3937 struct scsi_inquiry *prt = (struct scsi_inquiry *)privp->data_buf;
3938 struct sf *sf = privp->sf;
3939 struct sf *tsf;
3940 struct sf_target *target = privp->target;
3941 struct fcp_rsp *rsp;
3942 int delayed_retry = FALSE;
3943 short ncmds;
3944
3945
3946 mutex_enter(&sf->sf_mutex);
3947 /* use as temporary state variable */
3948 if (privp->timeout == SF_INVALID_TIMEOUT) {
3949 mutex_exit(&sf->sf_mutex);
3950 return;
3951 }
3952 if (privp->prev != NULL) {
3953 privp->prev->next = privp->next;
3954 }
3955 if (privp->next != NULL) {
3956 privp->next->prev = privp->prev;
3957 }
3958 if (sf->sf_els_list == privp) {
3959 sf->sf_els_list = privp->next;
3960 }
3961 privp->prev = privp->next = NULL;
3962 mutex_exit(&sf->sf_mutex);
3963 ncmds = fpkt->fcal_ncmds;
3964 ASSERT(ncmds >= 0);
3965 mutex_enter(&sf->sf_cmd_mutex);
3966 sf->sf_ncmds = ncmds;
3967 mutex_exit(&sf->sf_cmd_mutex);
3968
3969 if (fpkt->fcal_pkt_status == FCAL_STATUS_OK) {
3970
3971 (void) ddi_dma_sync(privp->rsp_dma_handle, (off_t)0,
3972 (size_t)0, DDI_DMA_SYNC_FORKERNEL);
3973
3974 rsp = (struct fcp_rsp *)privp->rsp;
3975 SF_DEBUG(2, (sf, CE_CONT,
3976 "!INQUIRY to al_pa %x scsi status %x",
3977 privp->dest_nport_id, rsp->fcp_u.fcp_status.scsi_status));
3978
3979 if ((rsp->fcp_u.fcp_status.scsi_status == STATUS_GOOD) &&
3980 !rsp->fcp_u.fcp_status.resid_over &&
3981 (!rsp->fcp_u.fcp_status.resid_under ||
3982 ((SUN_INQSIZE - rsp->fcp_resid) >= SUN_MIN_INQLEN))) {
3983 struct fcp_rsp_info *bep;
3984
3985 bep = (struct fcp_rsp_info *)(&rsp->
3986 fcp_response_len + 1);
3987
3988 if (!rsp->fcp_u.fcp_status.rsp_len_set ||
3989 (bep->rsp_code == FCP_NO_FAILURE)) {
3990
3991 SF_DEBUG(2, (sf, CE_CONT,
3992 "!INQUIRY to al_pa %x lun %" PRIx64
3993 " succeeded\n",
3994 privp->dest_nport_id, SCSA_LUN(target)));
3995
3996 (void) ddi_dma_sync(privp->data_dma_handle,
3997 (off_t)0, (size_t)0,
3998 DDI_DMA_SYNC_FORKERNEL);
3999
4000 mutex_enter(&sf->sf_mutex);
4001
4002 if (sf->sf_lip_cnt == privp->lip_cnt) {
4003 mutex_enter(&target->sft_mutex);
4004 target->sft_device_type =
4005 prt->inq_dtype;
4006 bcopy(prt, &target->sft_inq,
4007 sizeof (*prt));
4008 mutex_exit(&target->sft_mutex);
4009 sf->sf_device_count--;
4010 ASSERT(sf->sf_device_count >= 0);
4011 if (sf->sf_device_count == 0) {
4012 sf_finish_init(sf,
4013 privp->lip_cnt);
4014 }
4015 }
4016 mutex_exit(&sf->sf_mutex);
4017 sf_els_free(fpkt);
4018 return;
4019 }
4020 } else if ((rsp->fcp_u.fcp_status.scsi_status ==
4021 STATUS_BUSY) ||
4022 (rsp->fcp_u.fcp_status.scsi_status == STATUS_QFULL) ||
4023 (rsp->fcp_u.fcp_status.scsi_status == STATUS_CHECK)) {
4024 delayed_retry = TRUE;
4025 }
4026 } else {
4027 SF_DEBUG(2, (sf, CE_CONT, "!INQUIRY to al_pa %x fc status %x",
4028 privp->dest_nport_id, fpkt->fcal_pkt_status));
4029 }
4030
4031 if (++(privp->retries) < sf_els_retries ||
4032 (delayed_retry && privp->retries < SF_BSY_RETRIES)) {
4033 if (fpkt->fcal_pkt_status == FCAL_STATUS_MAX_XCHG_EXCEEDED) {
4034 tsf = sf->sf_sibling;
4035 if (tsf != NULL) {
4036 mutex_enter(&tsf->sf_cmd_mutex);
4037 tsf->sf_flag = 1;
4038 tsf->sf_throttle = SF_DECR_DELTA;
4039 mutex_exit(&tsf->sf_cmd_mutex);
4040 }
4041 delayed_retry = 1;
4042 }
4043 if (delayed_retry) {
4044 privp->retries--;
4045 privp->timeout = sf_watchdog_time + SF_BSY_TIMEOUT;
4046 privp->delayed_retry = TRUE;
4047 } else {
4048 privp->timeout = sf_watchdog_time + SF_FCP_TIMEOUT;
4049 }
4050
4051 privp->prev = NULL;
4052 mutex_enter(&sf->sf_mutex);
4053 if (privp->lip_cnt == sf->sf_lip_cnt) {
4054 if (!delayed_retry) {
4055 SF_DEBUG(1, (sf, CE_WARN,
4056 "INQUIRY to al_pa %x failed, retrying",
4057 privp->dest_nport_id));
4058 }
4059 privp->next = sf->sf_els_list;
4060 if (sf->sf_els_list != NULL) {
4061 sf->sf_els_list->prev = privp;
4062 }
4063 sf->sf_els_list = privp;
4064 mutex_exit(&sf->sf_mutex);
4065 /* if not delayed call transport to send a pkt */
4066 if (!delayed_retry &&
4067 (soc_transport(sf->sf_sochandle, fpkt,
4068 FCAL_NOSLEEP, CQ_REQUEST_1) !=
4069 FCAL_TRANSPORT_SUCCESS)) {
4070 mutex_enter(&sf->sf_mutex);
4071 if (privp->prev != NULL) {
4072 privp->prev->next = privp->next;
4073 }
4074 if (privp->next != NULL) {
4075 privp->next->prev = privp->prev;
4076 }
4077 if (sf->sf_els_list == privp) {
4078 sf->sf_els_list = privp->next;
4079 }
4080 mutex_exit(&sf->sf_mutex);
4081 goto fail;
4082 }
4083 return;
4084 }
4085 mutex_exit(&sf->sf_mutex);
4086 } else {
4087 fail:
4088 mutex_enter(&sf->sf_mutex);
4089 if (sf->sf_lip_cnt == privp->lip_cnt) {
4090 sf_offline_target(sf, target);
4091 sf_log(sf, CE_NOTE,
4092 "INQUIRY to target 0x%x lun %" PRIx64 " failed. "
4093 "Retry Count: %d\n",
4094 sf_alpa_to_switch[privp->dest_nport_id],
4095 SCSA_LUN(target),
4096 privp->retries);
4097 sf->sf_device_count--;
4098 ASSERT(sf->sf_device_count >= 0);
4099 if (sf->sf_device_count == 0) {
4100 sf_finish_init(sf, privp->lip_cnt);
4101 }
4102 }
4103 mutex_exit(&sf->sf_mutex);
4104 }
4105 sf_els_free(fpkt);
4106 }
4107
4108
4109 static void
4110 sf_finish_init(struct sf *sf, int lip_cnt)
4111 {
4112 int i; /* loop index */
4113 int cflag;
4114 struct sf_target *target; /* current target */
4115 dev_info_t *dip;
4116 struct sf_hp_elem *elem; /* hotplug element created */
4117
4118 SF_DEBUG(1, (sf, CE_WARN, "!sf_finish_init\n"));
4119 ASSERT(mutex_owned(&sf->sf_mutex));
4120
4121 /* scan all hash queues */
4122 for (i = 0; i < SF_NUM_HASH_QUEUES; i++) {
4123 target = sf->sf_wwn_lists[i];
4124 while (target != NULL) {
4125 mutex_enter(&target->sft_mutex);
4126
4127 /* see if target is not offline */
4128 if ((target->sft_state & SF_TARGET_OFFLINE)) {
4129 /*
4130 * target already offline
4131 */
4132 mutex_exit(&target->sft_mutex);
4133 goto next_entry;
4134 }
4135
4136 /*
4137 * target is not already offline -- see if it has
4138 * already been marked as ready to go offline
4139 */
4140 if (target->sft_state & SF_TARGET_MARK) {
4141 /*
4142 * target already marked, so take it offline
4143 */
4144 mutex_exit(&target->sft_mutex);
4145 sf_offline_target(sf, target);
4146 goto next_entry;
4147 }
4148
4149 /* clear target busy flag */
4150 target->sft_state &= ~SF_TARGET_BUSY;
4151
4152 /* is target init not yet done ?? */
4153 cflag = !(target->sft_state & SF_TARGET_INIT_DONE);
4154
4155 /* get pointer to target dip */
4156 dip = target->sft_dip;
4157
4158 mutex_exit(&target->sft_mutex);
4159 mutex_exit(&sf->sf_mutex);
4160
4161 if (cflag && (dip == NULL)) {
4162 /*
4163 * target init not yet done &&
4164 * devinfo not yet created
4165 */
4166 sf_create_devinfo(sf, target, lip_cnt);
4167 mutex_enter(&sf->sf_mutex);
4168 goto next_entry;
4169 }
4170
4171 /*
4172 * target init already done || devinfo already created
4173 */
4174 ASSERT(dip != NULL);
4175 if (!sf_create_props(dip, target, lip_cnt)) {
4176 /* a problem creating properties */
4177 mutex_enter(&sf->sf_mutex);
4178 goto next_entry;
4179 }
4180
4181 /* create a new element for the hotplug list */
4182 if ((elem = kmem_zalloc(sizeof (struct sf_hp_elem),
4183 KM_NOSLEEP)) != NULL) {
4184
4185 /* fill in the new element */
4186 elem->dip = dip;
4187 elem->target = target;
4188 elem->what = SF_ONLINE;
4189
4190 /* add the new element into the hotplug list */
4191 mutex_enter(&sf->sf_hp_daemon_mutex);
4192 if (sf->sf_hp_elem_tail != NULL) {
4193 sf->sf_hp_elem_tail->next = elem;
4194 sf->sf_hp_elem_tail = elem;
4195 } else {
4196 /* this is the first element in list */
4197 sf->sf_hp_elem_head =
4198 sf->sf_hp_elem_tail =
4199 elem;
4200 }
4201 cv_signal(&sf->sf_hp_daemon_cv);
4202 mutex_exit(&sf->sf_hp_daemon_mutex);
4203 } else {
4204 /* could not allocate memory for element ?? */
4205 (void) ndi_devi_online_async(dip, 0);
4206 }
4207
4208 mutex_enter(&sf->sf_mutex);
4209
4210 next_entry:
4211 /* ensure no new LIPs have occurred */
4212 if (sf->sf_lip_cnt != lip_cnt) {
4213 return;
4214 }
4215 target = target->sft_next;
4216 }
4217
4218 /* done scanning all targets in this queue */
4219 }
4220
4221 /* done with all hash queues */
4222
4223 sf->sf_state = SF_STATE_ONLINE;
4224 sf->sf_online_timer = 0;
4225 }
4226
4227
4228 /*
4229 * create devinfo node
4230 */
4231 static void
4232 sf_create_devinfo(struct sf *sf, struct sf_target *target, int lip_cnt)
4233 {
4234 dev_info_t *cdip = NULL;
4235 char *nname = NULL;
4236 char **compatible = NULL;
4237 int ncompatible;
4238 struct scsi_inquiry *inq = &target->sft_inq;
4239 char *scsi_binding_set;
4240
4241 /* get the 'scsi-binding-set' property */
4242 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, sf->sf_dip,
4243 DDI_PROP_NOTPROM | DDI_PROP_DONTPASS, "scsi-binding-set",
4244 &scsi_binding_set) != DDI_PROP_SUCCESS)
4245 scsi_binding_set = NULL;
4246
4247 /* determine the node name and compatible */
4248 scsi_hba_nodename_compatible_get(inq, scsi_binding_set,
4249 inq->inq_dtype, NULL, &nname, &compatible, &ncompatible);
4250 if (scsi_binding_set)
4251 ddi_prop_free(scsi_binding_set);
4252
4253 /* if nodename can't be determined then print a message and skip it */
4254 if (nname == NULL) {
4255 #ifndef RAID_LUNS
4256 sf_log(sf, CE_WARN, "%s%d: no driver for device "
4257 "@w%02x%02x%02x%02x%02x%02x%02x%02x,%x\n"
4258 " compatible: %s",
4259 ddi_driver_name(sf->sf_dip), ddi_get_instance(sf->sf_dip),
4260 target->sft_port_wwn[0], target->sft_port_wwn[1],
4261 target->sft_port_wwn[2], target->sft_port_wwn[3],
4262 target->sft_port_wwn[4], target->sft_port_wwn[5],
4263 target->sft_port_wwn[6], target->sft_port_wwn[7],
4264 target->sft_lun.l, *compatible);
4265 #else
4266 sf_log(sf, CE_WARN, "%s%d: no driver for device "
4267 "@w%02x%02x%02x%02x%02x%02x%02x%02x,%x\n"
4268 " compatible: %s",
4269 ddi_driver_name(sf->sf_dip), ddi_get_instance(sf->sf_dip),
4270 target->sft_port_wwn[0], target->sft_port_wwn[1],
4271 target->sft_port_wwn[2], target->sft_port_wwn[3],
4272 target->sft_port_wwn[4], target->sft_port_wwn[5],
4273 target->sft_port_wwn[6], target->sft_port_wwn[7],
4274 target->sft_raid_lun, *compatible);
4275 #endif
4276 goto fail;
4277 }
4278
4279 /* allocate the node */
4280 if (ndi_devi_alloc(sf->sf_dip, nname,
4281 DEVI_SID_NODEID, &cdip) != NDI_SUCCESS) {
4282 goto fail;
4283 }
4284
4285 /* decorate the node with compatible */
4286 if (ndi_prop_update_string_array(DDI_DEV_T_NONE, cdip,
4287 "compatible", compatible, ncompatible) != DDI_PROP_SUCCESS) {
4288 goto fail;
4289 }
4290
4291 /* add addressing properties to the node */
4292 if (sf_create_props(cdip, target, lip_cnt) != 1) {
4293 goto fail;
4294 }
4295
4296 mutex_enter(&target->sft_mutex);
4297 if (target->sft_dip != NULL) {
4298 mutex_exit(&target->sft_mutex);
4299 goto fail;
4300 }
4301 target->sft_dip = cdip;
4302 mutex_exit(&target->sft_mutex);
4303
4304 if (ndi_devi_online_async(cdip, 0) != DDI_SUCCESS) {
4305 goto fail;
4306 }
4307
4308 scsi_hba_nodename_compatible_free(nname, compatible);
4309 return;
4310
4311 fail:
4312 scsi_hba_nodename_compatible_free(nname, compatible);
4313 if (cdip != NULL) {
4314 (void) ndi_prop_remove(DDI_DEV_T_NONE, cdip, NODE_WWN_PROP);
4315 (void) ndi_prop_remove(DDI_DEV_T_NONE, cdip, PORT_WWN_PROP);
4316 (void) ndi_prop_remove(DDI_DEV_T_NONE, cdip, LIP_CNT_PROP);
4317 (void) ndi_prop_remove(DDI_DEV_T_NONE, cdip, TARGET_PROP);
4318 (void) ndi_prop_remove(DDI_DEV_T_NONE, cdip, LUN_PROP);
4319 if (ndi_devi_free(cdip) != NDI_SUCCESS) {
4320 sf_log(sf, CE_WARN, "ndi_devi_free failed\n");
4321 } else {
4322 mutex_enter(&target->sft_mutex);
4323 if (cdip == target->sft_dip) {
4324 target->sft_dip = NULL;
4325 }
4326 mutex_exit(&target->sft_mutex);
4327 }
4328 }
4329 }
4330
4331 /*
4332 * create required properties, returning TRUE iff we succeed, else
4333 * returning FALSE
4334 */
4335 static int
4336 sf_create_props(dev_info_t *cdip, struct sf_target *target, int lip_cnt)
4337 {
4338 int tgt_id = sf_alpa_to_switch[target->sft_al_pa];
4339
4340
4341 if (ndi_prop_update_byte_array(DDI_DEV_T_NONE,
4342 cdip, NODE_WWN_PROP, target->sft_node_wwn, FC_WWN_SIZE) !=
4343 DDI_PROP_SUCCESS) {
4344 return (FALSE);
4345 }
4346
4347 if (ndi_prop_update_byte_array(DDI_DEV_T_NONE,
4348 cdip, PORT_WWN_PROP, target->sft_port_wwn, FC_WWN_SIZE) !=
4349 DDI_PROP_SUCCESS) {
4350 return (FALSE);
4351 }
4352
4353 if (ndi_prop_update_int(DDI_DEV_T_NONE,
4354 cdip, LIP_CNT_PROP, lip_cnt) != DDI_PROP_SUCCESS) {
4355 return (FALSE);
4356 }
4357
4358 if (ndi_prop_update_int(DDI_DEV_T_NONE,
4359 cdip, TARGET_PROP, tgt_id) != DDI_PROP_SUCCESS) {
4360 return (FALSE);
4361 }
4362
4363 #ifndef RAID_LUNS
4364 if (ndi_prop_update_int(DDI_DEV_T_NONE,
4365 cdip, LUN_PROP, target->sft_lun.l) != DDI_PROP_SUCCESS) {
4366 return (0);
4367 }
4368 #else
4369 if (ndi_prop_update_int(DDI_DEV_T_NONE,
4370 cdip, LUN_PROP, target->sft_raid_lun) != DDI_PROP_SUCCESS) {
4371 return (0);
4372 }
4373 #endif
4374
4375 return (TRUE);
4376 }
4377
4378
4379 /*
4380 * called by the transport to offline a target
4381 */
4382 /* ARGSUSED */
4383 static void
4384 sf_offline_target(struct sf *sf, struct sf_target *target)
4385 {
4386 dev_info_t *dip;
4387 struct sf_target *next_target = NULL;
4388 struct sf_hp_elem *elem;
4389
4390 ASSERT(mutex_owned(&sf->sf_mutex));
4391
4392 if (sf_core && (sf_core & SF_CORE_OFFLINE_TARGET)) {
4393 (void) soc_take_core(sf->sf_sochandle, sf->sf_socp);
4394 sf_core = 0;
4395 }
4396
4397 while (target != NULL) {
4398 sf_log(sf, CE_NOTE,
4399 "!target 0x%x al_pa 0x%x lun %" PRIx64 " offlined\n",
4400 sf_alpa_to_switch[target->sft_al_pa],
4401 target->sft_al_pa, SCSA_LUN(target));
4402 mutex_enter(&target->sft_mutex);
4403 target->sft_state &= ~(SF_TARGET_BUSY|SF_TARGET_MARK);
4404 target->sft_state |= SF_TARGET_OFFLINE;
4405 mutex_exit(&target->sft_mutex);
4406 mutex_exit(&sf->sf_mutex);
4407
4408 /* XXXX if this is LUN 0, offline all other LUNs */
4409 if (next_target || target->sft_lun.l == 0)
4410 next_target = target->sft_next_lun;
4411
4412 /* abort all cmds for this target */
4413 sf_abort_all(sf, target, FALSE, sf->sf_lip_cnt, FALSE);
4414
4415 mutex_enter(&sf->sf_mutex);
4416 mutex_enter(&target->sft_mutex);
4417 if (target->sft_state & SF_TARGET_INIT_DONE) {
4418 dip = target->sft_dip;
4419 mutex_exit(&target->sft_mutex);
4420 mutex_exit(&sf->sf_mutex);
4421 (void) ndi_prop_remove(DDI_DEV_T_NONE, dip,
4422 TARGET_PROP);
4423 (void) ndi_event_retrieve_cookie(sf->sf_event_hdl,
4424 dip, FCAL_REMOVE_EVENT, &sf_remove_eid,
4425 NDI_EVENT_NOPASS);
4426 (void) ndi_event_run_callbacks(sf->sf_event_hdl,
4427 target->sft_dip, sf_remove_eid, NULL);
4428
4429 elem = kmem_zalloc(sizeof (struct sf_hp_elem),
4430 KM_NOSLEEP);
4431 if (elem != NULL) {
4432 elem->dip = dip;
4433 elem->target = target;
4434 elem->what = SF_OFFLINE;
4435 mutex_enter(&sf->sf_hp_daemon_mutex);
4436 if (sf->sf_hp_elem_tail != NULL) {
4437 sf->sf_hp_elem_tail->next = elem;
4438 sf->sf_hp_elem_tail = elem;
4439 } else {
4440 sf->sf_hp_elem_head =
4441 sf->sf_hp_elem_tail =
4442 elem;
4443 }
4444 cv_signal(&sf->sf_hp_daemon_cv);
4445 mutex_exit(&sf->sf_hp_daemon_mutex);
4446 } else {
4447 /* don't do NDI_DEVI_REMOVE for now */
4448 if (ndi_devi_offline(dip, 0) != NDI_SUCCESS) {
4449 SF_DEBUG(1, (sf, CE_WARN,
4450 "target %x lun %" PRIx64 ", "
4451 "device offline failed",
4452 sf_alpa_to_switch[target->
4453 sft_al_pa],
4454 SCSA_LUN(target)));
4455 } else {
4456 SF_DEBUG(1, (sf, CE_NOTE,
4457 "target %x, lun %" PRIx64 ", "
4458 "device offline succeeded\n",
4459 sf_alpa_to_switch[target->
4460 sft_al_pa],
4461 SCSA_LUN(target)));
4462 }
4463 }
4464 mutex_enter(&sf->sf_mutex);
4465 } else {
4466 mutex_exit(&target->sft_mutex);
4467 }
4468 target = next_target;
4469 }
4470 }
4471
4472
4473 /*
4474 * routine to get/set a capability
4475 *
4476 * returning:
4477 * 1 (TRUE) boolean capability is true (on get)
4478 * 0 (FALSE) invalid capability, can't set capability (on set),
4479 * or boolean capability is false (on get)
4480 * -1 (UNDEFINED) can't find capability (SCSA) or unsupported capability
4481 * 3 when getting SCSI version number
4482 * AL_PA when getting port initiator ID
4483 */
4484 static int
4485 sf_commoncap(struct scsi_address *ap, char *cap,
4486 int val, int tgtonly, int doset)
4487 {
4488 struct sf *sf = ADDR2SF(ap);
4489 int cidx;
4490 int rval = FALSE;
4491
4492
4493 if (cap == NULL) {
4494 SF_DEBUG(3, (sf, CE_WARN, "sf_commoncap: invalid arg"));
4495 return (rval);
4496 }
4497
4498 /* get index of capability string */
4499 if ((cidx = scsi_hba_lookup_capstr(cap)) == -1) {
4500 /* can't find capability */
4501 return (UNDEFINED);
4502 }
4503
4504 if (doset) {
4505 /*
4506 * Process setcap request.
4507 */
4508
4509 /*
4510 * At present, we can only set binary (0/1) values
4511 */
4512 switch (cidx) {
4513 case SCSI_CAP_ARQ: /* can't set this capability */
4514 break;
4515 default:
4516 SF_DEBUG(3, (sf, CE_WARN,
4517 "sf_setcap: unsupported %d", cidx));
4518 rval = UNDEFINED;
4519 break;
4520 }
4521
4522 SF_DEBUG(4, (sf, CE_NOTE,
4523 "set cap: cap=%s,val=0x%x,tgtonly=0x%x"
4524 ",doset=0x%x,rval=%d\n",
4525 cap, val, tgtonly, doset, rval));
4526
4527 } else {
4528 /*
4529 * Process getcap request.
4530 */
4531 switch (cidx) {
4532 case SCSI_CAP_DMA_MAX:
4533 break; /* don't' have this capability */
4534 case SCSI_CAP_INITIATOR_ID:
4535 rval = sf->sf_al_pa;
4536 break;
4537 case SCSI_CAP_ARQ:
4538 rval = TRUE; /* do have this capability */
4539 break;
4540 case SCSI_CAP_RESET_NOTIFICATION:
4541 case SCSI_CAP_TAGGED_QING:
4542 rval = TRUE; /* do have this capability */
4543 break;
4544 case SCSI_CAP_SCSI_VERSION:
4545 rval = 3;
4546 break;
4547 case SCSI_CAP_INTERCONNECT_TYPE:
4548 rval = INTERCONNECT_FIBRE;
4549 break;
4550 default:
4551 SF_DEBUG(4, (sf, CE_WARN,
4552 "sf_scsi_getcap: unsupported"));
4553 rval = UNDEFINED;
4554 break;
4555 }
4556 SF_DEBUG(4, (sf, CE_NOTE,
4557 "get cap: cap=%s,val=0x%x,tgtonly=0x%x,"
4558 "doset=0x%x,rval=%d\n",
4559 cap, val, tgtonly, doset, rval));
4560 }
4561
4562 return (rval);
4563 }
4564
4565
4566 /*
4567 * called by the transport to get a capability
4568 */
4569 static int
4570 sf_getcap(struct scsi_address *ap, char *cap, int whom)
4571 {
4572 return (sf_commoncap(ap, cap, 0, whom, FALSE));
4573 }
4574
4575
4576 /*
4577 * called by the transport to set a capability
4578 */
4579 static int
4580 sf_setcap(struct scsi_address *ap, char *cap, int value, int whom)
4581 {
4582 return (sf_commoncap(ap, cap, value, whom, TRUE));
4583 }
4584
4585
4586 /*
4587 * called by the transport to abort a target
4588 */
4589 static int
4590 sf_abort(struct scsi_address *ap, struct scsi_pkt *pkt)
4591 {
4592 struct sf *sf = ADDR2SF(ap);
4593 struct sf_target *target = ADDR2TARGET(ap);
4594 struct sf_pkt *cmd, *ncmd, *pcmd;
4595 struct fcal_packet *fpkt;
4596 int rval = 0, t, my_rval = FALSE;
4597 int old_target_state;
4598 int lip_cnt;
4599 int tgt_id;
4600 fc_frame_header_t *hp;
4601 int deferred_destroy;
4602
4603 deferred_destroy = 0;
4604
4605 if (pkt != NULL) {
4606 cmd = PKT2CMD(pkt);
4607 fpkt = cmd->cmd_fp_pkt;
4608 SF_DEBUG(2, (sf, CE_NOTE, "sf_abort packet %p\n",
4609 (void *)fpkt));
4610 pcmd = NULL;
4611 mutex_enter(&sf->sf_cmd_mutex);
4612 ncmd = sf->sf_pkt_head;
4613 while (ncmd != NULL) {
4614 if (ncmd == cmd) {
4615 if (pcmd != NULL) {
4616 pcmd->cmd_next = cmd->cmd_next;
4617 } else {
4618 sf->sf_pkt_head = cmd->cmd_next;
4619 }
4620 cmd->cmd_flags &= ~CFLAG_IN_QUEUE;
4621 cmd->cmd_state = SF_STATE_IDLE;
4622 pkt->pkt_reason = CMD_ABORTED;
4623 pkt->pkt_statistics |= STAT_ABORTED;
4624 my_rval = TRUE;
4625 break;
4626 } else {
4627 pcmd = ncmd;
4628 ncmd = ncmd->cmd_next;
4629 }
4630 }
4631 mutex_exit(&sf->sf_cmd_mutex);
4632 if (ncmd == NULL) {
4633 mutex_enter(&cmd->cmd_abort_mutex);
4634 if (cmd->cmd_state == SF_STATE_ISSUED) {
4635 cmd->cmd_state = SF_STATE_ABORTING;
4636 cmd->cmd_timeout = sf_watchdog_time + 20;
4637 mutex_exit(&cmd->cmd_abort_mutex);
4638 /* call transport to abort command */
4639 if (((rval = soc_abort(sf->sf_sochandle,
4640 sf->sf_socp, sf->sf_sochandle->fcal_portno,
4641 fpkt, 1)) == FCAL_ABORTED) ||
4642 (rval == FCAL_ABORT_FAILED)) {
4643 my_rval = TRUE;
4644 pkt->pkt_reason = CMD_ABORTED;
4645 pkt->pkt_statistics |= STAT_ABORTED;
4646 cmd->cmd_state = SF_STATE_IDLE;
4647 } else if (rval == FCAL_BAD_ABORT) {
4648 cmd->cmd_timeout = sf_watchdog_time
4649 + 20;
4650 my_rval = FALSE;
4651 } else {
4652 SF_DEBUG(1, (sf, CE_NOTE,
4653 "Command Abort failed\n"));
4654 }
4655 } else {
4656 mutex_exit(&cmd->cmd_abort_mutex);
4657 }
4658 }
4659 } else {
4660 SF_DEBUG(2, (sf, CE_NOTE, "sf_abort target\n"));
4661 mutex_enter(&sf->sf_mutex);
4662 lip_cnt = sf->sf_lip_cnt;
4663 mutex_enter(&target->sft_mutex);
4664 if (target->sft_state & (SF_TARGET_BUSY |
4665 SF_TARGET_OFFLINE)) {
4666 mutex_exit(&target->sft_mutex);
4667 return (rval);
4668 }
4669 old_target_state = target->sft_state;
4670 target->sft_state |= SF_TARGET_BUSY;
4671 mutex_exit(&target->sft_mutex);
4672 mutex_exit(&sf->sf_mutex);
4673
4674 if ((pkt = sf_scsi_init_pkt(ap, NULL, NULL, 0,
4675 0, 0, 0, NULL, 0)) != NULL) {
4676
4677 cmd = PKT2CMD(pkt);
4678 cmd->cmd_block->fcp_cntl.cntl_abort_tsk = 1;
4679 cmd->cmd_fp_pkt->fcal_pkt_comp = NULL;
4680 cmd->cmd_pkt->pkt_flags |= FLAG_NOINTR;
4681
4682 /* prepare the packet for transport */
4683 if (sf_prepare_pkt(sf, cmd, target) == TRAN_ACCEPT) {
4684
4685 cmd->cmd_state = SF_STATE_ISSUED;
4686 /*
4687 * call transport to send a pkt polled
4688 *
4689 * if that fails call the transport to abort it
4690 */
4691 if (soc_transport_poll(sf->sf_sochandle,
4692 cmd->cmd_fp_pkt, SF_ABORT_TIMEOUT,
4693 CQ_REQUEST_1) == FCAL_TRANSPORT_SUCCESS) {
4694 (void) ddi_dma_sync(
4695 cmd->cmd_cr_pool->rsp_dma_handle,
4696 (off_t)
4697 ((caddr_t)cmd->cmd_rsp_block -
4698 cmd->cmd_cr_pool->rsp_base),
4699 FCP_MAX_RSP_IU_SIZE,
4700 DDI_DMA_SYNC_FORKERNEL);
4701 if (((struct fcp_rsp_info *)
4702 (&cmd->cmd_rsp_block->
4703 fcp_response_len + 1))->
4704 rsp_code == FCP_NO_FAILURE) {
4705 /* abort cmds for this targ */
4706 sf_abort_all(sf, target, TRUE,
4707 lip_cnt, TRUE);
4708 } else {
4709 hp = &cmd->cmd_fp_pkt->
4710 fcal_socal_request.
4711 sr_fc_frame_hdr;
4712 tgt_id = sf_alpa_to_switch[
4713 (uchar_t)hp->d_id];
4714 sf->sf_stats.tstats[tgt_id].
4715 task_mgmt_failures++;
4716 SF_DEBUG(1, (sf, CE_NOTE,
4717 "Target %d Abort Task "
4718 "Set failed\n", hp->d_id));
4719 }
4720 } else {
4721 mutex_enter(&cmd->cmd_abort_mutex);
4722 if (cmd->cmd_state == SF_STATE_ISSUED) {
4723 cmd->cmd_state = SF_STATE_ABORTING;
4724 cmd->cmd_timeout = sf_watchdog_time
4725 + 20;
4726 mutex_exit(&cmd->cmd_abort_mutex);
4727 if ((t = soc_abort(sf->sf_sochandle,
4728 sf->sf_socp, sf->sf_sochandle->
4729 fcal_portno, cmd->cmd_fp_pkt, 1)) !=
4730 FCAL_ABORTED &&
4731 (t != FCAL_ABORT_FAILED)) {
4732 sf_log(sf, CE_NOTE,
4733 "sf_abort failed, "
4734 "initiating LIP\n");
4735 sf_force_lip(sf);
4736 deferred_destroy = 1;
4737 }
4738 } else {
4739 mutex_exit(&cmd->cmd_abort_mutex);
4740 }
4741 }
4742 }
4743 if (!deferred_destroy) {
4744 cmd->cmd_fp_pkt->fcal_pkt_comp =
4745 sf_cmd_callback;
4746 cmd->cmd_block->fcp_cntl.cntl_abort_tsk = 0;
4747 sf_scsi_destroy_pkt(ap, pkt);
4748 my_rval = TRUE;
4749 }
4750 }
4751 mutex_enter(&sf->sf_mutex);
4752 if (lip_cnt == sf->sf_lip_cnt) {
4753 mutex_enter(&target->sft_mutex);
4754 target->sft_state = old_target_state;
4755 mutex_exit(&target->sft_mutex);
4756 }
4757 mutex_exit(&sf->sf_mutex);
4758 }
4759 return (my_rval);
4760 }
4761
4762
4763 /*
4764 * called by the transport and internally to reset a target
4765 */
4766 static int
4767 sf_reset(struct scsi_address *ap, int level)
4768 {
4769 struct scsi_pkt *pkt;
4770 struct fcal_packet *fpkt;
4771 struct sf *sf = ADDR2SF(ap);
4772 struct sf_target *target = ADDR2TARGET(ap), *ntarget;
4773 struct sf_pkt *cmd;
4774 int rval = FALSE, t;
4775 int lip_cnt;
4776 int tgt_id, ret;
4777 fc_frame_header_t *hp;
4778 int deferred_destroy;
4779
4780 /* We don't support RESET_LUN yet. */
4781 if (level == RESET_TARGET) {
4782 struct sf_reset_list *p;
4783
4784 if ((p = kmem_alloc(sizeof (struct sf_reset_list), KM_NOSLEEP))
4785 == NULL)
4786 return (rval);
4787
4788 SF_DEBUG(2, (sf, CE_NOTE, "sf_reset target\n"));
4789 mutex_enter(&sf->sf_mutex);
4790 /* All target resets go to LUN 0 */
4791 if (target->sft_lun.l) {
4792 target = sf_lookup_target(sf, target->sft_port_wwn, 0);
4793 }
4794 mutex_enter(&target->sft_mutex);
4795 if (target->sft_state & (SF_TARGET_BUSY |
4796 SF_TARGET_OFFLINE)) {
4797 mutex_exit(&target->sft_mutex);
4798 mutex_exit(&sf->sf_mutex);
4799 kmem_free(p, sizeof (struct sf_reset_list));
4800 return (rval);
4801 }
4802 lip_cnt = sf->sf_lip_cnt;
4803 target->sft_state |= SF_TARGET_BUSY;
4804 for (ntarget = target->sft_next_lun;
4805 ntarget;
4806 ntarget = ntarget->sft_next_lun) {
4807 mutex_enter(&ntarget->sft_mutex);
4808 /*
4809 * XXXX If we supported RESET_LUN we should check here
4810 * to see if any LUN were being reset and somehow fail
4811 * that operation.
4812 */
4813 ntarget->sft_state |= SF_TARGET_BUSY;
4814 mutex_exit(&ntarget->sft_mutex);
4815 }
4816 mutex_exit(&target->sft_mutex);
4817 mutex_exit(&sf->sf_mutex);
4818
4819 deferred_destroy = 0;
4820 if ((pkt = sf_scsi_init_pkt(ap, NULL, NULL, 0,
4821 0, 0, 0, NULL, 0)) != NULL) {
4822 cmd = PKT2CMD(pkt);
4823 cmd->cmd_block->fcp_cntl.cntl_reset = 1;
4824 cmd->cmd_fp_pkt->fcal_pkt_comp = NULL;
4825 cmd->cmd_pkt->pkt_flags |= FLAG_NOINTR;
4826
4827 /* prepare the packet for transport */
4828 if (sf_prepare_pkt(sf, cmd, target) == TRAN_ACCEPT) {
4829 /* call transport to send a pkt polled */
4830 cmd->cmd_state = SF_STATE_ISSUED;
4831 if ((ret = soc_transport_poll(sf->sf_sochandle,
4832 cmd->cmd_fp_pkt, SF_ABORT_TIMEOUT,
4833 CQ_REQUEST_1)) == FCAL_TRANSPORT_SUCCESS) {
4834 (void) ddi_dma_sync(cmd->cmd_cr_pool->
4835 rsp_dma_handle, (caddr_t)cmd->
4836 cmd_rsp_block - cmd->cmd_cr_pool->
4837 rsp_base, FCP_MAX_RSP_IU_SIZE,
4838 DDI_DMA_SYNC_FORKERNEL);
4839 fpkt = cmd->cmd_fp_pkt;
4840 if ((fpkt->fcal_pkt_status ==
4841 FCAL_STATUS_OK) &&
4842 (((struct fcp_rsp_info *)
4843 (&cmd->cmd_rsp_block->
4844 fcp_response_len + 1))->
4845 rsp_code == FCP_NO_FAILURE)) {
4846 sf_log(sf, CE_NOTE,
4847 "!sf%d: Target 0x%x Reset "
4848 "successful\n",
4849 ddi_get_instance(\
4850 sf->sf_dip),
4851 sf_alpa_to_switch[
4852 target->sft_al_pa]);
4853 rval = TRUE;
4854 } else {
4855 hp = &cmd->cmd_fp_pkt->
4856 fcal_socal_request.
4857 sr_fc_frame_hdr;
4858 tgt_id = sf_alpa_to_switch[
4859 (uchar_t)hp->d_id];
4860 sf->sf_stats.tstats[tgt_id].
4861 task_mgmt_failures++;
4862 sf_log(sf, CE_NOTE,
4863 "!sf%d: Target 0x%x "
4864 "Reset failed."
4865 "Status code 0x%x "
4866 "Resp code 0x%x\n",
4867 ddi_get_instance(\
4868 sf->sf_dip),
4869 tgt_id,
4870 fpkt->fcal_pkt_status,
4871 ((struct fcp_rsp_info *)
4872 (&cmd->cmd_rsp_block->
4873 fcp_response_len + 1))->
4874 rsp_code);
4875 }
4876 } else {
4877 sf_log(sf, CE_NOTE, "!sf%d: Target "
4878 "0x%x Reset Failed. Ret=%x\n",
4879 ddi_get_instance(sf->sf_dip),
4880 sf_alpa_to_switch[
4881 target->sft_al_pa], ret);
4882 mutex_enter(&cmd->cmd_abort_mutex);
4883 if (cmd->cmd_state == SF_STATE_ISSUED) {
4884 /* call the transport to abort a cmd */
4885 cmd->cmd_timeout = sf_watchdog_time
4886 + 20;
4887 cmd->cmd_state = SF_STATE_ABORTING;
4888 mutex_exit(&cmd->cmd_abort_mutex);
4889 if (((t = soc_abort(sf->sf_sochandle,
4890 sf->sf_socp,
4891 sf->sf_sochandle->fcal_portno,
4892 cmd->cmd_fp_pkt, 1)) !=
4893 FCAL_ABORTED) &&
4894 (t != FCAL_ABORT_FAILED)) {
4895 sf_log(sf, CE_NOTE,
4896 "!sf%d: Target 0x%x Reset "
4897 "failed. Abort Failed, "
4898 "forcing LIP\n",
4899 ddi_get_instance(
4900 sf->sf_dip),
4901 sf_alpa_to_switch[
4902 target->sft_al_pa]);
4903 sf_force_lip(sf);
4904 rval = TRUE;
4905 deferred_destroy = 1;
4906 }
4907 } else {
4908 mutex_exit
4909 (&cmd->cmd_abort_mutex);
4910 }
4911 }
4912 }
4913 /*
4914 * Defer releasing the packet if we abort returned with
4915 * a BAD_ABORT or timed out, because there is a
4916 * possibility that the ucode might return it.
4917 * We wait for at least 20s and let it be released
4918 * by the sf_watch thread
4919 */
4920 if (!deferred_destroy) {
4921 cmd->cmd_block->fcp_cntl.cntl_reset = 0;
4922 cmd->cmd_fp_pkt->fcal_pkt_comp =
4923 sf_cmd_callback;
4924 cmd->cmd_state = SF_STATE_IDLE;
4925 /* for cache */
4926 sf_scsi_destroy_pkt(ap, pkt);
4927 }
4928 } else {
4929 cmn_err(CE_WARN, "!sf%d: Target 0x%x Reset Failed. "
4930 "Resource allocation error.\n",
4931 ddi_get_instance(sf->sf_dip),
4932 sf_alpa_to_switch[target->sft_al_pa]);
4933 }
4934 mutex_enter(&sf->sf_mutex);
4935 if ((rval == TRUE) && (lip_cnt == sf->sf_lip_cnt)) {
4936 p->target = target;
4937 p->lip_cnt = lip_cnt;
4938 p->timeout = ddi_get_lbolt() +
4939 drv_usectohz(SF_TARGET_RESET_DELAY);
4940 p->next = sf->sf_reset_list;
4941 sf->sf_reset_list = p;
4942 mutex_exit(&sf->sf_mutex);
4943 mutex_enter(&sf_global_mutex);
4944 if (sf_reset_timeout_id == 0) {
4945 sf_reset_timeout_id = timeout(
4946 sf_check_reset_delay, NULL,
4947 drv_usectohz(SF_TARGET_RESET_DELAY));
4948 }
4949 mutex_exit(&sf_global_mutex);
4950 } else {
4951 if (lip_cnt == sf->sf_lip_cnt) {
4952 mutex_enter(&target->sft_mutex);
4953 target->sft_state &= ~SF_TARGET_BUSY;
4954 for (ntarget = target->sft_next_lun;
4955 ntarget;
4956 ntarget = ntarget->sft_next_lun) {
4957 mutex_enter(&ntarget->sft_mutex);
4958 ntarget->sft_state &= ~SF_TARGET_BUSY;
4959 mutex_exit(&ntarget->sft_mutex);
4960 }
4961 mutex_exit(&target->sft_mutex);
4962 }
4963 mutex_exit(&sf->sf_mutex);
4964 kmem_free(p, sizeof (struct sf_reset_list));
4965 }
4966 } else {
4967 mutex_enter(&sf->sf_mutex);
4968 if ((sf->sf_state == SF_STATE_OFFLINE) &&
4969 (sf_watchdog_time < sf->sf_timer)) {
4970 /*
4971 * We are currently in a lip, so let this one
4972 * finish before forcing another one.
4973 */
4974 mutex_exit(&sf->sf_mutex);
4975 return (TRUE);
4976 }
4977 mutex_exit(&sf->sf_mutex);
4978 sf_log(sf, CE_NOTE, "!sf:Target driver initiated lip\n");
4979 sf_force_lip(sf);
4980 rval = TRUE;
4981 }
4982 return (rval);
4983 }
4984
4985
4986 /*
4987 * abort all commands for a target
4988 *
4989 * if try_abort is set then send an abort
4990 * if abort is set then this is abort, else this is a reset
4991 */
4992 static void
4993 sf_abort_all(struct sf *sf, struct sf_target *target, int abort, int
4994 lip_cnt, int try_abort)
4995 {
4996 struct sf_target *ntarget;
4997 struct sf_pkt *cmd, *head = NULL, *tail = NULL, *pcmd = NULL, *tcmd;
4998 struct fcal_packet *fpkt;
4999 struct scsi_pkt *pkt;
5000 int rval = FCAL_ABORTED;
5001
5002 /*
5003 * First pull all commands for all LUNs on this target out of the
5004 * overflow list. We can tell it's the same target by comparing
5005 * the node WWN.
5006 */
5007 mutex_enter(&sf->sf_mutex);
5008 if (lip_cnt == sf->sf_lip_cnt) {
5009 mutex_enter(&sf->sf_cmd_mutex);
5010 cmd = sf->sf_pkt_head;
5011 while (cmd != NULL) {
5012 ntarget = ADDR2TARGET(&cmd->cmd_pkt->
5013 pkt_address);
5014 if (ntarget == target) {
5015 if (pcmd != NULL)
5016 pcmd->cmd_next = cmd->cmd_next;
5017 else
5018 sf->sf_pkt_head = cmd->cmd_next;
5019 if (sf->sf_pkt_tail == cmd) {
5020 sf->sf_pkt_tail = pcmd;
5021 if (pcmd != NULL)
5022 pcmd->cmd_next = NULL;
5023 }
5024 tcmd = cmd->cmd_next;
5025 if (head == NULL) {
5026 head = cmd;
5027 tail = cmd;
5028 } else {
5029 tail->cmd_next = cmd;
5030 tail = cmd;
5031 }
5032 cmd->cmd_next = NULL;
5033 cmd = tcmd;
5034 } else {
5035 pcmd = cmd;
5036 cmd = cmd->cmd_next;
5037 }
5038 }
5039 mutex_exit(&sf->sf_cmd_mutex);
5040 }
5041 mutex_exit(&sf->sf_mutex);
5042
5043 /*
5044 * Now complete all the commands on our list. In the process,
5045 * the completion routine may take the commands off the target
5046 * lists.
5047 */
5048 cmd = head;
5049 while (cmd != NULL) {
5050 pkt = cmd->cmd_pkt;
5051 if (abort) {
5052 pkt->pkt_reason = CMD_ABORTED;
5053 pkt->pkt_statistics |= STAT_ABORTED;
5054 } else {
5055 pkt->pkt_reason = CMD_RESET;
5056 pkt->pkt_statistics |= STAT_DEV_RESET;
5057 }
5058 cmd->cmd_flags &= ~CFLAG_IN_QUEUE;
5059 cmd->cmd_state = SF_STATE_IDLE;
5060 cmd = cmd->cmd_next;
5061 /*
5062 * call the packet completion routine only for
5063 * non-polled commands. Ignore the polled commands as
5064 * they timeout and will be handled differently
5065 */
5066 if ((pkt->pkt_comp) && !(pkt->pkt_flags & FLAG_NOINTR))
5067 (*pkt->pkt_comp)(pkt);
5068
5069 }
5070
5071 /*
5072 * Finally get all outstanding commands for each LUN, and abort them if
5073 * they've been issued, and call the completion routine.
5074 * For the case where sf_offline_target is called from sf_watch
5075 * due to a Offline Timeout, it is quite possible that the soc+
5076 * ucode is hosed and therefore cannot return the commands.
5077 * Clear up all the issued commands as well.
5078 * Try_abort will be false only if sf_abort_all is coming from
5079 * sf_target_offline.
5080 */
5081
5082 if (try_abort || sf->sf_state == SF_STATE_OFFLINE) {
5083 mutex_enter(&target->sft_pkt_mutex);
5084 cmd = tcmd = target->sft_pkt_head;
5085 while (cmd != (struct sf_pkt *)&target->sft_pkt_head) {
5086 fpkt = cmd->cmd_fp_pkt;
5087 pkt = cmd->cmd_pkt;
5088 mutex_enter(&cmd->cmd_abort_mutex);
5089 if ((cmd->cmd_state == SF_STATE_ISSUED) &&
5090 (fpkt->fcal_cmd_state &
5091 FCAL_CMD_IN_TRANSPORT) &&
5092 ((fpkt->fcal_cmd_state & FCAL_CMD_COMPLETE) ==
5093 0) && !(pkt->pkt_flags & FLAG_NOINTR)) {
5094 cmd->cmd_state = SF_STATE_ABORTING;
5095 cmd->cmd_timeout = sf_watchdog_time +
5096 cmd->cmd_pkt->pkt_time + 20;
5097 mutex_exit(&cmd->cmd_abort_mutex);
5098 mutex_exit(&target->sft_pkt_mutex);
5099 if (try_abort) {
5100 /* call the transport to abort a pkt */
5101 rval = soc_abort(sf->sf_sochandle,
5102 sf->sf_socp,
5103 sf->sf_sochandle->fcal_portno,
5104 fpkt, 1);
5105 }
5106 if ((rval == FCAL_ABORTED) ||
5107 (rval == FCAL_ABORT_FAILED)) {
5108 if (abort) {
5109 pkt->pkt_reason = CMD_ABORTED;
5110 pkt->pkt_statistics |=
5111 STAT_ABORTED;
5112 } else {
5113 pkt->pkt_reason = CMD_RESET;
5114 pkt->pkt_statistics |=
5115 STAT_DEV_RESET;
5116 }
5117 cmd->cmd_state = SF_STATE_IDLE;
5118 if (pkt->pkt_comp)
5119 (*pkt->pkt_comp)(pkt);
5120 }
5121 mutex_enter(&sf->sf_mutex);
5122 if (lip_cnt != sf->sf_lip_cnt) {
5123 mutex_exit(&sf->sf_mutex);
5124 return;
5125 }
5126 mutex_exit(&sf->sf_mutex);
5127 mutex_enter(&target->sft_pkt_mutex);
5128 cmd = target->sft_pkt_head;
5129 } else {
5130 mutex_exit(&cmd->cmd_abort_mutex);
5131 cmd = cmd->cmd_forw;
5132 }
5133 }
5134 mutex_exit(&target->sft_pkt_mutex);
5135 }
5136 }
5137
5138
5139 /*
5140 * called by the transport to start a packet
5141 */
5142 static int
5143 sf_start(struct scsi_address *ap, struct scsi_pkt *pkt)
5144 {
5145 struct sf *sf = ADDR2SF(ap);
5146 struct sf_target *target = ADDR2TARGET(ap);
5147 struct sf_pkt *cmd = PKT2CMD(pkt);
5148 int rval;
5149
5150
5151 SF_DEBUG(6, (sf, CE_NOTE, "sf_start\n"));
5152
5153 if (cmd->cmd_state == SF_STATE_ISSUED) {
5154 cmn_err(CE_PANIC, "sf: issuing packet twice 0x%p\n",
5155 (void *)cmd);
5156 }
5157
5158 /* prepare the packet for transport */
5159 if ((rval = sf_prepare_pkt(sf, cmd, target)) != TRAN_ACCEPT) {
5160 return (rval);
5161 }
5162
5163 if (target->sft_state & (SF_TARGET_BUSY|SF_TARGET_OFFLINE)) {
5164 if (target->sft_state & SF_TARGET_OFFLINE) {
5165 return (TRAN_FATAL_ERROR);
5166 }
5167 if (pkt->pkt_flags & FLAG_NOINTR) {
5168 return (TRAN_BUSY);
5169 }
5170 mutex_enter(&sf->sf_cmd_mutex);
5171 sf->sf_use_lock = TRUE;
5172 goto enque;
5173 }
5174
5175
5176 /* if no interrupts then do polled I/O */
5177 if (pkt->pkt_flags & FLAG_NOINTR) {
5178 return (sf_dopoll(sf, cmd));
5179 }
5180
5181 /* regular interrupt-driven I/O */
5182
5183 if (!sf->sf_use_lock) {
5184
5185 /* locking no needed */
5186
5187 cmd->cmd_timeout = cmd->cmd_pkt->pkt_time ?
5188 sf_watchdog_time + cmd->cmd_pkt->pkt_time : 0;
5189 cmd->cmd_state = SF_STATE_ISSUED;
5190
5191 /* call the transport to send a pkt */
5192 if (soc_transport(sf->sf_sochandle, cmd->cmd_fp_pkt,
5193 FCAL_NOSLEEP, CQ_REQUEST_1) != FCAL_TRANSPORT_SUCCESS) {
5194 cmd->cmd_state = SF_STATE_IDLE;
5195 return (TRAN_BADPKT);
5196 }
5197 return (TRAN_ACCEPT);
5198 }
5199
5200 /* regular I/O using locking */
5201
5202 mutex_enter(&sf->sf_cmd_mutex);
5203 if ((sf->sf_ncmds >= sf->sf_throttle) ||
5204 (sf->sf_pkt_head != NULL)) {
5205 enque:
5206 /*
5207 * either we're throttling back or there are already commands
5208 * on the queue, so enqueue this one for later
5209 */
5210 cmd->cmd_flags |= CFLAG_IN_QUEUE;
5211 if (sf->sf_pkt_head != NULL) {
5212 /* add to the queue */
5213 sf->sf_pkt_tail->cmd_next = cmd;
5214 cmd->cmd_next = NULL;
5215 sf->sf_pkt_tail = cmd;
5216 } else {
5217 /* this is the first entry in the queue */
5218 sf->sf_pkt_head = sf->sf_pkt_tail = cmd;
5219 cmd->cmd_next = NULL;
5220 }
5221 mutex_exit(&sf->sf_cmd_mutex);
5222 return (TRAN_ACCEPT);
5223 }
5224
5225 /*
5226 * start this packet now
5227 */
5228
5229 /* still have cmd mutex */
5230 return (sf_start_internal(sf, cmd));
5231 }
5232
5233
5234 /*
5235 * internal routine to start a packet from the queue now
5236 *
5237 * enter with cmd mutex held and leave with it released
5238 */
5239 static int
5240 sf_start_internal(struct sf *sf, struct sf_pkt *cmd)
5241 {
5242 /* we have the cmd mutex */
5243 sf->sf_ncmds++;
5244 mutex_exit(&sf->sf_cmd_mutex);
5245
5246 ASSERT(cmd->cmd_state != SF_STATE_ISSUED);
5247 SF_DEBUG(6, (sf, CE_NOTE, "sf_start_internal\n"));
5248
5249 cmd->cmd_timeout = cmd->cmd_pkt->pkt_time ? sf_watchdog_time +
5250 cmd->cmd_pkt->pkt_time : 0;
5251 cmd->cmd_state = SF_STATE_ISSUED;
5252
5253 /* call transport to send the pkt */
5254 if (soc_transport(sf->sf_sochandle, cmd->cmd_fp_pkt, FCAL_NOSLEEP,
5255 CQ_REQUEST_1) != FCAL_TRANSPORT_SUCCESS) {
5256 cmd->cmd_state = SF_STATE_IDLE;
5257 mutex_enter(&sf->sf_cmd_mutex);
5258 sf->sf_ncmds--;
5259 mutex_exit(&sf->sf_cmd_mutex);
5260 return (TRAN_BADPKT);
5261 }
5262 return (TRAN_ACCEPT);
5263 }
5264
5265
5266 /*
5267 * prepare a packet for transport
5268 */
5269 static int
5270 sf_prepare_pkt(struct sf *sf, struct sf_pkt *cmd, struct sf_target *target)
5271 {
5272 struct fcp_cmd *fcmd = cmd->cmd_block;
5273
5274 /* XXXX Need to set the LUN ? */
5275 bcopy((caddr_t)&target->sft_lun.b,
5276 (caddr_t)&fcmd->fcp_ent_addr,
5277 FCP_LUN_SIZE);
5278 cmd->cmd_pkt->pkt_reason = CMD_CMPLT;
5279 cmd->cmd_pkt->pkt_state = 0;
5280 cmd->cmd_pkt->pkt_statistics = 0;
5281
5282
5283 if ((cmd->cmd_pkt->pkt_comp == NULL) &&
5284 ((cmd->cmd_pkt->pkt_flags & FLAG_NOINTR) == 0)) {
5285 return (TRAN_BADPKT);
5286 }
5287
5288 /* invalidate imp field(s) of rsp block */
5289 cmd->cmd_rsp_block->fcp_u.i_fcp_status = SF_BAD_DMA_MAGIC;
5290
5291 /* set up amt of I/O to do */
5292 if (cmd->cmd_flags & CFLAG_DMAVALID) {
5293 cmd->cmd_pkt->pkt_resid = cmd->cmd_dmacount;
5294 if (cmd->cmd_flags & CFLAG_CMDIOPB) {
5295 (void) ddi_dma_sync(cmd->cmd_dmahandle, 0, 0,
5296 DDI_DMA_SYNC_FORDEV);
5297 }
5298 } else {
5299 cmd->cmd_pkt->pkt_resid = 0;
5300 }
5301
5302 /* set up the Tagged Queuing type */
5303 if (cmd->cmd_pkt->pkt_flags & FLAG_HTAG) {
5304 fcmd->fcp_cntl.cntl_qtype = FCP_QTYPE_HEAD_OF_Q;
5305 } else if (cmd->cmd_pkt->pkt_flags & FLAG_OTAG) {
5306 fcmd->fcp_cntl.cntl_qtype = FCP_QTYPE_ORDERED;
5307 }
5308
5309 /*
5310 * Sync the cmd segment
5311 */
5312 (void) ddi_dma_sync(cmd->cmd_cr_pool->cmd_dma_handle,
5313 (caddr_t)fcmd - cmd->cmd_cr_pool->cmd_base,
5314 sizeof (struct fcp_cmd), DDI_DMA_SYNC_FORDEV);
5315
5316 sf_fill_ids(sf, cmd, target);
5317 return (TRAN_ACCEPT);
5318 }
5319
5320
5321 /*
5322 * fill in packet hdr source and destination IDs and hdr byte count
5323 */
5324 static void
5325 sf_fill_ids(struct sf *sf, struct sf_pkt *cmd, struct sf_target *target)
5326 {
5327 struct fcal_packet *fpkt = cmd->cmd_fp_pkt;
5328 fc_frame_header_t *hp;
5329
5330
5331 hp = &fpkt->fcal_socal_request.sr_fc_frame_hdr;
5332 hp->d_id = target->sft_al_pa;
5333 hp->s_id = sf->sf_al_pa;
5334 fpkt->fcal_socal_request.sr_soc_hdr.sh_byte_cnt =
5335 cmd->cmd_dmacookie.dmac_size;
5336 }
5337
5338
5339 /*
5340 * do polled I/O using transport
5341 */
5342 static int
5343 sf_dopoll(struct sf *sf, struct sf_pkt *cmd)
5344 {
5345 int timeout;
5346 int rval;
5347
5348
5349 mutex_enter(&sf->sf_cmd_mutex);
5350 sf->sf_ncmds++;
5351 mutex_exit(&sf->sf_cmd_mutex);
5352
5353 timeout = cmd->cmd_pkt->pkt_time ? cmd->cmd_pkt->pkt_time
5354 : SF_POLL_TIMEOUT;
5355 cmd->cmd_timeout = 0;
5356 cmd->cmd_fp_pkt->fcal_pkt_comp = NULL;
5357 cmd->cmd_state = SF_STATE_ISSUED;
5358
5359 /* call transport to send a pkt polled */
5360 rval = soc_transport_poll(sf->sf_sochandle, cmd->cmd_fp_pkt,
5361 timeout*1000000, CQ_REQUEST_1);
5362 mutex_enter(&cmd->cmd_abort_mutex);
5363 cmd->cmd_fp_pkt->fcal_pkt_comp = sf_cmd_callback;
5364 if (rval != FCAL_TRANSPORT_SUCCESS) {
5365 if (rval == FCAL_TRANSPORT_TIMEOUT) {
5366 cmd->cmd_state = SF_STATE_ABORTING;
5367 mutex_exit(&cmd->cmd_abort_mutex);
5368 (void) sf_target_timeout(sf, cmd);
5369 } else {
5370 mutex_exit(&cmd->cmd_abort_mutex);
5371 }
5372 cmd->cmd_state = SF_STATE_IDLE;
5373 cmd->cmd_fp_pkt->fcal_pkt_comp = sf_cmd_callback;
5374 mutex_enter(&sf->sf_cmd_mutex);
5375 sf->sf_ncmds--;
5376 mutex_exit(&sf->sf_cmd_mutex);
5377 return (TRAN_BADPKT);
5378 }
5379 mutex_exit(&cmd->cmd_abort_mutex);
5380 cmd->cmd_fp_pkt->fcal_pkt_comp = sf_cmd_callback;
5381 sf_cmd_callback(cmd->cmd_fp_pkt);
5382 return (TRAN_ACCEPT);
5383 }
5384
5385
5386 /* a shortcut for defining debug messages below */
5387 #ifdef DEBUG
5388 #define SF_DMSG1(s) msg1 = s
5389 #else
5390 #define SF_DMSG1(s) /* do nothing */
5391 #endif
5392
5393
5394 /*
5395 * the pkt_comp callback for command packets
5396 */
5397 static void
5398 sf_cmd_callback(struct fcal_packet *fpkt)
5399 {
5400 struct sf_pkt *cmd = (struct sf_pkt *)fpkt->fcal_pkt_private;
5401 struct scsi_pkt *pkt = cmd->cmd_pkt;
5402 struct sf *sf = ADDR2SF(&pkt->pkt_address);
5403 struct sf_target *target = ADDR2TARGET(&pkt->pkt_address);
5404 struct fcp_rsp *rsp;
5405 char *msg1 = NULL;
5406 char *msg2 = NULL;
5407 short ncmds;
5408 int tgt_id;
5409 int good_scsi_status = TRUE;
5410
5411
5412
5413 if (cmd->cmd_state == SF_STATE_IDLE) {
5414 cmn_err(CE_PANIC, "sf: completing idle packet 0x%p\n",
5415 (void *)cmd);
5416 }
5417
5418 mutex_enter(&cmd->cmd_abort_mutex);
5419 if (cmd->cmd_state == SF_STATE_ABORTING) {
5420 /* cmd already being aborted -- nothing to do */
5421 mutex_exit(&cmd->cmd_abort_mutex);
5422 return;
5423 }
5424
5425 cmd->cmd_state = SF_STATE_IDLE;
5426 mutex_exit(&cmd->cmd_abort_mutex);
5427
5428 if (fpkt->fcal_pkt_status == FCAL_STATUS_OK) {
5429
5430 (void) ddi_dma_sync(cmd->cmd_cr_pool->rsp_dma_handle,
5431 (caddr_t)cmd->cmd_rsp_block - cmd->cmd_cr_pool->rsp_base,
5432 FCP_MAX_RSP_IU_SIZE, DDI_DMA_SYNC_FORKERNEL);
5433
5434 rsp = (struct fcp_rsp *)cmd->cmd_rsp_block;
5435
5436 if (rsp->fcp_u.i_fcp_status == SF_BAD_DMA_MAGIC) {
5437
5438 if (sf_core && (sf_core & SF_CORE_BAD_DMA)) {
5439 sf_token = (int *)(uintptr_t)
5440 fpkt->fcal_socal_request.\
5441 sr_soc_hdr.sh_request_token;
5442 (void) soc_take_core(sf->sf_sochandle,
5443 sf->sf_socp);
5444 }
5445
5446 pkt->pkt_reason = CMD_INCOMPLETE;
5447 pkt->pkt_state = STATE_GOT_BUS;
5448 pkt->pkt_statistics |= STAT_ABORTED;
5449
5450 } else {
5451
5452 pkt->pkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
5453 STATE_SENT_CMD | STATE_GOT_STATUS;
5454 pkt->pkt_resid = 0;
5455 if (cmd->cmd_flags & CFLAG_DMAVALID) {
5456 pkt->pkt_state |= STATE_XFERRED_DATA;
5457 }
5458
5459 if ((pkt->pkt_scbp != NULL) &&
5460 ((*(pkt->pkt_scbp) =
5461 rsp->fcp_u.fcp_status.scsi_status)
5462 != STATUS_GOOD)) {
5463 good_scsi_status = FALSE;
5464 /*
5465 * The next two checks make sure that if there
5466 * is no sense data or a valid response and
5467 * the command came back with check condition,
5468 * the command should be retried
5469 */
5470 if (!rsp->fcp_u.fcp_status.rsp_len_set &&
5471 !rsp->fcp_u.fcp_status.sense_len_set) {
5472 pkt->pkt_state &= ~STATE_XFERRED_DATA;
5473 pkt->pkt_resid = cmd->cmd_dmacount;
5474 }
5475 }
5476
5477 if ((cmd->cmd_flags & CFLAG_CMDIOPB) &&
5478 (pkt->pkt_state & STATE_XFERRED_DATA)) {
5479 (void) ddi_dma_sync(cmd->cmd_dmahandle, 0,
5480 (uint_t)0, DDI_DMA_SYNC_FORCPU);
5481 }
5482 /*
5483 * Update the transfer resid, if appropriate
5484 */
5485 if (rsp->fcp_u.fcp_status.resid_over ||
5486 rsp->fcp_u.fcp_status.resid_under)
5487 pkt->pkt_resid = rsp->fcp_resid;
5488
5489 /*
5490 * Check to see if the SCSI command failed.
5491 *
5492 */
5493
5494 /*
5495 * First see if we got a FCP protocol error.
5496 */
5497 if (rsp->fcp_u.fcp_status.rsp_len_set) {
5498 struct fcp_rsp_info *bep;
5499
5500 bep = (struct fcp_rsp_info *)
5501 (&rsp->fcp_response_len + 1);
5502 if (bep->rsp_code != FCP_NO_FAILURE) {
5503 pkt->pkt_reason = CMD_TRAN_ERR;
5504 tgt_id = pkt->pkt_address.a_target;
5505 switch (bep->rsp_code) {
5506 case FCP_CMND_INVALID:
5507 SF_DMSG1("FCP_RSP FCP_CMND "
5508 "fields invalid");
5509 break;
5510 case FCP_TASK_MGMT_NOT_SUPPTD:
5511 SF_DMSG1("FCP_RSP Task"
5512 "Management Function"
5513 "Not Supported");
5514 break;
5515 case FCP_TASK_MGMT_FAILED:
5516 SF_DMSG1("FCP_RSP Task "
5517 "Management Function"
5518 "Failed");
5519 sf->sf_stats.tstats[tgt_id].
5520 task_mgmt_failures++;
5521 break;
5522 case FCP_DATA_RO_MISMATCH:
5523 SF_DMSG1("FCP_RSP FCP_DATA RO "
5524 "mismatch with "
5525 "FCP_XFER_RDY DATA_RO");
5526 sf->sf_stats.tstats[tgt_id].
5527 data_ro_mismatches++;
5528 break;
5529 case FCP_DL_LEN_MISMATCH:
5530 SF_DMSG1("FCP_RSP FCP_DATA "
5531 "length "
5532 "different than BURST_LEN");
5533 sf->sf_stats.tstats[tgt_id].
5534 dl_len_mismatches++;
5535 break;
5536 default:
5537 SF_DMSG1("FCP_RSP invalid "
5538 "RSP_CODE");
5539 break;
5540 }
5541 }
5542 }
5543
5544 /*
5545 * See if we got a SCSI error with sense data
5546 */
5547 if (rsp->fcp_u.fcp_status.sense_len_set) {
5548 uchar_t rqlen = min(rsp->fcp_sense_len,
5549 sizeof (struct scsi_extended_sense));
5550 caddr_t sense = (caddr_t)rsp +
5551 sizeof (struct fcp_rsp) +
5552 rsp->fcp_response_len;
5553 struct scsi_arq_status *arq;
5554 struct scsi_extended_sense *sensep =
5555 (struct scsi_extended_sense *)sense;
5556
5557 if (rsp->fcp_u.fcp_status.scsi_status !=
5558 STATUS_GOOD) {
5559 if (rsp->fcp_u.fcp_status.scsi_status
5560 == STATUS_CHECK) {
5561 if (sensep->es_key ==
5562 KEY_RECOVERABLE_ERROR)
5563 good_scsi_status = 1;
5564 if (sensep->es_key ==
5565 KEY_UNIT_ATTENTION &&
5566 sensep->es_add_code == 0x3f &&
5567 sensep->es_qual_code == 0x0e) {
5568 /* REPORT_LUNS_HAS_CHANGED */
5569 sf_log(sf, CE_NOTE,
5570 "!REPORT_LUNS_HAS_CHANGED\n");
5571 sf_force_lip(sf);
5572 }
5573 }
5574 }
5575
5576 if ((pkt->pkt_scbp != NULL) &&
5577 (cmd->cmd_scblen >=
5578 sizeof (struct scsi_arq_status))) {
5579
5580 pkt->pkt_state |= STATE_ARQ_DONE;
5581
5582 arq = (struct scsi_arq_status *)pkt->pkt_scbp;
5583 /*
5584 * copy out sense information
5585 */
5586 bcopy(sense, (caddr_t)&arq->sts_sensedata,
5587 rqlen);
5588 arq->sts_rqpkt_resid =
5589 sizeof (struct scsi_extended_sense) -
5590 rqlen;
5591 *((uchar_t *)&arq->sts_rqpkt_status) =
5592 STATUS_GOOD;
5593 arq->sts_rqpkt_reason = 0;
5594 arq->sts_rqpkt_statistics = 0;
5595 arq->sts_rqpkt_state = STATE_GOT_BUS |
5596 STATE_GOT_TARGET | STATE_SENT_CMD |
5597 STATE_GOT_STATUS | STATE_ARQ_DONE |
5598 STATE_XFERRED_DATA;
5599 }
5600 target->sft_alive = TRUE;
5601 }
5602
5603 /*
5604 * The firmware returns the number of bytes actually
5605 * xfered into/out of host. Compare this with what
5606 * we asked and if it is different, we lost frames ?
5607 */
5608 if ((pkt->pkt_reason == 0) && (pkt->pkt_resid == 0) &&
5609 (good_scsi_status) &&
5610 (pkt->pkt_state & STATE_XFERRED_DATA) &&
5611 (!(cmd->cmd_flags & CFLAG_CMDIOPB)) &&
5612 (target->sft_device_type != DTYPE_ESI)) {
5613 int byte_cnt =
5614 fpkt->fcal_socal_request.
5615 sr_soc_hdr.sh_byte_cnt;
5616 if (cmd->cmd_flags & CFLAG_DMASEND) {
5617 if (byte_cnt != 0) {
5618 sf_log(sf, CE_NOTE,
5619 "!sf_cmd_callback: Lost Frame: "
5620 "(write) received 0x%x expected"
5621 " 0x%x target 0x%x\n",
5622 byte_cnt, cmd->cmd_dmacount,
5623 sf_alpa_to_switch[
5624 target->sft_al_pa]);
5625 pkt->pkt_reason = CMD_INCOMPLETE;
5626 pkt->pkt_statistics |= STAT_ABORTED;
5627 }
5628 } else if (byte_cnt < cmd->cmd_dmacount) {
5629 sf_log(sf, CE_NOTE,
5630 "!sf_cmd_callback: "
5631 "Lost Frame: (read) "
5632 "received 0x%x expected 0x%x "
5633 "target 0x%x\n", byte_cnt,
5634 cmd->cmd_dmacount,
5635 sf_alpa_to_switch[
5636 target->sft_al_pa]);
5637 pkt->pkt_reason = CMD_INCOMPLETE;
5638 pkt->pkt_statistics |= STAT_ABORTED;
5639 }
5640 }
5641 }
5642
5643 } else {
5644
5645 /* pkt status was not ok */
5646
5647 switch (fpkt->fcal_pkt_status) {
5648
5649 case FCAL_STATUS_ERR_OFFLINE:
5650 SF_DMSG1("Fibre Channel Offline");
5651 mutex_enter(&target->sft_mutex);
5652 if (!(target->sft_state & SF_TARGET_OFFLINE)) {
5653 target->sft_state |= (SF_TARGET_BUSY
5654 | SF_TARGET_MARK);
5655 }
5656 mutex_exit(&target->sft_mutex);
5657 (void) ndi_event_retrieve_cookie(sf->sf_event_hdl,
5658 target->sft_dip, FCAL_REMOVE_EVENT,
5659 &sf_remove_eid, NDI_EVENT_NOPASS);
5660 (void) ndi_event_run_callbacks(sf->sf_event_hdl,
5661 target->sft_dip, sf_remove_eid, NULL);
5662 pkt->pkt_reason = CMD_TRAN_ERR;
5663 pkt->pkt_statistics |= STAT_BUS_RESET;
5664 break;
5665
5666 case FCAL_STATUS_MAX_XCHG_EXCEEDED:
5667 sf_throttle(sf);
5668 sf->sf_use_lock = TRUE;
5669 pkt->pkt_reason = CMD_TRAN_ERR;
5670 pkt->pkt_state = STATE_GOT_BUS;
5671 pkt->pkt_statistics |= STAT_ABORTED;
5672 break;
5673
5674 case FCAL_STATUS_TIMEOUT:
5675 SF_DMSG1("Fibre Channel Timeout");
5676 pkt->pkt_reason = CMD_TIMEOUT;
5677 break;
5678
5679 case FCAL_STATUS_ERR_OVERRUN:
5680 SF_DMSG1("CMD_DATA_OVR");
5681 pkt->pkt_reason = CMD_DATA_OVR;
5682 break;
5683
5684 case FCAL_STATUS_UNKNOWN_CQ_TYPE:
5685 SF_DMSG1("Unknown CQ type");
5686 pkt->pkt_reason = CMD_TRAN_ERR;
5687 break;
5688
5689 case FCAL_STATUS_BAD_SEG_CNT:
5690 SF_DMSG1("Bad SEG CNT");
5691 pkt->pkt_reason = CMD_TRAN_ERR;
5692 break;
5693
5694 case FCAL_STATUS_BAD_XID:
5695 SF_DMSG1("Fibre Channel Invalid X_ID");
5696 pkt->pkt_reason = CMD_TRAN_ERR;
5697 break;
5698
5699 case FCAL_STATUS_XCHG_BUSY:
5700 SF_DMSG1("Fibre Channel Exchange Busy");
5701 pkt->pkt_reason = CMD_TRAN_ERR;
5702 break;
5703
5704 case FCAL_STATUS_INSUFFICIENT_CQES:
5705 SF_DMSG1("Insufficient CQEs");
5706 pkt->pkt_reason = CMD_TRAN_ERR;
5707 break;
5708
5709 case FCAL_STATUS_ALLOC_FAIL:
5710 SF_DMSG1("ALLOC FAIL");
5711 pkt->pkt_reason = CMD_TRAN_ERR;
5712 break;
5713
5714 case FCAL_STATUS_BAD_SID:
5715 SF_DMSG1("Fibre Channel Invalid S_ID");
5716 pkt->pkt_reason = CMD_TRAN_ERR;
5717 break;
5718
5719 case FCAL_STATUS_INCOMPLETE_DMA_ERR:
5720 if (sf_core && (sf_core & SF_CORE_INCOMPLETE_DMA)) {
5721 sf_token = (int *)(uintptr_t)
5722 fpkt->fcal_socal_request.\
5723 sr_soc_hdr.sh_request_token;
5724 (void) soc_take_core(sf->sf_sochandle,
5725 sf->sf_socp);
5726 sf_core = 0;
5727 }
5728 msg2 =
5729 "INCOMPLETE DMA XFER due to bad SOC+ card, replace HBA";
5730 pkt->pkt_reason = CMD_INCOMPLETE;
5731 pkt->pkt_state = STATE_GOT_BUS;
5732 pkt->pkt_statistics |= STAT_ABORTED;
5733 break;
5734
5735 case FCAL_STATUS_CRC_ERR:
5736 msg2 = "Fibre Channel CRC Error on frames";
5737 pkt->pkt_reason = CMD_INCOMPLETE;
5738 pkt->pkt_state = STATE_GOT_BUS;
5739 pkt->pkt_statistics |= STAT_ABORTED;
5740 break;
5741
5742 case FCAL_STATUS_NO_SEQ_INIT:
5743 SF_DMSG1("Fibre Channel Seq Init Error");
5744 pkt->pkt_reason = CMD_TRAN_ERR;
5745 break;
5746
5747 case FCAL_STATUS_OPEN_FAIL:
5748 pkt->pkt_reason = CMD_TRAN_ERR;
5749 SF_DMSG1("Fibre Channel Open Failure");
5750 if ((target->sft_state & (SF_TARGET_BUSY |
5751 SF_TARGET_MARK | SF_TARGET_OFFLINE)) == 0) {
5752 sf_log(sf, CE_NOTE,
5753 "!Open failure to target 0x%x "
5754 "forcing LIP\n",
5755 sf_alpa_to_switch[target->sft_al_pa]);
5756 sf_force_lip(sf);
5757 }
5758 break;
5759
5760
5761 case FCAL_STATUS_ONLINE_TIMEOUT:
5762 SF_DMSG1("Fibre Channel Online Timeout");
5763 pkt->pkt_reason = CMD_TRAN_ERR;
5764 break;
5765
5766 default:
5767 SF_DMSG1("Unknown FC Status");
5768 pkt->pkt_reason = CMD_TRAN_ERR;
5769 break;
5770 }
5771 }
5772
5773 #ifdef DEBUG
5774 /*
5775 * msg1 will be non-NULL if we've detected some sort of error
5776 */
5777 if (msg1 != NULL && sfdebug >= 4) {
5778 sf_log(sf, CE_WARN,
5779 "!Transport error on cmd=0x%p target=0x%x: %s\n",
5780 (void *)fpkt, pkt->pkt_address.a_target, msg1);
5781 }
5782 #endif
5783
5784 if (msg2 != NULL) {
5785 sf_log(sf, CE_WARN, "!Transport error on target=0x%x: %s\n",
5786 pkt->pkt_address.a_target, msg2);
5787 }
5788
5789 ncmds = fpkt->fcal_ncmds;
5790 ASSERT(ncmds >= 0);
5791 if (ncmds >= (sf->sf_throttle - SF_HI_CMD_DELTA)) {
5792 #ifdef DEBUG
5793 if (!sf->sf_use_lock) {
5794 SF_DEBUG(4, (sf, CE_NOTE, "use lock flag on\n"));
5795 }
5796 #endif
5797 sf->sf_use_lock = TRUE;
5798 }
5799
5800 mutex_enter(&sf->sf_cmd_mutex);
5801 sf->sf_ncmds = ncmds;
5802 sf_throttle_start(sf);
5803 mutex_exit(&sf->sf_cmd_mutex);
5804
5805 if (!msg1 && !msg2)
5806 SF_DEBUG(6, (sf, CE_NOTE, "Completing pkt 0x%p\n",
5807 (void *)pkt));
5808 if (pkt->pkt_comp != NULL) {
5809 (*pkt->pkt_comp)(pkt);
5810 }
5811 }
5812
5813 #undef SF_DMSG1
5814
5815
5816
5817 /*
5818 * start throttling for this instance
5819 */
5820 static void
5821 sf_throttle_start(struct sf *sf)
5822 {
5823 struct sf_pkt *cmd, *prev_cmd = NULL;
5824 struct scsi_pkt *pkt;
5825 struct sf_target *target;
5826
5827
5828 ASSERT(mutex_owned(&sf->sf_cmd_mutex));
5829
5830 cmd = sf->sf_pkt_head;
5831 while ((cmd != NULL) &&
5832 (sf->sf_state == SF_STATE_ONLINE) &&
5833 (sf->sf_ncmds < sf->sf_throttle)) {
5834
5835 pkt = CMD2PKT(cmd);
5836
5837 target = ADDR2TARGET(&pkt->pkt_address);
5838 if (target->sft_state & SF_TARGET_BUSY) {
5839 /* this command is busy -- go to next */
5840 ASSERT(cmd->cmd_state != SF_STATE_ISSUED);
5841 prev_cmd = cmd;
5842 cmd = cmd->cmd_next;
5843 continue;
5844 }
5845
5846 ASSERT(cmd->cmd_state != SF_STATE_ISSUED);
5847
5848 /* this cmd not busy and not issued */
5849
5850 /* remove this packet from the queue */
5851 if (sf->sf_pkt_head == cmd) {
5852 /* this was the first packet */
5853 sf->sf_pkt_head = cmd->cmd_next;
5854 } else if (sf->sf_pkt_tail == cmd) {
5855 /* this was the last packet */
5856 sf->sf_pkt_tail = prev_cmd;
5857 if (prev_cmd != NULL) {
5858 prev_cmd->cmd_next = NULL;
5859 }
5860 } else {
5861 /* some packet in the middle of the queue */
5862 ASSERT(prev_cmd != NULL);
5863 prev_cmd->cmd_next = cmd->cmd_next;
5864 }
5865 cmd->cmd_flags &= ~CFLAG_IN_QUEUE;
5866
5867 if (target->sft_state & SF_TARGET_OFFLINE) {
5868 mutex_exit(&sf->sf_cmd_mutex);
5869 pkt->pkt_reason = CMD_TRAN_ERR;
5870 if (pkt->pkt_comp != NULL) {
5871 (*pkt->pkt_comp)(cmd->cmd_pkt);
5872 }
5873 } else {
5874 sf_fill_ids(sf, cmd, target);
5875 if (sf_start_internal(sf, cmd) != TRAN_ACCEPT) {
5876 pkt->pkt_reason = CMD_TRAN_ERR;
5877 if (pkt->pkt_comp != NULL) {
5878 (*pkt->pkt_comp)(cmd->cmd_pkt);
5879 }
5880 }
5881 }
5882 mutex_enter(&sf->sf_cmd_mutex);
5883 cmd = sf->sf_pkt_head;
5884 prev_cmd = NULL;
5885 }
5886 }
5887
5888
5889 /*
5890 * called when the max exchange value is exceeded to throttle back commands
5891 */
5892 static void
5893 sf_throttle(struct sf *sf)
5894 {
5895 int cmdmax = sf->sf_sochandle->fcal_cmdmax;
5896
5897
5898 mutex_enter(&sf->sf_cmd_mutex);
5899
5900 sf->sf_flag = TRUE;
5901
5902 if (sf->sf_ncmds > (cmdmax / 2)) {
5903 sf->sf_throttle = cmdmax / 2;
5904 } else {
5905 if (sf->sf_ncmds > SF_DECR_DELTA) {
5906 sf->sf_throttle = sf->sf_ncmds - SF_DECR_DELTA;
5907 } else {
5908 /*
5909 * This case is just a safeguard, should not really
5910 * happen(ncmds < SF_DECR_DELTA and MAX_EXCHG exceed
5911 */
5912 sf->sf_throttle = SF_DECR_DELTA;
5913 }
5914 }
5915 mutex_exit(&sf->sf_cmd_mutex);
5916
5917 sf = sf->sf_sibling;
5918 if (sf != NULL) {
5919 mutex_enter(&sf->sf_cmd_mutex);
5920 sf->sf_flag = TRUE;
5921 if (sf->sf_ncmds >= (cmdmax / 2)) {
5922 sf->sf_throttle = cmdmax / 2;
5923 } else {
5924 if (sf->sf_ncmds > SF_DECR_DELTA) {
5925 sf->sf_throttle = sf->sf_ncmds - SF_DECR_DELTA;
5926 } else {
5927 sf->sf_throttle = SF_DECR_DELTA;
5928 }
5929 }
5930
5931 mutex_exit(&sf->sf_cmd_mutex);
5932 }
5933 }
5934
5935
5936 /*
5937 * sf watchdog routine, called for a timeout
5938 */
5939 /*ARGSUSED*/
5940 static void
5941 sf_watch(void *arg)
5942 {
5943 struct sf *sf;
5944 struct sf_els_hdr *privp;
5945 static int count = 0, pscan_count = 0;
5946 int cmdmax, i, mescount = 0;
5947 struct sf_target *target;
5948
5949
5950 sf_watchdog_time += sf_watchdog_timeout;
5951 count++;
5952 pscan_count++;
5953
5954 mutex_enter(&sf_global_mutex);
5955 sf_watch_running = 1;
5956 for (sf = sf_head; sf != NULL; sf = sf->sf_next) {
5957
5958 mutex_exit(&sf_global_mutex);
5959
5960 /* disable throttling while we're suspended */
5961 mutex_enter(&sf->sf_mutex);
5962 if (sf->sf_state & SF_STATE_SUSPENDED) {
5963 mutex_exit(&sf->sf_mutex);
5964 SF_DEBUG(1, (sf, CE_CONT,
5965 "sf_watch, sf%d:throttle disabled "
5966 "due to DDI_SUSPEND\n",
5967 ddi_get_instance(sf->sf_dip)));
5968 mutex_enter(&sf_global_mutex);
5969 continue;
5970 }
5971 mutex_exit(&sf->sf_mutex);
5972
5973 cmdmax = sf->sf_sochandle->fcal_cmdmax;
5974
5975 if (sf->sf_take_core) {
5976 (void) soc_take_core(sf->sf_sochandle, sf->sf_socp);
5977 }
5978
5979 mutex_enter(&sf->sf_cmd_mutex);
5980
5981 if (!sf->sf_flag) {
5982 if (sf->sf_throttle < (cmdmax / 2)) {
5983 sf->sf_throttle = cmdmax / 2;
5984 } else if ((sf->sf_throttle += SF_INCR_DELTA) >
5985 cmdmax) {
5986 sf->sf_throttle = cmdmax;
5987 }
5988 } else {
5989 sf->sf_flag = FALSE;
5990 }
5991
5992 sf->sf_ncmds_exp_avg = (sf->sf_ncmds + sf->sf_ncmds_exp_avg)
5993 >> 2;
5994 if ((sf->sf_ncmds <= (sf->sf_throttle - SF_LO_CMD_DELTA)) &&
5995 (sf->sf_pkt_head == NULL)) {
5996 #ifdef DEBUG
5997 if (sf->sf_use_lock) {
5998 SF_DEBUG(4, (sf, CE_NOTE,
5999 "use lock flag off\n"));
6000 }
6001 #endif
6002 sf->sf_use_lock = FALSE;
6003 }
6004
6005 if (sf->sf_state == SF_STATE_ONLINE && sf->sf_pkt_head &&
6006 sf->sf_ncmds < sf->sf_throttle) {
6007 sf_throttle_start(sf);
6008 }
6009
6010 mutex_exit(&sf->sf_cmd_mutex);
6011
6012 if (pscan_count >= sf_pool_scan_cnt) {
6013 if (sf->sf_ncmds_exp_avg < (sf->sf_cr_pool_cnt <<
6014 SF_LOG2_ELEMS_IN_POOL) - SF_FREE_CR_EPSILON) {
6015 sf_crpool_free(sf);
6016 }
6017 }
6018 mutex_enter(&sf->sf_mutex);
6019
6020 privp = sf->sf_els_list;
6021 while (privp != NULL) {
6022 if (privp->timeout < sf_watchdog_time) {
6023 /* timeout this command */
6024 privp = sf_els_timeout(sf, privp);
6025 } else if ((privp->timeout == SF_INVALID_TIMEOUT) &&
6026 (privp->lip_cnt != sf->sf_lip_cnt)) {
6027 if (privp->prev != NULL) {
6028 privp->prev->next = privp->next;
6029 }
6030 if (sf->sf_els_list == privp) {
6031 sf->sf_els_list = privp->next;
6032 }
6033 if (privp->next != NULL) {
6034 privp->next->prev = privp->prev;
6035 }
6036 mutex_exit(&sf->sf_mutex);
6037 sf_els_free(privp->fpkt);
6038 mutex_enter(&sf->sf_mutex);
6039 privp = sf->sf_els_list;
6040 } else {
6041 privp = privp->next;
6042 }
6043 }
6044
6045 if (sf->sf_online_timer && sf->sf_online_timer <
6046 sf_watchdog_time) {
6047 for (i = 0; i < sf_max_targets; i++) {
6048 target = sf->sf_targets[i];
6049 if (target != NULL) {
6050 if (!mescount && target->sft_state &
6051 SF_TARGET_BUSY) {
6052 sf_log(sf, CE_WARN, "!Loop "
6053 "Unstable: Failed to bring "
6054 "Loop Online\n");
6055 mescount = 1;
6056 }
6057 target->sft_state |= SF_TARGET_MARK;
6058 }
6059 }
6060 sf_finish_init(sf, sf->sf_lip_cnt);
6061 sf->sf_state = SF_STATE_INIT;
6062 sf->sf_online_timer = 0;
6063 }
6064
6065 if (sf->sf_state == SF_STATE_ONLINE) {
6066 mutex_exit(&sf->sf_mutex);
6067 if (count >= sf_pkt_scan_cnt) {
6068 sf_check_targets(sf);
6069 }
6070 } else if ((sf->sf_state == SF_STATE_OFFLINE) &&
6071 (sf->sf_timer < sf_watchdog_time)) {
6072 for (i = 0; i < sf_max_targets; i++) {
6073 target = sf->sf_targets[i];
6074 if ((target != NULL) &&
6075 (target->sft_state &
6076 SF_TARGET_BUSY)) {
6077 sf_log(sf, CE_WARN,
6078 "!Offline Timeout\n");
6079 if (sf_core && (sf_core &
6080 SF_CORE_OFFLINE_TIMEOUT)) {
6081 (void) soc_take_core(
6082 sf->sf_sochandle,
6083 sf->sf_socp);
6084 sf_core = 0;
6085 }
6086 break;
6087 }
6088 }
6089 sf_finish_init(sf, sf->sf_lip_cnt);
6090 sf->sf_state = SF_STATE_INIT;
6091 mutex_exit(&sf->sf_mutex);
6092 } else {
6093 mutex_exit(&sf->sf_mutex);
6094 }
6095 mutex_enter(&sf_global_mutex);
6096 }
6097 mutex_exit(&sf_global_mutex);
6098 if (count >= sf_pkt_scan_cnt) {
6099 count = 0;
6100 }
6101 if (pscan_count >= sf_pool_scan_cnt) {
6102 pscan_count = 0;
6103 }
6104
6105 /* reset timeout */
6106 sf_watchdog_id = timeout(sf_watch, (caddr_t)0, sf_watchdog_tick);
6107
6108 /* signal waiting thread */
6109 mutex_enter(&sf_global_mutex);
6110 sf_watch_running = 0;
6111 cv_broadcast(&sf_watch_cv);
6112 mutex_exit(&sf_global_mutex);
6113 }
6114
6115
6116 /*
6117 * called during a timeout to check targets
6118 */
6119 static void
6120 sf_check_targets(struct sf *sf)
6121 {
6122 struct sf_target *target;
6123 int i;
6124 struct sf_pkt *cmd;
6125 struct scsi_pkt *pkt;
6126 int lip_cnt;
6127
6128 mutex_enter(&sf->sf_mutex);
6129 lip_cnt = sf->sf_lip_cnt;
6130 mutex_exit(&sf->sf_mutex);
6131
6132 /* check scan all possible targets */
6133 for (i = 0; i < sf_max_targets; i++) {
6134 target = sf->sf_targets[i];
6135 while (target != NULL) {
6136 mutex_enter(&target->sft_pkt_mutex);
6137 if (target->sft_alive && target->sft_scan_count !=
6138 sf_target_scan_cnt) {
6139 target->sft_alive = 0;
6140 target->sft_scan_count++;
6141 mutex_exit(&target->sft_pkt_mutex);
6142 return;
6143 }
6144 target->sft_alive = 0;
6145 target->sft_scan_count = 0;
6146 cmd = target->sft_pkt_head;
6147 while (cmd != (struct sf_pkt *)&target->sft_pkt_head) {
6148 mutex_enter(&cmd->cmd_abort_mutex);
6149 if (cmd->cmd_state == SF_STATE_ISSUED &&
6150 ((cmd->cmd_timeout && sf_watchdog_time >
6151 #ifdef DEBUG
6152 cmd->cmd_timeout) || sf_abort_flag)) {
6153 sf_abort_flag = 0;
6154 #else
6155 cmd->cmd_timeout))) {
6156 #endif
6157 cmd->cmd_timeout = 0;
6158 /* prevent reset from getting at this packet */
6159 cmd->cmd_state = SF_STATE_ABORTING;
6160 mutex_exit(&cmd->cmd_abort_mutex);
6161 mutex_exit(&target->sft_pkt_mutex);
6162 sf->sf_stats.tstats[i].timeouts++;
6163 if (sf_target_timeout(sf, cmd))
6164 return;
6165 else {
6166 if (lip_cnt != sf->sf_lip_cnt) {
6167 return;
6168 } else {
6169 mutex_enter(&target->
6170 sft_pkt_mutex);
6171 cmd = target->
6172 sft_pkt_head;
6173 }
6174 }
6175 /*
6176 * if the abort and lip fail, a reset will be carried out.
6177 * But the reset will ignore this packet. We have waited at least
6178 * 20 seconds after the initial timeout. Now, complete it here.
6179 * This also takes care of spurious bad aborts.
6180 */
6181 } else if ((cmd->cmd_state ==
6182 SF_STATE_ABORTING) && (cmd->cmd_timeout
6183 <= sf_watchdog_time)) {
6184 cmd->cmd_state = SF_STATE_IDLE;
6185 mutex_exit(&cmd->cmd_abort_mutex);
6186 mutex_exit(&target->sft_pkt_mutex);
6187 SF_DEBUG(1, (sf, CE_NOTE,
6188 "Command 0x%p to sft 0x%p"
6189 " delayed release\n",
6190 (void *)cmd, (void *)target));
6191 pkt = cmd->cmd_pkt;
6192 pkt->pkt_statistics |=
6193 (STAT_TIMEOUT|STAT_ABORTED);
6194 pkt->pkt_reason = CMD_TIMEOUT;
6195 if (pkt->pkt_comp) {
6196 scsi_hba_pkt_comp(pkt);
6197 /* handle deferred_destroy case */
6198 } else {
6199 if ((cmd->cmd_block->fcp_cntl.
6200 cntl_reset == 1) ||
6201 (cmd->cmd_block->
6202 fcp_cntl.cntl_abort_tsk ==
6203 1)) {
6204 cmd->cmd_block->
6205 fcp_cntl.
6206 cntl_reset = 0;
6207 cmd->cmd_block->
6208 fcp_cntl.
6209 cntl_abort_tsk = 0;
6210 cmd->cmd_fp_pkt->
6211 fcal_pkt_comp =
6212 sf_cmd_callback;
6213 /* for cache */
6214 sf_scsi_destroy_pkt
6215 (&pkt->pkt_address,
6216 pkt);
6217 }
6218 }
6219 mutex_enter(&target->sft_pkt_mutex);
6220 cmd = target->sft_pkt_head;
6221 } else {
6222 mutex_exit(&cmd->cmd_abort_mutex);
6223 cmd = cmd->cmd_forw;
6224 }
6225 }
6226 mutex_exit(&target->sft_pkt_mutex);
6227 target = target->sft_next_lun;
6228 }
6229 }
6230 }
6231
6232
6233 /*
6234 * a command to a target has timed out
6235 * return TRUE iff cmd abort failed or timed out, else return FALSE
6236 */
6237 static int
6238 sf_target_timeout(struct sf *sf, struct sf_pkt *cmd)
6239 {
6240 int rval;
6241 struct scsi_pkt *pkt;
6242 struct fcal_packet *fpkt;
6243 int tgt_id;
6244 int retval = FALSE;
6245
6246
6247 SF_DEBUG(1, (sf, CE_NOTE, "Command 0x%p to target %x timed out\n",
6248 (void *)cmd->cmd_fp_pkt, cmd->cmd_pkt->pkt_address.a_target));
6249
6250 fpkt = cmd->cmd_fp_pkt;
6251
6252 if (sf_core && (sf_core & SF_CORE_CMD_TIMEOUT)) {
6253 sf_token = (int *)(uintptr_t)
6254 fpkt->fcal_socal_request.sr_soc_hdr.\
6255 sh_request_token;
6256 (void) soc_take_core(sf->sf_sochandle, sf->sf_socp);
6257 sf_core = 0;
6258 }
6259
6260 /* call the transport to abort a command */
6261 rval = soc_abort(sf->sf_sochandle, sf->sf_socp,
6262 sf->sf_sochandle->fcal_portno, fpkt, 1);
6263
6264 switch (rval) {
6265 case FCAL_ABORTED:
6266 SF_DEBUG(1, (sf, CE_NOTE, "Command Abort succeeded\n"));
6267 pkt = cmd->cmd_pkt;
6268 cmd->cmd_state = SF_STATE_IDLE;
6269 pkt->pkt_statistics |= (STAT_TIMEOUT|STAT_ABORTED);
6270 pkt->pkt_reason = CMD_TIMEOUT;
6271 if (pkt->pkt_comp != NULL) {
6272 (*pkt->pkt_comp)(pkt);
6273 }
6274 break; /* success */
6275
6276 case FCAL_ABORT_FAILED:
6277 SF_DEBUG(1, (sf, CE_NOTE, "Command Abort failed at target\n"));
6278 pkt = cmd->cmd_pkt;
6279 cmd->cmd_state = SF_STATE_IDLE;
6280 pkt->pkt_reason = CMD_TIMEOUT;
6281 pkt->pkt_statistics |= STAT_TIMEOUT;
6282 tgt_id = pkt->pkt_address.a_target;
6283 sf->sf_stats.tstats[tgt_id].abts_failures++;
6284 if (pkt->pkt_comp != NULL) {
6285 (*pkt->pkt_comp)(pkt);
6286 }
6287 break;
6288
6289 case FCAL_BAD_ABORT:
6290 if (sf_core && (sf_core & SF_CORE_BAD_ABORT)) {
6291 sf_token = (int *)(uintptr_t)fpkt->fcal_socal_request.\
6292 sr_soc_hdr.sh_request_token;
6293 (void) soc_take_core(sf->sf_sochandle, sf->sf_socp);
6294 sf_core = 0;
6295 }
6296 SF_DEBUG(1, (sf, CE_NOTE, "Command Abort bad abort\n"));
6297 cmd->cmd_timeout = sf_watchdog_time + cmd->cmd_pkt->pkt_time
6298 + 20;
6299 break;
6300
6301 case FCAL_TIMEOUT:
6302 retval = TRUE;
6303 break;
6304
6305 default:
6306 pkt = cmd->cmd_pkt;
6307 tgt_id = pkt->pkt_address.a_target;
6308 sf_log(sf, CE_WARN,
6309 "Command Abort failed target 0x%x, forcing a LIP\n", tgt_id);
6310 if (sf_core && (sf_core & SF_CORE_ABORT_TIMEOUT)) {
6311 sf_token = (int *)(uintptr_t)fpkt->fcal_socal_request.\
6312 sr_soc_hdr.sh_request_token;
6313 (void) soc_take_core(sf->sf_sochandle, sf->sf_socp);
6314 sf_core = 0;
6315 }
6316 sf_force_lip(sf);
6317 retval = TRUE;
6318 break;
6319 }
6320
6321 return (retval);
6322 }
6323
6324
6325 /*
6326 * an ELS command has timed out
6327 * return ???
6328 */
6329 static struct sf_els_hdr *
6330 sf_els_timeout(struct sf *sf, struct sf_els_hdr *privp)
6331 {
6332 struct fcal_packet *fpkt;
6333 int rval, dflag, timeout = SF_ELS_TIMEOUT;
6334 uint_t lip_cnt = privp->lip_cnt;
6335 uchar_t els_code = privp->els_code;
6336 struct sf_target *target = privp->target;
6337 char what[64];
6338
6339 fpkt = privp->fpkt;
6340 dflag = privp->delayed_retry;
6341 /* use as temporary state variable */
6342 privp->timeout = SF_INVALID_TIMEOUT;
6343 mutex_exit(&sf->sf_mutex);
6344
6345 if (privp->fpkt->fcal_pkt_comp == sf_els_callback) {
6346 /*
6347 * take socal core if required. Timeouts for IB and hosts
6348 * are not very interesting, so we take socal core only
6349 * if the timeout is *not* for a IB or host.
6350 */
6351 if (sf_core && (sf_core & SF_CORE_ELS_TIMEOUT) &&
6352 ((sf_alpa_to_switch[privp->dest_nport_id] &
6353 0x0d) != 0x0d) && ((privp->dest_nport_id != 1) ||
6354 (privp->dest_nport_id != 2) ||
6355 (privp->dest_nport_id != 4) ||
6356 (privp->dest_nport_id != 8) ||
6357 (privp->dest_nport_id != 0xf))) {
6358 sf_token = (int *)(uintptr_t)fpkt->fcal_socal_request.\
6359 sr_soc_hdr.sh_request_token;
6360 (void) soc_take_core(sf->sf_sochandle, sf->sf_socp);
6361 sf_core = 0;
6362 }
6363 (void) sprintf(what, "ELS 0x%x", privp->els_code);
6364 } else if (privp->fpkt->fcal_pkt_comp == sf_reportlun_callback) {
6365 if (sf_core && (sf_core & SF_CORE_REPORTLUN_TIMEOUT)) {
6366 sf_token = (int *)(uintptr_t)fpkt->fcal_socal_request.\
6367 sr_soc_hdr.sh_request_token;
6368 (void) soc_take_core(sf->sf_sochandle, sf->sf_socp);
6369 sf_core = 0;
6370 }
6371 timeout = SF_FCP_TIMEOUT;
6372 (void) sprintf(what, "REPORT_LUNS");
6373 } else if (privp->fpkt->fcal_pkt_comp == sf_inq_callback) {
6374 if (sf_core && (sf_core & SF_CORE_INQUIRY_TIMEOUT)) {
6375 sf_token = (int *)(uintptr_t)
6376 fpkt->fcal_socal_request.\
6377 sr_soc_hdr.sh_request_token;
6378 (void) soc_take_core(sf->sf_sochandle, sf->sf_socp);
6379 sf_core = 0;
6380 }
6381 timeout = SF_FCP_TIMEOUT;
6382 (void) sprintf(what, "INQUIRY to LUN 0x%lx",
6383 (long)SCSA_LUN(target));
6384 } else {
6385 (void) sprintf(what, "UNKNOWN OPERATION");
6386 }
6387
6388 if (dflag) {
6389 /* delayed retry */
6390 SF_DEBUG(2, (sf, CE_CONT,
6391 "!sf%d: %s to target %x delayed retry\n",
6392 ddi_get_instance(sf->sf_dip), what,
6393 sf_alpa_to_switch[privp->dest_nport_id]));
6394 privp->delayed_retry = FALSE;
6395 goto try_again;
6396 }
6397
6398 sf_log(sf, CE_NOTE, "!%s to target 0x%x alpa 0x%x timed out\n",
6399 what, sf_alpa_to_switch[privp->dest_nport_id],
6400 privp->dest_nport_id);
6401
6402 rval = soc_abort(sf->sf_sochandle, sf->sf_socp, sf->sf_sochandle
6403 ->fcal_portno, fpkt, 1);
6404 if (rval == FCAL_ABORTED || rval == FCAL_ABORT_FAILED) {
6405 SF_DEBUG(1, (sf, CE_NOTE, "!%s abort to al_pa %x succeeded\n",
6406 what, privp->dest_nport_id));
6407 try_again:
6408
6409 mutex_enter(&sf->sf_mutex);
6410 if (privp->prev != NULL) {
6411 privp->prev->next = privp->next;
6412 }
6413 if (sf->sf_els_list == privp) {
6414 sf->sf_els_list = privp->next;
6415 }
6416 if (privp->next != NULL) {
6417 privp->next->prev = privp->prev;
6418 }
6419 privp->prev = privp->next = NULL;
6420 if (lip_cnt == sf->sf_lip_cnt) {
6421 privp->timeout = sf_watchdog_time + timeout;
6422 if ((++(privp->retries) < sf_els_retries) ||
6423 (dflag && (privp->retries < SF_BSY_RETRIES))) {
6424 mutex_exit(&sf->sf_mutex);
6425 sf_log(sf, CE_NOTE,
6426 "!%s to target 0x%x retrying\n",
6427 what,
6428 sf_alpa_to_switch[privp->dest_nport_id]);
6429 if (sf_els_transport(sf, privp) == 1) {
6430 mutex_enter(&sf->sf_mutex);
6431 return (sf->sf_els_list); /* success */
6432 }
6433 mutex_enter(&sf->sf_mutex);
6434 fpkt = NULL;
6435 }
6436 if ((lip_cnt == sf->sf_lip_cnt) &&
6437 (els_code != LA_ELS_LOGO)) {
6438 if (target != NULL) {
6439 sf_offline_target(sf, target);
6440 }
6441 if (sf->sf_lip_cnt == lip_cnt) {
6442 sf->sf_device_count--;
6443 ASSERT(sf->sf_device_count >= 0);
6444 if (sf->sf_device_count == 0) {
6445 sf_finish_init(sf,
6446 sf->sf_lip_cnt);
6447 }
6448 }
6449 }
6450 privp = sf->sf_els_list;
6451 mutex_exit(&sf->sf_mutex);
6452 if (fpkt != NULL) {
6453 sf_els_free(fpkt);
6454 }
6455 } else {
6456 mutex_exit(&sf->sf_mutex);
6457 sf_els_free(privp->fpkt);
6458 privp = NULL;
6459 }
6460 } else {
6461 if (sf_core && (sf_core & SF_CORE_ELS_FAILED)) {
6462 sf_token = (int *)(uintptr_t)
6463 fpkt->fcal_socal_request.\
6464 sr_soc_hdr.sh_request_token;
6465 (void) soc_take_core(sf->sf_sochandle, sf->sf_socp);
6466 sf_core = 0;
6467 }
6468 sf_log(sf, CE_NOTE, "%s abort to target 0x%x failed. "
6469 "status=0x%x, forcing LIP\n", what,
6470 sf_alpa_to_switch[privp->dest_nport_id], rval);
6471 privp = NULL;
6472 if (sf->sf_lip_cnt == lip_cnt) {
6473 sf_force_lip(sf);
6474 }
6475 }
6476
6477 mutex_enter(&sf->sf_mutex);
6478 return (privp);
6479 }
6480
6481
6482 /*
6483 * called by timeout when a reset times out
6484 */
6485 /*ARGSUSED*/
6486 static void
6487 sf_check_reset_delay(void *arg)
6488 {
6489 struct sf *sf;
6490 struct sf_target *target;
6491 struct sf_reset_list *rp, *tp;
6492 uint_t lip_cnt, reset_timeout_flag = FALSE;
6493 clock_t lb;
6494
6495 lb = ddi_get_lbolt();
6496
6497 mutex_enter(&sf_global_mutex);
6498
6499 sf_reset_timeout_id = 0;
6500
6501 for (sf = sf_head; sf != NULL; sf = sf->sf_next) {
6502
6503 mutex_exit(&sf_global_mutex);
6504 mutex_enter(&sf->sf_mutex);
6505
6506 /* is this type cast needed? */
6507 tp = (struct sf_reset_list *)&sf->sf_reset_list;
6508
6509 rp = sf->sf_reset_list;
6510 while (rp != NULL) {
6511 if (((rp->timeout - lb) < 0) &&
6512 (rp->lip_cnt == sf->sf_lip_cnt)) {
6513 tp->next = rp->next;
6514 mutex_exit(&sf->sf_mutex);
6515 target = rp->target;
6516 lip_cnt = rp->lip_cnt;
6517 kmem_free(rp, sizeof (struct sf_reset_list));
6518 /* abort all cmds for this target */
6519 while (target) {
6520 sf_abort_all(sf, target, FALSE,
6521 lip_cnt, TRUE);
6522 mutex_enter(&target->sft_mutex);
6523 if (lip_cnt == sf->sf_lip_cnt) {
6524 target->sft_state &=
6525 ~SF_TARGET_BUSY;
6526 }
6527 mutex_exit(&target->sft_mutex);
6528 target = target->sft_next_lun;
6529 }
6530 mutex_enter(&sf->sf_mutex);
6531 tp = (struct sf_reset_list *)
6532 &sf->sf_reset_list;
6533 rp = sf->sf_reset_list;
6534 lb = ddi_get_lbolt();
6535 } else if (rp->lip_cnt != sf->sf_lip_cnt) {
6536 tp->next = rp->next;
6537 kmem_free(rp, sizeof (struct sf_reset_list));
6538 rp = tp->next;
6539 } else {
6540 reset_timeout_flag = TRUE;
6541 tp = rp;
6542 rp = rp->next;
6543 }
6544 }
6545 mutex_exit(&sf->sf_mutex);
6546 mutex_enter(&sf_global_mutex);
6547 }
6548
6549 if (reset_timeout_flag && (sf_reset_timeout_id == 0)) {
6550 sf_reset_timeout_id = timeout(sf_check_reset_delay,
6551 NULL, drv_usectohz(SF_TARGET_RESET_DELAY));
6552 }
6553
6554 mutex_exit(&sf_global_mutex);
6555 }
6556
6557
6558 /*
6559 * called to "reset the bus", i.e. force loop initialization (and address
6560 * re-negotiation)
6561 */
6562 static void
6563 sf_force_lip(struct sf *sf)
6564 {
6565 int i;
6566 struct sf_target *target;
6567
6568
6569 /* disable restart of lip if we're suspended */
6570 mutex_enter(&sf->sf_mutex);
6571 if (sf->sf_state & SF_STATE_SUSPENDED) {
6572 mutex_exit(&sf->sf_mutex);
6573 SF_DEBUG(1, (sf, CE_CONT,
6574 "sf_force_lip, sf%d: lip restart disabled "
6575 "due to DDI_SUSPEND\n",
6576 ddi_get_instance(sf->sf_dip)));
6577 return;
6578 }
6579
6580 sf_log(sf, CE_NOTE, "Forcing lip\n");
6581
6582 for (i = 0; i < sf_max_targets; i++) {
6583 target = sf->sf_targets[i];
6584 while (target != NULL) {
6585 mutex_enter(&target->sft_mutex);
6586 if (!(target->sft_state & SF_TARGET_OFFLINE))
6587 target->sft_state |= SF_TARGET_BUSY;
6588 mutex_exit(&target->sft_mutex);
6589 target = target->sft_next_lun;
6590 }
6591 }
6592
6593 sf->sf_lip_cnt++;
6594 sf->sf_timer = sf_watchdog_time + SF_OFFLINE_TIMEOUT;
6595 sf->sf_state = SF_STATE_OFFLINE;
6596 mutex_exit(&sf->sf_mutex);
6597 sf->sf_stats.lip_count++; /* no mutex for this? */
6598
6599 #ifdef DEBUG
6600 /* are we allowing LIPs ?? */
6601 if (sf_lip_flag != 0) {
6602 #endif
6603 /* call the transport to force loop initialization */
6604 if (((i = soc_force_lip(sf->sf_sochandle, sf->sf_socp,
6605 sf->sf_sochandle->fcal_portno, 1,
6606 FCAL_FORCE_LIP)) != FCAL_SUCCESS) &&
6607 (i != FCAL_TIMEOUT)) {
6608 /* force LIP failed */
6609 if (sf_core && (sf_core & SF_CORE_LIP_FAILED)) {
6610 (void) soc_take_core(sf->sf_sochandle,
6611 sf->sf_socp);
6612 sf_core = 0;
6613 }
6614 #ifdef DEBUG
6615 /* are we allowing reset after LIP failed ?? */
6616 if (sf_reset_flag != 0) {
6617 #endif
6618 /* restart socal after resetting it */
6619 sf_log(sf, CE_NOTE,
6620 "!Force lip failed Status code 0x%x."
6621 " Reseting\n", i);
6622 /* call transport to force a reset */
6623 soc_force_reset(sf->sf_sochandle, sf->sf_socp,
6624 sf->sf_sochandle->fcal_portno, 1);
6625 #ifdef DEBUG
6626 }
6627 #endif
6628 }
6629 #ifdef DEBUG
6630 }
6631 #endif
6632 }
6633
6634
6635 /*
6636 * called by the transport when an unsolicited ELS is received
6637 */
6638 static void
6639 sf_unsol_els_callback(void *arg, soc_response_t *srp, caddr_t payload)
6640 {
6641 struct sf *sf = (struct sf *)arg;
6642 els_payload_t *els = (els_payload_t *)payload;
6643 struct la_els_rjt *rsp;
6644 int i, tgt_id;
6645 uchar_t dest_id;
6646 struct fcal_packet *fpkt;
6647 fc_frame_header_t *hp;
6648 struct sf_els_hdr *privp;
6649
6650
6651 if ((els == NULL) || ((i = srp->sr_soc_hdr.sh_byte_cnt) == 0)) {
6652 return;
6653 }
6654
6655 if (i > SOC_CQE_PAYLOAD) {
6656 i = SOC_CQE_PAYLOAD;
6657 }
6658
6659 dest_id = (uchar_t)srp->sr_fc_frame_hdr.s_id;
6660 tgt_id = sf_alpa_to_switch[dest_id];
6661
6662 switch (els->els_cmd.c.ls_command) {
6663
6664 case LA_ELS_LOGO:
6665 /*
6666 * logout received -- log the fact
6667 */
6668 sf->sf_stats.tstats[tgt_id].logouts_recvd++;
6669 sf_log(sf, CE_NOTE, "!LOGO recvd from target %x, %s\n",
6670 tgt_id,
6671 sf_lip_on_plogo ? "Forcing LIP...." : "");
6672 if (sf_lip_on_plogo) {
6673 sf_force_lip(sf);
6674 }
6675 break;
6676
6677 default: /* includes LA_ELS_PLOGI */
6678 /*
6679 * something besides a logout received -- we don't handle
6680 * this so send back a reject saying its unsupported
6681 */
6682
6683 sf_log(sf, CE_NOTE, "!ELS 0x%x recvd from target 0x%x\n",
6684 els->els_cmd.c.ls_command, tgt_id);
6685
6686
6687 /* allocate room for a response */
6688 if (sf_els_alloc(sf, dest_id, sizeof (struct sf_els_hdr),
6689 sizeof (struct la_els_rjt), sizeof (union sf_els_rsp),
6690 (caddr_t *)&privp, (caddr_t *)&rsp) == NULL) {
6691 break;
6692 }
6693
6694 fpkt = privp->fpkt;
6695
6696 /* fill in pkt header */
6697 hp = &fpkt->fcal_socal_request.sr_fc_frame_hdr;
6698 hp->r_ctl = R_CTL_ELS_RSP;
6699 hp->f_ctl = F_CTL_LAST_SEQ | F_CTL_XCHG_CONTEXT;
6700 hp->ox_id = srp->sr_fc_frame_hdr.ox_id;
6701 hp->rx_id = srp->sr_fc_frame_hdr.rx_id;
6702 fpkt->fcal_socal_request.sr_cqhdr.cq_hdr_type =
6703 CQ_TYPE_OUTBOUND;
6704
6705 fpkt->fcal_socal_request.sr_soc_hdr.sh_seg_cnt = 1;
6706
6707 /* fill in response */
6708 rsp->ls_code = LA_ELS_RJT; /* reject this ELS */
6709 rsp->mbz[0] = 0;
6710 rsp->mbz[1] = 0;
6711 rsp->mbz[2] = 0;
6712 ((struct la_els_logi *)privp->rsp)->ls_code = LA_ELS_ACC;
6713 *((int *)&rsp->reserved) = 0;
6714 rsp->reason_code = RJT_UNSUPPORTED;
6715 privp->retries = sf_els_retries;
6716 privp->els_code = LA_ELS_RJT;
6717 privp->timeout = (unsigned)0xffffffff;
6718 (void) sf_els_transport(sf, privp);
6719 break;
6720 }
6721 }
6722
6723
6724 /*
6725 * Error logging, printing, and debug print routines
6726 */
6727
6728 /*PRINTFLIKE3*/
6729 static void
6730 sf_log(struct sf *sf, int level, const char *fmt, ...)
6731 {
6732 char buf[256];
6733 dev_info_t *dip;
6734 va_list ap;
6735
6736 if (sf != NULL) {
6737 dip = sf->sf_dip;
6738 } else {
6739 dip = NULL;
6740 }
6741
6742 va_start(ap, fmt);
6743 (void) vsprintf(buf, fmt, ap);
6744 va_end(ap);
6745 scsi_log(dip, "sf", level, buf);
6746 }
6747
6748
6749 /*
6750 * called to get some sf kstats -- return 0 on success else return errno
6751 */
6752 static int
6753 sf_kstat_update(kstat_t *ksp, int rw)
6754 {
6755 struct sf *sf;
6756
6757 if (rw == KSTAT_WRITE) {
6758 /* can't write */
6759 return (EACCES);
6760 }
6761
6762 sf = ksp->ks_private;
6763 sf->sf_stats.ncmds = sf->sf_ncmds;
6764 sf->sf_stats.throttle_limit = sf->sf_throttle;
6765 sf->sf_stats.cr_pool_size = sf->sf_cr_pool_cnt;
6766
6767 return (0); /* success */
6768 }
6769
6770
6771 /*
6772 * Unix Entry Points
6773 */
6774
6775 /*
6776 * driver entry point for opens on control device
6777 */
6778 /* ARGSUSED */
6779 static int
6780 sf_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p)
6781 {
6782 dev_t dev = *dev_p;
6783 struct sf *sf;
6784
6785
6786 /* just ensure soft state exists for this device */
6787 sf = ddi_get_soft_state(sf_state, SF_MINOR2INST(getminor(dev)));
6788 if (sf == NULL) {
6789 return (ENXIO);
6790 }
6791
6792 ++(sf->sf_check_n_close);
6793
6794 return (0);
6795 }
6796
6797
6798 /*
6799 * driver entry point for last close on control device
6800 */
6801 /* ARGSUSED */
6802 static int
6803 sf_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
6804 {
6805 struct sf *sf;
6806
6807 sf = ddi_get_soft_state(sf_state, SF_MINOR2INST(getminor(dev)));
6808 if (sf == NULL) {
6809 return (ENXIO);
6810 }
6811
6812 if (!sf->sf_check_n_close) { /* if this flag is zero */
6813 cmn_err(CE_WARN, "sf%d: trying to close unopened instance",
6814 SF_MINOR2INST(getminor(dev)));
6815 return (ENODEV);
6816 } else {
6817 --(sf->sf_check_n_close);
6818 }
6819 return (0);
6820 }
6821
6822
6823 /*
6824 * driver entry point for sf ioctl commands
6825 */
6826 /* ARGSUSED */
6827 static int
6828 sf_ioctl(dev_t dev,
6829 int cmd, intptr_t arg, int mode, cred_t *cred_p, int *rval_p)
6830 {
6831 struct sf *sf;
6832 struct sf_target *target;
6833 uchar_t al_pa;
6834 struct sf_al_map map;
6835 int cnt, i;
6836 int retval; /* return value */
6837 struct devctl_iocdata *dcp;
6838 dev_info_t *cdip;
6839 struct scsi_address ap;
6840 scsi_hba_tran_t *tran;
6841
6842
6843 sf = ddi_get_soft_state(sf_state, SF_MINOR2INST(getminor(dev)));
6844 if (sf == NULL) {
6845 return (ENXIO);
6846 }
6847
6848 /* handle all ioctls */
6849 switch (cmd) {
6850
6851 /*
6852 * We can use the generic implementation for these ioctls
6853 */
6854 case DEVCTL_DEVICE_GETSTATE:
6855 case DEVCTL_DEVICE_ONLINE:
6856 case DEVCTL_DEVICE_OFFLINE:
6857 case DEVCTL_BUS_GETSTATE:
6858 return (ndi_devctl_ioctl(sf->sf_dip, cmd, arg, mode, 0));
6859
6860 /*
6861 * return FC map
6862 */
6863 case SFIOCGMAP:
6864 if ((sf->sf_lilp_map->lilp_magic != FCAL_LILP_MAGIC &&
6865 sf->sf_lilp_map->lilp_magic != FCAL_BADLILP_MAGIC) ||
6866 sf->sf_state != SF_STATE_ONLINE) {
6867 retval = ENOENT;
6868 goto dun;
6869 }
6870 mutex_enter(&sf->sf_mutex);
6871 if (sf->sf_lilp_map->lilp_magic == FCAL_BADLILP_MAGIC) {
6872 int i, j = 0;
6873
6874 /* Need to generate a fake lilp map */
6875 for (i = 0; i < sf_max_targets; i++) {
6876 if (sf->sf_targets[i])
6877 sf->sf_lilp_map->lilp_alpalist[j++] =
6878 sf->sf_targets[i]->
6879 sft_hard_address;
6880 }
6881 sf->sf_lilp_map->lilp_length = (uchar_t)j;
6882 }
6883 cnt = sf->sf_lilp_map->lilp_length;
6884 map.sf_count = (short)cnt;
6885 bcopy((caddr_t)&sf->sf_sochandle->fcal_n_wwn,
6886 (caddr_t)&map.sf_hba_addr.sf_node_wwn,
6887 sizeof (la_wwn_t));
6888 bcopy((caddr_t)&sf->sf_sochandle->fcal_p_wwn,
6889 (caddr_t)&map.sf_hba_addr.sf_port_wwn,
6890 sizeof (la_wwn_t));
6891 map.sf_hba_addr.sf_al_pa = sf->sf_al_pa;
6892 map.sf_hba_addr.sf_hard_address = 0;
6893 map.sf_hba_addr.sf_inq_dtype = DTYPE_UNKNOWN;
6894 for (i = 0; i < cnt; i++) {
6895 al_pa = sf->sf_lilp_map->lilp_alpalist[i];
6896 map.sf_addr_pair[i].sf_al_pa = al_pa;
6897 if (al_pa == sf->sf_al_pa) {
6898 (void) bcopy((caddr_t)&sf->sf_sochandle
6899 ->fcal_n_wwn, (caddr_t)&map.
6900 sf_addr_pair[i].sf_node_wwn,
6901 sizeof (la_wwn_t));
6902 (void) bcopy((caddr_t)&sf->sf_sochandle
6903 ->fcal_p_wwn, (caddr_t)&map.
6904 sf_addr_pair[i].sf_port_wwn,
6905 sizeof (la_wwn_t));
6906 map.sf_addr_pair[i].sf_hard_address =
6907 al_pa;
6908 map.sf_addr_pair[i].sf_inq_dtype =
6909 DTYPE_PROCESSOR;
6910 continue;
6911 }
6912 target = sf->sf_targets[sf_alpa_to_switch[
6913 al_pa]];
6914 if (target != NULL) {
6915 mutex_enter(&target->sft_mutex);
6916 if (!(target->sft_state &
6917 (SF_TARGET_OFFLINE |
6918 SF_TARGET_BUSY))) {
6919 bcopy((caddr_t)&target->
6920 sft_node_wwn,
6921 (caddr_t)&map.sf_addr_pair
6922 [i].sf_node_wwn,
6923 sizeof (la_wwn_t));
6924 bcopy((caddr_t)&target->
6925 sft_port_wwn,
6926 (caddr_t)&map.sf_addr_pair
6927 [i].sf_port_wwn,
6928 sizeof (la_wwn_t));
6929 map.sf_addr_pair[i].
6930 sf_hard_address
6931 = target->sft_hard_address;
6932 map.sf_addr_pair[i].
6933 sf_inq_dtype
6934 = target->sft_device_type;
6935 mutex_exit(&target->sft_mutex);
6936 continue;
6937 }
6938 mutex_exit(&target->sft_mutex);
6939 }
6940 bzero((caddr_t)&map.sf_addr_pair[i].
6941 sf_node_wwn, sizeof (la_wwn_t));
6942 bzero((caddr_t)&map.sf_addr_pair[i].
6943 sf_port_wwn, sizeof (la_wwn_t));
6944 map.sf_addr_pair[i].sf_inq_dtype =
6945 DTYPE_UNKNOWN;
6946 }
6947 mutex_exit(&sf->sf_mutex);
6948 if (ddi_copyout((caddr_t)&map, (caddr_t)arg,
6949 sizeof (struct sf_al_map), mode) != 0) {
6950 retval = EFAULT;
6951 goto dun;
6952 }
6953 break;
6954
6955 /*
6956 * handle device control ioctls
6957 */
6958 case DEVCTL_DEVICE_RESET:
6959 if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS) {
6960 retval = EFAULT;
6961 goto dun;
6962 }
6963 if ((ndi_dc_getname(dcp) == NULL) ||
6964 (ndi_dc_getaddr(dcp) == NULL)) {
6965 ndi_dc_freehdl(dcp);
6966 retval = EINVAL;
6967 goto dun;
6968 }
6969 cdip = ndi_devi_find(sf->sf_dip,
6970 ndi_dc_getname(dcp), ndi_dc_getaddr(dcp));
6971 ndi_dc_freehdl(dcp);
6972
6973 if (cdip == NULL) {
6974 retval = ENXIO;
6975 goto dun;
6976 }
6977
6978 if ((target = sf_get_target_from_dip(sf, cdip)) == NULL) {
6979 retval = ENXIO;
6980 goto dun;
6981 }
6982 mutex_enter(&target->sft_mutex);
6983 if (!(target->sft_state & SF_TARGET_INIT_DONE)) {
6984 mutex_exit(&target->sft_mutex);
6985 retval = ENXIO;
6986 goto dun;
6987 }
6988
6989 /* This is ugly */
6990 tran = kmem_zalloc(scsi_hba_tran_size(), KM_SLEEP);
6991 bcopy(target->sft_tran, tran, scsi_hba_tran_size());
6992 mutex_exit(&target->sft_mutex);
6993 ap.a_hba_tran = tran;
6994 ap.a_target = sf_alpa_to_switch[target->sft_al_pa];
6995 if (sf_reset(&ap, RESET_TARGET) == FALSE) {
6996 retval = EIO;
6997 } else {
6998 retval = 0;
6999 }
7000 kmem_free(tran, scsi_hba_tran_size());
7001 goto dun;
7002
7003 case DEVCTL_BUS_QUIESCE:
7004 case DEVCTL_BUS_UNQUIESCE:
7005 retval = ENOTSUP;
7006 goto dun;
7007
7008 case DEVCTL_BUS_RESET:
7009 case DEVCTL_BUS_RESETALL:
7010 sf_force_lip(sf);
7011 break;
7012
7013 default:
7014 retval = ENOTTY;
7015 goto dun;
7016 }
7017
7018 retval = 0; /* success */
7019
7020 dun:
7021 return (retval);
7022 }
7023
7024
7025 /*
7026 * get the target given a DIP
7027 */
7028 static struct sf_target *
7029 sf_get_target_from_dip(struct sf *sf, dev_info_t *dip)
7030 {
7031 int i;
7032 struct sf_target *target;
7033
7034
7035 /* scan each hash queue for the DIP in question */
7036 for (i = 0; i < SF_NUM_HASH_QUEUES; i++) {
7037 target = sf->sf_wwn_lists[i];
7038 while (target != NULL) {
7039 if (target->sft_dip == dip) {
7040 return (target); /* success: target found */
7041 }
7042 target = target->sft_next;
7043 }
7044 }
7045 return (NULL); /* failure: target not found */
7046 }
7047
7048
7049 /*
7050 * called by the transport to get an event cookie
7051 */
7052 static int
7053 sf_bus_get_eventcookie(dev_info_t *dip, dev_info_t *rdip, char *name,
7054 ddi_eventcookie_t *event_cookiep)
7055 {
7056 struct sf *sf;
7057
7058 sf = ddi_get_soft_state(sf_state, ddi_get_instance(dip));
7059 if (sf == NULL) {
7060 /* can't find instance for this device */
7061 return (DDI_FAILURE);
7062 }
7063
7064 return (ndi_event_retrieve_cookie(sf->sf_event_hdl, rdip, name,
7065 event_cookiep, NDI_EVENT_NOPASS));
7066
7067 }
7068
7069
7070 /*
7071 * called by the transport to add an event callback
7072 */
7073 static int
7074 sf_bus_add_eventcall(dev_info_t *dip, dev_info_t *rdip,
7075 ddi_eventcookie_t eventid, void (*callback)(dev_info_t *dip,
7076 ddi_eventcookie_t event, void *arg, void *impl_data), void *arg,
7077 ddi_callback_id_t *cb_id)
7078 {
7079 struct sf *sf;
7080
7081 sf = ddi_get_soft_state(sf_state, ddi_get_instance(dip));
7082 if (sf == NULL) {
7083 /* can't find instance for this device */
7084 return (DDI_FAILURE);
7085 }
7086
7087 return (ndi_event_add_callback(sf->sf_event_hdl, rdip,
7088 eventid, callback, arg, NDI_SLEEP, cb_id));
7089
7090 }
7091
7092
7093 /*
7094 * called by the transport to remove an event callback
7095 */
7096 static int
7097 sf_bus_remove_eventcall(dev_info_t *devi, ddi_callback_id_t cb_id)
7098 {
7099 struct sf *sf;
7100
7101 sf = ddi_get_soft_state(sf_state, ddi_get_instance(devi));
7102 if (sf == NULL) {
7103 /* can't find instance for this device */
7104 return (DDI_FAILURE);
7105 }
7106
7107 return (ndi_event_remove_callback(sf->sf_event_hdl, cb_id));
7108 }
7109
7110
7111 /*
7112 * called by the transport to post an event
7113 */
7114 static int
7115 sf_bus_post_event(dev_info_t *dip, dev_info_t *rdip,
7116 ddi_eventcookie_t eventid, void *impldata)
7117 {
7118 ddi_eventcookie_t remove_cookie, cookie;
7119
7120 /* is this a remove event ?? */
7121 struct sf *sf = ddi_get_soft_state(sf_state, ddi_get_instance(dip));
7122 remove_cookie = ndi_event_tag_to_cookie(sf->sf_event_hdl,
7123 SF_EVENT_TAG_REMOVE);
7124
7125 if (remove_cookie == eventid) {
7126 struct sf_target *target;
7127
7128 /* handle remove event */
7129
7130 if (sf == NULL) {
7131 /* no sf instance for this device */
7132 return (NDI_FAILURE);
7133 }
7134
7135 /* get the target for this event */
7136 if ((target = sf_get_target_from_dip(sf, rdip)) != NULL) {
7137 /*
7138 * clear device info for this target and mark as
7139 * not done
7140 */
7141 mutex_enter(&target->sft_mutex);
7142 target->sft_dip = NULL;
7143 target->sft_state &= ~SF_TARGET_INIT_DONE;
7144 mutex_exit(&target->sft_mutex);
7145 return (NDI_SUCCESS); /* event handled */
7146 }
7147
7148 /* no target for this event */
7149 return (NDI_FAILURE);
7150 }
7151
7152 /* an insertion event */
7153 if (ndi_busop_get_eventcookie(dip, rdip, FCAL_INSERT_EVENT, &cookie)
7154 != NDI_SUCCESS) {
7155 return (NDI_FAILURE);
7156 }
7157
7158 return (ndi_post_event(dip, rdip, cookie, impldata));
7159 }
7160
7161
7162 /*
7163 * the sf hotplug daemon, one thread per sf instance
7164 */
7165 static void
7166 sf_hp_daemon(void *arg)
7167 {
7168 struct sf *sf = (struct sf *)arg;
7169 struct sf_hp_elem *elem;
7170 struct sf_target *target;
7171 int tgt_id;
7172 callb_cpr_t cprinfo;
7173
7174 CALLB_CPR_INIT(&cprinfo, &sf->sf_hp_daemon_mutex,
7175 callb_generic_cpr, "sf_hp_daemon");
7176
7177 mutex_enter(&sf->sf_hp_daemon_mutex);
7178
7179 do {
7180 while (sf->sf_hp_elem_head != NULL) {
7181
7182 /* save ptr to head of list */
7183 elem = sf->sf_hp_elem_head;
7184
7185 /* take element off of list */
7186 if (sf->sf_hp_elem_head == sf->sf_hp_elem_tail) {
7187 /* element only one in list -- list now empty */
7188 sf->sf_hp_elem_head = NULL;
7189 sf->sf_hp_elem_tail = NULL;
7190 } else {
7191 /* remove element from head of list */
7192 sf->sf_hp_elem_head = sf->sf_hp_elem_head->next;
7193 }
7194
7195 mutex_exit(&sf->sf_hp_daemon_mutex);
7196
7197 switch (elem->what) {
7198 case SF_ONLINE:
7199 /* online this target */
7200 target = elem->target;
7201 (void) ndi_devi_online(elem->dip, 0);
7202 (void) ndi_event_retrieve_cookie(
7203 sf->sf_event_hdl,
7204 target->sft_dip, FCAL_INSERT_EVENT,
7205 &sf_insert_eid, NDI_EVENT_NOPASS);
7206 (void) ndi_event_run_callbacks(sf->sf_event_hdl,
7207 target->sft_dip, sf_insert_eid, NULL);
7208 break;
7209 case SF_OFFLINE:
7210 /* offline this target */
7211 target = elem->target;
7212 tgt_id = sf_alpa_to_switch[target->sft_al_pa];
7213 /* don't do NDI_DEVI_REMOVE for now */
7214 if (ndi_devi_offline(elem->dip, 0) !=
7215 NDI_SUCCESS) {
7216 SF_DEBUG(1, (sf, CE_WARN, "target %x, "
7217 "device offline failed", tgt_id));
7218 } else {
7219 SF_DEBUG(1, (sf, CE_NOTE, "target %x, "
7220 "device offline succeeded\n",
7221 tgt_id));
7222 }
7223 break;
7224 }
7225 kmem_free(elem, sizeof (struct sf_hp_elem));
7226 mutex_enter(&sf->sf_hp_daemon_mutex);
7227 }
7228
7229 /* if exit is not already signaled */
7230 if (sf->sf_hp_exit == 0) {
7231 /* wait to be signaled by work or exit */
7232 CALLB_CPR_SAFE_BEGIN(&cprinfo);
7233 cv_wait(&sf->sf_hp_daemon_cv, &sf->sf_hp_daemon_mutex);
7234 CALLB_CPR_SAFE_END(&cprinfo, &sf->sf_hp_daemon_mutex);
7235 }
7236 } while (sf->sf_hp_exit == 0);
7237
7238 /* sf_hp_daemon_mutex is dropped by CALLB_CPR_EXIT */
7239 CALLB_CPR_EXIT(&cprinfo);
7240 thread_exit(); /* no more hotplug thread */
7241 /* NOTREACHED */
7242 }