~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to drivers/scsi/libfc/fc_libfc.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright(c) 2009 Intel Corporation. All rights reserved.
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or modify it
 
5
 * under the terms and conditions of the GNU General Public License,
 
6
 * version 2, as published by the Free Software Foundation.
 
7
 *
 
8
 * This program is distributed in the hope it will be useful, but WITHOUT
 
9
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
10
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 
11
 * more details.
 
12
 *
 
13
 * You should have received a copy of the GNU General Public License along with
 
14
 * this program; if not, write to the Free Software Foundation, Inc.,
 
15
 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 
16
 *
 
17
 * Maintained at www.Open-FCoE.org
 
18
 */
 
19
 
 
20
#include <linux/kernel.h>
 
21
#include <linux/types.h>
 
22
#include <linux/scatterlist.h>
 
23
#include <linux/crc32.h>
 
24
#include <linux/module.h>
 
25
 
 
26
#include <scsi/libfc.h>
 
27
#include <scsi/fc_encode.h>
 
28
 
 
29
#include "fc_libfc.h"
 
30
 
 
31
MODULE_AUTHOR("Open-FCoE.org");
 
32
MODULE_DESCRIPTION("libfc");
 
33
MODULE_LICENSE("GPL v2");
 
34
 
 
35
unsigned int fc_debug_logging;
 
36
module_param_named(debug_logging, fc_debug_logging, int, S_IRUGO|S_IWUSR);
 
37
MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels");
 
38
 
 
39
DEFINE_MUTEX(fc_prov_mutex);
 
40
static LIST_HEAD(fc_local_ports);
 
41
struct blocking_notifier_head fc_lport_notifier_head =
 
42
                BLOCKING_NOTIFIER_INIT(fc_lport_notifier_head);
 
43
EXPORT_SYMBOL(fc_lport_notifier_head);
 
44
 
 
45
/*
 
46
 * Providers which primarily send requests and PRLIs.
 
47
 */
 
48
struct fc4_prov *fc_active_prov[FC_FC4_PROV_SIZE] = {
 
49
        [0] = &fc_rport_t0_prov,
 
50
        [FC_TYPE_FCP] = &fc_rport_fcp_init,
 
51
};
 
52
 
 
53
/*
 
54
 * Providers which receive requests.
 
55
 */
 
56
struct fc4_prov *fc_passive_prov[FC_FC4_PROV_SIZE] = {
 
57
        [FC_TYPE_ELS] = &fc_lport_els_prov,
 
58
};
 
59
 
 
60
/**
 
61
 * libfc_init() - Initialize libfc.ko
 
62
 */
 
63
static int __init libfc_init(void)
 
64
{
 
65
        int rc = 0;
 
66
 
 
67
        rc = fc_setup_fcp();
 
68
        if (rc)
 
69
                return rc;
 
70
 
 
71
        rc = fc_setup_exch_mgr();
 
72
        if (rc)
 
73
                goto destroy_pkt_cache;
 
74
 
 
75
        rc = fc_setup_rport();
 
76
        if (rc)
 
77
                goto destroy_em;
 
78
 
 
79
        return rc;
 
80
destroy_em:
 
81
        fc_destroy_exch_mgr();
 
82
destroy_pkt_cache:
 
83
        fc_destroy_fcp();
 
84
        return rc;
 
85
}
 
86
module_init(libfc_init);
 
87
 
 
88
/**
 
89
 * libfc_exit() - Tear down libfc.ko
 
90
 */
 
91
static void __exit libfc_exit(void)
 
92
{
 
93
        fc_destroy_fcp();
 
94
        fc_destroy_exch_mgr();
 
95
        fc_destroy_rport();
 
96
}
 
97
module_exit(libfc_exit);
 
98
 
 
99
/**
 
100
 * fc_copy_buffer_to_sglist() - This routine copies the data of a buffer
 
101
 *                              into a scatter-gather list (SG list).
 
102
 *
 
103
 * @buf: pointer to the data buffer.
 
104
 * @len: the byte-length of the data buffer.
 
105
 * @sg: pointer to the pointer of the SG list.
 
106
 * @nents: pointer to the remaining number of entries in the SG list.
 
107
 * @offset: pointer to the current offset in the SG list.
 
108
 * @km_type: dedicated page table slot type for kmap_atomic.
 
109
 * @crc: pointer to the 32-bit crc value.
 
110
 *       If crc is NULL, CRC is not calculated.
 
111
 */
 
112
u32 fc_copy_buffer_to_sglist(void *buf, size_t len,
 
113
                             struct scatterlist *sg,
 
114
                             u32 *nents, size_t *offset,
 
115
                             enum km_type km_type, u32 *crc)
 
116
{
 
117
        size_t remaining = len;
 
118
        u32 copy_len = 0;
 
119
 
 
120
        while (remaining > 0 && sg) {
 
121
                size_t off, sg_bytes;
 
122
                void *page_addr;
 
123
 
 
124
                if (*offset >= sg->length) {
 
125
                        /*
 
126
                         * Check for end and drop resources
 
127
                         * from the last iteration.
 
128
                         */
 
129
                        if (!(*nents))
 
130
                                break;
 
131
                        --(*nents);
 
132
                        *offset -= sg->length;
 
133
                        sg = sg_next(sg);
 
134
                        continue;
 
135
                }
 
136
                sg_bytes = min(remaining, sg->length - *offset);
 
137
 
 
138
                /*
 
139
                 * The scatterlist item may be bigger than PAGE_SIZE,
 
140
                 * but we are limited to mapping PAGE_SIZE at a time.
 
141
                 */
 
142
                off = *offset + sg->offset;
 
143
                sg_bytes = min(sg_bytes,
 
144
                               (size_t)(PAGE_SIZE - (off & ~PAGE_MASK)));
 
145
                page_addr = kmap_atomic(sg_page(sg) + (off >> PAGE_SHIFT),
 
146
                                        km_type);
 
147
                if (crc)
 
148
                        *crc = crc32(*crc, buf, sg_bytes);
 
149
                memcpy((char *)page_addr + (off & ~PAGE_MASK), buf, sg_bytes);
 
150
                kunmap_atomic(page_addr, km_type);
 
151
                buf += sg_bytes;
 
152
                *offset += sg_bytes;
 
153
                remaining -= sg_bytes;
 
154
                copy_len += sg_bytes;
 
155
        }
 
156
        return copy_len;
 
157
}
 
158
 
 
159
/**
 
160
 * fc_fill_hdr() -  fill FC header fields based on request
 
161
 * @fp: reply frame containing header to be filled in
 
162
 * @in_fp: request frame containing header to use in filling in reply
 
163
 * @r_ctl: R_CTL value for header
 
164
 * @f_ctl: F_CTL value for header, with 0 pad
 
165
 * @seq_cnt: sequence count for the header, ignored if frame has a sequence
 
166
 * @parm_offset: parameter / offset value
 
167
 */
 
168
void fc_fill_hdr(struct fc_frame *fp, const struct fc_frame *in_fp,
 
169
                 enum fc_rctl r_ctl, u32 f_ctl, u16 seq_cnt, u32 parm_offset)
 
170
{
 
171
        struct fc_frame_header *fh;
 
172
        struct fc_frame_header *in_fh;
 
173
        struct fc_seq *sp;
 
174
        u32 fill;
 
175
 
 
176
        fh = __fc_frame_header_get(fp);
 
177
        in_fh = __fc_frame_header_get(in_fp);
 
178
 
 
179
        if (f_ctl & FC_FC_END_SEQ) {
 
180
                fill = -fr_len(fp) & 3;
 
181
                if (fill) {
 
182
                        /* TODO, this may be a problem with fragmented skb */
 
183
                        memset(skb_put(fp_skb(fp), fill), 0, fill);
 
184
                        f_ctl |= fill;
 
185
                }
 
186
                fr_eof(fp) = FC_EOF_T;
 
187
        } else {
 
188
                WARN_ON(fr_len(fp) % 4 != 0);   /* no pad to non last frame */
 
189
                fr_eof(fp) = FC_EOF_N;
 
190
        }
 
191
 
 
192
        fh->fh_r_ctl = r_ctl;
 
193
        memcpy(fh->fh_d_id, in_fh->fh_s_id, sizeof(fh->fh_d_id));
 
194
        memcpy(fh->fh_s_id, in_fh->fh_d_id, sizeof(fh->fh_s_id));
 
195
        fh->fh_type = in_fh->fh_type;
 
196
        hton24(fh->fh_f_ctl, f_ctl);
 
197
        fh->fh_ox_id = in_fh->fh_ox_id;
 
198
        fh->fh_rx_id = in_fh->fh_rx_id;
 
199
        fh->fh_cs_ctl = 0;
 
200
        fh->fh_df_ctl = 0;
 
201
        fh->fh_parm_offset = htonl(parm_offset);
 
202
 
 
203
        sp = fr_seq(in_fp);
 
204
        if (sp) {
 
205
                fr_seq(fp) = sp;
 
206
                fh->fh_seq_id = sp->id;
 
207
                seq_cnt = sp->cnt;
 
208
        } else {
 
209
                fh->fh_seq_id = 0;
 
210
        }
 
211
        fh->fh_seq_cnt = ntohs(seq_cnt);
 
212
        fr_sof(fp) = seq_cnt ? FC_SOF_N3 : FC_SOF_I3;
 
213
        fr_encaps(fp) = fr_encaps(in_fp);
 
214
}
 
215
EXPORT_SYMBOL(fc_fill_hdr);
 
216
 
 
217
/**
 
218
 * fc_fill_reply_hdr() -  fill FC reply header fields based on request
 
219
 * @fp: reply frame containing header to be filled in
 
220
 * @in_fp: request frame containing header to use in filling in reply
 
221
 * @r_ctl: R_CTL value for reply
 
222
 * @parm_offset: parameter / offset value
 
223
 */
 
224
void fc_fill_reply_hdr(struct fc_frame *fp, const struct fc_frame *in_fp,
 
225
                       enum fc_rctl r_ctl, u32 parm_offset)
 
226
{
 
227
        struct fc_seq *sp;
 
228
 
 
229
        sp = fr_seq(in_fp);
 
230
        if (sp)
 
231
                fr_seq(fp) = fr_dev(in_fp)->tt.seq_start_next(sp);
 
232
        fc_fill_hdr(fp, in_fp, r_ctl, FC_FCTL_RESP, 0, parm_offset);
 
233
}
 
234
EXPORT_SYMBOL(fc_fill_reply_hdr);
 
235
 
 
236
/**
 
237
 * fc_fc4_conf_lport_params() - Modify "service_params" of specified lport
 
238
 * if there is service provider (target provider) registered with libfc
 
239
 * for specified "fc_ft_type"
 
240
 * @lport: Local port which service_params needs to be modified
 
241
 * @type: FC-4 type, such as FC_TYPE_FCP
 
242
 */
 
243
void fc_fc4_conf_lport_params(struct fc_lport *lport, enum fc_fh_type type)
 
244
{
 
245
        struct fc4_prov *prov_entry;
 
246
        BUG_ON(type >= FC_FC4_PROV_SIZE);
 
247
        BUG_ON(!lport);
 
248
        prov_entry = fc_passive_prov[type];
 
249
        if (type == FC_TYPE_FCP) {
 
250
                if (prov_entry && prov_entry->recv)
 
251
                        lport->service_params |= FCP_SPPF_TARG_FCN;
 
252
        }
 
253
}
 
254
 
 
255
void fc_lport_iterate(void (*notify)(struct fc_lport *, void *), void *arg)
 
256
{
 
257
        struct fc_lport *lport;
 
258
 
 
259
        mutex_lock(&fc_prov_mutex);
 
260
        list_for_each_entry(lport, &fc_local_ports, lport_list)
 
261
                notify(lport, arg);
 
262
        mutex_unlock(&fc_prov_mutex);
 
263
}
 
264
EXPORT_SYMBOL(fc_lport_iterate);
 
265
 
 
266
/**
 
267
 * fc_fc4_register_provider() - register FC-4 upper-level provider.
 
268
 * @type: FC-4 type, such as FC_TYPE_FCP
 
269
 * @prov: structure describing provider including ops vector.
 
270
 *
 
271
 * Returns 0 on success, negative error otherwise.
 
272
 */
 
273
int fc_fc4_register_provider(enum fc_fh_type type, struct fc4_prov *prov)
 
274
{
 
275
        struct fc4_prov **prov_entry;
 
276
        int ret = 0;
 
277
 
 
278
        if (type >= FC_FC4_PROV_SIZE)
 
279
                return -EINVAL;
 
280
        mutex_lock(&fc_prov_mutex);
 
281
        prov_entry = (prov->recv ? fc_passive_prov : fc_active_prov) + type;
 
282
        if (*prov_entry)
 
283
                ret = -EBUSY;
 
284
        else
 
285
                *prov_entry = prov;
 
286
        mutex_unlock(&fc_prov_mutex);
 
287
        return ret;
 
288
}
 
289
EXPORT_SYMBOL(fc_fc4_register_provider);
 
290
 
 
291
/**
 
292
 * fc_fc4_deregister_provider() - deregister FC-4 upper-level provider.
 
293
 * @type: FC-4 type, such as FC_TYPE_FCP
 
294
 * @prov: structure describing provider including ops vector.
 
295
 */
 
296
void fc_fc4_deregister_provider(enum fc_fh_type type, struct fc4_prov *prov)
 
297
{
 
298
        BUG_ON(type >= FC_FC4_PROV_SIZE);
 
299
        mutex_lock(&fc_prov_mutex);
 
300
        if (prov->recv)
 
301
                rcu_assign_pointer(fc_passive_prov[type], NULL);
 
302
        else
 
303
                rcu_assign_pointer(fc_active_prov[type], NULL);
 
304
        mutex_unlock(&fc_prov_mutex);
 
305
        synchronize_rcu();
 
306
}
 
307
EXPORT_SYMBOL(fc_fc4_deregister_provider);
 
308
 
 
309
/**
 
310
 * fc_fc4_add_lport() - add new local port to list and run notifiers.
 
311
 * @lport:  The new local port.
 
312
 */
 
313
void fc_fc4_add_lport(struct fc_lport *lport)
 
314
{
 
315
        mutex_lock(&fc_prov_mutex);
 
316
        list_add_tail(&lport->lport_list, &fc_local_ports);
 
317
        blocking_notifier_call_chain(&fc_lport_notifier_head,
 
318
                                     FC_LPORT_EV_ADD, lport);
 
319
        mutex_unlock(&fc_prov_mutex);
 
320
}
 
321
 
 
322
/**
 
323
 * fc_fc4_del_lport() - remove local port from list and run notifiers.
 
324
 * @lport:  The new local port.
 
325
 */
 
326
void fc_fc4_del_lport(struct fc_lport *lport)
 
327
{
 
328
        mutex_lock(&fc_prov_mutex);
 
329
        list_del(&lport->lport_list);
 
330
        blocking_notifier_call_chain(&fc_lport_notifier_head,
 
331
                                     FC_LPORT_EV_DEL, lport);
 
332
        mutex_unlock(&fc_prov_mutex);
 
333
}