aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/ide/ide-cd.c171
1 files changed, 58 insertions, 113 deletions
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index 6f698b4c275a..97d0c1375247 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -1061,90 +1061,7 @@ static void ide_cd_request_sense_fixup(struct request *rq)
1061 } 1061 }
1062} 1062}
1063 1063
1064/* Interrupt routine for packet command completion. */ 1064static ide_startstop_t cdrom_newpc_intr(ide_drive_t *);
1065static ide_startstop_t cdrom_pc_intr (ide_drive_t *drive)
1066{
1067 struct request *rq = HWGROUP(drive)->rq;
1068 xfer_func_t *xferfunc = NULL;
1069 int stat, ireason, len, thislen, write, update;
1070 u8 lowcyl = 0, highcyl = 0;
1071
1072 /* Check for errors. */
1073 if (cdrom_decode_status(drive, 0, &stat))
1074 return ide_stopped;
1075
1076 /* Read the interrupt reason and the transfer length. */
1077 ireason = HWIF(drive)->INB(IDE_IREASON_REG) & 0x3;
1078 lowcyl = HWIF(drive)->INB(IDE_BCOUNTL_REG);
1079 highcyl = HWIF(drive)->INB(IDE_BCOUNTH_REG);
1080
1081 len = lowcyl + (256 * highcyl);
1082
1083 /* If DRQ is clear, the command has completed.
1084 Complain if we still have data left to transfer. */
1085 if ((stat & DRQ_STAT) == 0) {
1086 ide_cd_request_sense_fixup(rq);
1087 update = rq->data_len ? 0 : 1;
1088 goto end_request;
1089 }
1090
1091 /* Figure out how much data to transfer. */
1092 thislen = rq->data_len;
1093 if (thislen > len)
1094 thislen = len;
1095
1096 if (ireason == 0) {
1097 write = 1;
1098 xferfunc = HWIF(drive)->atapi_output_bytes;
1099 } else if (ireason == 2) {
1100 write = 0;
1101 xferfunc = HWIF(drive)->atapi_input_bytes;
1102 }
1103
1104 if (xferfunc) {
1105 if (!rq->data) {
1106 printk(KERN_ERR "%s: confused, missing data\n",
1107 drive->name);
1108 blk_dump_rq_flags(rq, write ? "cdrom_pc_intr, write"
1109 : "cdrom_pc_intr, read");
1110 goto pad;
1111 }
1112 /* Transfer the data. */
1113 xferfunc(drive, rq->data, thislen);
1114
1115 /* Keep count of how much data we've moved. */
1116 len -= thislen;
1117 rq->data += thislen;
1118 rq->data_len -= thislen;
1119
1120 if (write && blk_sense_request(rq))
1121 rq->sense_len += thislen;
1122 } else {
1123 printk (KERN_ERR "%s: cdrom_pc_intr: The drive "
1124 "appears confused (ireason = 0x%02x). "
1125 "Trying to recover by ending request.\n",
1126 drive->name, ireason);
1127 update = 0;
1128 goto end_request;
1129 }
1130pad:
1131 /*
1132 * If we haven't moved enough data to satisfy the drive,
1133 * add some padding.
1134 */
1135 if (len > 0)
1136 ide_cd_pad_transfer(drive, xferfunc, len);
1137
1138 /* Now we wait for another interrupt. */
1139 ide_set_handler(drive, &cdrom_pc_intr, ATAPI_WAIT_PC, cdrom_timer_expiry);
1140 return ide_started;
1141
1142end_request:
1143 if (!update)
1144 rq->cmd_flags |= REQ_FAILED;
1145 cdrom_end_request(drive, update);
1146 return ide_stopped;
1147}
1148 1065
1149static ide_startstop_t cdrom_do_pc_continuation (ide_drive_t *drive) 1066static ide_startstop_t cdrom_do_pc_continuation (ide_drive_t *drive)
1150{ 1067{
@@ -1154,10 +1071,9 @@ static ide_startstop_t cdrom_do_pc_continuation (ide_drive_t *drive)
1154 rq->timeout = ATAPI_WAIT_PC; 1071 rq->timeout = ATAPI_WAIT_PC;
1155 1072
1156 /* Send the command to the drive and return. */ 1073 /* Send the command to the drive and return. */
1157 return cdrom_transfer_packet_command(drive, rq, &cdrom_pc_intr); 1074 return cdrom_transfer_packet_command(drive, rq, cdrom_newpc_intr);
1158} 1075}
1159 1076
1160
1161static ide_startstop_t cdrom_do_packet_command (ide_drive_t *drive) 1077static ide_startstop_t cdrom_do_packet_command (ide_drive_t *drive)
1162{ 1078{
1163 int len; 1079 int len;
@@ -1263,27 +1179,27 @@ static int cdrom_newpc_intr_dummy_cb(struct request *rq)
1263/* 1179/*
1264 * best way to deal with dma that is not sector aligned right now... note 1180 * best way to deal with dma that is not sector aligned right now... note
1265 * that in this path we are not using ->data or ->buffer at all. this irs 1181 * that in this path we are not using ->data or ->buffer at all. this irs
1266 * can replace cdrom_pc_intr, cdrom_read_intr, and cdrom_write_intr in the 1182 * can replace cdrom_read_intr() and cdrom_write_intr() in the future.
1267 * future.
1268 */ 1183 */
1269static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) 1184static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
1270{ 1185{
1271 struct cdrom_info *info = drive->driver_data; 1186 struct cdrom_info *info = drive->driver_data;
1272 struct request *rq = HWGROUP(drive)->rq; 1187 struct request *rq = HWGROUP(drive)->rq;
1273 int dma_error, dma, stat, ireason, len, thislen;
1274 u8 lowcyl, highcyl;
1275 xfer_func_t *xferfunc; 1188 xfer_func_t *xferfunc;
1276 unsigned long flags; 1189 ide_expiry_t *expiry;
1190 int dma_error = 0, dma, stat, ireason, len, thislen, uptodate = 0;
1191 int write = (rq_data_dir(rq) == WRITE) ? 1 : 0;
1192 unsigned int timeout;
1193 u8 lowcyl, highcyl;
1277 1194
1278 /* Check for errors. */ 1195 /* Check for errors. */
1279 dma_error = 0;
1280 dma = info->dma; 1196 dma = info->dma;
1281 if (dma) { 1197 if (dma) {
1282 info->dma = 0; 1198 info->dma = 0;
1283 dma_error = HWIF(drive)->ide_dma_end(drive); 1199 dma_error = HWIF(drive)->ide_dma_end(drive);
1284 if (dma_error) { 1200 if (dma_error) {
1285 printk(KERN_ERR "%s: DMA %s error\n", drive->name, 1201 printk(KERN_ERR "%s: DMA %s error\n", drive->name,
1286 rq_data_dir(rq) ? "write" : "read"); 1202 write ? "write" : "read");
1287 ide_dma_off(drive); 1203 ide_dma_off(drive);
1288 } 1204 }
1289 } 1205 }
@@ -1297,14 +1213,7 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
1297 if (dma) { 1213 if (dma) {
1298 if (dma_error) 1214 if (dma_error)
1299 return ide_error(drive, "dma error", stat); 1215 return ide_error(drive, "dma error", stat);
1300 1216 goto end_request;
1301 spin_lock_irqsave(&ide_lock, flags);
1302 if (__blk_end_request(rq, 0, rq->data_len))
1303 BUG();
1304 HWGROUP(drive)->rq = NULL;
1305 spin_unlock_irqrestore(&ide_lock, flags);
1306
1307 return ide_stopped;
1308 } 1217 }
1309 1218
1310 /* 1219 /*
@@ -1323,34 +1232,43 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
1323 * If DRQ is clear, the command has completed. 1232 * If DRQ is clear, the command has completed.
1324 */ 1233 */
1325 if ((stat & DRQ_STAT) == 0) { 1234 if ((stat & DRQ_STAT) == 0) {
1326 spin_lock_irqsave(&ide_lock, flags); 1235 if (!blk_pc_request(rq)) {
1327 if (__blk_end_request(rq, 0, rq->data_len)) 1236 ide_cd_request_sense_fixup(rq);
1328 BUG(); 1237 /* Complain if we still have data left to transfer. */
1329 HWGROUP(drive)->rq = NULL; 1238 uptodate = rq->data_len ? 0 : 1;
1330 spin_unlock_irqrestore(&ide_lock, flags); 1239 }
1331 1240 goto end_request;
1332 return ide_stopped;
1333 } 1241 }
1334 1242
1335 /* 1243 /*
1336 * check which way to transfer data 1244 * check which way to transfer data
1337 */ 1245 */
1338 if (rq_data_dir(rq) == WRITE) { 1246 if (blk_pc_request(rq) && rq_data_dir(rq) == WRITE) {
1339 /* 1247 /*
1340 * write to drive 1248 * write to drive
1341 */ 1249 */
1342 if (cdrom_write_check_ireason(drive, len, ireason)) 1250 if (cdrom_write_check_ireason(drive, len, ireason))
1343 return ide_stopped; 1251 return ide_stopped;
1344 1252 } else if (blk_pc_request(rq)) {
1345 xferfunc = HWIF(drive)->atapi_output_bytes;
1346 } else {
1347 /* 1253 /*
1348 * read from drive 1254 * read from drive
1349 */ 1255 */
1350 if (cdrom_read_check_ireason(drive, len, ireason)) 1256 if (cdrom_read_check_ireason(drive, len, ireason))
1351 return ide_stopped; 1257 return ide_stopped;
1258 }
1352 1259
1260 if (ireason == 0) {
1261 write = 1;
1262 xferfunc = HWIF(drive)->atapi_output_bytes;
1263 } else if (ireason == 2 || (ireason == 1 && blk_pc_request(rq))) {
1264 write = 0;
1353 xferfunc = HWIF(drive)->atapi_input_bytes; 1265 xferfunc = HWIF(drive)->atapi_input_bytes;
1266 } else {
1267 printk(KERN_ERR "%s: %s: The drive "
1268 "appears confused (ireason = 0x%02x). "
1269 "Trying to recover by ending request.\n",
1270 drive->name, __FUNCTION__, ireason);
1271 goto end_request;
1354 } 1272 }
1355 1273
1356 /* 1274 /*
@@ -1399,14 +1317,41 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
1399 rq->data += blen; 1317 rq->data += blen;
1400 } 1318 }
1401 1319
1320 if (write && blk_sense_request(rq))
1321 rq->sense_len += thislen;
1322
1402 /* 1323 /*
1403 * pad, if necessary 1324 * pad, if necessary
1404 */ 1325 */
1405 if (len > 0) 1326 if (len > 0)
1406 ide_cd_pad_transfer(drive, xferfunc, len); 1327 ide_cd_pad_transfer(drive, xferfunc, len);
1407 1328
1408 ide_set_handler(drive, cdrom_newpc_intr, rq->timeout, NULL); 1329 if (blk_pc_request(rq)) {
1330 timeout = rq->timeout;
1331 expiry = NULL;
1332 } else {
1333 timeout = ATAPI_WAIT_PC;
1334 expiry = cdrom_timer_expiry;
1335 }
1336
1337 ide_set_handler(drive, cdrom_newpc_intr, timeout, expiry);
1409 return ide_started; 1338 return ide_started;
1339
1340end_request:
1341 if (blk_pc_request(rq)) {
1342 unsigned long flags;
1343
1344 spin_lock_irqsave(&ide_lock, flags);
1345 if (__blk_end_request(rq, 0, rq->data_len))
1346 BUG();
1347 HWGROUP(drive)->rq = NULL;
1348 spin_unlock_irqrestore(&ide_lock, flags);
1349 } else {
1350 if (!uptodate)
1351 rq->cmd_flags |= REQ_FAILED;
1352 cdrom_end_request(drive, uptodate);
1353 }
1354 return ide_stopped;
1410} 1355}
1411 1356
1412static ide_startstop_t cdrom_write_intr(ide_drive_t *drive) 1357static ide_startstop_t cdrom_write_intr(ide_drive_t *drive)