diff options
author | Mike Miller <mike.miller@hp.com> | 2005-09-13 04:25:22 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-09-13 11:22:30 -0400 |
commit | ddd474420a0b0dfeda38b6b5f83c7af751235cc3 (patch) | |
tree | e081ba3d447eb4c1dd5a6ab38d7902c2db03ae59 /drivers/block/cciss.c | |
parent | 1f8ef3806c40e74733f45f436d44b3d8e9a2fa48 (diff) |
[PATCH] cciss: new disk register/deregister routines
This patch removes a couple of functions dealing with configuration and
replaces them with new functions. This implementation fixes some bugs
associated with the ACUXE. It also allows a logical volume to be removed from
the middle without deleting all volumes behind it.
If a user has 5 logical volumes and decides he wants to reconfigure volume
number 3, he can now do that without removing volumes 4 & 5 first. This code
has been tested in our labs against all application software.
Signed-off-by: Chase Maupin <chase.maupin@hp.com>
Signed-off-by: Mike Miller <mike.miller@hp.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/block/cciss.c')
-rw-r--r-- | drivers/block/cciss.c | 515 |
1 files changed, 326 insertions, 189 deletions
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 8bcd6c498c60..3c6a6a21d540 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c | |||
@@ -155,15 +155,24 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, | |||
155 | 155 | ||
156 | static int revalidate_allvol(ctlr_info_t *host); | 156 | static int revalidate_allvol(ctlr_info_t *host); |
157 | static int cciss_revalidate(struct gendisk *disk); | 157 | static int cciss_revalidate(struct gendisk *disk); |
158 | static int deregister_disk(struct gendisk *disk); | 158 | static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk); |
159 | static int register_new_disk(ctlr_info_t *h); | 159 | static int deregister_disk(struct gendisk *disk, drive_info_struct *drv, int clear_all); |
160 | 160 | ||
161 | static void cciss_read_capacity(int ctlr, int logvol, ReadCapdata_struct *buf, | ||
162 | int withirq, unsigned int *total_size, unsigned int *block_size); | ||
163 | static void cciss_geometry_inquiry(int ctlr, int logvol, | ||
164 | int withirq, unsigned int total_size, | ||
165 | unsigned int block_size, InquiryData_struct *inq_buff, | ||
166 | drive_info_struct *drv); | ||
161 | static void cciss_getgeometry(int cntl_num); | 167 | static void cciss_getgeometry(int cntl_num); |
162 | 168 | ||
163 | static void start_io( ctlr_info_t *h); | 169 | static void start_io( ctlr_info_t *h); |
164 | static int sendcmd( __u8 cmd, int ctlr, void *buff, size_t size, | 170 | static int sendcmd( __u8 cmd, int ctlr, void *buff, size_t size, |
165 | unsigned int use_unit_num, unsigned int log_unit, __u8 page_code, | 171 | unsigned int use_unit_num, unsigned int log_unit, __u8 page_code, |
166 | unsigned char *scsi3addr, int cmd_type); | 172 | unsigned char *scsi3addr, int cmd_type); |
173 | static int sendcmd_withirq(__u8 cmd, int ctlr, void *buff, size_t size, | ||
174 | unsigned int use_unit_num, unsigned int log_unit, __u8 page_code, | ||
175 | int cmd_type); | ||
167 | 176 | ||
168 | #ifdef CONFIG_PROC_FS | 177 | #ifdef CONFIG_PROC_FS |
169 | static int cciss_proc_get_info(char *buffer, char **start, off_t offset, | 178 | static int cciss_proc_get_info(char *buffer, char **start, off_t offset, |
@@ -280,7 +289,7 @@ static int cciss_proc_get_info(char *buffer, char **start, off_t offset, | |||
280 | for(i=0; i<=h->highest_lun; i++) { | 289 | for(i=0; i<=h->highest_lun; i++) { |
281 | 290 | ||
282 | drv = &h->drv[i]; | 291 | drv = &h->drv[i]; |
283 | if (drv->block_size == 0) | 292 | if (drv->heads == 0) |
284 | continue; | 293 | continue; |
285 | 294 | ||
286 | vol_sz = drv->nr_blocks; | 295 | vol_sz = drv->nr_blocks; |
@@ -471,6 +480,8 @@ static int cciss_open(struct inode *inode, struct file *filep) | |||
471 | if (host->busy_initializing) | 480 | if (host->busy_initializing) |
472 | return -EBUSY; | 481 | return -EBUSY; |
473 | 482 | ||
483 | if (host->busy_initializing || drv->busy_configuring) | ||
484 | return -EBUSY; | ||
474 | /* | 485 | /* |
475 | * Root is allowed to open raw volume zero even if it's not configured | 486 | * Root is allowed to open raw volume zero even if it's not configured |
476 | * so array config can still work. Root is also allowed to open any | 487 | * so array config can still work. Root is also allowed to open any |
@@ -814,10 +825,10 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, | |||
814 | return(0); | 825 | return(0); |
815 | } | 826 | } |
816 | case CCISS_DEREGDISK: | 827 | case CCISS_DEREGDISK: |
817 | return deregister_disk(disk); | 828 | return rebuild_lun_table(host, disk); |
818 | 829 | ||
819 | case CCISS_REGNEWD: | 830 | case CCISS_REGNEWD: |
820 | return register_new_disk(host); | 831 | return rebuild_lun_table(host, NULL); |
821 | 832 | ||
822 | case CCISS_PASSTHRU: | 833 | case CCISS_PASSTHRU: |
823 | { | 834 | { |
@@ -1161,48 +1172,323 @@ static int revalidate_allvol(ctlr_info_t *host) | |||
1161 | return 0; | 1172 | return 0; |
1162 | } | 1173 | } |
1163 | 1174 | ||
1164 | static int deregister_disk(struct gendisk *disk) | 1175 | /* This function will check the usage_count of the drive to be updated/added. |
1176 | * If the usage_count is zero then the drive information will be updated and | ||
1177 | * the disk will be re-registered with the kernel. If not then it will be | ||
1178 | * left alone for the next reboot. The exception to this is disk 0 which | ||
1179 | * will always be left registered with the kernel since it is also the | ||
1180 | * controller node. Any changes to disk 0 will show up on the next | ||
1181 | * reboot. | ||
1182 | */ | ||
1183 | static void cciss_update_drive_info(int ctlr, int drv_index) | ||
1184 | { | ||
1185 | ctlr_info_t *h = hba[ctlr]; | ||
1186 | struct gendisk *disk; | ||
1187 | ReadCapdata_struct *size_buff = NULL; | ||
1188 | InquiryData_struct *inq_buff = NULL; | ||
1189 | unsigned int block_size; | ||
1190 | unsigned int total_size; | ||
1191 | unsigned long flags = 0; | ||
1192 | int ret = 0; | ||
1193 | |||
1194 | /* if the disk already exists then deregister it before proceeding*/ | ||
1195 | if (h->drv[drv_index].raid_level != -1){ | ||
1196 | spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags); | ||
1197 | h->drv[drv_index].busy_configuring = 1; | ||
1198 | spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); | ||
1199 | ret = deregister_disk(h->gendisk[drv_index], | ||
1200 | &h->drv[drv_index], 0); | ||
1201 | h->drv[drv_index].busy_configuring = 0; | ||
1202 | } | ||
1203 | |||
1204 | /* If the disk is in use return */ | ||
1205 | if (ret) | ||
1206 | return; | ||
1207 | |||
1208 | |||
1209 | /* Get information about the disk and modify the driver sturcture */ | ||
1210 | size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL); | ||
1211 | if (size_buff == NULL) | ||
1212 | goto mem_msg; | ||
1213 | inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL); | ||
1214 | if (inq_buff == NULL) | ||
1215 | goto mem_msg; | ||
1216 | |||
1217 | cciss_read_capacity(ctlr, drv_index, size_buff, 1, | ||
1218 | &total_size, &block_size); | ||
1219 | cciss_geometry_inquiry(ctlr, drv_index, 1, total_size, block_size, | ||
1220 | inq_buff, &h->drv[drv_index]); | ||
1221 | |||
1222 | ++h->num_luns; | ||
1223 | disk = h->gendisk[drv_index]; | ||
1224 | set_capacity(disk, h->drv[drv_index].nr_blocks); | ||
1225 | |||
1226 | |||
1227 | /* if it's the controller it's already added */ | ||
1228 | if (drv_index){ | ||
1229 | disk->queue = blk_init_queue(do_cciss_request, &h->lock); | ||
1230 | |||
1231 | /* Set up queue information */ | ||
1232 | disk->queue->backing_dev_info.ra_pages = READ_AHEAD; | ||
1233 | blk_queue_bounce_limit(disk->queue, hba[ctlr]->pdev->dma_mask); | ||
1234 | |||
1235 | /* This is a hardware imposed limit. */ | ||
1236 | blk_queue_max_hw_segments(disk->queue, MAXSGENTRIES); | ||
1237 | |||
1238 | /* This is a limit in the driver and could be eliminated. */ | ||
1239 | blk_queue_max_phys_segments(disk->queue, MAXSGENTRIES); | ||
1240 | |||
1241 | blk_queue_max_sectors(disk->queue, 512); | ||
1242 | |||
1243 | disk->queue->queuedata = hba[ctlr]; | ||
1244 | |||
1245 | blk_queue_hardsect_size(disk->queue, | ||
1246 | hba[ctlr]->drv[drv_index].block_size); | ||
1247 | |||
1248 | h->drv[drv_index].queue = disk->queue; | ||
1249 | add_disk(disk); | ||
1250 | } | ||
1251 | |||
1252 | freeret: | ||
1253 | kfree(size_buff); | ||
1254 | kfree(inq_buff); | ||
1255 | return; | ||
1256 | mem_msg: | ||
1257 | printk(KERN_ERR "cciss: out of memory\n"); | ||
1258 | goto freeret; | ||
1259 | } | ||
1260 | |||
1261 | /* This function will find the first index of the controllers drive array | ||
1262 | * that has a -1 for the raid_level and will return that index. This is | ||
1263 | * where new drives will be added. If the index to be returned is greater | ||
1264 | * than the highest_lun index for the controller then highest_lun is set | ||
1265 | * to this new index. If there are no available indexes then -1 is returned. | ||
1266 | */ | ||
1267 | static int cciss_find_free_drive_index(int ctlr) | ||
1268 | { | ||
1269 | int i; | ||
1270 | |||
1271 | for (i=0; i < CISS_MAX_LUN; i++){ | ||
1272 | if (hba[ctlr]->drv[i].raid_level == -1){ | ||
1273 | if (i > hba[ctlr]->highest_lun) | ||
1274 | hba[ctlr]->highest_lun = i; | ||
1275 | return i; | ||
1276 | } | ||
1277 | } | ||
1278 | return -1; | ||
1279 | } | ||
1280 | |||
1281 | /* This function will add and remove logical drives from the Logical | ||
1282 | * drive array of the controller and maintain persistancy of ordering | ||
1283 | * so that mount points are preserved until the next reboot. This allows | ||
1284 | * for the removal of logical drives in the middle of the drive array | ||
1285 | * without a re-ordering of those drives. | ||
1286 | * INPUT | ||
1287 | * h = The controller to perform the operations on | ||
1288 | * del_disk = The disk to remove if specified. If the value given | ||
1289 | * is NULL then no disk is removed. | ||
1290 | */ | ||
1291 | static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk) | ||
1165 | { | 1292 | { |
1293 | int ctlr = h->ctlr; | ||
1294 | int num_luns; | ||
1295 | ReportLunData_struct *ld_buff = NULL; | ||
1296 | drive_info_struct *drv = NULL; | ||
1297 | int return_code; | ||
1298 | int listlength = 0; | ||
1299 | int i; | ||
1300 | int drv_found; | ||
1301 | int drv_index = 0; | ||
1302 | __u32 lunid = 0; | ||
1166 | unsigned long flags; | 1303 | unsigned long flags; |
1304 | |||
1305 | /* Set busy_configuring flag for this operation */ | ||
1306 | spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags); | ||
1307 | if (h->num_luns >= CISS_MAX_LUN){ | ||
1308 | spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); | ||
1309 | return -EINVAL; | ||
1310 | } | ||
1311 | |||
1312 | if (h->busy_configuring){ | ||
1313 | spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); | ||
1314 | return -EBUSY; | ||
1315 | } | ||
1316 | h->busy_configuring = 1; | ||
1317 | |||
1318 | /* if del_disk is NULL then we are being called to add a new disk | ||
1319 | * and update the logical drive table. If it is not NULL then | ||
1320 | * we will check if the disk is in use or not. | ||
1321 | */ | ||
1322 | if (del_disk != NULL){ | ||
1323 | drv = get_drv(del_disk); | ||
1324 | drv->busy_configuring = 1; | ||
1325 | spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); | ||
1326 | return_code = deregister_disk(del_disk, drv, 1); | ||
1327 | drv->busy_configuring = 0; | ||
1328 | h->busy_configuring = 0; | ||
1329 | return return_code; | ||
1330 | } else { | ||
1331 | spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); | ||
1332 | if (!capable(CAP_SYS_RAWIO)) | ||
1333 | return -EPERM; | ||
1334 | |||
1335 | ld_buff = kzalloc(sizeof(ReportLunData_struct), GFP_KERNEL); | ||
1336 | if (ld_buff == NULL) | ||
1337 | goto mem_msg; | ||
1338 | |||
1339 | return_code = sendcmd_withirq(CISS_REPORT_LOG, ctlr, ld_buff, | ||
1340 | sizeof(ReportLunData_struct), 0, 0, 0, | ||
1341 | TYPE_CMD); | ||
1342 | |||
1343 | if (return_code == IO_OK){ | ||
1344 | listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[0])) << 24; | ||
1345 | listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[1])) << 16; | ||
1346 | listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[2])) << 8; | ||
1347 | listlength |= 0xff & (unsigned int)(ld_buff->LUNListLength[3]); | ||
1348 | } else{ /* reading number of logical volumes failed */ | ||
1349 | printk(KERN_WARNING "cciss: report logical volume" | ||
1350 | " command failed\n"); | ||
1351 | listlength = 0; | ||
1352 | goto freeret; | ||
1353 | } | ||
1354 | |||
1355 | num_luns = listlength / 8; /* 8 bytes per entry */ | ||
1356 | if (num_luns > CISS_MAX_LUN){ | ||
1357 | num_luns = CISS_MAX_LUN; | ||
1358 | printk(KERN_WARNING "cciss: more luns configured" | ||
1359 | " on controller than can be handled by" | ||
1360 | " this driver.\n"); | ||
1361 | } | ||
1362 | |||
1363 | /* Compare controller drive array to drivers drive array. | ||
1364 | * Check for updates in the drive information and any new drives | ||
1365 | * on the controller. | ||
1366 | */ | ||
1367 | for (i=0; i < num_luns; i++){ | ||
1368 | int j; | ||
1369 | |||
1370 | drv_found = 0; | ||
1371 | |||
1372 | lunid = (0xff & | ||
1373 | (unsigned int)(ld_buff->LUN[i][3])) << 24; | ||
1374 | lunid |= (0xff & | ||
1375 | (unsigned int)(ld_buff->LUN[i][2])) << 16; | ||
1376 | lunid |= (0xff & | ||
1377 | (unsigned int)(ld_buff->LUN[i][1])) << 8; | ||
1378 | lunid |= 0xff & | ||
1379 | (unsigned int)(ld_buff->LUN[i][0]); | ||
1380 | |||
1381 | /* Find if the LUN is already in the drive array | ||
1382 | * of the controller. If so then update its info | ||
1383 | * if not is use. If it does not exist then find | ||
1384 | * the first free index and add it. | ||
1385 | */ | ||
1386 | for (j=0; j <= h->highest_lun; j++){ | ||
1387 | if (h->drv[j].LunID == lunid){ | ||
1388 | drv_index = j; | ||
1389 | drv_found = 1; | ||
1390 | } | ||
1391 | } | ||
1392 | |||
1393 | /* check if the drive was found already in the array */ | ||
1394 | if (!drv_found){ | ||
1395 | drv_index = cciss_find_free_drive_index(ctlr); | ||
1396 | if (drv_index == -1) | ||
1397 | goto freeret; | ||
1398 | |||
1399 | } | ||
1400 | h->drv[drv_index].LunID = lunid; | ||
1401 | cciss_update_drive_info(ctlr, drv_index); | ||
1402 | } /* end for */ | ||
1403 | } /* end else */ | ||
1404 | |||
1405 | freeret: | ||
1406 | kfree(ld_buff); | ||
1407 | h->busy_configuring = 0; | ||
1408 | /* We return -1 here to tell the ACU that we have registered/updated | ||
1409 | * all of the drives that we can and to keep it from calling us | ||
1410 | * additional times. | ||
1411 | */ | ||
1412 | return -1; | ||
1413 | mem_msg: | ||
1414 | printk(KERN_ERR "cciss: out of memory\n"); | ||
1415 | goto freeret; | ||
1416 | } | ||
1417 | |||
1418 | /* This function will deregister the disk and it's queue from the | ||
1419 | * kernel. It must be called with the controller lock held and the | ||
1420 | * drv structures busy_configuring flag set. It's parameters are: | ||
1421 | * | ||
1422 | * disk = This is the disk to be deregistered | ||
1423 | * drv = This is the drive_info_struct associated with the disk to be | ||
1424 | * deregistered. It contains information about the disk used | ||
1425 | * by the driver. | ||
1426 | * clear_all = This flag determines whether or not the disk information | ||
1427 | * is going to be completely cleared out and the highest_lun | ||
1428 | * reset. Sometimes we want to clear out information about | ||
1429 | * the disk in preperation for re-adding it. In this case | ||
1430 | * the highest_lun should be left unchanged and the LunID | ||
1431 | * should not be cleared. | ||
1432 | */ | ||
1433 | static int deregister_disk(struct gendisk *disk, drive_info_struct *drv, | ||
1434 | int clear_all) | ||
1435 | { | ||
1167 | ctlr_info_t *h = get_host(disk); | 1436 | ctlr_info_t *h = get_host(disk); |
1168 | drive_info_struct *drv = get_drv(disk); | ||
1169 | int ctlr = h->ctlr; | ||
1170 | 1437 | ||
1171 | if (!capable(CAP_SYS_RAWIO)) | 1438 | if (!capable(CAP_SYS_RAWIO)) |
1172 | return -EPERM; | 1439 | return -EPERM; |
1173 | 1440 | ||
1174 | spin_lock_irqsave(CCISS_LOCK(ctlr), flags); | ||
1175 | /* make sure logical volume is NOT is use */ | 1441 | /* make sure logical volume is NOT is use */ |
1176 | if( drv->usage_count > 1) { | 1442 | if(clear_all || (h->gendisk[0] == disk)) { |
1177 | spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); | 1443 | if (drv->usage_count > 1) |
1178 | return -EBUSY; | 1444 | return -EBUSY; |
1179 | } | 1445 | } |
1180 | drv->usage_count++; | 1446 | else |
1181 | spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); | 1447 | if( drv->usage_count > 0 ) |
1448 | return -EBUSY; | ||
1182 | 1449 | ||
1183 | /* invalidate the devices and deregister the disk */ | 1450 | /* invalidate the devices and deregister the disk. If it is disk |
1184 | if (disk->flags & GENHD_FL_UP) | 1451 | * zero do not deregister it but just zero out it's values. This |
1452 | * allows us to delete disk zero but keep the controller registered. | ||
1453 | */ | ||
1454 | if (h->gendisk[0] != disk){ | ||
1455 | if (disk->flags & GENHD_FL_UP){ | ||
1456 | blk_cleanup_queue(disk->queue); | ||
1185 | del_gendisk(disk); | 1457 | del_gendisk(disk); |
1458 | drv->queue = NULL; | ||
1459 | } | ||
1460 | } | ||
1461 | |||
1462 | --h->num_luns; | ||
1463 | /* zero out the disk size info */ | ||
1464 | drv->nr_blocks = 0; | ||
1465 | drv->block_size = 0; | ||
1466 | drv->heads = 0; | ||
1467 | drv->sectors = 0; | ||
1468 | drv->cylinders = 0; | ||
1469 | drv->raid_level = -1; /* This can be used as a flag variable to | ||
1470 | * indicate that this element of the drive | ||
1471 | * array is free. | ||
1472 | */ | ||
1473 | |||
1474 | if (clear_all){ | ||
1186 | /* check to see if it was the last disk */ | 1475 | /* check to see if it was the last disk */ |
1187 | if (drv == h->drv + h->highest_lun) { | 1476 | if (drv == h->drv + h->highest_lun) { |
1188 | /* if so, find the new hightest lun */ | 1477 | /* if so, find the new hightest lun */ |
1189 | int i, newhighest =-1; | 1478 | int i, newhighest =-1; |
1190 | for(i=0; i<h->highest_lun; i++) { | 1479 | for(i=0; i<h->highest_lun; i++) { |
1191 | /* if the disk has size > 0, it is available */ | 1480 | /* if the disk has size > 0, it is available */ |
1192 | if (h->drv[i].nr_blocks) | 1481 | if (h->drv[i].heads) |
1193 | newhighest = i; | 1482 | newhighest = i; |
1194 | } | 1483 | } |
1195 | h->highest_lun = newhighest; | 1484 | h->highest_lun = newhighest; |
1196 | |||
1197 | } | 1485 | } |
1198 | --h->num_luns; | 1486 | |
1199 | /* zero out the disk size info */ | ||
1200 | drv->nr_blocks = 0; | ||
1201 | drv->block_size = 0; | ||
1202 | drv->cylinders = 0; | ||
1203 | drv->LunID = 0; | 1487 | drv->LunID = 0; |
1488 | } | ||
1204 | return(0); | 1489 | return(0); |
1205 | } | 1490 | } |
1491 | |||
1206 | static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, | 1492 | static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, |
1207 | size_t size, | 1493 | size_t size, |
1208 | unsigned int use_unit_num, /* 0: address the controller, | 1494 | unsigned int use_unit_num, /* 0: address the controller, |
@@ -1513,164 +1799,6 @@ cciss_read_capacity(int ctlr, int logvol, ReadCapdata_struct *buf, | |||
1513 | return; | 1799 | return; |
1514 | } | 1800 | } |
1515 | 1801 | ||
1516 | static int register_new_disk(ctlr_info_t *h) | ||
1517 | { | ||
1518 | struct gendisk *disk; | ||
1519 | int ctlr = h->ctlr; | ||
1520 | int i; | ||
1521 | int num_luns; | ||
1522 | int logvol; | ||
1523 | int new_lun_found = 0; | ||
1524 | int new_lun_index = 0; | ||
1525 | int free_index_found = 0; | ||
1526 | int free_index = 0; | ||
1527 | ReportLunData_struct *ld_buff = NULL; | ||
1528 | ReadCapdata_struct *size_buff = NULL; | ||
1529 | InquiryData_struct *inq_buff = NULL; | ||
1530 | int return_code; | ||
1531 | int listlength = 0; | ||
1532 | __u32 lunid = 0; | ||
1533 | unsigned int block_size; | ||
1534 | unsigned int total_size; | ||
1535 | |||
1536 | if (!capable(CAP_SYS_RAWIO)) | ||
1537 | return -EPERM; | ||
1538 | /* if we have no space in our disk array left to add anything */ | ||
1539 | if( h->num_luns >= CISS_MAX_LUN) | ||
1540 | return -EINVAL; | ||
1541 | |||
1542 | ld_buff = kmalloc(sizeof(ReportLunData_struct), GFP_KERNEL); | ||
1543 | if (ld_buff == NULL) | ||
1544 | goto mem_msg; | ||
1545 | memset(ld_buff, 0, sizeof(ReportLunData_struct)); | ||
1546 | size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL); | ||
1547 | if (size_buff == NULL) | ||
1548 | goto mem_msg; | ||
1549 | inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL); | ||
1550 | if (inq_buff == NULL) | ||
1551 | goto mem_msg; | ||
1552 | |||
1553 | return_code = sendcmd_withirq(CISS_REPORT_LOG, ctlr, ld_buff, | ||
1554 | sizeof(ReportLunData_struct), 0, 0, 0, TYPE_CMD); | ||
1555 | |||
1556 | if( return_code == IO_OK) | ||
1557 | { | ||
1558 | |||
1559 | // printk("LUN Data\n--------------------------\n"); | ||
1560 | |||
1561 | listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[0])) << 24; | ||
1562 | listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[1])) << 16; | ||
1563 | listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[2])) << 8; | ||
1564 | listlength |= 0xff & (unsigned int)(ld_buff->LUNListLength[3]); | ||
1565 | } else /* reading number of logical volumes failed */ | ||
1566 | { | ||
1567 | printk(KERN_WARNING "cciss: report logical volume" | ||
1568 | " command failed\n"); | ||
1569 | listlength = 0; | ||
1570 | goto free_err; | ||
1571 | } | ||
1572 | num_luns = listlength / 8; // 8 bytes pre entry | ||
1573 | if (num_luns > CISS_MAX_LUN) | ||
1574 | { | ||
1575 | num_luns = CISS_MAX_LUN; | ||
1576 | } | ||
1577 | #ifdef CCISS_DEBUG | ||
1578 | printk(KERN_DEBUG "Length = %x %x %x %x = %d\n", ld_buff->LUNListLength[0], | ||
1579 | ld_buff->LUNListLength[1], ld_buff->LUNListLength[2], | ||
1580 | ld_buff->LUNListLength[3], num_luns); | ||
1581 | #endif | ||
1582 | for(i=0; i< num_luns; i++) | ||
1583 | { | ||
1584 | int j; | ||
1585 | int lunID_found = 0; | ||
1586 | |||
1587 | lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3])) << 24; | ||
1588 | lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2])) << 16; | ||
1589 | lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1])) << 8; | ||
1590 | lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]); | ||
1591 | |||
1592 | /* check to see if this is a new lun */ | ||
1593 | for(j=0; j <= h->highest_lun; j++) | ||
1594 | { | ||
1595 | #ifdef CCISS_DEBUG | ||
1596 | printk("Checking %d %x against %x\n", j,h->drv[j].LunID, | ||
1597 | lunid); | ||
1598 | #endif /* CCISS_DEBUG */ | ||
1599 | if (h->drv[j].LunID == lunid) | ||
1600 | { | ||
1601 | lunID_found = 1; | ||
1602 | break; | ||
1603 | } | ||
1604 | |||
1605 | } | ||
1606 | if( lunID_found == 1) | ||
1607 | continue; | ||
1608 | else | ||
1609 | { /* It is the new lun we have been looking for */ | ||
1610 | #ifdef CCISS_DEBUG | ||
1611 | printk("new lun found at %d\n", i); | ||
1612 | #endif /* CCISS_DEBUG */ | ||
1613 | new_lun_index = i; | ||
1614 | new_lun_found = 1; | ||
1615 | break; | ||
1616 | } | ||
1617 | } | ||
1618 | if (!new_lun_found) | ||
1619 | { | ||
1620 | printk(KERN_WARNING "cciss: New Logical Volume not found\n"); | ||
1621 | goto free_err; | ||
1622 | } | ||
1623 | /* Now find the free index */ | ||
1624 | for(i=0; i <CISS_MAX_LUN; i++) | ||
1625 | { | ||
1626 | #ifdef CCISS_DEBUG | ||
1627 | printk("Checking Index %d\n", i); | ||
1628 | #endif /* CCISS_DEBUG */ | ||
1629 | if(h->drv[i].LunID == 0) | ||
1630 | { | ||
1631 | #ifdef CCISS_DEBUG | ||
1632 | printk("free index found at %d\n", i); | ||
1633 | #endif /* CCISS_DEBUG */ | ||
1634 | free_index_found = 1; | ||
1635 | free_index = i; | ||
1636 | break; | ||
1637 | } | ||
1638 | } | ||
1639 | if (!free_index_found) | ||
1640 | { | ||
1641 | printk(KERN_WARNING "cciss: unable to find free slot for disk\n"); | ||
1642 | goto free_err; | ||
1643 | } | ||
1644 | |||
1645 | logvol = free_index; | ||
1646 | h->drv[logvol].LunID = lunid; | ||
1647 | /* there could be gaps in lun numbers, track hightest */ | ||
1648 | if(h->highest_lun < lunid) | ||
1649 | h->highest_lun = logvol; | ||
1650 | cciss_read_capacity(ctlr, logvol, size_buff, 1, | ||
1651 | &total_size, &block_size); | ||
1652 | cciss_geometry_inquiry(ctlr, logvol, 1, total_size, block_size, | ||
1653 | inq_buff, &h->drv[logvol]); | ||
1654 | h->drv[logvol].usage_count = 0; | ||
1655 | ++h->num_luns; | ||
1656 | /* setup partitions per disk */ | ||
1657 | disk = h->gendisk[logvol]; | ||
1658 | set_capacity(disk, h->drv[logvol].nr_blocks); | ||
1659 | /* if it's the controller it's already added */ | ||
1660 | if(logvol) | ||
1661 | add_disk(disk); | ||
1662 | freeret: | ||
1663 | kfree(ld_buff); | ||
1664 | kfree(size_buff); | ||
1665 | kfree(inq_buff); | ||
1666 | return (logvol); | ||
1667 | mem_msg: | ||
1668 | printk(KERN_ERR "cciss: out of memory\n"); | ||
1669 | free_err: | ||
1670 | logvol = -1; | ||
1671 | goto freeret; | ||
1672 | } | ||
1673 | |||
1674 | static int cciss_revalidate(struct gendisk *disk) | 1802 | static int cciss_revalidate(struct gendisk *disk) |
1675 | { | 1803 | { |
1676 | ctlr_info_t *h = get_host(disk); | 1804 | ctlr_info_t *h = get_host(disk); |
@@ -2652,12 +2780,16 @@ static void cciss_getgeometry(int cntl_num) | |||
2652 | #endif /* CCISS_DEBUG */ | 2780 | #endif /* CCISS_DEBUG */ |
2653 | 2781 | ||
2654 | hba[cntl_num]->highest_lun = hba[cntl_num]->num_luns-1; | 2782 | hba[cntl_num]->highest_lun = hba[cntl_num]->num_luns-1; |
2655 | for(i=0; i< hba[cntl_num]->num_luns; i++) | 2783 | // for(i=0; i< hba[cntl_num]->num_luns; i++) |
2784 | for(i=0; i < CISS_MAX_LUN; i++) | ||
2656 | { | 2785 | { |
2657 | 2786 | if (i < hba[cntl_num]->num_luns){ | |
2658 | lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3])) << 24; | 2787 | lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3])) |
2659 | lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2])) << 16; | 2788 | << 24; |
2660 | lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1])) << 8; | 2789 | lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2])) |
2790 | << 16; | ||
2791 | lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1])) | ||
2792 | << 8; | ||
2661 | lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]); | 2793 | lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]); |
2662 | 2794 | ||
2663 | hba[cntl_num]->drv[i].LunID = lunid; | 2795 | hba[cntl_num]->drv[i].LunID = lunid; |
@@ -2665,13 +2797,18 @@ static void cciss_getgeometry(int cntl_num) | |||
2665 | 2797 | ||
2666 | #ifdef CCISS_DEBUG | 2798 | #ifdef CCISS_DEBUG |
2667 | printk(KERN_DEBUG "LUN[%d]: %x %x %x %x = %x\n", i, | 2799 | printk(KERN_DEBUG "LUN[%d]: %x %x %x %x = %x\n", i, |
2668 | ld_buff->LUN[i][0], ld_buff->LUN[i][1],ld_buff->LUN[i][2], | 2800 | ld_buff->LUN[i][0], ld_buff->LUN[i][1], |
2669 | ld_buff->LUN[i][3], hba[cntl_num]->drv[i].LunID); | 2801 | ld_buff->LUN[i][2], ld_buff->LUN[i][3], |
2802 | hba[cntl_num]->drv[i].LunID); | ||
2670 | #endif /* CCISS_DEBUG */ | 2803 | #endif /* CCISS_DEBUG */ |
2671 | cciss_read_capacity(cntl_num, i, size_buff, 0, | 2804 | cciss_read_capacity(cntl_num, i, size_buff, 0, |
2672 | &total_size, &block_size); | 2805 | &total_size, &block_size); |
2673 | cciss_geometry_inquiry(cntl_num, i, 0, total_size, block_size, | 2806 | cciss_geometry_inquiry(cntl_num, i, 0, total_size, |
2674 | inq_buff, &hba[cntl_num]->drv[i]); | 2807 | block_size, inq_buff, &hba[cntl_num]->drv[i]); |
2808 | } else { | ||
2809 | /* initialize raid_level to indicate a free space */ | ||
2810 | hba[cntl_num]->drv[i].raid_level = -1; | ||
2811 | } | ||
2675 | } | 2812 | } |
2676 | kfree(ld_buff); | 2813 | kfree(ld_buff); |
2677 | kfree(size_buff); | 2814 | kfree(size_buff); |