Print this page
re #13365 rb4427 - pppt "mutex_enter: bad mutex" panic (son of 8564)
re #8564, rb4224 "mutex_enter: bad mutex" panic when under heavy load
re #12375 rb4141 Create ALUA Support on NexentaStor; Failover causes loss of storage
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/io/comstar/port/pppt/pppt_msg.c
+++ new/usr/src/uts/common/io/comstar/port/pppt/pppt_msg.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
|
↓ open down ↓ |
10 lines elided |
↑ open up ↑ |
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 +
21 22 /*
22 23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
23 - * Copyright 2013, Nexenta Systems, Inc. All rights reserved.
24 + * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
24 25 */
25 26
26 27 #include <sys/cpuvar.h>
27 28 #include <sys/types.h>
28 29 #include <sys/conf.h>
29 30 #include <sys/file.h>
30 31 #include <sys/ddi.h>
31 32 #include <sys/sunddi.h>
32 33 #include <sys/modctl.h>
33 34 #include <sys/sysmacros.h>
34 35
35 36 #include <sys/socket.h>
36 37 #include <sys/strsubr.h>
37 38 #include <sys/door.h>
38 39
39 40 #include <sys/stmf.h>
40 41 #include <sys/stmf_ioctl.h>
41 42 #include <sys/portif.h>
42 43
43 44 #include "pppt.h"
44 45
45 46 static void pppt_msg_tgt_register(stmf_ic_msg_t *reg_port);
46 47
47 48 static void pppt_msg_tgt_deregister(stmf_ic_msg_t *msg);
48 49
49 50 static void pppt_msg_session_destroy(stmf_ic_msg_t *msg);
50 51
51 52 static void pppt_msg_scsi_cmd(stmf_ic_msg_t *msg);
52 53
53 54 static void pppt_msg_data_xfer_done(stmf_ic_msg_t *msg);
54 55
55 56 static void pppt_msg_handle_status(stmf_ic_msg_t *msg);
56 57
57 58 void
58 59 pppt_msg_rx(stmf_ic_msg_t *msg)
59 60 {
60 61 switch (msg->icm_msg_type) {
61 62 case STMF_ICM_REGISTER_PROXY_PORT:
62 63 pppt_msg_tgt_register(msg);
63 64 break;
64 65 case STMF_ICM_DEREGISTER_PROXY_PORT:
65 66 pppt_msg_tgt_deregister(msg);
66 67 break;
67 68 case STMF_ICM_SESSION_CREATE:
68 69 pppt_msg_tx_status(msg, STMF_NOT_SUPPORTED);
69 70 stmf_ic_msg_free(msg);
70 71 break;
71 72 case STMF_ICM_SESSION_DESTROY:
72 73 pppt_msg_session_destroy(msg);
73 74 break;
74 75 case STMF_ICM_SCSI_CMD:
75 76 pppt_msg_scsi_cmd(msg);
76 77 break;
77 78 case STMF_ICM_SCSI_DATA_XFER_DONE:
78 79 pppt_msg_data_xfer_done(msg);
79 80 break;
80 81 case STMF_ICM_SCSI_DATA:
81 82 /* Ignore, all proxy data will be immediate for now */
82 83 pppt_msg_tx_status(msg, STMF_NOT_SUPPORTED);
83 84 stmf_ic_msg_free(msg);
84 85 break;
85 86 case STMF_ICM_STATUS:
86 87 pppt_msg_handle_status(msg);
87 88 break;
88 89 default:
89 90 /* Other message types are not allowed */
90 91 ASSERT(0);
91 92 break;
92 93 }
93 94 }
94 95
95 96 void
96 97 pppt_msg_tx_status(stmf_ic_msg_t *orig_msg, stmf_status_t status)
97 98 {
98 99 stmf_ic_msg_t *msg;
99 100
100 101 /*
101 102 * If TX of status fails it should be treated the same as a loss of
102 103 * connection. We expect the remote node to handle it.
103 104 */
104 105 msg = stmf_ic_status_msg_alloc(status, orig_msg->icm_msg_type,
105 106 orig_msg->icm_msgid);
106 107
107 108 if (msg != NULL) {
108 109 (void) stmf_ic_tx_msg(msg);
109 110 }
110 111 }
111 112
112 113 static void
113 114 pppt_msg_tgt_register(stmf_ic_msg_t *msg)
114 115 {
115 116 stmf_ic_reg_port_msg_t *reg_port;
116 117 pppt_tgt_t *result;
117 118 stmf_status_t stmf_status;
118 119
119 120 reg_port = msg->icm_msg;
120 121
121 122 PPPT_GLOBAL_LOCK();
122 123 if (pppt_global.global_svc_state != PSS_ENABLED) {
123 124 stmf_status = STMF_FAILURE;
124 125 PPPT_INC_STAT(es_tgt_reg_svc_disabled);
125 126 goto pppt_register_tgt_done;
126 127 }
127 128
128 129 /*
129 130 * For now we assume that the marshall/unmarshall code is responsible
130 131 * for validating the message length and ensuring the resulting
131 132 * request structure is self consistent. Make sure this
132 133 * target doesn't already exist.
133 134 */
134 135 if ((result = pppt_tgt_lookup_locked(reg_port->icrp_port_id)) != NULL) {
135 136 stmf_status = STMF_ALREADY;
136 137 PPPT_INC_STAT(es_tgt_reg_duplicate);
137 138 goto pppt_register_tgt_done;
138 139 }
139 140
140 141 result = pppt_tgt_create(reg_port, &stmf_status);
141 142
142 143 if (result == NULL) {
143 144 stmf_status = STMF_TARGET_FAILURE;
144 145 PPPT_INC_STAT(es_tgt_reg_create_fail);
145 146 goto pppt_register_tgt_done;
146 147 }
147 148
148 149 avl_add(&pppt_global.global_target_list, result);
149 150
150 151 stmf_status = STMF_SUCCESS;
151 152
152 153 pppt_register_tgt_done:
153 154 PPPT_GLOBAL_UNLOCK();
154 155 pppt_msg_tx_status(msg, stmf_status);
155 156 stmf_ic_msg_free(msg);
156 157 }
157 158
158 159 static void
159 160 pppt_msg_tgt_deregister(stmf_ic_msg_t *msg)
160 161 {
161 162 stmf_ic_dereg_port_msg_t *dereg_port;
162 163 stmf_status_t stmf_status;
163 164 pppt_tgt_t *tgt;
164 165
165 166 PPPT_GLOBAL_LOCK();
166 167 if (pppt_global.global_svc_state != PSS_ENABLED) {
167 168 PPPT_GLOBAL_UNLOCK();
168 169 stmf_status = STMF_FAILURE;
169 170 PPPT_INC_STAT(es_tgt_dereg_svc_disabled);
170 171 goto pppt_deregister_tgt_done;
171 172 }
172 173
173 174 dereg_port = msg->icm_msg;
174 175
175 176 /* Lookup target */
176 177 if ((tgt = pppt_tgt_lookup_locked(dereg_port->icdp_port_id)) == NULL) {
177 178 PPPT_GLOBAL_UNLOCK();
178 179 stmf_status = STMF_NOT_FOUND;
179 180 PPPT_INC_STAT(es_tgt_dereg_not_found);
180 181 goto pppt_deregister_tgt_done;
181 182 }
182 183 avl_remove(&pppt_global.global_target_list, tgt);
183 184 pppt_tgt_async_delete(tgt);
184 185
185 186 PPPT_GLOBAL_UNLOCK();
186 187
187 188 /* Wait for delete to complete */
188 189 mutex_enter(&tgt->target_mutex);
189 190 while ((tgt->target_refcount > 0) ||
190 191 (tgt->target_state != TS_DELETING)) {
191 192 cv_wait(&tgt->target_cv, &tgt->target_mutex);
192 193 }
193 194 mutex_exit(&tgt->target_mutex);
194 195
195 196 pppt_tgt_destroy(tgt);
196 197 stmf_status = STMF_SUCCESS;
197 198
198 199 pppt_deregister_tgt_done:
199 200 pppt_msg_tx_status(msg, stmf_status);
200 201 stmf_ic_msg_free(msg);
201 202 }
202 203
203 204 static void
204 205 pppt_msg_session_destroy(stmf_ic_msg_t *msg)
205 206 {
206 207 stmf_ic_session_create_destroy_msg_t *sess_destroy;
207 208 pppt_tgt_t *tgt;
208 209 pppt_sess_t *ps;
209 210
210 211 sess_destroy = msg->icm_msg;
211 212
212 213 PPPT_GLOBAL_LOCK();
213 214
214 215 /*
215 216 * Look for existing session for this ID
216 217 */
217 218 ps = pppt_sess_lookup_locked(sess_destroy->icscd_session_id,
218 219 sess_destroy->icscd_tgt_devid, sess_destroy->icscd_rport);
219 220
220 221 if (ps == NULL) {
221 222 PPPT_GLOBAL_UNLOCK();
222 223 stmf_ic_msg_free(msg);
223 224 PPPT_INC_STAT(es_sess_destroy_no_session);
224 225 return;
225 226 }
226 227
227 228 tgt = ps->ps_target;
228 229
229 230 mutex_enter(&tgt->target_mutex);
230 231 mutex_enter(&ps->ps_mutex);
231 232
232 233 /* Release the reference from the lookup */
233 234 pppt_sess_rele_locked(ps);
234 235
235 236 /* Make sure another thread is not already closing the session */
236 237 if (!ps->ps_closed) {
237 238 /* Found matching open session, quiesce... */
238 239 pppt_sess_close_locked(ps);
239 240 }
240 241 mutex_exit(&ps->ps_mutex);
241 242 mutex_exit(&tgt->target_mutex);
242 243 PPPT_GLOBAL_UNLOCK();
243 244
244 245 stmf_ic_msg_free(msg);
245 246 }
246 247
247 248 static void
248 249 pppt_msg_scsi_cmd(stmf_ic_msg_t *msg)
249 250 {
250 251 pppt_sess_t *pppt_sess;
251 252 pppt_buf_t *pbuf;
252 253 stmf_ic_scsi_cmd_msg_t *scmd;
253 254 pppt_task_t *ptask;
254 255 scsi_task_t *task;
255 256 pppt_status_t pppt_status;
256 257 stmf_local_port_t *lport;
257 258 stmf_scsi_session_t *stmf_sess;
258 259 stmf_status_t stmf_status;
259 260
260 261 /*
261 262 * Get a task context
262 263 */
263 264 ptask = pppt_task_alloc();
264 265 if (ptask == NULL) {
265 266 /*
266 267 * We must be very low on memory. Just free the message
267 268 * and let the command timeout.
268 269 */
269 270 stmf_ic_msg_free(msg);
270 271 PPPT_INC_STAT(es_scmd_ptask_alloc_fail);
271 272 return;
272 273 }
273 274
274 275 scmd = msg->icm_msg;
275 276
276 277 /*
277 278 * Session are created implicitly on the first use of an
278 279 * IT nexus
279 280 */
280 281 pppt_sess = pppt_sess_lookup_create(scmd->icsc_tgt_devid,
281 282 scmd->icsc_ini_devid, scmd->icsc_rport,
282 283 scmd->icsc_session_id, &stmf_status);
283 284 if (pppt_sess == NULL) {
284 285 pppt_task_free(ptask);
285 286 pppt_msg_tx_status(msg, stmf_status);
286 287 stmf_ic_msg_free(msg);
287 288 PPPT_INC_STAT(es_scmd_sess_create_fail);
288 289 return;
289 290 }
290 291
291 292 ptask->pt_sess = pppt_sess;
292 293 ptask->pt_task_id = scmd->icsc_task_msgid;
293 294 stmf_sess = pppt_sess->ps_stmf_sess;
294 295 lport = stmf_sess->ss_lport;
295 296
296 297 /*
297 298 * Add task to our internal task set.
298 299 */
299 300 pppt_status = pppt_task_start(ptask);
300 301
301 302 if (pppt_status != 0) {
302 303 /* Release hold from pppt_sess_lookup_create() */
303 304 PPPT_LOG(CE_WARN, "Duplicate taskid from remote node 0x%llx",
304 305 (longlong_t)scmd->icsc_task_msgid);
305 306 pppt_task_free(ptask);
306 307 pppt_sess_rele(pppt_sess);
307 308 pppt_msg_tx_status(msg, STMF_ALREADY);
308 309 stmf_ic_msg_free(msg);
309 310 PPPT_INC_STAT(es_scmd_dup_task_count);
310 311 return;
311 312 }
312 313
313 314 /*
314 315 * Allocate STMF task context
315 316 */
316 317 ptask->pt_stmf_task = stmf_task_alloc(lport, stmf_sess,
317 318 scmd->icsc_task_lun_no,
318 319 scmd->icsc_task_cdb_length, 0);
319 320 if (ptask->pt_stmf_task == NULL) {
320 321 /* NOTE: pppt_task_done() will free ptask. */
321 322 (void) pppt_task_done(ptask);
322 323 pppt_sess_rele(pppt_sess);
323 324 pppt_msg_tx_status(msg, STMF_ALLOC_FAILURE);
|
↓ open down ↓ |
290 lines elided |
↑ open up ↑ |
324 325 stmf_ic_msg_free(msg);
325 326 PPPT_INC_STAT(es_scmd_stask_alloc_fail);
326 327 return;
327 328 }
328 329
329 330 task = ptask->pt_stmf_task;
330 331 /* task_port_private reference is a real reference. */
331 332 (void) pppt_task_hold(ptask);
332 333 task->task_port_private = ptask;
333 334 task->task_flags = scmd->icsc_task_flags;
334 - task->task_additional_flags = 0;
335 + task->task_additional_flags = TASK_AF_PPPT_TASK;
335 336 task->task_priority = 0;
336 337
337 338 /*
338 339 * Set task->task_mgmt_function to TM_NONE for a normal SCSI task
339 340 * or one of these values for a task management command:
340 341 *
341 342 * TM_ABORT_TASK ***
342 343 * TM_ABORT_TASK_SET
343 344 * TM_CLEAR_ACA
344 345 * TM_CLEAR_TASK_SET
345 346 * TM_LUN_RESET
346 347 * TM_TARGET_WARM_RESET
347 348 * TM_TARGET_COLD_RESET
348 349 *
349 350 * *** Note that STMF does not currently support TM_ABORT_TASK so
350 351 * port providers must implement this command on their own
351 352 * (e.g. lookup the desired task and call stmf_abort).
352 353 */
353 354 task->task_mgmt_function = scmd->icsc_task_mgmt_function;
354 355
355 356 task->task_max_nbufs = 1; /* Don't allow parallel xfers */
356 357 task->task_cmd_seq_no = msg->icm_msgid;
357 358 task->task_expected_xfer_length =
358 359 scmd->icsc_task_expected_xfer_length;
359 360
360 361 if (scmd->icsc_task_cdb_length) {
361 362 bcopy(scmd->icsc_task_cdb, task->task_cdb,
362 363 scmd->icsc_task_cdb_length);
363 364 }
364 365 bcopy(scmd->icsc_lun_id, ptask->pt_lun_id, 16);
365 366
366 367 if (scmd->icsc_immed_data_len) {
367 368 pbuf = ptask->pt_immed_data;
368 369 pbuf->pbuf_immed_msg = msg;
369 370 pbuf->pbuf_stmf_buf->db_data_size = scmd->icsc_immed_data_len;
370 371 pbuf->pbuf_stmf_buf->db_buf_size = scmd->icsc_immed_data_len;
371 372 pbuf->pbuf_stmf_buf->db_relative_offset = 0;
372 373 pbuf->pbuf_stmf_buf->db_sglist[0].seg_length =
373 374 scmd->icsc_immed_data_len;
374 375 pbuf->pbuf_stmf_buf->db_sglist[0].seg_addr =
375 376 scmd->icsc_immed_data;
376 377
377 378 stmf_post_task(task, pbuf->pbuf_stmf_buf);
378 379 } else {
379 380 stmf_post_task(task, NULL);
380 381 stmf_ic_msg_free(msg);
381 382 }
382 383 }
383 384
384 385 static void
385 386 pppt_msg_data_xfer_done(stmf_ic_msg_t *msg)
386 387 {
387 388 pppt_task_t *pppt_task;
388 389 stmf_ic_scsi_data_xfer_done_msg_t *data_xfer_done;
389 390
390 391 data_xfer_done = msg->icm_msg;
391 392
392 393 /*
393 394 * Find task
394 395 */
395 396 pppt_task = pppt_task_lookup(data_xfer_done->icsx_task_msgid);
396 397
397 398 /* If we found one, complete the transfer */
398 399 if (pppt_task != NULL) {
399 400 pppt_xfer_read_complete(pppt_task, data_xfer_done->icsx_status);
400 401 }
401 402
402 403 stmf_ic_msg_free(msg);
403 404 }
404 405
405 406 static void
406 407 pppt_msg_handle_status(stmf_ic_msg_t *msg)
407 408 {
408 409 /* Don't care for now */
409 410 stmf_ic_msg_free(msg);
410 411 }
|
↓ open down ↓ |
66 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX