aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBoaz Harrosh <bharrosh@panasas.com>2009-11-29 09:26:45 -0500
committerJames Bottomley <James.Bottomley@suse.de>2009-12-04 13:01:46 -0500
commit2cdd6410e5a1665823f2a048fc7f8f6a8384be1d (patch)
tree327ae154abd84aea9c18eb24eb87c9d6f8029d26
parentd6ae4333e648492721a098bdc329bbd82d25eb67 (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.c26
-rw-r--r--drivers/scsi/osd/osd_uld.c100
-rw-r--r--include/scsi/osd_initiator.h38
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
76static int _osd_print_system_info(struct osd_dev *od, void *caps) 76static 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 }
176out: 189out:
@@ -178,16 +191,17 @@ out:
178 return ret; 191 return ret;
179} 192}
180 193
181int osd_auto_detect_ver(struct osd_dev *od, void *caps) 194int 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}
226EXPORT_SYMBOL(osduld_path_lookup); 227EXPORT_SYMBOL(osduld_path_lookup);
227 228
229static 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
241struct find_oud_t {
242 const struct osd_dev_info *odi;
243 struct device *dev;
244 struct osd_uld_device *oud;
245} ;
246
247int _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 */
272struct 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}
293EXPORT_SYMBOL(osduld_info_lookup);
294
228void osduld_put_device(struct osd_dev *od) 295void 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}
249EXPORT_SYMBOL(osduld_put_device); 318EXPORT_SYMBOL(osduld_put_device);
250 319
320const 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}
326EXPORT_SYMBOL(osduld_device_info);
327
328bool 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}
341EXPORT_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 */
59struct osd_dev *osduld_path_lookup(const char *dev_name); /*Use IS_ERR/ERR_PTR*/ 59struct 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 */
69struct osd_dev *osduld_path_lookup(const char *dev_name);
70struct osd_dev *osduld_info_lookup(const struct osd_dev_info *odi);
60void osduld_put_device(struct osd_dev *od); 71void osduld_put_device(struct osd_dev *od);
61 72
73const struct osd_dev_info *osduld_device_info(struct osd_dev *od);
74bool 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 */
63typedef int (do_test_fn)(struct osd_dev *od, unsigned cmd, unsigned long arg); 77typedef int (do_test_fn)(struct osd_dev *od, unsigned cmd, unsigned long arg);
64int osduld_register_test(unsigned ioctl, do_test_fn *do_test); 78int osduld_register_test(unsigned ioctl, do_test_fn *do_test);
@@ -68,8 +82,24 @@ void osduld_unregister_test(unsigned ioctl);
68void osd_dev_init(struct osd_dev *od, struct scsi_device *scsi_device); 82void osd_dev_init(struct osd_dev *od, struct scsi_device *scsi_device);
69void osd_dev_fini(struct osd_dev *od); 83void osd_dev_fini(struct osd_dev *od);
70 84
71/* some hi level device operations */ 85/**
72int 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 */
100int osd_auto_detect_ver(struct osd_dev *od,
101 void *caps, struct osd_dev_info *odi);
102
73static inline struct request_queue *osd_request_queue(struct osd_dev *od) 103static 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;