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 | |
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')
-rw-r--r-- | drivers/ata/libata-core.c | 133 | ||||
-rw-r--r-- | drivers/ata/libata-scsi.c | 120 | ||||
-rw-r--r-- | drivers/ata/libata.h | 4 |
3 files changed, 145 insertions, 112 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 0a5103b707c6..4ac53ef0e4b0 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c | |||
@@ -199,7 +199,8 @@ static const u8 ata_rw_cmds[] = { | |||
199 | 199 | ||
200 | /** | 200 | /** |
201 | * ata_rwcmd_protocol - set taskfile r/w commands and protocol | 201 | * ata_rwcmd_protocol - set taskfile r/w commands and protocol |
202 | * @qc: command to examine and configure | 202 | * @tf: command to examine and configure |
203 | * @dev: device tf belongs to | ||
203 | * | 204 | * |
204 | * Examine the device configuration and tf->flags to calculate | 205 | * Examine the device configuration and tf->flags to calculate |
205 | * the proper read/write commands and protocol to use. | 206 | * the proper read/write commands and protocol to use. |
@@ -207,10 +208,8 @@ static const u8 ata_rw_cmds[] = { | |||
207 | * LOCKING: | 208 | * LOCKING: |
208 | * caller. | 209 | * caller. |
209 | */ | 210 | */ |
210 | int ata_rwcmd_protocol(struct ata_queued_cmd *qc) | 211 | static int ata_rwcmd_protocol(struct ata_taskfile *tf, struct ata_device *dev) |
211 | { | 212 | { |
212 | struct ata_taskfile *tf = &qc->tf; | ||
213 | struct ata_device *dev = qc->dev; | ||
214 | u8 cmd; | 213 | u8 cmd; |
215 | 214 | ||
216 | int index, fua, lba48, write; | 215 | int index, fua, lba48, write; |
@@ -222,7 +221,7 @@ int ata_rwcmd_protocol(struct ata_queued_cmd *qc) | |||
222 | if (dev->flags & ATA_DFLAG_PIO) { | 221 | if (dev->flags & ATA_DFLAG_PIO) { |
223 | tf->protocol = ATA_PROT_PIO; | 222 | tf->protocol = ATA_PROT_PIO; |
224 | index = dev->multi_count ? 0 : 8; | 223 | index = dev->multi_count ? 0 : 8; |
225 | } else if (lba48 && (qc->ap->flags & ATA_FLAG_PIO_LBA48)) { | 224 | } else if (lba48 && (dev->ap->flags & ATA_FLAG_PIO_LBA48)) { |
226 | /* Unable to use DMA due to host limitation */ | 225 | /* Unable to use DMA due to host limitation */ |
227 | tf->protocol = ATA_PROT_PIO; | 226 | tf->protocol = ATA_PROT_PIO; |
228 | index = dev->multi_count ? 0 : 8; | 227 | index = dev->multi_count ? 0 : 8; |
@@ -283,6 +282,130 @@ u64 ata_tf_read_block(struct ata_taskfile *tf, struct ata_device *dev) | |||
283 | } | 282 | } |
284 | 283 | ||
285 | /** | 284 | /** |
285 | * ata_build_rw_tf - Build ATA taskfile for given read/write request | ||
286 | * @tf: Target ATA taskfile | ||
287 | * @dev: ATA device @tf belongs to | ||
288 | * @block: Block address | ||
289 | * @n_block: Number of blocks | ||
290 | * @tf_flags: RW/FUA etc... | ||
291 | * @tag: tag | ||
292 | * | ||
293 | * LOCKING: | ||
294 | * None. | ||
295 | * | ||
296 | * Build ATA taskfile @tf for read/write request described by | ||
297 | * @block, @n_block, @tf_flags and @tag on @dev. | ||
298 | * | ||
299 | * RETURNS: | ||
300 | * | ||
301 | * 0 on success, -ERANGE if the request is too large for @dev, | ||
302 | * -EINVAL if the request is invalid. | ||
303 | */ | ||
304 | int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev, | ||
305 | u64 block, u32 n_block, unsigned int tf_flags, | ||
306 | unsigned int tag) | ||
307 | { | ||
308 | tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; | ||
309 | tf->flags |= tf_flags; | ||
310 | |||
311 | if ((dev->flags & (ATA_DFLAG_PIO | ATA_DFLAG_NCQ_OFF | | ||
312 | ATA_DFLAG_NCQ)) == ATA_DFLAG_NCQ) { | ||
313 | /* yay, NCQ */ | ||
314 | if (!lba_48_ok(block, n_block)) | ||
315 | return -ERANGE; | ||
316 | |||
317 | tf->protocol = ATA_PROT_NCQ; | ||
318 | tf->flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48; | ||
319 | |||
320 | if (tf->flags & ATA_TFLAG_WRITE) | ||
321 | tf->command = ATA_CMD_FPDMA_WRITE; | ||
322 | else | ||
323 | tf->command = ATA_CMD_FPDMA_READ; | ||
324 | |||
325 | tf->nsect = tag << 3; | ||
326 | tf->hob_feature = (n_block >> 8) & 0xff; | ||
327 | tf->feature = n_block & 0xff; | ||
328 | |||
329 | tf->hob_lbah = (block >> 40) & 0xff; | ||
330 | tf->hob_lbam = (block >> 32) & 0xff; | ||
331 | tf->hob_lbal = (block >> 24) & 0xff; | ||
332 | tf->lbah = (block >> 16) & 0xff; | ||
333 | tf->lbam = (block >> 8) & 0xff; | ||
334 | tf->lbal = block & 0xff; | ||
335 | |||
336 | tf->device = 1 << 6; | ||
337 | if (tf->flags & ATA_TFLAG_FUA) | ||
338 | tf->device |= 1 << 7; | ||
339 | } else if (dev->flags & ATA_DFLAG_LBA) { | ||
340 | tf->flags |= ATA_TFLAG_LBA; | ||
341 | |||
342 | if (lba_28_ok(block, n_block)) { | ||
343 | /* use LBA28 */ | ||
344 | tf->device |= (block >> 24) & 0xf; | ||
345 | } else if (lba_48_ok(block, n_block)) { | ||
346 | if (!(dev->flags & ATA_DFLAG_LBA48)) | ||
347 | return -ERANGE; | ||
348 | |||
349 | /* use LBA48 */ | ||
350 | tf->flags |= ATA_TFLAG_LBA48; | ||
351 | |||
352 | tf->hob_nsect = (n_block >> 8) & 0xff; | ||
353 | |||
354 | tf->hob_lbah = (block >> 40) & 0xff; | ||
355 | tf->hob_lbam = (block >> 32) & 0xff; | ||
356 | tf->hob_lbal = (block >> 24) & 0xff; | ||
357 | } else | ||
358 | /* request too large even for LBA48 */ | ||
359 | return -ERANGE; | ||
360 | |||
361 | if (unlikely(ata_rwcmd_protocol(tf, dev) < 0)) | ||
362 | return -EINVAL; | ||
363 | |||
364 | tf->nsect = n_block & 0xff; | ||
365 | |||
366 | tf->lbah = (block >> 16) & 0xff; | ||
367 | tf->lbam = (block >> 8) & 0xff; | ||
368 | tf->lbal = block & 0xff; | ||
369 | |||
370 | tf->device |= ATA_LBA; | ||
371 | } else { | ||
372 | /* CHS */ | ||
373 | u32 sect, head, cyl, track; | ||
374 | |||
375 | /* The request -may- be too large for CHS addressing. */ | ||
376 | if (!lba_28_ok(block, n_block)) | ||
377 | return -ERANGE; | ||
378 | |||
379 | if (unlikely(ata_rwcmd_protocol(tf, dev) < 0)) | ||
380 | return -EINVAL; | ||
381 | |||
382 | /* Convert LBA to CHS */ | ||
383 | track = (u32)block / dev->sectors; | ||
384 | cyl = track / dev->heads; | ||
385 | head = track % dev->heads; | ||
386 | sect = (u32)block % dev->sectors + 1; | ||
387 | |||
388 | DPRINTK("block %u track %u cyl %u head %u sect %u\n", | ||
389 | (u32)block, track, cyl, head, sect); | ||
390 | |||
391 | /* Check whether the converted CHS can fit. | ||
392 | Cylinder: 0-65535 | ||
393 | Head: 0-15 | ||
394 | Sector: 1-255*/ | ||
395 | if ((cyl >> 16) || (head >> 4) || (sect >> 8) || (!sect)) | ||
396 | return -ERANGE; | ||
397 | |||
398 | tf->nsect = n_block & 0xff; /* Sector count 0 means 256 sectors */ | ||
399 | tf->lbal = sect; | ||
400 | tf->lbam = cyl; | ||
401 | tf->lbah = cyl >> 8; | ||
402 | tf->device |= head; | ||
403 | } | ||
404 | |||
405 | return 0; | ||
406 | } | ||
407 | |||
408 | /** | ||
286 | * ata_pack_xfermask - Pack pio, mwdma and udma masks into xfer_mask | 409 | * ata_pack_xfermask - Pack pio, mwdma and udma masks into xfer_mask |
287 | * @pio_mask: pio_mask | 410 | * @pio_mask: pio_mask |
288 | * @mwdma_mask: mwdma_mask | 411 | * @mwdma_mask: mwdma_mask |
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" */ |
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index ca6f36c13115..60576b1237e4 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h | |||
@@ -51,7 +51,9 @@ extern int atapi_enabled; | |||
51 | extern int atapi_dmadir; | 51 | extern int atapi_dmadir; |
52 | extern int libata_fua; | 52 | extern int libata_fua; |
53 | extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev); | 53 | extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev); |
54 | extern int ata_rwcmd_protocol(struct ata_queued_cmd *qc); | 54 | extern int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev, |
55 | u64 block, u32 n_block, unsigned int tf_flags, | ||
56 | unsigned int tag); | ||
55 | extern u64 ata_tf_read_block(struct ata_taskfile *tf, struct ata_device *dev); | 57 | extern u64 ata_tf_read_block(struct ata_taskfile *tf, struct ata_device *dev); |
56 | extern void ata_dev_disable(struct ata_device *dev); | 58 | extern void ata_dev_disable(struct ata_device *dev); |
57 | extern void ata_port_flush_task(struct ata_port *ap); | 59 | extern void ata_port_flush_task(struct ata_port *ap); |