diff options
author | Tejun Heo <htejun@gmail.com> | 2006-11-14 08:47:10 -0500 |
---|---|---|
committer | Tejun Heo <htejun@gmail.com> | 2006-12-03 03:56:24 -0500 |
commit | bd056d7eeb55d696556ee4f5ee2acb67b2d16df4 (patch) | |
tree | f6ca604abc43d73d42354d977f1bcedd262dbcda /drivers/ata/libata-scsi.c | |
parent | 2432697ba0ce312d60be5009ffe1fa054a761bb9 (diff) |
[PATCH] libata: separate out rw ATA taskfile building into ata_build_rw_tf()
Separate out rw ATA taskfile building from ata_scsi_rw_xlat() into
ata_build_rw_tf(). This will be used to improve media error handling.
Signed-off-by: Tejun Heo <htejun@gmail.com>
Diffstat (limited to 'drivers/ata/libata-scsi.c')
-rw-r--r-- | drivers/ata/libata-scsi.c | 120 |
1 files changed, 14 insertions, 106 deletions
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index d250858d201c..8eaace94d963 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c | |||
@@ -1265,17 +1265,14 @@ nothing_to_do: | |||
1265 | 1265 | ||
1266 | static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd) | 1266 | static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd) |
1267 | { | 1267 | { |
1268 | struct ata_taskfile *tf = &qc->tf; | 1268 | unsigned int tf_flags = 0; |
1269 | struct ata_device *dev = qc->dev; | ||
1270 | u64 block; | 1269 | u64 block; |
1271 | u32 n_block; | 1270 | u32 n_block; |
1272 | 1271 | int rc; | |
1273 | qc->flags |= ATA_QCFLAG_IO; | ||
1274 | tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; | ||
1275 | 1272 | ||
1276 | if (scsicmd[0] == WRITE_10 || scsicmd[0] == WRITE_6 || | 1273 | if (scsicmd[0] == WRITE_10 || scsicmd[0] == WRITE_6 || |
1277 | scsicmd[0] == WRITE_16) | 1274 | scsicmd[0] == WRITE_16) |
1278 | tf->flags |= ATA_TFLAG_WRITE; | 1275 | tf_flags |= ATA_TFLAG_WRITE; |
1279 | 1276 | ||
1280 | /* Calculate the SCSI LBA, transfer length and FUA. */ | 1277 | /* Calculate the SCSI LBA, transfer length and FUA. */ |
1281 | switch (scsicmd[0]) { | 1278 | switch (scsicmd[0]) { |
@@ -1283,7 +1280,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm | |||
1283 | case WRITE_10: | 1280 | case WRITE_10: |
1284 | scsi_10_lba_len(scsicmd, &block, &n_block); | 1281 | scsi_10_lba_len(scsicmd, &block, &n_block); |
1285 | if (unlikely(scsicmd[1] & (1 << 3))) | 1282 | if (unlikely(scsicmd[1] & (1 << 3))) |
1286 | tf->flags |= ATA_TFLAG_FUA; | 1283 | tf_flags |= ATA_TFLAG_FUA; |
1287 | break; | 1284 | break; |
1288 | case READ_6: | 1285 | case READ_6: |
1289 | case WRITE_6: | 1286 | case WRITE_6: |
@@ -1299,7 +1296,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm | |||
1299 | case WRITE_16: | 1296 | case WRITE_16: |
1300 | scsi_16_lba_len(scsicmd, &block, &n_block); | 1297 | scsi_16_lba_len(scsicmd, &block, &n_block); |
1301 | if (unlikely(scsicmd[1] & (1 << 3))) | 1298 | if (unlikely(scsicmd[1] & (1 << 3))) |
1302 | tf->flags |= ATA_TFLAG_FUA; | 1299 | tf_flags |= ATA_TFLAG_FUA; |
1303 | break; | 1300 | break; |
1304 | default: | 1301 | default: |
1305 | DPRINTK("no-byte command\n"); | 1302 | DPRINTK("no-byte command\n"); |
@@ -1317,106 +1314,17 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm | |||
1317 | */ | 1314 | */ |
1318 | goto nothing_to_do; | 1315 | goto nothing_to_do; |
1319 | 1316 | ||
1320 | if ((dev->flags & (ATA_DFLAG_PIO | ATA_DFLAG_NCQ_OFF | | 1317 | qc->flags |= ATA_QCFLAG_IO; |
1321 | ATA_DFLAG_NCQ)) == ATA_DFLAG_NCQ) { | 1318 | qc->nsect = n_block; |
1322 | /* yay, NCQ */ | ||
1323 | if (!lba_48_ok(block, n_block)) | ||
1324 | goto out_of_range; | ||
1325 | |||
1326 | tf->protocol = ATA_PROT_NCQ; | ||
1327 | tf->flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48; | ||
1328 | |||
1329 | if (tf->flags & ATA_TFLAG_WRITE) | ||
1330 | tf->command = ATA_CMD_FPDMA_WRITE; | ||
1331 | else | ||
1332 | tf->command = ATA_CMD_FPDMA_READ; | ||
1333 | |||
1334 | qc->nsect = n_block; | ||
1335 | |||
1336 | tf->nsect = qc->tag << 3; | ||
1337 | tf->hob_feature = (n_block >> 8) & 0xff; | ||
1338 | tf->feature = n_block & 0xff; | ||
1339 | |||
1340 | tf->hob_lbah = (block >> 40) & 0xff; | ||
1341 | tf->hob_lbam = (block >> 32) & 0xff; | ||
1342 | tf->hob_lbal = (block >> 24) & 0xff; | ||
1343 | tf->lbah = (block >> 16) & 0xff; | ||
1344 | tf->lbam = (block >> 8) & 0xff; | ||
1345 | tf->lbal = block & 0xff; | ||
1346 | |||
1347 | tf->device = 1 << 6; | ||
1348 | if (tf->flags & ATA_TFLAG_FUA) | ||
1349 | tf->device |= 1 << 7; | ||
1350 | } else if (dev->flags & ATA_DFLAG_LBA) { | ||
1351 | tf->flags |= ATA_TFLAG_LBA; | ||
1352 | |||
1353 | if (lba_28_ok(block, n_block)) { | ||
1354 | /* use LBA28 */ | ||
1355 | tf->device |= (block >> 24) & 0xf; | ||
1356 | } else if (lba_48_ok(block, n_block)) { | ||
1357 | if (!(dev->flags & ATA_DFLAG_LBA48)) | ||
1358 | goto out_of_range; | ||
1359 | |||
1360 | /* use LBA48 */ | ||
1361 | tf->flags |= ATA_TFLAG_LBA48; | ||
1362 | |||
1363 | tf->hob_nsect = (n_block >> 8) & 0xff; | ||
1364 | |||
1365 | tf->hob_lbah = (block >> 40) & 0xff; | ||
1366 | tf->hob_lbam = (block >> 32) & 0xff; | ||
1367 | tf->hob_lbal = (block >> 24) & 0xff; | ||
1368 | } else | ||
1369 | /* request too large even for LBA48 */ | ||
1370 | goto out_of_range; | ||
1371 | |||
1372 | if (unlikely(ata_rwcmd_protocol(qc) < 0)) | ||
1373 | goto invalid_fld; | ||
1374 | |||
1375 | qc->nsect = n_block; | ||
1376 | tf->nsect = n_block & 0xff; | ||
1377 | |||
1378 | tf->lbah = (block >> 16) & 0xff; | ||
1379 | tf->lbam = (block >> 8) & 0xff; | ||
1380 | tf->lbal = block & 0xff; | ||
1381 | |||
1382 | tf->device |= ATA_LBA; | ||
1383 | } else { | ||
1384 | /* CHS */ | ||
1385 | u32 sect, head, cyl, track; | ||
1386 | |||
1387 | /* The request -may- be too large for CHS addressing. */ | ||
1388 | if (!lba_28_ok(block, n_block)) | ||
1389 | goto out_of_range; | ||
1390 | |||
1391 | if (unlikely(ata_rwcmd_protocol(qc) < 0)) | ||
1392 | goto invalid_fld; | ||
1393 | |||
1394 | /* Convert LBA to CHS */ | ||
1395 | track = (u32)block / dev->sectors; | ||
1396 | cyl = track / dev->heads; | ||
1397 | head = track % dev->heads; | ||
1398 | sect = (u32)block % dev->sectors + 1; | ||
1399 | |||
1400 | DPRINTK("block %u track %u cyl %u head %u sect %u\n", | ||
1401 | (u32)block, track, cyl, head, sect); | ||
1402 | |||
1403 | /* Check whether the converted CHS can fit. | ||
1404 | Cylinder: 0-65535 | ||
1405 | Head: 0-15 | ||
1406 | Sector: 1-255*/ | ||
1407 | if ((cyl >> 16) || (head >> 4) || (sect >> 8) || (!sect)) | ||
1408 | goto out_of_range; | ||
1409 | |||
1410 | qc->nsect = n_block; | ||
1411 | tf->nsect = n_block & 0xff; /* Sector count 0 means 256 sectors */ | ||
1412 | tf->lbal = sect; | ||
1413 | tf->lbam = cyl; | ||
1414 | tf->lbah = cyl >> 8; | ||
1415 | tf->device |= head; | ||
1416 | } | ||
1417 | 1319 | ||
1418 | return 0; | 1320 | rc = ata_build_rw_tf(&qc->tf, qc->dev, block, n_block, tf_flags, |
1321 | qc->tag); | ||
1322 | if (likely(rc == 0)) | ||
1323 | return 0; | ||
1419 | 1324 | ||
1325 | if (rc == -ERANGE) | ||
1326 | goto out_of_range; | ||
1327 | /* treat all other errors as -EINVAL, fall through */ | ||
1420 | invalid_fld: | 1328 | invalid_fld: |
1421 | ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x0); | 1329 | ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x0); |
1422 | /* "Invalid field in cbd" */ | 1330 | /* "Invalid field in cbd" */ |