aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libfc/fc_exch.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/libfc/fc_exch.c')
-rw-r--r--drivers/scsi/libfc/fc_exch.c111
1 files changed, 82 insertions, 29 deletions
diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c
index d21367d3305f..28231badd9e6 100644
--- a/drivers/scsi/libfc/fc_exch.c
+++ b/drivers/scsi/libfc/fc_exch.c
@@ -38,7 +38,7 @@ u16 fc_cpu_mask; /* cpu mask for possible cpus */
38EXPORT_SYMBOL(fc_cpu_mask); 38EXPORT_SYMBOL(fc_cpu_mask);
39static u16 fc_cpu_order; /* 2's power to represent total possible cpus */ 39static u16 fc_cpu_order; /* 2's power to represent total possible cpus */
40static struct kmem_cache *fc_em_cachep; /* cache for exchanges */ 40static struct kmem_cache *fc_em_cachep; /* cache for exchanges */
41struct workqueue_struct *fc_exch_workqueue; 41static struct workqueue_struct *fc_exch_workqueue;
42 42
43/* 43/*
44 * Structure and function definitions for managing Fibre Channel Exchanges 44 * Structure and function definitions for managing Fibre Channel Exchanges
@@ -558,6 +558,22 @@ static struct fc_seq *fc_seq_start_next(struct fc_seq *sp)
558 return sp; 558 return sp;
559} 559}
560 560
561/*
562 * Set the response handler for the exchange associated with a sequence.
563 */
564static void fc_seq_set_resp(struct fc_seq *sp,
565 void (*resp)(struct fc_seq *, struct fc_frame *,
566 void *),
567 void *arg)
568{
569 struct fc_exch *ep = fc_seq_exch(sp);
570
571 spin_lock_bh(&ep->ex_lock);
572 ep->resp = resp;
573 ep->arg = arg;
574 spin_unlock_bh(&ep->ex_lock);
575}
576
561/** 577/**
562 * fc_seq_exch_abort() - Abort an exchange and sequence 578 * fc_seq_exch_abort() - Abort an exchange and sequence
563 * @req_sp: The sequence to be aborted 579 * @req_sp: The sequence to be aborted
@@ -650,13 +666,10 @@ static void fc_exch_timeout(struct work_struct *work)
650 if (e_stat & ESB_ST_ABNORMAL) 666 if (e_stat & ESB_ST_ABNORMAL)
651 rc = fc_exch_done_locked(ep); 667 rc = fc_exch_done_locked(ep);
652 spin_unlock_bh(&ep->ex_lock); 668 spin_unlock_bh(&ep->ex_lock);
669 if (!rc)
670 fc_exch_delete(ep);
653 if (resp) 671 if (resp)
654 resp(sp, ERR_PTR(-FC_EX_TIMEOUT), arg); 672 resp(sp, ERR_PTR(-FC_EX_TIMEOUT), arg);
655 if (!rc) {
656 /* delete the exchange if it's already being aborted */
657 fc_exch_delete(ep);
658 return;
659 }
660 fc_seq_exch_abort(sp, 2 * ep->r_a_tov); 673 fc_seq_exch_abort(sp, 2 * ep->r_a_tov);
661 goto done; 674 goto done;
662 } 675 }
@@ -1266,6 +1279,8 @@ free:
1266 * @fp: The request frame 1279 * @fp: The request frame
1267 * 1280 *
1268 * On success, the sequence pointer will be returned and also in fr_seq(@fp). 1281 * On success, the sequence pointer will be returned and also in fr_seq(@fp).
1282 * A reference will be held on the exchange/sequence for the caller, which
1283 * must call fc_seq_release().
1269 */ 1284 */
1270static struct fc_seq *fc_seq_assign(struct fc_lport *lport, struct fc_frame *fp) 1285static struct fc_seq *fc_seq_assign(struct fc_lport *lport, struct fc_frame *fp)
1271{ 1286{
@@ -1283,6 +1298,15 @@ static struct fc_seq *fc_seq_assign(struct fc_lport *lport, struct fc_frame *fp)
1283} 1298}
1284 1299
1285/** 1300/**
1301 * fc_seq_release() - Release the hold
1302 * @sp: The sequence.
1303 */
1304static void fc_seq_release(struct fc_seq *sp)
1305{
1306 fc_exch_release(fc_seq_exch(sp));
1307}
1308
1309/**
1286 * fc_exch_recv_req() - Handler for an incoming request 1310 * fc_exch_recv_req() - Handler for an incoming request
1287 * @lport: The local port that received the request 1311 * @lport: The local port that received the request
1288 * @mp: The EM that the exchange is on 1312 * @mp: The EM that the exchange is on
@@ -2151,6 +2175,7 @@ err:
2151 fc_exch_mgr_del(ema); 2175 fc_exch_mgr_del(ema);
2152 return -ENOMEM; 2176 return -ENOMEM;
2153} 2177}
2178EXPORT_SYMBOL(fc_exch_mgr_list_clone);
2154 2179
2155/** 2180/**
2156 * fc_exch_mgr_alloc() - Allocate an exchange manager 2181 * fc_exch_mgr_alloc() - Allocate an exchange manager
@@ -2254,16 +2279,45 @@ void fc_exch_mgr_free(struct fc_lport *lport)
2254EXPORT_SYMBOL(fc_exch_mgr_free); 2279EXPORT_SYMBOL(fc_exch_mgr_free);
2255 2280
2256/** 2281/**
2282 * fc_find_ema() - Lookup and return appropriate Exchange Manager Anchor depending
2283 * upon 'xid'.
2284 * @f_ctl: f_ctl
2285 * @lport: The local port the frame was received on
2286 * @fh: The received frame header
2287 */
2288static struct fc_exch_mgr_anchor *fc_find_ema(u32 f_ctl,
2289 struct fc_lport *lport,
2290 struct fc_frame_header *fh)
2291{
2292 struct fc_exch_mgr_anchor *ema;
2293 u16 xid;
2294
2295 if (f_ctl & FC_FC_EX_CTX)
2296 xid = ntohs(fh->fh_ox_id);
2297 else {
2298 xid = ntohs(fh->fh_rx_id);
2299 if (xid == FC_XID_UNKNOWN)
2300 return list_entry(lport->ema_list.prev,
2301 typeof(*ema), ema_list);
2302 }
2303
2304 list_for_each_entry(ema, &lport->ema_list, ema_list) {
2305 if ((xid >= ema->mp->min_xid) &&
2306 (xid <= ema->mp->max_xid))
2307 return ema;
2308 }
2309 return NULL;
2310}
2311/**
2257 * fc_exch_recv() - Handler for received frames 2312 * fc_exch_recv() - Handler for received frames
2258 * @lport: The local port the frame was received on 2313 * @lport: The local port the frame was received on
2259 * @fp: The received frame 2314 * @fp: The received frame
2260 */ 2315 */
2261void fc_exch_recv(struct fc_lport *lport, struct fc_frame *fp) 2316void fc_exch_recv(struct fc_lport *lport, struct fc_frame *fp)
2262{ 2317{
2263 struct fc_frame_header *fh = fc_frame_header_get(fp); 2318 struct fc_frame_header *fh = fc_frame_header_get(fp);
2264 struct fc_exch_mgr_anchor *ema; 2319 struct fc_exch_mgr_anchor *ema;
2265 u32 f_ctl, found = 0; 2320 u32 f_ctl;
2266 u16 oxid;
2267 2321
2268 /* lport lock ? */ 2322 /* lport lock ? */
2269 if (!lport || lport->state == LPORT_ST_DISABLED) { 2323 if (!lport || lport->state == LPORT_ST_DISABLED) {
@@ -2274,24 +2328,17 @@ void fc_exch_recv(struct fc_lport *lport, struct fc_frame *fp)
2274 } 2328 }
2275 2329
2276 f_ctl = ntoh24(fh->fh_f_ctl); 2330 f_ctl = ntoh24(fh->fh_f_ctl);
2277 oxid = ntohs(fh->fh_ox_id); 2331 ema = fc_find_ema(f_ctl, lport, fh);
2278 if (f_ctl & FC_FC_EX_CTX) { 2332 if (!ema) {
2279 list_for_each_entry(ema, &lport->ema_list, ema_list) { 2333 FC_LPORT_DBG(lport, "Unable to find Exchange Manager Anchor,"
2280 if ((oxid >= ema->mp->min_xid) && 2334 "fc_ctl <0x%x>, xid <0x%x>\n",
2281 (oxid <= ema->mp->max_xid)) { 2335 f_ctl,
2282 found = 1; 2336 (f_ctl & FC_FC_EX_CTX) ?
2283 break; 2337 ntohs(fh->fh_ox_id) :
2284 } 2338 ntohs(fh->fh_rx_id));
2285 } 2339 fc_frame_free(fp);
2286 2340 return;
2287 if (!found) { 2341 }
2288 FC_LPORT_DBG(lport, "Received response for out "
2289 "of range oxid:%hx\n", oxid);
2290 fc_frame_free(fp);
2291 return;
2292 }
2293 } else
2294 ema = list_entry(lport->ema_list.prev, typeof(*ema), ema_list);
2295 2342
2296 /* 2343 /*
2297 * If frame is marked invalid, just drop it. 2344 * If frame is marked invalid, just drop it.
@@ -2329,6 +2376,9 @@ int fc_exch_init(struct fc_lport *lport)
2329 if (!lport->tt.seq_start_next) 2376 if (!lport->tt.seq_start_next)
2330 lport->tt.seq_start_next = fc_seq_start_next; 2377 lport->tt.seq_start_next = fc_seq_start_next;
2331 2378
2379 if (!lport->tt.seq_set_resp)
2380 lport->tt.seq_set_resp = fc_seq_set_resp;
2381
2332 if (!lport->tt.exch_seq_send) 2382 if (!lport->tt.exch_seq_send)
2333 lport->tt.exch_seq_send = fc_exch_seq_send; 2383 lport->tt.exch_seq_send = fc_exch_seq_send;
2334 2384
@@ -2350,6 +2400,9 @@ int fc_exch_init(struct fc_lport *lport)
2350 if (!lport->tt.seq_assign) 2400 if (!lport->tt.seq_assign)
2351 lport->tt.seq_assign = fc_seq_assign; 2401 lport->tt.seq_assign = fc_seq_assign;
2352 2402
2403 if (!lport->tt.seq_release)
2404 lport->tt.seq_release = fc_seq_release;
2405
2353 return 0; 2406 return 0;
2354} 2407}
2355EXPORT_SYMBOL(fc_exch_init); 2408EXPORT_SYMBOL(fc_exch_init);
@@ -2357,7 +2410,7 @@ EXPORT_SYMBOL(fc_exch_init);
2357/** 2410/**
2358 * fc_setup_exch_mgr() - Setup an exchange manager 2411 * fc_setup_exch_mgr() - Setup an exchange manager
2359 */ 2412 */
2360int fc_setup_exch_mgr() 2413int fc_setup_exch_mgr(void)
2361{ 2414{
2362 fc_em_cachep = kmem_cache_create("libfc_em", sizeof(struct fc_exch), 2415 fc_em_cachep = kmem_cache_create("libfc_em", sizeof(struct fc_exch),
2363 0, SLAB_HWCACHE_ALIGN, NULL); 2416 0, SLAB_HWCACHE_ALIGN, NULL);
@@ -2395,7 +2448,7 @@ int fc_setup_exch_mgr()
2395/** 2448/**
2396 * fc_destroy_exch_mgr() - Destroy an exchange manager 2449 * fc_destroy_exch_mgr() - Destroy an exchange manager
2397 */ 2450 */
2398void fc_destroy_exch_mgr() 2451void fc_destroy_exch_mgr(void)
2399{ 2452{
2400 destroy_workqueue(fc_exch_workqueue); 2453 destroy_workqueue(fc_exch_workqueue);
2401 kmem_cache_destroy(fc_em_cachep); 2454 kmem_cache_destroy(fc_em_cachep);