Add support for PIO-only devices.
Fix maxio values and 256 sectors transactions for 28bits commands.
Implement periodic ordered commands insertion, sames as da driver does.
Remove some SCSIsms.
This commit is contained in:
Alexander Motin 2009-10-21 14:20:55 +00:00
parent 56d7cd7cf1
commit 46f118fe3f
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=198328

View File

@ -63,37 +63,32 @@ __FBSDID("$FreeBSD$");
#define ATA_MAX_28BIT_LBA 268435455UL
typedef enum {
ADA_STATE_NORMAL
ADA_STATE_NORMAL,
ADA_STATE_SET_MULTI
} ada_state;
typedef enum {
ADA_FLAG_PACK_INVALID = 0x001,
ADA_FLAG_CAN_48BIT = 0x002,
ADA_FLAG_CAN_FLUSHCACHE = 0x004,
ADA_FLAG_CAN_NCQ = 0x008,
ADA_FLAG_TAGGED_QUEUING = 0x010,
ADA_FLAG_CAN_NCQ = 0x008,
ADA_FLAG_CAN_DMA = 0x010,
ADA_FLAG_NEED_OTAG = 0x020,
ADA_FLAG_WENT_IDLE = 0x040,
ADA_FLAG_RETRY_UA = 0x080,
ADA_FLAG_OPEN = 0x100,
ADA_FLAG_SCTX_INIT = 0x200
} ada_flags;
typedef enum {
ADA_Q_NONE = 0x00,
ADA_Q_NO_SYNC_CACHE = 0x01,
ADA_Q_NO_6_BYTE = 0x02,
ADA_Q_NO_PREVENT = 0x04
ADA_Q_NONE = 0x00
} ada_quirks;
typedef enum {
ADA_CCB_PROBE = 0x01,
ADA_CCB_PROBE2 = 0x02,
ADA_CCB_SET_MULTI = 0x01,
ADA_CCB_BUFFER_IO = 0x03,
ADA_CCB_WAITING = 0x04,
ADA_CCB_DUMP = 0x05,
ADA_CCB_TYPE_MASK = 0x0F,
ADA_CCB_RETRY_UA = 0x10
} ada_ccb_state;
/* Offsets into our private area for storing information */
@ -117,6 +112,7 @@ struct ada_softc {
ada_quirks quirks;
int ordered_tag_count;
int outstanding_cmds;
int secsperint;
struct disk_params params;
struct disk *disk;
union ccb saved_ccb;
@ -289,8 +285,7 @@ adaclose(struct disk *dp)
else
ata_28bit_cmd(&ccb->ataio, ATA_FLUSHCACHE, 0, 0, 0);
cam_periph_runccb(ccb, /*error_routine*/NULL, /*cam_flags*/0,
/*sense_flags*/SF_RETRY_UA,
softc->disk->d_devstat);
/*sense_flags*/0, softc->disk->d_devstat);
if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)
xpt_print(periph->path, "Synchronize cache failed\n");
@ -331,19 +326,6 @@ adastrategy(struct bio *bp)
cam_periph_lock(periph);
#if 0
/*
* check it's not too big a transfer for our adapter
*/
scsi_minphys(bp,&sd_switch);
#endif
/*
* Mask interrupts so that the pack cannot be invalidated until
* after we are in the queue. Otherwise, we might not properly
* clean up one of the buffers.
*/
/*
* If the device has been made invalid, error out
*/
@ -551,11 +533,6 @@ adaasync(void *callback_arg, u_int32_t code,
if (cgd->protocol != PROTO_ATA)
break;
// if (SID_TYPE(&cgd->inq_data) != T_DIRECT
// && SID_TYPE(&cgd->inq_data) != T_RBC
// && SID_TYPE(&cgd->inq_data) != T_OPTICAL)
// break;
/*
* Allocate a peripheral instance for
* this device and start the probe
@ -576,18 +553,18 @@ adaasync(void *callback_arg, u_int32_t code,
case AC_SENT_BDR:
case AC_BUS_RESET:
{
struct ada_softc *softc;
struct ccb_hdr *ccbh;
struct ada_softc *softc = (struct ada_softc *)periph->softc;
softc = (struct ada_softc *)periph->softc;
cam_periph_async(periph, code, path, arg);
if (softc->state != ADA_STATE_NORMAL)
break;
/*
* Don't fail on the expected unit attention
* that will occur.
* Restore device configuration.
*/
softc->flags |= ADA_FLAG_RETRY_UA;
LIST_FOREACH(ccbh, &softc->pending_ccbs, periph_links.le)
ccbh->ccb_state |= ADA_CCB_RETRY_UA;
/* FALLTHROUGH*/
softc->state = ADA_STATE_SET_MULTI;
cam_periph_acquire(periph);
xpt_schedule(periph, 0);
break;
}
default:
cam_periph_async(periph, code, path, arg);
@ -651,14 +628,15 @@ adaregister(struct cam_periph *periph, void *arg)
if (softc == NULL) {
printf("adaregister: Unable to probe new device. "
"Unable to allocate softc\n");
"Unable to allocate softc\n");
return(CAM_REQ_CMP_ERR);
}
LIST_INIT(&softc->pending_ccbs);
softc->state = ADA_STATE_NORMAL;
bioq_init(&softc->bio_queue);
if (cgd->ident_data.capabilities1 & ATA_SUPPORT_DMA)
softc->flags |= ADA_FLAG_CAN_DMA;
if (cgd->ident_data.support.command2 & ATA_SUPPORT_ADDRESS48)
softc->flags |= ADA_FLAG_CAN_48BIT;
if (cgd->ident_data.support.command2 & ATA_SUPPORT_FLUSHCACHE)
@ -666,8 +644,8 @@ adaregister(struct cam_periph *periph, void *arg)
if (cgd->ident_data.satacapabilities & ATA_SUPPORT_NCQ &&
cgd->ident_data.queue >= 31)
softc->flags |= ADA_FLAG_CAN_NCQ;
// if ((cgd->inq_data.flags & SID_CmdQue) != 0)
// softc->flags |= ADA_FLAG_TAGGED_QUEUING;
softc->secsperint = max(1, min(cgd->ident_data.sectors_intr, 16));
softc->state = ADA_STATE_SET_MULTI;
periph->softc = softc;
@ -713,9 +691,9 @@ adaregister(struct cam_periph *periph, void *arg)
else if (maxio > MAXPHYS)
maxio = MAXPHYS; /* for safety */
if (cgd->ident_data.support.command2 & ATA_SUPPORT_ADDRESS48)
maxio = min(maxio, 65535 * 512);
maxio = min(maxio, 65536 * 512);
else /* 28bit ATA command limit */
maxio = min(maxio, 255 * 512);
maxio = min(maxio, 256 * 512);
softc->disk->d_maxsize = maxio;
softc->disk->d_unit = periph->unit_number;
softc->disk->d_flags = 0;
@ -730,8 +708,6 @@ adaregister(struct cam_periph *periph, void *arg)
/* XXX: these are not actually "firmware" values, so they may be wrong */
softc->disk->d_fwsectors = softc->params.secs_per_track;
softc->disk->d_fwheads = softc->params.heads;
// softc->disk->d_devstat->block_size = softc->params.secsize;
// softc->disk->d_devstat->flags &= ~DEVSTAT_BS_UNAVAILABLE;
disk_create(softc->disk, DISK_VERSION);
mtx_lock(periph->sim->mtx);
@ -766,8 +742,8 @@ adaregister(struct cam_periph *periph, void *arg)
* to finish the probe. The reference will be dropped in adadone at
* the end of probe.
*/
// (void)cam_periph_hold(periph, PRIBIO);
// xpt_schedule(periph, /*priority*/5);
cam_periph_acquire(periph);
xpt_schedule(periph, /*priority*/5);
/*
* Schedule a periodic event to occasionally send an
@ -784,9 +760,8 @@ adaregister(struct cam_periph *periph, void *arg)
static void
adastart(struct cam_periph *periph, union ccb *start_ccb)
{
struct ada_softc *softc;
softc = (struct ada_softc *)periph->softc;
struct ada_softc *softc = (struct ada_softc *)periph->softc;
struct ccb_ataio *ataio = &start_ccb->ataio;
switch (softc->state) {
case ADA_STATE_NORMAL:
@ -809,7 +784,6 @@ adastart(struct cam_periph *periph, union ccb *start_ccb)
} else if (bp == NULL) {
xpt_release_ccb(start_ccb);
} else {
struct ccb_ataio *ataio = &start_ccb->ataio;
u_int8_t tag_code;
bioq_remove(&softc->bio_queue, bp);
@ -817,9 +791,9 @@ adastart(struct cam_periph *periph, union ccb *start_ccb)
if ((softc->flags & ADA_FLAG_NEED_OTAG) != 0) {
softc->flags &= ~ADA_FLAG_NEED_OTAG;
softc->ordered_tag_count++;
tag_code = 0;//MSG_ORDERED_Q_TAG;
tag_code = 0;
} else {
tag_code = 0;//MSG_SIMPLE_Q_TAG;
tag_code = 1;
}
switch (bp->bio_cmd) {
case BIO_READ:
@ -838,7 +812,7 @@ adastart(struct cam_periph *periph, union ccb *start_ccb)
bp->bio_bcount,
ada_default_timeout*1000);
if (softc->flags & ADA_FLAG_CAN_NCQ) {
if ((softc->flags & ADA_FLAG_CAN_NCQ) && tag_code) {
if (bp->bio_cmd == BIO_READ) {
ata_ncq_cmd(ataio, ATA_READ_FPDMA_QUEUED,
lba, count);
@ -848,21 +822,43 @@ adastart(struct cam_periph *periph, union ccb *start_ccb)
}
} else if ((softc->flags & ADA_FLAG_CAN_48BIT) &&
(lba + count >= ATA_MAX_28BIT_LBA ||
count >= 256)) {
if (bp->bio_cmd == BIO_READ) {
ata_48bit_cmd(ataio, ATA_READ_DMA48,
0, lba, count);
count > 256)) {
if (softc->flags & ADA_FLAG_CAN_DMA) {
if (bp->bio_cmd == BIO_READ) {
ata_48bit_cmd(ataio, ATA_READ_DMA48,
0, lba, count);
} else {
ata_48bit_cmd(ataio, ATA_WRITE_DMA48,
0, lba, count);
}
} else {
ata_48bit_cmd(ataio, ATA_WRITE_DMA48,
0, lba, count);
if (bp->bio_cmd == BIO_READ) {
ata_48bit_cmd(ataio, ATA_READ_MUL48,
0, lba, count);
} else {
ata_48bit_cmd(ataio, ATA_WRITE_MUL48,
0, lba, count);
}
}
} else {
if (bp->bio_cmd == BIO_READ) {
ata_28bit_cmd(ataio, ATA_READ_DMA,
0, lba, count);
if (count == 256)
count = 0;
if (softc->flags & ADA_FLAG_CAN_DMA) {
if (bp->bio_cmd == BIO_READ) {
ata_28bit_cmd(ataio, ATA_READ_DMA,
0, lba, count);
} else {
ata_28bit_cmd(ataio, ATA_WRITE_DMA,
0, lba, count);
}
} else {
ata_28bit_cmd(ataio, ATA_WRITE_DMA,
0, lba, count);
if (bp->bio_cmd == BIO_READ) {
ata_28bit_cmd(ataio, ATA_READ_MUL,
0, lba, count);
} else {
ata_28bit_cmd(ataio, ATA_WRITE_MUL,
0, lba, count);
}
}
}
}
@ -872,7 +868,7 @@ adastart(struct cam_periph *periph, union ccb *start_ccb)
1,
adadone,
CAM_DIR_NONE,
tag_code,
0,
NULL,
0,
ada_default_timeout*1000);
@ -893,12 +889,6 @@ adastart(struct cam_periph *periph, union ccb *start_ccb)
&start_ccb->ccb_h, periph_links.le);
softc->outstanding_cmds++;
/* We expect a unit attention from this device */
if ((softc->flags & ADA_FLAG_RETRY_UA) != 0) {
start_ccb->ccb_h.ccb_state |= ADA_CCB_RETRY_UA;
softc->flags &= ~ADA_FLAG_RETRY_UA;
}
start_ccb->ccb_h.ccb_bp = bp;
bp = bioq_first(&softc->bio_queue);
@ -911,6 +901,21 @@ adastart(struct cam_periph *periph, union ccb *start_ccb)
}
break;
}
case ADA_STATE_SET_MULTI:
{
cam_fill_ataio(ataio,
ada_retry_count,
adadone,
CAM_DIR_NONE,
0,
NULL,
0,
ada_default_timeout*1000);
ata_28bit_cmd(ataio, ATA_SET_MULTI, 0, 0, softc->secsperint);
start_ccb->ccb_h.ccb_state = ADA_CCB_SET_MULTI;
xpt_action(start_ccb);
}
}
}
@ -931,16 +936,12 @@ adadone(struct cam_periph *periph, union ccb *done_ccb)
if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
int error;
error = adaerror(done_ccb, CAM_RETRY_SELTO, 0);
error = adaerror(done_ccb, 0, 0);
if (error == ERESTART) {
/*
* A retry was scheuled, so
* just return.
*/
/* A retry was scheduled, so just return. */
return;
}
if (error != 0) {
if (error == ENXIO) {
/*
* Catastrophic error. Mark our pack as
@ -1002,6 +1003,35 @@ adadone(struct cam_periph *periph, union ccb *done_ccb)
wakeup(&done_ccb->ccb_h.cbfcnp);
return;
}
case ADA_CCB_SET_MULTI:
{
if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
} else {
int error;
error = adaerror(done_ccb, 0, 0);
if (error == ERESTART) {
/* A retry was scheduled, so just return. */
return;
}
}
softc->state = ADA_STATE_NORMAL;
/*
* Since our peripheral may be invalidated by an error
* above or an external event, we must release our CCB
* before releasing the probe lock on the peripheral.
* The peripheral will only go away once the last lock
* is removed, and we need it around for the CCB release
* operation.
*/
xpt_release_ccb(done_ccb);
if (bioq_first(&softc->bio_queue) != NULL) {
/* Have more work to do, so ensure we stay scheduled */
xpt_schedule(periph, 1);
}
cam_periph_release_locked(periph);
return;
}
case ADA_CCB_DUMP:
/* No-op. We're polling */
return;
@ -1049,10 +1079,6 @@ adasetgeom(struct cam_periph *periph, struct ccb_getdev *cgd)
lbasize = (u_int32_t)cgd->ident_data.lba_size_1 |
((u_int32_t)cgd->ident_data.lba_size_2 << 16);
/* does this device need oldstyle CHS addressing */
// if (!ad_version(cgd->ident_data.version_major) || !lbasize)
// atadev->flags |= ATA_D_USE_CHS;
/* use the 28bit LBA size if valid or bigger than the CHS mapping */
if (cgd->ident_data.cylinders == 16383 || dp->sectors < lbasize)
dp->sectors = lbasize;