Linux那些事儿之我是SCSI硬盘(6)三座大山(三) – fudan

1385 /*

1386 * sd_read_cache_type – called only from sd_revalidate_disk()

1387 * called with buffer of length SD_BUF_SIZE

1388 */

1389 static void

1390 sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer)

1391 {

1392 int len = 0, res;

1393 struct scsi_device *sdp = sdkp->device;

1394

1395 int dbd;

1396 int modepage;

1397 struct scsi_mode_data data;

1398 struct scsi_sense_hdr sshdr;

1399

1400 if (sdp->skip_ms_page_8)

1401 goto defaults;

1402

1403 if (sdp->type == TYPE_RBC) {

1404 modepage = 6;

1405 dbd = 8;

1406 } else {

1407 modepage = 8;

1408 dbd = 0;

1409 }

1410

1411 /* cautiously ask */

1412 res = sd_do_mode_sense(sdp, dbd, modepage, buffer, 4, &data, &sshdr);

1413

1414 if (!scsi_status_is_good(res))

1415 goto bad_sense;

1416

1417 if (!data.header_length) {

1418 modepage = 6;

1419 sd_printk(KERN_ERR, sdkp, "Missing header in MODE_SENSE response/n");

1420 }

1421

1422 /* that went OK, now ask for the proper length */

1423 len = data.length;

1424

1425 /*

1426 * We’re only interested in the first three bytes, actually.

1427 * But the data cache page is defined for the first 20.

1428 */

1429 if (len < 3)

1430 goto bad_sense;

1431 if (len > 20)

1432 len = 20;

1433

1434 /* Take headers and block descriptors into account */

1435 len += data.header_length + data.block_descriptor_length;

1436 if (len > SD_BUF_SIZE)

1437 goto bad_sense;

1438

1439 /* Get the data */

1440 res = sd_do_mode_sense(sdp, dbd, modepage, buffer, len, &data, &sshdr);

1441

1442 if (scsi_status_is_good(res)) {

1443 int offset = data.header_length + data.block_descriptor_length;

1444

1445 if (offset >= SD_BUF_SIZE – 2) {

1446 sd_printk(KERN_ERR, sdkp, "Malformed MODE SENSE response/n");

1447 goto defaults;

1448 }

1449

1450 if ((buffer[offset] & 0x3f) != modepage) {

1451 sd_printk(KERN_ERR, sdkp, "Got wrong page/n");

1452 goto defaults;

1453 }

1454

1455 if (modepage == 8) {

1456 sdkp->WCE = ((buffer[offset + 2] & 0x04) != 0);

1457 sdkp->RCD = ((buffer[offset + 2] & 0x01) != 0);

1458 } else {

1459 sdkp->WCE = ((buffer[offset + 2] & 0x01) == 0);

1460 sdkp->RCD = 0;

1461 }

1462

1463 sdkp->DPOFUA = (data.device_specific & 0x10) != 0;

1464 if (sdkp->DPOFUA && !sdkp->device->use_10_for_rw) {

1465 sd_printk(KERN_NOTICE, sdkp,

1466 "Uses READ/WRITE(6), disabling FUA/n");

1467 sdkp->DPOFUA = 0;

1468 }

1469

1470 sd_printk(KERN_NOTICE, sdkp,

1471 "Write cache: %s, read cache: %s, %s/n",

1472 sdkp->WCE ? "enabled" : "disabled",

1473 sdkp->RCD ? "disabled" : "enabled",

1474 sdkp->DPOFUA ? "supports DPO and FUA"

1475 : "doesn’t support DPO or FUA");

1476

1477 return;

1478 }

1479

1480 bad_sense:

1481 if (scsi_sense_valid(&sshdr) &&

1482 sshdr.sense_key == ILLEGAL_REQUEST &&

1483 sshdr.asc == 0x24 && sshdr.ascq == 0x0)

1484 /* Invalid field in CDB */

1485 sd_printk(KERN_NOTICE, sdkp, "Cache data unavailable/n");

1486 else

1487 sd_printk(KERN_ERR, sdkp, "Asking for cache data failed/n");

1488

1489 defaults:

1490 sd_printk(KERN_ERR, sdkp, "Assuming drive cache: write through/n");

1491 sdkp->WCE = 0;

1492 sdkp->RCD = 0;

1493 sdkp->DPOFUA = 0;

1494 }

理想的路总是为有信心的人预备着

Linux那些事儿之我是SCSI硬盘(6)三座大山(三) – fudan

相关文章:

你感兴趣的文章:

标签云: