diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-22 20:03:12 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-22 20:03:12 -0400 |
commit | 8abfc6e7a45eb74e51904bbae676fae008b11366 (patch) | |
tree | 57d0a24558c0693e3a52e8e756616f6c72def1e9 /drivers/block/cciss.c | |
parent | e9dd2b6837e26fe202708cce5ea4bb4ee3e3482e (diff) | |
parent | 6362beea8914cbd4630ccde3617d944aeca2d48f (diff) |
Merge branch 'for-2.6.37/drivers' of git://git.kernel.dk/linux-2.6-block
* 'for-2.6.37/drivers' of git://git.kernel.dk/linux-2.6-block: (95 commits)
cciss: fix PCI IDs for new Smart Array controllers
drbd: add race-breaker to drbd_go_diskless
drbd: use dynamic_dev_dbg to optionally log uuid changes
dynamic_debug.h: Fix dynamic_dev_dbg() macro if CONFIG_DYNAMIC_DEBUG not set
drbd: cleanup: change "<= 0" to "== 0"
drbd: relax the grace period of the md_sync timer again
drbd: add some more explicit drbd_md_sync
drbd: drop wrong debug asserts, fix recently introduced race
drbd: cleanup useless leftover warn/error printk's
drbd: add explicit drbd_md_sync to drbd_resync_finished
drbd: Do not log an ASSERT for P_OV_REQUEST packets while C_CONNECTED
drbd: fix for possible deadlock on IO error during resync
drbd: fix unlikely access after free and list corruption
drbd: fix for spurious fullsync (uuids rotated too fast)
drbd: allow for explicit resync-finished notifications
drbd: preparation commit, using full state in receive_state()
drbd: drbd_send_ack_dp must not rely on header information
drbd: Fix regression in recv_bm_rle_bits (compressed bitmap)
drbd: Fixed a stupid copy and paste error
drbd: Allow larger values for c-fill-target.
...
Fix up trivial conflict in drivers/block/ataflop.c due to BKL removal
Diffstat (limited to 'drivers/block/cciss.c')
-rw-r--r-- | drivers/block/cciss.c | 864 |
1 files changed, 424 insertions, 440 deletions
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index c484c96e22a6..f09e6df15aa7 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c | |||
@@ -105,11 +105,12 @@ static const struct pci_device_id cciss_pci_device_id[] = { | |||
105 | {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3249}, | 105 | {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3249}, |
106 | {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x324A}, | 106 | {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x324A}, |
107 | {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x324B}, | 107 | {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x324B}, |
108 | {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3250}, | 108 | {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3350}, |
109 | {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3251}, | 109 | {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3351}, |
110 | {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3252}, | 110 | {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3352}, |
111 | {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3253}, | 111 | {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3353}, |
112 | {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3254}, | 112 | {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3354}, |
113 | {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3355}, | ||
113 | {0,} | 114 | {0,} |
114 | }; | 115 | }; |
115 | 116 | ||
@@ -149,11 +150,12 @@ static struct board_type products[] = { | |||
149 | {0x3249103C, "Smart Array P812", &SA5_access}, | 150 | {0x3249103C, "Smart Array P812", &SA5_access}, |
150 | {0x324A103C, "Smart Array P712m", &SA5_access}, | 151 | {0x324A103C, "Smart Array P712m", &SA5_access}, |
151 | {0x324B103C, "Smart Array P711m", &SA5_access}, | 152 | {0x324B103C, "Smart Array P711m", &SA5_access}, |
152 | {0x3250103C, "Smart Array", &SA5_access}, | 153 | {0x3350103C, "Smart Array", &SA5_access}, |
153 | {0x3251103C, "Smart Array", &SA5_access}, | 154 | {0x3351103C, "Smart Array", &SA5_access}, |
154 | {0x3252103C, "Smart Array", &SA5_access}, | 155 | {0x3352103C, "Smart Array", &SA5_access}, |
155 | {0x3253103C, "Smart Array", &SA5_access}, | 156 | {0x3353103C, "Smart Array", &SA5_access}, |
156 | {0x3254103C, "Smart Array", &SA5_access}, | 157 | {0x3354103C, "Smart Array", &SA5_access}, |
158 | {0x3355103C, "Smart Array", &SA5_access}, | ||
157 | }; | 159 | }; |
158 | 160 | ||
159 | /* How long to wait (in milliseconds) for board to go into simple mode */ | 161 | /* How long to wait (in milliseconds) for board to go into simple mode */ |
@@ -1232,470 +1234,452 @@ static void check_ioctl_unit_attention(ctlr_info_t *h, CommandList_struct *c) | |||
1232 | c->err_info->ScsiStatus != SAM_STAT_CHECK_CONDITION) | 1234 | c->err_info->ScsiStatus != SAM_STAT_CHECK_CONDITION) |
1233 | (void)check_for_unit_attention(h, c); | 1235 | (void)check_for_unit_attention(h, c); |
1234 | } | 1236 | } |
1235 | /* | 1237 | |
1236 | * ioctl | 1238 | static int cciss_getpciinfo(ctlr_info_t *h, void __user *argp) |
1237 | */ | ||
1238 | static int cciss_ioctl(struct block_device *bdev, fmode_t mode, | ||
1239 | unsigned int cmd, unsigned long arg) | ||
1240 | { | 1239 | { |
1241 | struct gendisk *disk = bdev->bd_disk; | 1240 | cciss_pci_info_struct pciinfo; |
1242 | ctlr_info_t *h = get_host(disk); | ||
1243 | drive_info_struct *drv = get_drv(disk); | ||
1244 | void __user *argp = (void __user *)arg; | ||
1245 | 1241 | ||
1246 | dev_dbg(&h->pdev->dev, "cciss_ioctl: Called with cmd=%x %lx\n", | 1242 | if (!argp) |
1247 | cmd, arg); | 1243 | return -EINVAL; |
1248 | switch (cmd) { | 1244 | pciinfo.domain = pci_domain_nr(h->pdev->bus); |
1249 | case CCISS_GETPCIINFO: | 1245 | pciinfo.bus = h->pdev->bus->number; |
1250 | { | 1246 | pciinfo.dev_fn = h->pdev->devfn; |
1251 | cciss_pci_info_struct pciinfo; | 1247 | pciinfo.board_id = h->board_id; |
1252 | 1248 | if (copy_to_user(argp, &pciinfo, sizeof(cciss_pci_info_struct))) | |
1253 | if (!arg) | 1249 | return -EFAULT; |
1254 | return -EINVAL; | 1250 | return 0; |
1255 | pciinfo.domain = pci_domain_nr(h->pdev->bus); | 1251 | } |
1256 | pciinfo.bus = h->pdev->bus->number; | ||
1257 | pciinfo.dev_fn = h->pdev->devfn; | ||
1258 | pciinfo.board_id = h->board_id; | ||
1259 | if (copy_to_user | ||
1260 | (argp, &pciinfo, sizeof(cciss_pci_info_struct))) | ||
1261 | return -EFAULT; | ||
1262 | return 0; | ||
1263 | } | ||
1264 | case CCISS_GETINTINFO: | ||
1265 | { | ||
1266 | cciss_coalint_struct intinfo; | ||
1267 | if (!arg) | ||
1268 | return -EINVAL; | ||
1269 | intinfo.delay = | ||
1270 | readl(&h->cfgtable->HostWrite.CoalIntDelay); | ||
1271 | intinfo.count = | ||
1272 | readl(&h->cfgtable->HostWrite.CoalIntCount); | ||
1273 | if (copy_to_user | ||
1274 | (argp, &intinfo, sizeof(cciss_coalint_struct))) | ||
1275 | return -EFAULT; | ||
1276 | return 0; | ||
1277 | } | ||
1278 | case CCISS_SETINTINFO: | ||
1279 | { | ||
1280 | cciss_coalint_struct intinfo; | ||
1281 | unsigned long flags; | ||
1282 | int i; | ||
1283 | |||
1284 | if (!arg) | ||
1285 | return -EINVAL; | ||
1286 | if (!capable(CAP_SYS_ADMIN)) | ||
1287 | return -EPERM; | ||
1288 | if (copy_from_user | ||
1289 | (&intinfo, argp, sizeof(cciss_coalint_struct))) | ||
1290 | return -EFAULT; | ||
1291 | if ((intinfo.delay == 0) && (intinfo.count == 0)) | ||
1292 | return -EINVAL; | ||
1293 | spin_lock_irqsave(&h->lock, flags); | ||
1294 | /* Update the field, and then ring the doorbell */ | ||
1295 | writel(intinfo.delay, | ||
1296 | &(h->cfgtable->HostWrite.CoalIntDelay)); | ||
1297 | writel(intinfo.count, | ||
1298 | &(h->cfgtable->HostWrite.CoalIntCount)); | ||
1299 | writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); | ||
1300 | |||
1301 | for (i = 0; i < MAX_IOCTL_CONFIG_WAIT; i++) { | ||
1302 | if (!(readl(h->vaddr + SA5_DOORBELL) | ||
1303 | & CFGTBL_ChangeReq)) | ||
1304 | break; | ||
1305 | /* delay and try again */ | ||
1306 | udelay(1000); | ||
1307 | } | ||
1308 | spin_unlock_irqrestore(&h->lock, flags); | ||
1309 | if (i >= MAX_IOCTL_CONFIG_WAIT) | ||
1310 | return -EAGAIN; | ||
1311 | return 0; | ||
1312 | } | ||
1313 | case CCISS_GETNODENAME: | ||
1314 | { | ||
1315 | NodeName_type NodeName; | ||
1316 | int i; | ||
1317 | |||
1318 | if (!arg) | ||
1319 | return -EINVAL; | ||
1320 | for (i = 0; i < 16; i++) | ||
1321 | NodeName[i] = | ||
1322 | readb(&h->cfgtable->ServerName[i]); | ||
1323 | if (copy_to_user(argp, NodeName, sizeof(NodeName_type))) | ||
1324 | return -EFAULT; | ||
1325 | return 0; | ||
1326 | } | ||
1327 | case CCISS_SETNODENAME: | ||
1328 | { | ||
1329 | NodeName_type NodeName; | ||
1330 | unsigned long flags; | ||
1331 | int i; | ||
1332 | 1252 | ||
1333 | if (!arg) | 1253 | static int cciss_getintinfo(ctlr_info_t *h, void __user *argp) |
1334 | return -EINVAL; | 1254 | { |
1335 | if (!capable(CAP_SYS_ADMIN)) | 1255 | cciss_coalint_struct intinfo; |
1336 | return -EPERM; | ||
1337 | 1256 | ||
1338 | if (copy_from_user | 1257 | if (!argp) |
1339 | (NodeName, argp, sizeof(NodeName_type))) | 1258 | return -EINVAL; |
1340 | return -EFAULT; | 1259 | intinfo.delay = readl(&h->cfgtable->HostWrite.CoalIntDelay); |
1260 | intinfo.count = readl(&h->cfgtable->HostWrite.CoalIntCount); | ||
1261 | if (copy_to_user | ||
1262 | (argp, &intinfo, sizeof(cciss_coalint_struct))) | ||
1263 | return -EFAULT; | ||
1264 | return 0; | ||
1265 | } | ||
1341 | 1266 | ||
1342 | spin_lock_irqsave(&h->lock, flags); | 1267 | static int cciss_setintinfo(ctlr_info_t *h, void __user *argp) |
1268 | { | ||
1269 | cciss_coalint_struct intinfo; | ||
1270 | unsigned long flags; | ||
1271 | int i; | ||
1343 | 1272 | ||
1344 | /* Update the field, and then ring the doorbell */ | 1273 | if (!argp) |
1345 | for (i = 0; i < 16; i++) | 1274 | return -EINVAL; |
1346 | writeb(NodeName[i], | 1275 | if (!capable(CAP_SYS_ADMIN)) |
1347 | &h->cfgtable->ServerName[i]); | 1276 | return -EPERM; |
1277 | if (copy_from_user(&intinfo, argp, sizeof(intinfo))) | ||
1278 | return -EFAULT; | ||
1279 | if ((intinfo.delay == 0) && (intinfo.count == 0)) | ||
1280 | return -EINVAL; | ||
1281 | spin_lock_irqsave(&h->lock, flags); | ||
1282 | /* Update the field, and then ring the doorbell */ | ||
1283 | writel(intinfo.delay, &(h->cfgtable->HostWrite.CoalIntDelay)); | ||
1284 | writel(intinfo.count, &(h->cfgtable->HostWrite.CoalIntCount)); | ||
1285 | writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); | ||
1348 | 1286 | ||
1349 | writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); | 1287 | for (i = 0; i < MAX_IOCTL_CONFIG_WAIT; i++) { |
1288 | if (!(readl(h->vaddr + SA5_DOORBELL) & CFGTBL_ChangeReq)) | ||
1289 | break; | ||
1290 | udelay(1000); /* delay and try again */ | ||
1291 | } | ||
1292 | spin_unlock_irqrestore(&h->lock, flags); | ||
1293 | if (i >= MAX_IOCTL_CONFIG_WAIT) | ||
1294 | return -EAGAIN; | ||
1295 | return 0; | ||
1296 | } | ||
1350 | 1297 | ||
1351 | for (i = 0; i < MAX_IOCTL_CONFIG_WAIT; i++) { | 1298 | static int cciss_getnodename(ctlr_info_t *h, void __user *argp) |
1352 | if (!(readl(h->vaddr + SA5_DOORBELL) | 1299 | { |
1353 | & CFGTBL_ChangeReq)) | 1300 | NodeName_type NodeName; |
1354 | break; | 1301 | int i; |
1355 | /* delay and try again */ | ||
1356 | udelay(1000); | ||
1357 | } | ||
1358 | spin_unlock_irqrestore(&h->lock, flags); | ||
1359 | if (i >= MAX_IOCTL_CONFIG_WAIT) | ||
1360 | return -EAGAIN; | ||
1361 | return 0; | ||
1362 | } | ||
1363 | 1302 | ||
1364 | case CCISS_GETHEARTBEAT: | 1303 | if (!argp) |
1365 | { | 1304 | return -EINVAL; |
1366 | Heartbeat_type heartbeat; | 1305 | for (i = 0; i < 16; i++) |
1367 | 1306 | NodeName[i] = readb(&h->cfgtable->ServerName[i]); | |
1368 | if (!arg) | 1307 | if (copy_to_user(argp, NodeName, sizeof(NodeName_type))) |
1369 | return -EINVAL; | 1308 | return -EFAULT; |
1370 | heartbeat = readl(&h->cfgtable->HeartBeat); | 1309 | return 0; |
1371 | if (copy_to_user | 1310 | } |
1372 | (argp, &heartbeat, sizeof(Heartbeat_type))) | ||
1373 | return -EFAULT; | ||
1374 | return 0; | ||
1375 | } | ||
1376 | case CCISS_GETBUSTYPES: | ||
1377 | { | ||
1378 | BusTypes_type BusTypes; | ||
1379 | |||
1380 | if (!arg) | ||
1381 | return -EINVAL; | ||
1382 | BusTypes = readl(&h->cfgtable->BusTypes); | ||
1383 | if (copy_to_user | ||
1384 | (argp, &BusTypes, sizeof(BusTypes_type))) | ||
1385 | return -EFAULT; | ||
1386 | return 0; | ||
1387 | } | ||
1388 | case CCISS_GETFIRMVER: | ||
1389 | { | ||
1390 | FirmwareVer_type firmware; | ||
1391 | 1311 | ||
1392 | if (!arg) | 1312 | static int cciss_setnodename(ctlr_info_t *h, void __user *argp) |
1393 | return -EINVAL; | 1313 | { |
1394 | memcpy(firmware, h->firm_ver, 4); | 1314 | NodeName_type NodeName; |
1315 | unsigned long flags; | ||
1316 | int i; | ||
1395 | 1317 | ||
1396 | if (copy_to_user | 1318 | if (!argp) |
1397 | (argp, firmware, sizeof(FirmwareVer_type))) | 1319 | return -EINVAL; |
1398 | return -EFAULT; | 1320 | if (!capable(CAP_SYS_ADMIN)) |
1399 | return 0; | 1321 | return -EPERM; |
1400 | } | 1322 | if (copy_from_user(NodeName, argp, sizeof(NodeName_type))) |
1401 | case CCISS_GETDRIVVER: | 1323 | return -EFAULT; |
1402 | { | 1324 | spin_lock_irqsave(&h->lock, flags); |
1403 | DriverVer_type DriverVer = DRIVER_VERSION; | 1325 | /* Update the field, and then ring the doorbell */ |
1326 | for (i = 0; i < 16; i++) | ||
1327 | writeb(NodeName[i], &h->cfgtable->ServerName[i]); | ||
1328 | writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); | ||
1329 | for (i = 0; i < MAX_IOCTL_CONFIG_WAIT; i++) { | ||
1330 | if (!(readl(h->vaddr + SA5_DOORBELL) & CFGTBL_ChangeReq)) | ||
1331 | break; | ||
1332 | udelay(1000); /* delay and try again */ | ||
1333 | } | ||
1334 | spin_unlock_irqrestore(&h->lock, flags); | ||
1335 | if (i >= MAX_IOCTL_CONFIG_WAIT) | ||
1336 | return -EAGAIN; | ||
1337 | return 0; | ||
1338 | } | ||
1404 | 1339 | ||
1405 | if (!arg) | 1340 | static int cciss_getheartbeat(ctlr_info_t *h, void __user *argp) |
1406 | return -EINVAL; | 1341 | { |
1342 | Heartbeat_type heartbeat; | ||
1407 | 1343 | ||
1408 | if (copy_to_user | 1344 | if (!argp) |
1409 | (argp, &DriverVer, sizeof(DriverVer_type))) | 1345 | return -EINVAL; |
1410 | return -EFAULT; | 1346 | heartbeat = readl(&h->cfgtable->HeartBeat); |
1411 | return 0; | 1347 | if (copy_to_user(argp, &heartbeat, sizeof(Heartbeat_type))) |
1412 | } | 1348 | return -EFAULT; |
1349 | return 0; | ||
1350 | } | ||
1413 | 1351 | ||
1414 | case CCISS_DEREGDISK: | 1352 | static int cciss_getbustypes(ctlr_info_t *h, void __user *argp) |
1415 | case CCISS_REGNEWD: | 1353 | { |
1416 | case CCISS_REVALIDVOLS: | 1354 | BusTypes_type BusTypes; |
1417 | return rebuild_lun_table(h, 0, 1); | 1355 | |
1356 | if (!argp) | ||
1357 | return -EINVAL; | ||
1358 | BusTypes = readl(&h->cfgtable->BusTypes); | ||
1359 | if (copy_to_user(argp, &BusTypes, sizeof(BusTypes_type))) | ||
1360 | return -EFAULT; | ||
1361 | return 0; | ||
1362 | } | ||
1418 | 1363 | ||
1419 | case CCISS_GETLUNINFO:{ | 1364 | static int cciss_getfirmver(ctlr_info_t *h, void __user *argp) |
1420 | LogvolInfo_struct luninfo; | 1365 | { |
1366 | FirmwareVer_type firmware; | ||
1421 | 1367 | ||
1422 | memcpy(&luninfo.LunID, drv->LunID, | 1368 | if (!argp) |
1423 | sizeof(luninfo.LunID)); | 1369 | return -EINVAL; |
1424 | luninfo.num_opens = drv->usage_count; | 1370 | memcpy(firmware, h->firm_ver, 4); |
1425 | luninfo.num_parts = 0; | 1371 | |
1426 | if (copy_to_user(argp, &luninfo, | 1372 | if (copy_to_user |
1427 | sizeof(LogvolInfo_struct))) | 1373 | (argp, firmware, sizeof(FirmwareVer_type))) |
1428 | return -EFAULT; | 1374 | return -EFAULT; |
1429 | return 0; | 1375 | return 0; |
1376 | } | ||
1377 | |||
1378 | static int cciss_getdrivver(ctlr_info_t *h, void __user *argp) | ||
1379 | { | ||
1380 | DriverVer_type DriverVer = DRIVER_VERSION; | ||
1381 | |||
1382 | if (!argp) | ||
1383 | return -EINVAL; | ||
1384 | if (copy_to_user(argp, &DriverVer, sizeof(DriverVer_type))) | ||
1385 | return -EFAULT; | ||
1386 | return 0; | ||
1387 | } | ||
1388 | |||
1389 | static int cciss_getluninfo(ctlr_info_t *h, | ||
1390 | struct gendisk *disk, void __user *argp) | ||
1391 | { | ||
1392 | LogvolInfo_struct luninfo; | ||
1393 | drive_info_struct *drv = get_drv(disk); | ||
1394 | |||
1395 | if (!argp) | ||
1396 | return -EINVAL; | ||
1397 | memcpy(&luninfo.LunID, drv->LunID, sizeof(luninfo.LunID)); | ||
1398 | luninfo.num_opens = drv->usage_count; | ||
1399 | luninfo.num_parts = 0; | ||
1400 | if (copy_to_user(argp, &luninfo, sizeof(LogvolInfo_struct))) | ||
1401 | return -EFAULT; | ||
1402 | return 0; | ||
1403 | } | ||
1404 | |||
1405 | static int cciss_passthru(ctlr_info_t *h, void __user *argp) | ||
1406 | { | ||
1407 | IOCTL_Command_struct iocommand; | ||
1408 | CommandList_struct *c; | ||
1409 | char *buff = NULL; | ||
1410 | u64bit temp64; | ||
1411 | DECLARE_COMPLETION_ONSTACK(wait); | ||
1412 | |||
1413 | if (!argp) | ||
1414 | return -EINVAL; | ||
1415 | |||
1416 | if (!capable(CAP_SYS_RAWIO)) | ||
1417 | return -EPERM; | ||
1418 | |||
1419 | if (copy_from_user | ||
1420 | (&iocommand, argp, sizeof(IOCTL_Command_struct))) | ||
1421 | return -EFAULT; | ||
1422 | if ((iocommand.buf_size < 1) && | ||
1423 | (iocommand.Request.Type.Direction != XFER_NONE)) { | ||
1424 | return -EINVAL; | ||
1425 | } | ||
1426 | if (iocommand.buf_size > 0) { | ||
1427 | buff = kmalloc(iocommand.buf_size, GFP_KERNEL); | ||
1428 | if (buff == NULL) | ||
1429 | return -EFAULT; | ||
1430 | } | ||
1431 | if (iocommand.Request.Type.Direction == XFER_WRITE) { | ||
1432 | /* Copy the data into the buffer we created */ | ||
1433 | if (copy_from_user(buff, iocommand.buf, iocommand.buf_size)) { | ||
1434 | kfree(buff); | ||
1435 | return -EFAULT; | ||
1430 | } | 1436 | } |
1431 | case CCISS_PASSTHRU: | 1437 | } else { |
1432 | { | 1438 | memset(buff, 0, iocommand.buf_size); |
1433 | IOCTL_Command_struct iocommand; | 1439 | } |
1434 | CommandList_struct *c; | 1440 | c = cmd_special_alloc(h); |
1435 | char *buff = NULL; | 1441 | if (!c) { |
1436 | u64bit temp64; | 1442 | kfree(buff); |
1437 | DECLARE_COMPLETION_ONSTACK(wait); | 1443 | return -ENOMEM; |
1438 | 1444 | } | |
1439 | if (!arg) | 1445 | /* Fill in the command type */ |
1440 | return -EINVAL; | 1446 | c->cmd_type = CMD_IOCTL_PEND; |
1441 | 1447 | /* Fill in Command Header */ | |
1442 | if (!capable(CAP_SYS_RAWIO)) | 1448 | c->Header.ReplyQueue = 0; /* unused in simple mode */ |
1443 | return -EPERM; | 1449 | if (iocommand.buf_size > 0) { /* buffer to fill */ |
1444 | 1450 | c->Header.SGList = 1; | |
1445 | if (copy_from_user | 1451 | c->Header.SGTotal = 1; |
1446 | (&iocommand, argp, sizeof(IOCTL_Command_struct))) | 1452 | } else { /* no buffers to fill */ |
1447 | return -EFAULT; | 1453 | c->Header.SGList = 0; |
1448 | if ((iocommand.buf_size < 1) && | 1454 | c->Header.SGTotal = 0; |
1449 | (iocommand.Request.Type.Direction != XFER_NONE)) { | 1455 | } |
1450 | return -EINVAL; | 1456 | c->Header.LUN = iocommand.LUN_info; |
1451 | } | 1457 | /* use the kernel address the cmd block for tag */ |
1452 | #if 0 /* 'buf_size' member is 16-bits, and always smaller than kmalloc limit */ | 1458 | c->Header.Tag.lower = c->busaddr; |
1453 | /* Check kmalloc limits */ | ||
1454 | if (iocommand.buf_size > 128000) | ||
1455 | return -EINVAL; | ||
1456 | #endif | ||
1457 | if (iocommand.buf_size > 0) { | ||
1458 | buff = kmalloc(iocommand.buf_size, GFP_KERNEL); | ||
1459 | if (buff == NULL) | ||
1460 | return -EFAULT; | ||
1461 | } | ||
1462 | if (iocommand.Request.Type.Direction == XFER_WRITE) { | ||
1463 | /* Copy the data into the buffer we created */ | ||
1464 | if (copy_from_user | ||
1465 | (buff, iocommand.buf, iocommand.buf_size)) { | ||
1466 | kfree(buff); | ||
1467 | return -EFAULT; | ||
1468 | } | ||
1469 | } else { | ||
1470 | memset(buff, 0, iocommand.buf_size); | ||
1471 | } | ||
1472 | c = cmd_special_alloc(h); | ||
1473 | if (!c) { | ||
1474 | kfree(buff); | ||
1475 | return -ENOMEM; | ||
1476 | } | ||
1477 | /* Fill in the command type */ | ||
1478 | c->cmd_type = CMD_IOCTL_PEND; | ||
1479 | /* Fill in Command Header */ | ||
1480 | c->Header.ReplyQueue = 0; /* unused in simple mode */ | ||
1481 | if (iocommand.buf_size > 0) /* buffer to fill */ | ||
1482 | { | ||
1483 | c->Header.SGList = 1; | ||
1484 | c->Header.SGTotal = 1; | ||
1485 | } else /* no buffers to fill */ | ||
1486 | { | ||
1487 | c->Header.SGList = 0; | ||
1488 | c->Header.SGTotal = 0; | ||
1489 | } | ||
1490 | c->Header.LUN = iocommand.LUN_info; | ||
1491 | /* use the kernel address the cmd block for tag */ | ||
1492 | c->Header.Tag.lower = c->busaddr; | ||
1493 | |||
1494 | /* Fill in Request block */ | ||
1495 | c->Request = iocommand.Request; | ||
1496 | |||
1497 | /* Fill in the scatter gather information */ | ||
1498 | if (iocommand.buf_size > 0) { | ||
1499 | temp64.val = pci_map_single(h->pdev, buff, | ||
1500 | iocommand.buf_size, | ||
1501 | PCI_DMA_BIDIRECTIONAL); | ||
1502 | c->SG[0].Addr.lower = temp64.val32.lower; | ||
1503 | c->SG[0].Addr.upper = temp64.val32.upper; | ||
1504 | c->SG[0].Len = iocommand.buf_size; | ||
1505 | c->SG[0].Ext = 0; /* we are not chaining */ | ||
1506 | } | ||
1507 | c->waiting = &wait; | ||
1508 | 1459 | ||
1509 | enqueue_cmd_and_start_io(h, c); | 1460 | /* Fill in Request block */ |
1510 | wait_for_completion(&wait); | 1461 | c->Request = iocommand.Request; |
1511 | 1462 | ||
1512 | /* unlock the buffers from DMA */ | 1463 | /* Fill in the scatter gather information */ |
1513 | temp64.val32.lower = c->SG[0].Addr.lower; | 1464 | if (iocommand.buf_size > 0) { |
1514 | temp64.val32.upper = c->SG[0].Addr.upper; | 1465 | temp64.val = pci_map_single(h->pdev, buff, |
1515 | pci_unmap_single(h->pdev, (dma_addr_t) temp64.val, | 1466 | iocommand.buf_size, PCI_DMA_BIDIRECTIONAL); |
1516 | iocommand.buf_size, | 1467 | c->SG[0].Addr.lower = temp64.val32.lower; |
1517 | PCI_DMA_BIDIRECTIONAL); | 1468 | c->SG[0].Addr.upper = temp64.val32.upper; |
1469 | c->SG[0].Len = iocommand.buf_size; | ||
1470 | c->SG[0].Ext = 0; /* we are not chaining */ | ||
1471 | } | ||
1472 | c->waiting = &wait; | ||
1518 | 1473 | ||
1519 | check_ioctl_unit_attention(h, c); | 1474 | enqueue_cmd_and_start_io(h, c); |
1475 | wait_for_completion(&wait); | ||
1520 | 1476 | ||
1521 | /* Copy the error information out */ | 1477 | /* unlock the buffers from DMA */ |
1522 | iocommand.error_info = *(c->err_info); | 1478 | temp64.val32.lower = c->SG[0].Addr.lower; |
1523 | if (copy_to_user | 1479 | temp64.val32.upper = c->SG[0].Addr.upper; |
1524 | (argp, &iocommand, sizeof(IOCTL_Command_struct))) { | 1480 | pci_unmap_single(h->pdev, (dma_addr_t) temp64.val, iocommand.buf_size, |
1525 | kfree(buff); | 1481 | PCI_DMA_BIDIRECTIONAL); |
1526 | cmd_special_free(h, c); | 1482 | check_ioctl_unit_attention(h, c); |
1527 | return -EFAULT; | 1483 | |
1528 | } | 1484 | /* Copy the error information out */ |
1485 | iocommand.error_info = *(c->err_info); | ||
1486 | if (copy_to_user(argp, &iocommand, sizeof(IOCTL_Command_struct))) { | ||
1487 | kfree(buff); | ||
1488 | cmd_special_free(h, c); | ||
1489 | return -EFAULT; | ||
1490 | } | ||
1529 | 1491 | ||
1530 | if (iocommand.Request.Type.Direction == XFER_READ) { | 1492 | if (iocommand.Request.Type.Direction == XFER_READ) { |
1531 | /* Copy the data out of the buffer we created */ | 1493 | /* Copy the data out of the buffer we created */ |
1532 | if (copy_to_user | 1494 | if (copy_to_user(iocommand.buf, buff, iocommand.buf_size)) { |
1533 | (iocommand.buf, buff, iocommand.buf_size)) { | ||
1534 | kfree(buff); | ||
1535 | cmd_special_free(h, c); | ||
1536 | return -EFAULT; | ||
1537 | } | ||
1538 | } | ||
1539 | kfree(buff); | 1495 | kfree(buff); |
1540 | cmd_special_free(h, c); | 1496 | cmd_special_free(h, c); |
1541 | return 0; | 1497 | return -EFAULT; |
1542 | } | 1498 | } |
1543 | case CCISS_BIG_PASSTHRU:{ | 1499 | } |
1544 | BIG_IOCTL_Command_struct *ioc; | 1500 | kfree(buff); |
1545 | CommandList_struct *c; | 1501 | cmd_special_free(h, c); |
1546 | unsigned char **buff = NULL; | 1502 | return 0; |
1547 | int *buff_size = NULL; | 1503 | } |
1548 | u64bit temp64; | 1504 | |
1549 | BYTE sg_used = 0; | 1505 | static int cciss_bigpassthru(ctlr_info_t *h, void __user *argp) |
1550 | int status = 0; | 1506 | { |
1551 | int i; | 1507 | BIG_IOCTL_Command_struct *ioc; |
1552 | DECLARE_COMPLETION_ONSTACK(wait); | 1508 | CommandList_struct *c; |
1553 | __u32 left; | 1509 | unsigned char **buff = NULL; |
1554 | __u32 sz; | 1510 | int *buff_size = NULL; |
1555 | BYTE __user *data_ptr; | 1511 | u64bit temp64; |
1556 | 1512 | BYTE sg_used = 0; | |
1557 | if (!arg) | 1513 | int status = 0; |
1558 | return -EINVAL; | 1514 | int i; |
1559 | if (!capable(CAP_SYS_RAWIO)) | 1515 | DECLARE_COMPLETION_ONSTACK(wait); |
1560 | return -EPERM; | 1516 | __u32 left; |
1561 | ioc = (BIG_IOCTL_Command_struct *) | 1517 | __u32 sz; |
1562 | kmalloc(sizeof(*ioc), GFP_KERNEL); | 1518 | BYTE __user *data_ptr; |
1563 | if (!ioc) { | 1519 | |
1564 | status = -ENOMEM; | 1520 | if (!argp) |
1565 | goto cleanup1; | 1521 | return -EINVAL; |
1566 | } | 1522 | if (!capable(CAP_SYS_RAWIO)) |
1567 | if (copy_from_user(ioc, argp, sizeof(*ioc))) { | 1523 | return -EPERM; |
1524 | ioc = (BIG_IOCTL_Command_struct *) | ||
1525 | kmalloc(sizeof(*ioc), GFP_KERNEL); | ||
1526 | if (!ioc) { | ||
1527 | status = -ENOMEM; | ||
1528 | goto cleanup1; | ||
1529 | } | ||
1530 | if (copy_from_user(ioc, argp, sizeof(*ioc))) { | ||
1531 | status = -EFAULT; | ||
1532 | goto cleanup1; | ||
1533 | } | ||
1534 | if ((ioc->buf_size < 1) && | ||
1535 | (ioc->Request.Type.Direction != XFER_NONE)) { | ||
1536 | status = -EINVAL; | ||
1537 | goto cleanup1; | ||
1538 | } | ||
1539 | /* Check kmalloc limits using all SGs */ | ||
1540 | if (ioc->malloc_size > MAX_KMALLOC_SIZE) { | ||
1541 | status = -EINVAL; | ||
1542 | goto cleanup1; | ||
1543 | } | ||
1544 | if (ioc->buf_size > ioc->malloc_size * MAXSGENTRIES) { | ||
1545 | status = -EINVAL; | ||
1546 | goto cleanup1; | ||
1547 | } | ||
1548 | buff = kzalloc(MAXSGENTRIES * sizeof(char *), GFP_KERNEL); | ||
1549 | if (!buff) { | ||
1550 | status = -ENOMEM; | ||
1551 | goto cleanup1; | ||
1552 | } | ||
1553 | buff_size = kmalloc(MAXSGENTRIES * sizeof(int), GFP_KERNEL); | ||
1554 | if (!buff_size) { | ||
1555 | status = -ENOMEM; | ||
1556 | goto cleanup1; | ||
1557 | } | ||
1558 | left = ioc->buf_size; | ||
1559 | data_ptr = ioc->buf; | ||
1560 | while (left) { | ||
1561 | sz = (left > ioc->malloc_size) ? ioc->malloc_size : left; | ||
1562 | buff_size[sg_used] = sz; | ||
1563 | buff[sg_used] = kmalloc(sz, GFP_KERNEL); | ||
1564 | if (buff[sg_used] == NULL) { | ||
1565 | status = -ENOMEM; | ||
1566 | goto cleanup1; | ||
1567 | } | ||
1568 | if (ioc->Request.Type.Direction == XFER_WRITE) { | ||
1569 | if (copy_from_user(buff[sg_used], data_ptr, sz)) { | ||
1568 | status = -EFAULT; | 1570 | status = -EFAULT; |
1569 | goto cleanup1; | 1571 | goto cleanup1; |
1570 | } | 1572 | } |
1571 | if ((ioc->buf_size < 1) && | 1573 | } else { |
1572 | (ioc->Request.Type.Direction != XFER_NONE)) { | 1574 | memset(buff[sg_used], 0, sz); |
1573 | status = -EINVAL; | 1575 | } |
1574 | goto cleanup1; | 1576 | left -= sz; |
1575 | } | 1577 | data_ptr += sz; |
1576 | /* Check kmalloc limits using all SGs */ | 1578 | sg_used++; |
1577 | if (ioc->malloc_size > MAX_KMALLOC_SIZE) { | 1579 | } |
1578 | status = -EINVAL; | 1580 | c = cmd_special_alloc(h); |
1579 | goto cleanup1; | 1581 | if (!c) { |
1580 | } | 1582 | status = -ENOMEM; |
1581 | if (ioc->buf_size > ioc->malloc_size * MAXSGENTRIES) { | 1583 | goto cleanup1; |
1582 | status = -EINVAL; | 1584 | } |
1583 | goto cleanup1; | 1585 | c->cmd_type = CMD_IOCTL_PEND; |
1584 | } | 1586 | c->Header.ReplyQueue = 0; |
1585 | buff = | 1587 | c->Header.SGList = sg_used; |
1586 | kzalloc(MAXSGENTRIES * sizeof(char *), GFP_KERNEL); | 1588 | c->Header.SGTotal = sg_used; |
1587 | if (!buff) { | 1589 | c->Header.LUN = ioc->LUN_info; |
1588 | status = -ENOMEM; | 1590 | c->Header.Tag.lower = c->busaddr; |
1589 | goto cleanup1; | ||
1590 | } | ||
1591 | buff_size = kmalloc(MAXSGENTRIES * sizeof(int), | ||
1592 | GFP_KERNEL); | ||
1593 | if (!buff_size) { | ||
1594 | status = -ENOMEM; | ||
1595 | goto cleanup1; | ||
1596 | } | ||
1597 | left = ioc->buf_size; | ||
1598 | data_ptr = ioc->buf; | ||
1599 | while (left) { | ||
1600 | sz = (left > | ||
1601 | ioc->malloc_size) ? ioc-> | ||
1602 | malloc_size : left; | ||
1603 | buff_size[sg_used] = sz; | ||
1604 | buff[sg_used] = kmalloc(sz, GFP_KERNEL); | ||
1605 | if (buff[sg_used] == NULL) { | ||
1606 | status = -ENOMEM; | ||
1607 | goto cleanup1; | ||
1608 | } | ||
1609 | if (ioc->Request.Type.Direction == XFER_WRITE) { | ||
1610 | if (copy_from_user | ||
1611 | (buff[sg_used], data_ptr, sz)) { | ||
1612 | status = -EFAULT; | ||
1613 | goto cleanup1; | ||
1614 | } | ||
1615 | } else { | ||
1616 | memset(buff[sg_used], 0, sz); | ||
1617 | } | ||
1618 | left -= sz; | ||
1619 | data_ptr += sz; | ||
1620 | sg_used++; | ||
1621 | } | ||
1622 | c = cmd_special_alloc(h); | ||
1623 | if (!c) { | ||
1624 | status = -ENOMEM; | ||
1625 | goto cleanup1; | ||
1626 | } | ||
1627 | c->cmd_type = CMD_IOCTL_PEND; | ||
1628 | c->Header.ReplyQueue = 0; | ||
1629 | 1591 | ||
1630 | if (ioc->buf_size > 0) { | 1592 | c->Request = ioc->Request; |
1631 | c->Header.SGList = sg_used; | 1593 | for (i = 0; i < sg_used; i++) { |
1632 | c->Header.SGTotal = sg_used; | 1594 | temp64.val = pci_map_single(h->pdev, buff[i], buff_size[i], |
1633 | } else { | 1595 | PCI_DMA_BIDIRECTIONAL); |
1634 | c->Header.SGList = 0; | 1596 | c->SG[i].Addr.lower = temp64.val32.lower; |
1635 | c->Header.SGTotal = 0; | 1597 | c->SG[i].Addr.upper = temp64.val32.upper; |
1636 | } | 1598 | c->SG[i].Len = buff_size[i]; |
1637 | c->Header.LUN = ioc->LUN_info; | 1599 | c->SG[i].Ext = 0; /* we are not chaining */ |
1638 | c->Header.Tag.lower = c->busaddr; | 1600 | } |
1639 | 1601 | c->waiting = &wait; | |
1640 | c->Request = ioc->Request; | 1602 | enqueue_cmd_and_start_io(h, c); |
1641 | if (ioc->buf_size > 0) { | 1603 | wait_for_completion(&wait); |
1642 | for (i = 0; i < sg_used; i++) { | 1604 | /* unlock the buffers from DMA */ |
1643 | temp64.val = | 1605 | for (i = 0; i < sg_used; i++) { |
1644 | pci_map_single(h->pdev, buff[i], | 1606 | temp64.val32.lower = c->SG[i].Addr.lower; |
1645 | buff_size[i], | 1607 | temp64.val32.upper = c->SG[i].Addr.upper; |
1646 | PCI_DMA_BIDIRECTIONAL); | 1608 | pci_unmap_single(h->pdev, |
1647 | c->SG[i].Addr.lower = | 1609 | (dma_addr_t) temp64.val, buff_size[i], |
1648 | temp64.val32.lower; | 1610 | PCI_DMA_BIDIRECTIONAL); |
1649 | c->SG[i].Addr.upper = | 1611 | } |
1650 | temp64.val32.upper; | 1612 | check_ioctl_unit_attention(h, c); |
1651 | c->SG[i].Len = buff_size[i]; | 1613 | /* Copy the error information out */ |
1652 | c->SG[i].Ext = 0; /* we are not chaining */ | 1614 | ioc->error_info = *(c->err_info); |
1653 | } | 1615 | if (copy_to_user(argp, ioc, sizeof(*ioc))) { |
1654 | } | 1616 | cmd_special_free(h, c); |
1655 | c->waiting = &wait; | 1617 | status = -EFAULT; |
1656 | enqueue_cmd_and_start_io(h, c); | 1618 | goto cleanup1; |
1657 | wait_for_completion(&wait); | 1619 | } |
1658 | /* unlock the buffers from DMA */ | 1620 | if (ioc->Request.Type.Direction == XFER_READ) { |
1659 | for (i = 0; i < sg_used; i++) { | 1621 | /* Copy the data out of the buffer we created */ |
1660 | temp64.val32.lower = c->SG[i].Addr.lower; | 1622 | BYTE __user *ptr = ioc->buf; |
1661 | temp64.val32.upper = c->SG[i].Addr.upper; | 1623 | for (i = 0; i < sg_used; i++) { |
1662 | pci_unmap_single(h->pdev, | 1624 | if (copy_to_user(ptr, buff[i], buff_size[i])) { |
1663 | (dma_addr_t) temp64.val, buff_size[i], | ||
1664 | PCI_DMA_BIDIRECTIONAL); | ||
1665 | } | ||
1666 | check_ioctl_unit_attention(h, c); | ||
1667 | /* Copy the error information out */ | ||
1668 | ioc->error_info = *(c->err_info); | ||
1669 | if (copy_to_user(argp, ioc, sizeof(*ioc))) { | ||
1670 | cmd_special_free(h, c); | 1625 | cmd_special_free(h, c); |
1671 | status = -EFAULT; | 1626 | status = -EFAULT; |
1672 | goto cleanup1; | 1627 | goto cleanup1; |
1673 | } | 1628 | } |
1674 | if (ioc->Request.Type.Direction == XFER_READ) { | 1629 | ptr += buff_size[i]; |
1675 | /* Copy the data out of the buffer we created */ | ||
1676 | BYTE __user *ptr = ioc->buf; | ||
1677 | for (i = 0; i < sg_used; i++) { | ||
1678 | if (copy_to_user | ||
1679 | (ptr, buff[i], buff_size[i])) { | ||
1680 | cmd_special_free(h, c); | ||
1681 | status = -EFAULT; | ||
1682 | goto cleanup1; | ||
1683 | } | ||
1684 | ptr += buff_size[i]; | ||
1685 | } | ||
1686 | } | ||
1687 | cmd_special_free(h, c); | ||
1688 | status = 0; | ||
1689 | cleanup1: | ||
1690 | if (buff) { | ||
1691 | for (i = 0; i < sg_used; i++) | ||
1692 | kfree(buff[i]); | ||
1693 | kfree(buff); | ||
1694 | } | ||
1695 | kfree(buff_size); | ||
1696 | kfree(ioc); | ||
1697 | return status; | ||
1698 | } | 1630 | } |
1631 | } | ||
1632 | cmd_special_free(h, c); | ||
1633 | status = 0; | ||
1634 | cleanup1: | ||
1635 | if (buff) { | ||
1636 | for (i = 0; i < sg_used; i++) | ||
1637 | kfree(buff[i]); | ||
1638 | kfree(buff); | ||
1639 | } | ||
1640 | kfree(buff_size); | ||
1641 | kfree(ioc); | ||
1642 | return status; | ||
1643 | } | ||
1644 | |||
1645 | static int cciss_ioctl(struct block_device *bdev, fmode_t mode, | ||
1646 | unsigned int cmd, unsigned long arg) | ||
1647 | { | ||
1648 | struct gendisk *disk = bdev->bd_disk; | ||
1649 | ctlr_info_t *h = get_host(disk); | ||
1650 | void __user *argp = (void __user *)arg; | ||
1651 | |||
1652 | dev_dbg(&h->pdev->dev, "cciss_ioctl: Called with cmd=%x %lx\n", | ||
1653 | cmd, arg); | ||
1654 | switch (cmd) { | ||
1655 | case CCISS_GETPCIINFO: | ||
1656 | return cciss_getpciinfo(h, argp); | ||
1657 | case CCISS_GETINTINFO: | ||
1658 | return cciss_getintinfo(h, argp); | ||
1659 | case CCISS_SETINTINFO: | ||
1660 | return cciss_setintinfo(h, argp); | ||
1661 | case CCISS_GETNODENAME: | ||
1662 | return cciss_getnodename(h, argp); | ||
1663 | case CCISS_SETNODENAME: | ||
1664 | return cciss_setnodename(h, argp); | ||
1665 | case CCISS_GETHEARTBEAT: | ||
1666 | return cciss_getheartbeat(h, argp); | ||
1667 | case CCISS_GETBUSTYPES: | ||
1668 | return cciss_getbustypes(h, argp); | ||
1669 | case CCISS_GETFIRMVER: | ||
1670 | return cciss_getfirmver(h, argp); | ||
1671 | case CCISS_GETDRIVVER: | ||
1672 | return cciss_getdrivver(h, argp); | ||
1673 | case CCISS_DEREGDISK: | ||
1674 | case CCISS_REGNEWD: | ||
1675 | case CCISS_REVALIDVOLS: | ||
1676 | return rebuild_lun_table(h, 0, 1); | ||
1677 | case CCISS_GETLUNINFO: | ||
1678 | return cciss_getluninfo(h, disk, argp); | ||
1679 | case CCISS_PASSTHRU: | ||
1680 | return cciss_passthru(h, argp); | ||
1681 | case CCISS_BIG_PASSTHRU: | ||
1682 | return cciss_bigpassthru(h, argp); | ||
1699 | 1683 | ||
1700 | /* scsi_cmd_ioctl handles these, below, though some are not */ | 1684 | /* scsi_cmd_ioctl handles these, below, though some are not */ |
1701 | /* very meaningful for cciss. SG_IO is the main one people want. */ | 1685 | /* very meaningful for cciss. SG_IO is the main one people want. */ |