Fixed debug code
[gpxe.git] / src / drivers / block / ata.c
1 /*
2  * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 #include <stddef.h>
20 #include <string.h>
21 #include <byteswap.h>
22 #include <gpxe/blockdev.h>
23 #include <gpxe/ata.h>
24
25 /** @file
26  *
27  * ATA block device
28  *
29  */
30
31 static inline __attribute__ (( always_inline )) struct ata_device *
32 block_to_ata ( struct block_device *blockdev ) {
33         return container_of ( blockdev, struct ata_device, blockdev );
34 }
35
36 /**
37  * Issue ATA command
38  *
39  * @v ata               ATA device
40  * @v command           ATA command
41  * @ret rc              Return status code
42  */
43 static inline __attribute__ (( always_inline )) int
44 ata_command ( struct ata_device *ata, struct ata_command *command ) {
45         DBG ( "ATA cmd %02x dev %02x fl %02x LBA %llx count %04x\n",
46               command->cb.cmd_stat, command->cb.device, command->cb.flags,
47               ( unsigned long long ) command->cb.lba.native,
48               command->cb.count.native );
49
50         return ata->command ( ata, command );   
51 }
52
53 /**
54  * Read block from / write block to ATA device
55  *
56  * @v write             Write flag (ATA_FL_WRITE or 0)
57  * @v blockdev          Block device
58  * @v block             LBA block number
59  * @v count             Block count
60  * @v buffer            Data buffer
61  * @ret rc              Return status code
62  */
63 static __attribute__ (( regparm ( 1 ) )) int
64 ata_rw ( int write, struct block_device *blockdev, uint64_t block,
65          unsigned long count, userptr_t buffer ) {
66         struct ata_device *ata = block_to_ata ( blockdev );
67         struct ata_command command;
68         int lba48 = ( ata->flags & ATA_FL_LBA48 );
69
70         memset ( &command, 0, sizeof ( command ) );
71         command.cb.lba.native = block;
72         command.cb.count.native = count;
73         command.cb.device = ( ata->flags | ATA_DEV_OBSOLETE | ATA_DEV_LBA );
74         command.cb.flags = ( ata->flags | write );
75         command.cb.cmd_stat = ( write ? ATA_CMD_WRITE : ATA_CMD_READ );
76         if ( lba48 ) {
77                 command.cb.cmd_stat |= ATA_CMD_EXT;
78         } else {
79                 command.cb.device |= command.cb.lba.bytes.low_prev;
80         }
81         command.data = buffer;
82         command.data_len = ( count * blockdev->blksize );
83         return ata_command ( ata, &command );
84 }
85
86 /**
87  * Read block from ATA device
88  *
89  * @v blockdev          Block device
90  * @v block             LBA block number
91  * @v count             Block count
92  * @v buffer            Data buffer
93  * @ret rc              Return status code
94  */
95 static int ata_read ( struct block_device *blockdev, uint64_t block,
96                       unsigned long count, userptr_t buffer ) {
97         /* Pass through to ata_rw().  Since ata_rw is regparm(1), this
98          * is extremely efficient; just a mov and a jmp.
99          */
100         return ata_rw ( 0, blockdev, block, count, buffer );
101 }
102
103 /**
104  * Write block to ATA device
105  *
106  * @v blockdev          Block device
107  * @v block             LBA block number
108  * @v count             Block count
109  * @v buffer            Data buffer
110  * @ret rc              Return status code
111  */
112 static int ata_write ( struct block_device *blockdev, uint64_t block,
113                        unsigned long count, userptr_t buffer ) {
114         /* Pass through to ata_rw().  Since ata_rw is regparm(1), this
115          * is extremely efficient; just a mov and a jmp.
116          */
117         return ata_rw ( ATA_FL_WRITE, blockdev, block, count, buffer );
118 }
119
120 /**
121  * Identify ATA device
122  *
123  * @v blockdev          Block device
124  * @ret rc              Return status code
125  */
126 static int ata_identify ( struct block_device *blockdev ) {
127         struct ata_device *ata = block_to_ata ( blockdev );
128         struct ata_command command;
129         struct ata_identity identity;
130         int rc;
131
132         /* Issue IDENTIFY */
133         memset ( &command, 0, sizeof ( command ) );
134         command.cb.device = ( ata->flags | ATA_DEV_OBSOLETE | ATA_DEV_LBA );
135         command.cb.cmd_stat = ATA_CMD_IDENTIFY;
136         command.data = virt_to_user ( &identity );
137         command.data_len = sizeof ( identity );
138         if ( ( rc = ata_command ( ata, &command ) ) != 0 )
139                 return rc;
140
141         /* Fill in block device parameters */
142         blockdev->blksize = ATA_SECTOR_SIZE;
143         if ( identity.supports_lba48 & cpu_to_le16 ( ATA_SUPPORTS_LBA48 ) ) {
144                 ata->flags |= ATA_FL_LBA48;
145                 blockdev->blocks = le64_to_cpu ( identity.lba48_sectors );
146         } else {
147                 blockdev->blocks = le32_to_cpu ( identity.lba_sectors );
148         }
149         return 0;
150 }
151
152 /**
153  * Initialise ATA device
154  *
155  * @v ata               ATA device
156  * @ret rc              Return status code
157  *
158  * Initialises an ATA device.  The ata_device::command field and the
159  * @c ATA_FL_SLAVE portion of the ata_device::flags field must already
160  * be filled in.  This function will configure ata_device::blockdev,
161  * including issuing an IDENTIFY DEVICE call to determine the block
162  * size and total device size.
163  */
164 int init_atadev ( struct ata_device *ata ) {
165         /** Fill in read and write methods, and get device capacity */
166         ata->blockdev.read = ata_read;
167         ata->blockdev.write = ata_write;
168         return ata_identify ( &ata->blockdev );
169 }