diff options
author | Boaz Harrosh <bharrosh@panasas.com> | 2009-11-29 09:26:45 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2009-12-04 13:01:46 -0500 |
commit | 2cdd6410e5a1665823f2a048fc7f8f6a8384be1d (patch) | |
tree | 327ae154abd84aea9c18eb24eb87c9d6f8029d26 | |
parent | d6ae4333e648492721a098bdc329bbd82d25eb67 (diff) |
[SCSI] libosd: osd_dev_info: Unique Identification of an OSD device
Define an osd_dev_info structure that Uniquely identifies an OSD
device lun on the network. The identification is built from unique
target attributes and is the same for all network/SAN machines.
osduld_info_lookup() - NEW
New API that will lookup an osd_dev by its osd_dev_info.
This is used by pNFS-objects for cross network global device
identification. And by exofs multy-device support, the device
info is specified in the on-disk exofs device table.
osduld_device_info() - NEW
Given an osd_dev handle returns its associated osd_dev_info.
The ULD fetches this information at startup and hangs it on
each OSD device. (This is a fast operation that can be called
at any condition)
osduld_device_same() - NEW
With a given osd_dev at one hand and an osd_dev_info
at another, we would like to know if they are the same
device.
Two osd_dev handles can be checked by:
osduld_device_same(od1, osduld_device_info(od2));
osd_auto_detect_ver() - REVISED
Now returns an osd_dev_info structure. Is only called once
by ULD as before. See added comments for how to use.
Signed-off-by: Boaz Harrosh <bharrosh@panasas.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
-rw-r--r-- | drivers/scsi/osd/osd_initiator.c | 26 | ||||
-rw-r--r-- | drivers/scsi/osd/osd_uld.c | 100 | ||||
-rw-r--r-- | include/scsi/osd_initiator.h | 38 |
3 files changed, 151 insertions, 13 deletions
diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c index 7a117c18114c..60b7ca1e9bc0 100644 --- a/drivers/scsi/osd/osd_initiator.c +++ b/drivers/scsi/osd/osd_initiator.c | |||
@@ -73,7 +73,8 @@ static const char *_osd_ver_desc(struct osd_request *or) | |||
73 | 73 | ||
74 | #define ATTR_DEF_RI(id, len) ATTR_DEF(OSD_APAGE_ROOT_INFORMATION, id, len) | 74 | #define ATTR_DEF_RI(id, len) ATTR_DEF(OSD_APAGE_ROOT_INFORMATION, id, len) |
75 | 75 | ||
76 | static int _osd_print_system_info(struct osd_dev *od, void *caps) | 76 | static int _osd_get_print_system_info(struct osd_dev *od, |
77 | void *caps, struct osd_dev_info *odi) | ||
77 | { | 78 | { |
78 | struct osd_request *or; | 79 | struct osd_request *or; |
79 | struct osd_attr get_attrs[] = { | 80 | struct osd_attr get_attrs[] = { |
@@ -137,8 +138,12 @@ static int _osd_print_system_info(struct osd_dev *od, void *caps) | |||
137 | OSD_INFO("PRODUCT_SERIAL_NUMBER [%s]\n", | 138 | OSD_INFO("PRODUCT_SERIAL_NUMBER [%s]\n", |
138 | (char *)pFirst); | 139 | (char *)pFirst); |
139 | 140 | ||
140 | pFirst = get_attrs[a].val_ptr; | 141 | odi->osdname_len = get_attrs[a].len; |
141 | OSD_INFO("OSD_NAME [%s]\n", (char *)pFirst); | 142 | /* Avoid NULL for memcmp optimization 0-length is good enough */ |
143 | odi->osdname = kzalloc(odi->osdname_len + 1, GFP_KERNEL); | ||
144 | if (odi->osdname_len) | ||
145 | memcpy(odi->osdname, get_attrs[a].val_ptr, odi->osdname_len); | ||
146 | OSD_INFO("OSD_NAME [%s]\n", odi->osdname); | ||
142 | a++; | 147 | a++; |
143 | 148 | ||
144 | pFirst = get_attrs[a++].val_ptr; | 149 | pFirst = get_attrs[a++].val_ptr; |
@@ -171,6 +176,14 @@ static int _osd_print_system_info(struct osd_dev *od, void *caps) | |||
171 | sid_dump, sizeof(sid_dump), true); | 176 | sid_dump, sizeof(sid_dump), true); |
172 | OSD_INFO("OSD_SYSTEM_ID(%d)\n" | 177 | OSD_INFO("OSD_SYSTEM_ID(%d)\n" |
173 | " [%s]\n", len, sid_dump); | 178 | " [%s]\n", len, sid_dump); |
179 | |||
180 | if (unlikely(len > sizeof(odi->systemid))) { | ||
181 | OSD_ERR("OSD Target error: OSD_SYSTEM_ID too long(%d). " | ||
182 | "device idetification might not work\n", len); | ||
183 | len = sizeof(odi->systemid); | ||
184 | } | ||
185 | odi->systemid_len = len; | ||
186 | memcpy(odi->systemid, get_attrs[a].val_ptr, len); | ||
174 | a++; | 187 | a++; |
175 | } | 188 | } |
176 | out: | 189 | out: |
@@ -178,16 +191,17 @@ out: | |||
178 | return ret; | 191 | return ret; |
179 | } | 192 | } |
180 | 193 | ||
181 | int osd_auto_detect_ver(struct osd_dev *od, void *caps) | 194 | int osd_auto_detect_ver(struct osd_dev *od, |
195 | void *caps, struct osd_dev_info *odi) | ||
182 | { | 196 | { |
183 | int ret; | 197 | int ret; |
184 | 198 | ||
185 | /* Auto-detect the osd version */ | 199 | /* Auto-detect the osd version */ |
186 | ret = _osd_print_system_info(od, caps); | 200 | ret = _osd_get_print_system_info(od, caps, odi); |
187 | if (ret) { | 201 | if (ret) { |
188 | osd_dev_set_ver(od, OSD_VER1); | 202 | osd_dev_set_ver(od, OSD_VER1); |
189 | OSD_DEBUG("converting to OSD1\n"); | 203 | OSD_DEBUG("converting to OSD1\n"); |
190 | ret = _osd_print_system_info(od, caps); | 204 | ret = _osd_get_print_system_info(od, caps, odi); |
191 | } | 205 | } |
192 | 206 | ||
193 | return ret; | 207 | return ret; |
diff --git a/drivers/scsi/osd/osd_uld.c b/drivers/scsi/osd/osd_uld.c index fc6fc1c4d4d1..0a90702b3d71 100644 --- a/drivers/scsi/osd/osd_uld.c +++ b/drivers/scsi/osd/osd_uld.c | |||
@@ -84,6 +84,7 @@ struct osd_uld_device { | |||
84 | struct device class_dev; | 84 | struct device class_dev; |
85 | struct cdev cdev; | 85 | struct cdev cdev; |
86 | struct osd_dev od; | 86 | struct osd_dev od; |
87 | struct osd_dev_info odi; | ||
87 | struct gendisk *disk; | 88 | struct gendisk *disk; |
88 | }; | 89 | }; |
89 | 90 | ||
@@ -225,6 +226,72 @@ free_od: | |||
225 | } | 226 | } |
226 | EXPORT_SYMBOL(osduld_path_lookup); | 227 | EXPORT_SYMBOL(osduld_path_lookup); |
227 | 228 | ||
229 | static inline bool _the_same_or_null(const u8 *a1, unsigned a1_len, | ||
230 | const u8 *a2, unsigned a2_len) | ||
231 | { | ||
232 | if (!a2_len) /* User string is Empty means don't care */ | ||
233 | return true; | ||
234 | |||
235 | if (a1_len != a2_len) | ||
236 | return false; | ||
237 | |||
238 | return 0 == memcmp(a1, a2, a1_len); | ||
239 | } | ||
240 | |||
241 | struct find_oud_t { | ||
242 | const struct osd_dev_info *odi; | ||
243 | struct device *dev; | ||
244 | struct osd_uld_device *oud; | ||
245 | } ; | ||
246 | |||
247 | int _mach_odi(struct device *dev, void *find_data) | ||
248 | { | ||
249 | struct osd_uld_device *oud = container_of(dev, struct osd_uld_device, | ||
250 | class_dev); | ||
251 | struct find_oud_t *fot = find_data; | ||
252 | const struct osd_dev_info *odi = fot->odi; | ||
253 | |||
254 | if (_the_same_or_null(oud->odi.systemid, oud->odi.systemid_len, | ||
255 | odi->systemid, odi->systemid_len) && | ||
256 | _the_same_or_null(oud->odi.osdname, oud->odi.osdname_len, | ||
257 | odi->osdname, odi->osdname_len)) { | ||
258 | OSD_DEBUG("found device sysid_len=%d osdname=%d\n", | ||
259 | odi->systemid_len, odi->osdname_len); | ||
260 | fot->oud = oud; | ||
261 | return 1; | ||
262 | } else { | ||
263 | return 0; | ||
264 | } | ||
265 | } | ||
266 | |||
267 | /* osduld_info_lookup - Loop through all devices, return the requested osd_dev. | ||
268 | * | ||
269 | * if @odi->systemid_len and/or @odi->osdname_len are zero, they act as a don't | ||
270 | * care. .e.g if they're both zero /dev/osd0 is returned. | ||
271 | */ | ||
272 | struct osd_dev *osduld_info_lookup(const struct osd_dev_info *odi) | ||
273 | { | ||
274 | struct find_oud_t find = {.odi = odi}; | ||
275 | |||
276 | find.dev = class_find_device(&osd_uld_class, NULL, &find, _mach_odi); | ||
277 | if (likely(find.dev)) { | ||
278 | struct osd_dev_handle *odh = kzalloc(sizeof(*odh), GFP_KERNEL); | ||
279 | |||
280 | if (unlikely(!odh)) { | ||
281 | put_device(find.dev); | ||
282 | return ERR_PTR(-ENOMEM); | ||
283 | } | ||
284 | |||
285 | odh->od = find.oud->od; | ||
286 | odh->oud = find.oud; | ||
287 | |||
288 | return &odh->od; | ||
289 | } | ||
290 | |||
291 | return ERR_PTR(-ENODEV); | ||
292 | } | ||
293 | EXPORT_SYMBOL(osduld_info_lookup); | ||
294 | |||
228 | void osduld_put_device(struct osd_dev *od) | 295 | void osduld_put_device(struct osd_dev *od) |
229 | { | 296 | { |
230 | if (od && !IS_ERR(od)) { | 297 | if (od && !IS_ERR(od)) { |
@@ -240,14 +307,39 @@ void osduld_put_device(struct osd_dev *od) | |||
240 | * is called after the fops->release. A get_/put_ pair makes | 307 | * is called after the fops->release. A get_/put_ pair makes |
241 | * sure we have a cdev for the duration of fput | 308 | * sure we have a cdev for the duration of fput |
242 | */ | 309 | */ |
243 | get_device(&oud->class_dev); | 310 | if (odh->file) { |
244 | fput(odh->file); | 311 | get_device(&oud->class_dev); |
312 | fput(odh->file); | ||
313 | } | ||
245 | put_device(&oud->class_dev); | 314 | put_device(&oud->class_dev); |
246 | kfree(odh); | 315 | kfree(odh); |
247 | } | 316 | } |
248 | } | 317 | } |
249 | EXPORT_SYMBOL(osduld_put_device); | 318 | EXPORT_SYMBOL(osduld_put_device); |
250 | 319 | ||
320 | const struct osd_dev_info *osduld_device_info(struct osd_dev *od) | ||
321 | { | ||
322 | struct osd_dev_handle *odh = | ||
323 | container_of(od, struct osd_dev_handle, od); | ||
324 | return &odh->oud->odi; | ||
325 | } | ||
326 | EXPORT_SYMBOL(osduld_device_info); | ||
327 | |||
328 | bool osduld_device_same(struct osd_dev *od, const struct osd_dev_info *odi) | ||
329 | { | ||
330 | struct osd_dev_handle *odh = | ||
331 | container_of(od, struct osd_dev_handle, od); | ||
332 | struct osd_uld_device *oud = odh->oud; | ||
333 | |||
334 | return (oud->odi.systemid_len == odi->systemid_len) && | ||
335 | _the_same_or_null(oud->odi.systemid, oud->odi.systemid_len, | ||
336 | odi->systemid, odi->systemid_len) && | ||
337 | (oud->odi.osdname_len == odi->osdname_len) && | ||
338 | _the_same_or_null(oud->odi.osdname, oud->odi.osdname_len, | ||
339 | odi->osdname, odi->osdname_len); | ||
340 | } | ||
341 | EXPORT_SYMBOL(osduld_device_same); | ||
342 | |||
251 | /* | 343 | /* |
252 | * Scsi Device operations | 344 | * Scsi Device operations |
253 | */ | 345 | */ |
@@ -268,7 +360,7 @@ static int __detect_osd(struct osd_uld_device *oud) | |||
268 | OSD_ERR("warning: scsi_test_unit_ready failed\n"); | 360 | OSD_ERR("warning: scsi_test_unit_ready failed\n"); |
269 | 361 | ||
270 | osd_sec_init_nosec_doall_caps(caps, &osd_root_object, false, true); | 362 | osd_sec_init_nosec_doall_caps(caps, &osd_root_object, false, true); |
271 | if (osd_auto_detect_ver(&oud->od, caps)) | 363 | if (osd_auto_detect_ver(&oud->od, caps, &oud->odi)) |
272 | return -ENODEV; | 364 | return -ENODEV; |
273 | 365 | ||
274 | return 0; | 366 | return 0; |
@@ -280,6 +372,8 @@ static void __remove(struct device *dev) | |||
280 | class_dev); | 372 | class_dev); |
281 | struct scsi_device *scsi_device = oud->od.scsi_device; | 373 | struct scsi_device *scsi_device = oud->od.scsi_device; |
282 | 374 | ||
375 | kfree(oud->odi.osdname); | ||
376 | |||
283 | if (oud->cdev.owner) | 377 | if (oud->cdev.owner) |
284 | cdev_del(&oud->cdev); | 378 | cdev_del(&oud->cdev); |
285 | 379 | ||
diff --git a/include/scsi/osd_initiator.h b/include/scsi/osd_initiator.h index 589e5f0d67b1..3ec346e15dda 100644 --- a/include/scsi/osd_initiator.h +++ b/include/scsi/osd_initiator.h | |||
@@ -55,10 +55,24 @@ struct osd_dev { | |||
55 | #endif | 55 | #endif |
56 | }; | 56 | }; |
57 | 57 | ||
58 | /* Retrieve/return osd_dev(s) for use by Kernel clients */ | 58 | /* Unique Identification of an OSD device */ |
59 | struct osd_dev *osduld_path_lookup(const char *dev_name); /*Use IS_ERR/ERR_PTR*/ | 59 | struct osd_dev_info { |
60 | unsigned systemid_len; | ||
61 | u8 systemid[OSD_SYSTEMID_LEN]; | ||
62 | unsigned osdname_len; | ||
63 | u8 *osdname; | ||
64 | }; | ||
65 | |||
66 | /* Retrieve/return osd_dev(s) for use by Kernel clients | ||
67 | * Use IS_ERR/ERR_PTR on returned "osd_dev *". | ||
68 | */ | ||
69 | struct osd_dev *osduld_path_lookup(const char *dev_name); | ||
70 | struct osd_dev *osduld_info_lookup(const struct osd_dev_info *odi); | ||
60 | void osduld_put_device(struct osd_dev *od); | 71 | void osduld_put_device(struct osd_dev *od); |
61 | 72 | ||
73 | const struct osd_dev_info *osduld_device_info(struct osd_dev *od); | ||
74 | bool osduld_device_same(struct osd_dev *od, const struct osd_dev_info *odi); | ||
75 | |||
62 | /* Add/remove test ioctls from external modules */ | 76 | /* Add/remove test ioctls from external modules */ |
63 | typedef int (do_test_fn)(struct osd_dev *od, unsigned cmd, unsigned long arg); | 77 | typedef int (do_test_fn)(struct osd_dev *od, unsigned cmd, unsigned long arg); |
64 | int osduld_register_test(unsigned ioctl, do_test_fn *do_test); | 78 | int osduld_register_test(unsigned ioctl, do_test_fn *do_test); |
@@ -68,8 +82,24 @@ void osduld_unregister_test(unsigned ioctl); | |||
68 | void osd_dev_init(struct osd_dev *od, struct scsi_device *scsi_device); | 82 | void osd_dev_init(struct osd_dev *od, struct scsi_device *scsi_device); |
69 | void osd_dev_fini(struct osd_dev *od); | 83 | void osd_dev_fini(struct osd_dev *od); |
70 | 84 | ||
71 | /* some hi level device operations */ | 85 | /** |
72 | int osd_auto_detect_ver(struct osd_dev *od, void *caps); /* GFP_KERNEL */ | 86 | * osd_auto_detect_ver - Detect the OSD version, return Unique Identification |
87 | * | ||
88 | * @od: OSD target lun handle | ||
89 | * @caps: Capabilities authorizing OSD root read attributes access | ||
90 | * @odi: Retrieved information uniquely identifying the osd target lun | ||
91 | * Note: odi->osdname must be kfreed by caller. | ||
92 | * | ||
93 | * Auto detects the OSD version of the OSD target and sets the @od | ||
94 | * accordingly. Meanwhile also returns the "system id" and "osd name" root | ||
95 | * attributes which uniquely identify the OSD target. This member is usually | ||
96 | * called by the ULD. ULD users should call osduld_device_info(). | ||
97 | * This rutine allocates osd requests and memory at GFP_KERNEL level and might | ||
98 | * sleep. | ||
99 | */ | ||
100 | int osd_auto_detect_ver(struct osd_dev *od, | ||
101 | void *caps, struct osd_dev_info *odi); | ||
102 | |||
73 | static inline struct request_queue *osd_request_queue(struct osd_dev *od) | 103 | static inline struct request_queue *osd_request_queue(struct osd_dev *od) |
74 | { | 104 | { |
75 | return od->scsi_device->request_queue; | 105 | return od->scsi_device->request_queue; |